AlexFSmirnov icon

Module Import Check

AlexFSmirnov | PRO | 05/14/21 10:35:20 AM UTC | 0 ⭐ | 963 👁️ | Never ⏰ | []
Python |

3.85 KB

|

None

|

0 👍

/

0 👎

import re
import os
import sys
import argparse
 
FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx']
 
parser = argparse.ArgumentParser(description='Detects invalid dependencies of a module')
parser.add_argument('-r', '--root', required=True, help='Path to the directory of the whole project')
parser.add_argument('-m', '--module', required=True, help='Path to the directory of the target module')
 
def get_path_from_import_line(import_line):
    matches = re.findall('[\'"](.+?)[\'"]', import_line)
    if len(matches) == 0:
        return None
 
    path = matches[0]
    if not path.startswith('.'):
        return None
 
    return path
 
def get_absolute_path_from_import_path(filepath, import_path):
    dir_path = os.path.dirname(filepath)
    absolute_import_path = os.path.join(dir_path, import_path)
    return os.path.normpath(absolute_import_path)
 
def get_imports(filepath):
    if os.path.splitext(filepath)[1] not in FILE_EXTENSIONS:
        return []
 
    imports = []
    with open(filepath, 'r') as fin:
        for i, code_line in enumerate(fin.readlines()):
            import_matches = re.findall('} from [\'"].+?[\'"];', code_line)
 
            if len(import_matches) == 0:
                continue
 
            import_relative_path = get_path_from_import_line(import_matches[0])
            if import_relative_path is not None:
                imports.append({
                    'line_number': i + 1,
                    'path': get_absolute_path_from_import_path(filepath, import_relative_path)
                })
 
    return imports
 
def is_importing_from_module_subdir(module_path, import_path):
    return import_path.startswith(module_path)
 
def is_importing_from_module(module_path, import_path):
    return import_path == module_path
 
def main(root_path, module_path):
    check_passed = True
 
    # Check that all external imports only import from the module's index file
    for dir_path, _, files in os.walk(root_path):
        if os.path.normpath(dir_path).startswith(module_path):
            continue
 
        for file in files:
            filepath = os.path.join(dir_path, file)
            imports = get_imports(filepath)
 
            errors = []
            for import_item in imports:
                if is_importing_from_module_subdir(module_path, import_item['path']) and not is_importing_from_module(module_path, import_item['path']):
                    errors.append(import_item)
 
            if len(errors) > 0:
                print(f'Incorrect imports from module subdir in {filepath}:')
                for import_item in errors:
                    print(f"  Line {import_item['line_number']}: '{import_item['path']}' should be '{module_path}'")
 
                check_passed = False
                print()
 
    # Check that there are files in the module that import something from outside the module
    for dir_path, _, files in os.walk(module_path):
        break
        for file in files:
            filepath = os.path.join(dir_path, file)
            imports = get_imports(filepath)
 
            errors = []
            for import_item in imports:
                if not is_importing_from_module_subdir(module_path, import_item['path']):
                    errors.append(import_item)
 
            if len(errors) > 0:
                print(f'Invalid external imports from module file {filepath}:')
                for import_item in errors:
                    print(f"  Line {import_item['line_number']}: '{import_item['path']}'")
 
                check_passed = False
                print()
 
    if not check_passed:
        sys.exit('Script failed: Not all imports are correct.')
    
    print('All imports are correct.')
 
if __name__ == '__main__':
    args = parser.parse_args()
    main(
        os.path.normpath(args.root),
        os.path.normpath(args.module)
    )

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎