diff --git a/src/codesnap/core/dependency_graph.py b/src/codesnap/core/dependency_graph.py index c7b5810..3d5e40f 100644 --- a/src/codesnap/core/dependency_graph.py +++ b/src/codesnap/core/dependency_graph.py @@ -1,33 +1 @@ -from __future__ import annotations - -import ast -from collections import defaultdict -from pathlib import Path -from codesnap.core.models import DependencyInfo - - -class DependencyGraph: - def __init__(self): - self.graph: dict[str, set[str]] = defaultdict(set) - self.file_modules: dict[str, str] = {} - - def add_file(self, file_path: Path, tree: ast.AST): - module_name = file_path.stem - self.file_modules[str(file_path)] = module_name - - for node in ast.walk(tree): - if isinstance(node, ast.Import): - for alias in node.names: - self.graph[module_name].add(alias.name) - elif isinstance(node, ast.ImportFrom): - module = node.module or "" - self.graph[module_name].add(module) - - def get_dependencies(self, file_path: Path) -> list[DependencyInfo]: - module_name = self.file_modules.get(str(file_path), file_path.stem) - deps = self.graph.get(module_name, set()) - - return [DependencyInfo(name=dep) for dep in deps] - - def visualize(self) -> dict[str, list[str]]: - return {k: list(v) for k, v in self.graph.items()} +I3sgRGVwZW5kZW5jeSBncmFwaCBhbmFseXNpcyBtb2R1bGUgZm9yIENvZGVTTmFwLicKCiAgICBmcm9tIF9faW5pdF9fIGltcG9ydCBhbm5vdGF0aW9ucwoKICAgIGltb3J0IHJlCiAgICBmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MsIGZpZWxkCiAgICBmcm9tIHBhdGhsYiBJbXBvcnQgUGF0aAoKICAgIGltcG9ydCBuZXR3b3JrX3ggbngKCiMgRGVwZW5kZW5jeQpgZGF0YWNsYXNzCmNsYXNzIERlcGVuZGVuY3k6CiAgICAicmVwcmVzZW50cyBhIGRlcGVuZGVuY3kgYmV0d2VlbiBmaWxlcy4iCiAgICBzb3VyY2VfZmlsZTogUGF0aAogICAgdGFyZ2V0X2ZpbGU6IFBhdGgKICAgIGltcG9ydF9zdGF0ZW1lbnQ6IHN0cgogICAgaW1wb3J0X3R5cGU6IHN0ciA9ICJpbXBvcnQiCgpgZGF0YWNsYXNzCmNsYXNzIEZpbGVOb2RlOgogICAgInJlcHJlc2VudHMgYSBmaWxlIGluIHRoZSBkZXBlbmRlbmN5IGdyYXBoLiIKCiAgICBwYXRoOiBQYXRoCiAgICBsYW5ndWFnZTogc3RyCiAgICBmaWxlX3NpemU6IGludCA9IDAKICAgIGxpbmVfY291bnQ6IGludCA9IDAKICAgIGZ1bmN0aW9uc19jb3VudDogaW50ID0gMAogICAgY2xhc3Nlcy1jb3VudDogaW50ID0gMAoKYGRhdGFjbGFzcwpjbGFzcyBHcmFwaE1ldHJpY3M6CiAgICAibWV0cmljcyBmb3IgdGhlIGRlcGVuZGVuY3kgZ3JhcGguIgogICAgdG90YWxfZmlsZXM6IGludCA9IDAKICAgIHRvdGFsX2VkZ2VzOiBpbnQgPSAwCiAgICBvcHBoYW5lZF9maWxlczogbGlzdFtQYXRoXSA9IGZpZWxkKGRlZmF1bHRfZmFjdG9yeT1saXN0KQogICAgY2lyY3VsYXJfZGVwZW5kZW5jaWVzOiBsaXN0W2xpc3RbUGF0aF1dXSA9IGZpZWxkKGRlZmF1bHRfZmFjdG9yeT1saXN0KQogICAgbWF4X2RlcHRoOiBpbnQgPSAwCiAgICBkZW5zaXR5OiBmbG9hdCA9IDAuMAoKCmNsYXNzIERlcGVuZGVuY3lQYXJzZXI6CiAgICAicGFyc2VyIGZvciBleHRyYWN0aW5nIGltcG9ydC9yZXF1aXJlIHN0YXRlbWVudHMgZnJvbSBmaWxlcy4iCgogICAgSU1QT1JUX1BBVFRFUk5TOiBkaWN0W3N0ciwgdHVwbGVbcmUuUGF0dGVybiwgc3RyXV0gPSB7CiAgICAgICAgInB5dGhvbiI6ICgKICAgICAgICAgICAgcmUuY29tcGlsZSgKICAgICAgICAgICAgICAgICdeKD86ZnJvbVxcLnswLDFbYS1aQTAtOV9dKyBcXGlmcm9tXFxcL3thLXpBLTEwX2JdKiknLAogICAgICAgICAgICAgICAgcmVfbXVsdGlsaW5lCiAgICAgICAgICApLAogICAgICAgICAgICAiaW1wb3J0IgogICAgICAgICksCiAgICAgICAgImpldmFzc2NyaXB0IjogKAogICAgICAgICAgICByZS5jb21waWxlKAogICAgICAgICAgICAgICAgJyg/OmVxdWlyZVxcKChcXCcqW15cXCcqXSpcXCdcXCdcXHxcXHcpJyArCiAgICAgICAgICAgICAgICgnKD86aW1wb3J0XFxiez9cfXxdXFxcKiBhcyBcdytcXC9cXC98XFx3KylcXHMmZnJvbVxcLiopW15cXCcqXSpcXCcqXSInLAogICAgICAgICAgICAgICAgcmVfbXVsdGlsaW5lCiAgICAgICAgICApLAogICAgICAgICAgICAicmVxdWlyZS9pbXBvcnQiCiAgICAgICAgKSwKICAgICAgICAidHlwZXNjcmlwdCI6ICgKICAgICAgICAgICAgcmUuY29tcGlsZSgKICAgICAgICAgICAgICAgICcoPzplcXVpcmVcXChcXHMqW15cXCcqXSpcXCdcXCdcXHxcXHcpJyArCiAgICAgICAgICAgICAgICgnKD86aW1wb3J0XFxiez9cfXxdXFxcKiBhcyBcdytcXC9cXC98XFx3KylcXHMmZnJvbVxcLiopW15cXCcqXSpcXCcqXSInLAogICAgICAgICAgICAgICAgcmVfbXVsdGlsaW5lCiAgICAgICAgICApLAogICAgICAgICAgICAiaW1wb3J0IgogICAgICAgICksCiAgICAgICAgImdvIjogKAogICAgICAgICAgICByZS5jb21waWxlKAogICAgICAgICAgICAgICAgJ15cXHMrPmltcG9ydFxcW15cXCcqXSpcXCcqJywKICAgICAgICAgICAgICAgIHJlX211bHRpbGluZQogICAgICAgICAgKSwKICAgICAgICAgICAgImltcG9ydCIKICAgICAgICApLAogICAgICAgICJydXN0IjogKAogICAgICAgICAgICByZS5jb21waWxlKAogICAgICAgICAgICAgICAgJyg/OnVzZVxcKChbYS1aQTAtOV86XSspJyArCiAgICAgICAgICAgICAgICgnZXh0ZXJuXFxcY3JhdGVcXChbYS1aQTAtOV9dKyknLAogICAgICAgICAgICAgICAgcmVfbXVsdGlsaW5lCiAgICAgICAgICApLAogICAgICAgICAgICAidXNlL2NyYXRlIgogICAgICAgICksCiAgICAgICAgImphdmEiOiAoCiAgICAgICAgICAgIHJlLmNvbXBpbGUoCiAgICAgICAgICAgICAgICdeXFxzKig/OmltcG9ydFxcKFthLXpBLTEwXy5dKykcXCpcXCk/JCksCiAgICAgICAgICAgICAgICByZV9tdWx0aWxpbmUKICAgICAgICApLAogICAgICAgICAgICAiaW1wb3J0IgogICAgICAgICksCiAgICB9CgogICAgZGVmIF9faW5pdF9fKHNlbGYpOgogICAgICAgIHNlbGYuX2ltcG9ydF9wYXR0ZXJucyA9IHNlbGYuSU1QT1JUX1BVVEVSTlMKCiAgICBkZWYgcGFyc2VfZmlsZShzZWxmLCBmaWxlX3BhdGg6IFBhdGgsIGNvbnRlbnQ6IHN0ciwgbGFuZ3VhZ2U6IHN0cikgLT4gbGlzdFtEZXBlbmRlbmN5XToKICAgICAgICAiYWRkIGEgZmlsZSBub2RlIHRvIHRoZSBncmFwaC4iCiAgICAgICAgZGVwZW5kZW5jaWVzID0gW10KICAgICAgICBwYXR0ZXJuX2luZm8gPSBzZWxmLmltcG9ydF9wYXR0ZXJucy5nZXQobGFuZ3VhZ2UpCgoKICAgICAgICBpZiBwYXR0ZXJuX2luZm8gaXMgTm9uZToKICAgICAgICAgICAgcmV0dXJuIGRlcGVuZGVuY2llcwoKICAgICAgICBwYXR0ZXJuLCBpbXBvcnRfdHlwZSA9IHBhdHRlcm5faW5mbwoKICAgICAgICBmb3IgbWF0Y2ggaW4gcGF0dGVybi5maW5kYWxsKGNvbnRlbnQpOgogICAgICAgICAgICBncm91cHMgPSBtYXRjaC5ncm91cHMKICAgICAgICAgICAgaW1wb3J0X3RhcmdldCA9IE5vbmUKCiAgICAgICAgICAgIGZvciBncm91cCBpbiBncm91cHM6CiAgICAgICAgICAgICAgICBpZiBncm91cDoKICAgICAgICAgICAgICAgICAgICBpbXBvcnRfdGFyZ2V0ID0gZ3JvdXAKICAgICAgICAgICAgICAgICAgICBicmVhawoKICAgICAgICBpZiBpbXBvcnRfdGFyZ2V0OgogICAgICAgICAgICBkZXBlbmRlbmN5ID0gRGVwZW5kZW5jeSgKICAgICAgICAgICAgICAgIHNvdXJjZV9maWxlID0gZmlsZV9wYXRoLAogICAgICAgICAgICAgICAgdGFyZ2V0X2ZpbGUgPSBQYXRoKGltcG9ydF90YXJnZXQpLAogICAgICAgICAgICAgICAgaW1wb3J0X3N0YXRlbWVudCA9IG1hdGNoLmdyb3VwKDEpLAogICAgICAgICAgICAgICAgaW1wb3J0X3R5cGUgPSBpbXBvcnRfdHlwZQogICAgICAgICAgICApCiAgICAgICAgICAgIGRlcGVuZGVuY2llcy5hcHBlbmQoZGVwZW5kZW5jeSkKCiAgICAgICAgcmV0dXJuIGRlcGVuZGVuY2llcwoKY2xhc3MgRGVwZW5kZW5jeUdyYXBoQnVpbGRlcjoKICAgICJidWlsZGVyIGZvciBjcmVhdGluZyBhbmQgYW5hbHl6aW5nIGRlcGVuZGVuY3kgZ3JhcGhzLiIKCiAgICBkZWYgX19pbml0X19fc2VsZik6CiAgICAgICAgc2VsZi5ncmFwaCA9IG54LkRpR3JhcGgoKQogICAgICAgIHNlbGYubm9kZV9kYXRhOiBkaWN0W1BhdGgsIEZpbGVPbmRdID0ge30KICAgICAgICBzZWxmLmRlcGVuZGVuY3lfcGFyc2VyID0gRGVwZW5kZW5jeVBhcnNlcigpCgogICAgZGVmIGFkZF9maWxlKHNlbGYsIGZpbGVfcGF0aDogUGF0aCwgbGFuZ3VhZ2U6IHN0ciwgZmlsZV9zaXplOiBpbnQgPSAwLAogICAgICAgICAgbGluZV9jb3VudDogaW50ID0gMCwgZnVuY3Rpb25zX2NvdW50OiBpbnQgPSAwLAogICAgICAgICAgY2xhc3Nlc19jb3VudDogaW50ID0gMCkgLT4gTm9uZToKICAgICAgICAiYWRkIGEgZmlsZSBub2RlIHRvIHRoZSBncmFwaC4iCiAgICAgICAgbm9kZSA9IEZpbGVOb2RlKAogICAgICAgICAgICBwYXRoID0gZmlsZV9wYXRoLAogICAgICAgICAgICBsYW5ndWFnZSA9IGxhbmd1YWdlLAogICAgICAgICAgICBmaWxlX3NpemUgPSBmaWxlX3NpemUsCiAgICAgICAgICAgIGxpbmVfY291bnQgPSBsaW5lX2NvdW50LAogICAgICAgICAgICBmdW5jdGlvbnNfY291bnQgPSBmdW5jdGlvbnNfY291bnQsCiAgICAgICAgICAgIGNsYXNzZXNfY291bnQgPSBjbGFzc2VzX2NvdW50CiAgICAgICAgKQoKICAgICAgICBzZWxmLm5vZGVfZGF0YVtm/aWxlX3BhdGhdID0gbm9kZQogICAgICAgIHNlbGYuZ3JhcGguYWRkX25vZGUoZmlsZV9wYXRoLCAqKHsKICAgICAgICAgICAgImxhbmd1YWdlIjogbGFuZ3VhZ2UsCiAgICAgICAgICAgICJmaWxlX3NpemUiOiBmaWxlX3NpemUsCiAgICAgICAgICAgICJsaW5lX2NvdW50IjogbGluZV9jb3VudCwKICAgICAgICAgICAgImZ1bmN0aW9uc19jb3VudCI6IGZ1bmN0aW9uc19jb3VudCwKICAgICAgICAgICAgImNsYXNzZXNfY291bnQiOiBjbGFzc2VzX2NvdW50CiAgICAgICAgfSkKCiAgICBkZWYgYWRkX2RlcGVuZGVuY3koc2VsZiwgZGVwZW5kZW5jeTogRGVwZW5kZW5jeSwKICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZWRfdGFyZ2V0OiBQYXRoIHwgTm9uZSA9IE5vbmUpIC0+IE5vbmU6CiAgICAgICAgImFkZCBhbiBlZGdlIHRvIHRoZSBncmFwaCByZXByZXNlbnRpbmcgYSBkZXBlbmRlbmN5LgogICAgICAgIHRhcmdldCA9IHJlc29sdmVkdF90YXJnZXQgaWYgcmVzb2x2ZWRfdGFyZ2V0IGVsc2UgZGVwZW5kZW5jeS50YXJnZXRfZmlsZQogICAgICAgIHNlbGYuZ3JhcGguYWRkX2VkZ2UoZGVwZW5kZW5jeS5zb3VyY2VfZmlsZSwgdGFyZ2V0LCAqKHsKICAgICAgICAgICAgImltcG9ydF9zdGF0ZW1lbnQiOiBkZXBlbmRlbmN5LmltcG9ydF9zdGF0ZW1lbnQsCiAgICAgICAgICAgICJpbXBvcnRfdHlwZSI6IGRlcGVuZGVuY3kuaW1wb3J0X3R5cGUKICAgICAgICB9KQoKICAgIGRlZiBhZGRfZGVwZW5kZW5jaWVzKHNlbGYsIGRlcGVuZGVuY2llczogbGlzdFtEZXBlbmRlbmN5XSwKICAgICAgICAgICAgICAgICAgcmVzb2x2ZXI6IGNhbGxhYmxlIHwgTm9uZSA9IE5vbmUpIC0+IE5vbmU6CiAgICAgICAgImFkZCBtdWx0aXBsZSBkZXBlbmRlbmNpZXMgdG8gdGhlIGdyYXBoLgogICAgICAgIGZvciBkZXAgaW4gZGVwZW5kZW5jaWVzOgogICAgICAgICAgICByZXNvbHZlZCA9IE5vbmUKICAgICAgICAgICAgaWYgcmVzb2x2ZXI6CiAgICAgICAgICAgICAgICByZXNvbHZlZCA9IHJlc29sdmVyKGRlcC50YXJnZXRfZmlsZSwgZGVwLnNvdXJjZV9maWxlKQogICAgICAgICAgICBzZWxmLmFkZF9kZXBlbmRlbmN5KGRlcCwgcmVzb2x2ZWQpCgogICAgZGVmIGJ1aWxkX2Zyb21fYW5hbHlzaXMoc2VsZiwgYW5hbHlzaXNfcmVzdWx0OiBkaWN0KSAtPiBOb25lOgogICAgICAgICJidWlsZCB0aGUgZ3JhcGggZnJvbSBhIGZ1bGwgYW5hbHlzaXMgcmVzdWx0LgogICAgICAgIGZvciBmaWxlX2luZm8gaW4gYW5hbHlzaXNfcmVzdWx0LmdldCgiZmlsZXMiLCBbXSk6CiAgICAgICAgICAgIGZpbGVfcGF0aCA9IFBhdGgoZmlsZV9pbmZvWyJwYXRoIl0pCiAgICAgICAgICAgIHNlbGYuYWRkX2ZpbGUoCiAgICAgICAgICAgICAgICBmaWxlX3BhdGggPSBmaWxlX3BhdGgsCiAgICAgICAgICAgICAgICBsYW5ndWFnZSA9IGZpbGVfaW5mby5nZXQoImxhbmd1YWdlIiwgInVua25vd24iKSwKICAgICAgICAgICAgICAgIGZpbGVfc2l6ZSA9IGZpbGVfaW5mby5nZXQoInNpemUiLCAwKSwKICAgICAgICAgICAgICAgIGxpbmVfY291bnQgPSBmaWxlX2luZm8uZ2V0KCJsaW5lcyIsIDApLAogICAgICAgICAgICAgICAgZnVuY3Rpb25zX2NvdW50ID0gbGVuKGZpbGVfaW5mby5nZXQoImZ1bmN0aW9ucyIsIFtdKSksCiAgICAgICAgICAgICAgICBjbGFzc2VzX2NvdW50ID0gbGVuKGZpbGVfaW5mby5nZXQoImNsYXNzZXMiLCBbXSkpCiAgICAgICAgICApCgogICAgICAgIGZvciBkZXBfaW5mbyBpbiBhbmFseXNpc19yZXN1bHQuZ2V0KCJkZXBlbmRlbmNpZXMiLCBbXSk6CiAgICAgICAgICAgIHNvdXJjZSA9IFBhdGgoZGVwX2luZm9bInNvdXJjZSJdKQogICAgICAgICAgICB0YXJnZXQgPSBQYXRoKGRlcF9pbmZvWyJ0YXJnZXQiXSkKICAgICAgICAgICAgc2VsZi5ncmFwaC5hZGRfZWRnZShzb3VyY2UsIHRhcmdldCkKCiAgICBkZWYgZmluZF9vcHBoYW5lZF9maWxlcyhzZWxmKSAtPiBsaXN0W1BhdGhdOgogICAgICAgICJmaW5kIGZpbGVzIHdpdGggbm8gZGVwZW5kZW5jaWVzIHRvIG9yIGZyb20gb3RoZXIgZmlsZXMuCiAgICAgICAgcmV0dXJuIG9ycGhhbmVkCgogICAgZGVmIGZpbmRfY3ljbGVzKHNlbGYpIC0+IGxpc3RbbGlzdFtQYXRoXV06CiAgICAgICAgImZpbmQgYWxsIGN5Y2xlcyBpbiB0aGUgZGVwZW5kZW5jeSBncmFwaC4KICAgICAgICByZXR1cm4gY3ljbGVzCgogICAgZGVmIGNhbGN1bGF0ZV9tZXRyaWNzKHNlbGYpIC0+IEdyYXBoTWV0cmljczogCiAgICAgICAgImNhbGN1bGF0ZSBtZXRyaWNzIGZvciB0aGUgZGVwZW5kZWNyeSBncmFwaC4KCiAgICAgICAgbWV0cmljcyA9IEdyYXBoTWV0cmljcygpCgogICAgICAgIG1ldHJpY3MudG90YWxfZmlsZXMgPSBzZWxmLmdyYXBoLm51bWJlcl9vZl9ub2RlcygpCiAgICAgICAgbWV0cmljcy50b3RhbF9lZGdlcyA9IHNlbGYuZ3JhcGguY291bnRfb2ZfZWRnZXMoKQoKICAgICAgICBtZXRyaWNzLm9ycGhhbmVkX2ZpbGVzID0gc2VsZi5maW5kX29ycGhhbmVkX2ZpbGVzKCkKICAgICAgICBtZXRyaWNzLmNpcmN1bGFyX2RlcGVuZGVuY2llcyA9IHNlbGYuZmluZF9jeWNsZXMoKQoKICAgICAgICBpZiBzZWxmLmdyYXBoLm51bWJlcl9vZl9ub2RlcygpID4gMDoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgbWV0cmljcy5tYXhfZGVwdGggPSBueC5kYWdfbG9uZ2VzdF9wYXRoX2xlbmd0aChzZWxmLmdyYXBoKQogICAgICAgICAgICBleGNlcHQgbnguTmV0d29ya1hFcnJvcjoKICAgICAgICAgICAgICAgIG1ldHJpY3MubWF4X2RlcHRoID0gMAoKICAgICAgICBpZiBzZWxmLmdyYXBoLm51bWJlcl9vZl9ub2RlcygpID4gMDoKICAgICAgICAgICAgbWF4X3Bvc3NpYmxlX2VkZ2VzID0gc2VsZi5ncmFwaC5udW1iZXJfb2Zfbm9kZXMoKSAqIChzZWxmLmdyYXBoLm51bWJlcl9vZl9ub2RlcygpIC0gMSkKICAgICAgICAgICAgaWYgbWF4X3Bvc3NpYmxlX2VkZ2VzID4gMDoKICAgICAgICAgICAgICAgIG1ldHJpY3MuZGVuc2l0eSA9IHNlbGYuZ3JhcGguY291bnRfb2ZfZWRnZXMoKSAvIG1heF9wb3NzaWJsZV9lZGdlcwoKICAgICAgICByZXR1cm4gbWV0cmljcwoKICAgIGRlZiBnZXRfdHJhbnNpdGl2ZV9jbG9zdXJlKHNlbGYsIGZpbGVfcGF0aDogUGF0aCkgLT4gc2V0W1BhdGhdOgogICAgICAgICJnZXQgYWxsIGZpbGVzIHRoYXQgZGVwZW5kIG9uIChkaXJlY3RseSBvciBpbmRpcmVjdGx5KSB0aGUgZ2l2ZW4gZmlsZS4KCiAgICAgICAgcmV0dXJuIGRlc2NlbmRhbnRzCgogICAgZGVmIGdldF9kZXBlbmRlbmNpZXMoc2VsZiwgZmlsZV9wYXRoOiBQYXRoKSAtPiBzZXRbUGF0aF06CiAgICAgICAgImdldCBhbGwgZmlsZXMgdGhhdCB0aGUgZ2l2ZW4gZmlsZSBkZXBlbmRzIG9uIChkaXJlY3RseSBvciBpbmRpcmVjdGx5KS4KCiAgICAgICAgcmV0dXJuIGFuY2VzdG9ycwoKICAgIGRlZiB0b19kb3Qoc2VsZikgLT4gc3RyOgogICAgICAgICJleHBvcnQgdGhlIGdyYXBoIGluIERPVCBmb3JtYXQgZm9yIHZpc3VhbGl6YXRpb24uCgogICAgICAgIHJldHVybiBueC5kcmF3aW5nLm5iX3hwdG8udG9fcHlkb3Qoc2VsZi5ncmFwaCkudG9fc3RyaW5nKQo= \ No newline at end of file