import ast
from pathlib import Path
from collections import defaultdict
def extract_imports(filepath):
try:
source = Path(filepath).read_text(encoding="utf-8")
tree = ast.parse(source)
except Exception:
return []
imports = []
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
imports.append(alias.name.split(".")[0])
elif isinstance(node, ast.ImportFrom):
if node.module:
imports.append(node.module.split(".")[0])
return imports
def analyze_project(project_dir):
deps = defaultdict(set)
py_files = list(Path(project_dir).rglob("*.py"))
project_modules = {f.stem for f in py_files}
for py_file in py_files:
module_name = py_file.stem
for imp in extract_imports(str(py_file)):
if imp in project_modules and imp != module_name:
deps[module_name].add(imp)
return dict(deps)
# 実行例
deps = analyze_project(".")
print("# モジュール依存関係")
for module, depends_on in sorted(deps.items()):
if depends_on:
print(f" {module:30s} -> {', '.join(sorted(depends_on))}")