AlexFSmirnov

Module Import Check

May 14th, 2021
625
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import re
  2. import os
  3. import sys
  4. import argparse
  5.  
  6. FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx']
  7.  
  8. parser = argparse.ArgumentParser(description='Detects invalid dependencies of a module')
  9. parser.add_argument('-r', '--root', required=True, help='Path to the directory of the whole project')
  10. parser.add_argument('-m', '--module', required=True, help='Path to the directory of the target module')
  11.  
  12. def get_path_from_import_line(import_line):
  13.     matches = re.findall('[\'"](.+?)[\'"]', import_line)
  14.     if len(matches) == 0:
  15.         return None
  16.  
  17.     path = matches[0]
  18.     if not path.startswith('.'):
  19.         return None
  20.  
  21.     return path
  22.  
  23. def get_absolute_path_from_import_path(filepath, import_path):
  24.     dir_path = os.path.dirname(filepath)
  25.     absolute_import_path = os.path.join(dir_path, import_path)
  26.     return os.path.normpath(absolute_import_path)
  27.  
  28. def get_imports(filepath):
  29.     if os.path.splitext(filepath)[1] not in FILE_EXTENSIONS:
  30.         return []
  31.  
  32.     imports = []
  33.     with open(filepath, 'r') as fin:
  34.         for i, code_line in enumerate(fin.readlines()):
  35.             import_matches = re.findall('} from [\'"].+?[\'"];', code_line)
  36.  
  37.             if len(import_matches) == 0:
  38.                 continue
  39.  
  40.             import_relative_path = get_path_from_import_line(import_matches[0])
  41.             if import_relative_path is not None:
  42.                 imports.append({
  43.                     'line_number': i + 1,
  44.                     'path': get_absolute_path_from_import_path(filepath, import_relative_path)
  45.                 })
  46.  
  47.     return imports
  48.  
  49. def is_importing_from_module_subdir(module_path, import_path):
  50.     return import_path.startswith(module_path)
  51.  
  52. def is_importing_from_module(module_path, import_path):
  53.     return import_path == module_path
  54.  
  55. def main(root_path, module_path):
  56.     check_passed = True
  57.  
  58.     # Check that all external imports only import from the module's index file
  59.     for dir_path, _, files in os.walk(root_path):
  60.         if os.path.normpath(dir_path).startswith(module_path):
  61.             continue
  62.  
  63.         for file in files:
  64.             filepath = os.path.join(dir_path, file)
  65.             imports = get_imports(filepath)
  66.  
  67.             errors = []
  68.             for import_item in imports:
  69.                 if is_importing_from_module_subdir(module_path, import_item['path']) and not is_importing_from_module(module_path, import_item['path']):
  70.                     errors.append(import_item)
  71.  
  72.             if len(errors) > 0:
  73.                 print(f'Incorrect imports from module subdir in {filepath}:')
  74.                 for import_item in errors:
  75.                     print(f"  Line {import_item['line_number']}: '{import_item['path']}' should be '{module_path}'")
  76.  
  77.                 check_passed = False
  78.                 print()
  79.  
  80.     # Check that there are files in the module that import something from outside the module
  81.     for dir_path, _, files in os.walk(module_path):
  82.         break
  83.         for file in files:
  84.             filepath = os.path.join(dir_path, file)
  85.             imports = get_imports(filepath)
  86.  
  87.             errors = []
  88.             for import_item in imports:
  89.                 if not is_importing_from_module_subdir(module_path, import_item['path']):
  90.                     errors.append(import_item)
  91.  
  92.             if len(errors) > 0:
  93.                 print(f'Invalid external imports from module file {filepath}:')
  94.                 for import_item in errors:
  95.                     print(f"  Line {import_item['line_number']}: '{import_item['path']}'")
  96.  
  97.                 check_passed = False
  98.                 print()
  99.  
  100.     if not check_passed:
  101.         sys.exit('Script failed: Not all imports are correct.')
  102.    
  103.     print('All imports are correct.')
  104.  
  105. if __name__ == '__main__':
  106.     args = parser.parse_args()
  107.     main(
  108.         os.path.normpath(args.root),
  109.         os.path.normpath(args.module)
  110.     )
RAW Paste Data