1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
# Copyright (c) 2026 Juancarlo AƱez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
from __future__ import annotations
import ast
import sys
from pathlib import Path
from typing import NamedTuple
class ModuleImports(NamedTuple):
name: str
path: Path
imports: tuple[str, ...]
def pathtomodulename(path: Path):
return str(path.with_suffix('')).replace('/', '.').replace('.__init__', '')
def moduledeps(name: str, path: Path, level: int = 1) -> ModuleImports:
source = path.read_text()
module = ast.parse(source, filename=name)
assert isinstance(module, ast.Module), module
def imported(fromimport: ast.ImportFrom) -> tuple[str, ...]:
if fromimport.module:
return (fromimport.module,)
return tuple(alias.name for alias in fromimport.names)
imports = {
imp
for s in module.body
if isinstance(s, ast.ImportFrom) and s.level >= level
for imp in imported(s)
}
imports = tuple(sorted(imports))
return ModuleImports(name=name, path=path, imports=imports)
def findeps(paths: list[Path], level: int = 1) -> list[ModuleImports]:
modulepaths = sorted((pathtomodulename(path), path) for path in paths)
return [moduledeps(name, path, level=level) for name, path in modulepaths]
def main(filenames: list[str]) -> None:
paths = [Path(filename) for filename in filenames]
for module in findeps(paths):
print(f'{module.name}: {module.imports}')
if __name__ == '__main__':
if not sys.argv[1:]:
print(f'usage:\n python3 {Path(__file__).name} FILENAME...')
sys.exit(1)
main(sys.argv[1:])
|