Skip to content

Commit 51ae1cb

Browse files
fix: forgot to 'poetry add click' as a dependency!
1 parent 49e2014 commit 51ae1cb

File tree

4 files changed

+77
-12
lines changed

4 files changed

+77
-12
lines changed

codegraph/core.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
from argparse import Namespace
3-
from collections import defaultdict
4-
from typing import Dict, List, Text, Tuple
3+
from collections import defaultdict, deque
4+
from typing import Dict, List, Set, Text, Tuple
55

66
from codegraph.parser import Import, create_objects_array
77
from codegraph.utils import get_python_paths_list
@@ -36,7 +36,7 @@ def get_code_objects(paths_list: List) -> Dict:
3636

3737
class CodeGraph:
3838
def __init__(self, args: Namespace):
39-
self.paths_list = get_python_paths_list(args.paths)
39+
self.paths_list = get_python_paths_list(args["paths"])
4040
# get py modules list data
4141
self.modules_data = get_code_objects(self.paths_list)
4242

@@ -87,6 +87,42 @@ def usage_graph(self) -> Dict:
8787
dependencies = populate_free_nodes(self.modules_data, dependencies)
8888
return dependencies
8989

90+
def get_dependencies(self, file_path: str, distance: int) -> Dict[str, Set[str]]:
91+
"""
92+
Get dependencies that are 'distance' nodes away from the given file.
93+
94+
:param file_path: Path of the file to start from
95+
:param distance: Number of edges to traverse
96+
:return: Dictionary with distances as keys and sets of dependent files as values
97+
"""
98+
dependencies = {i: set() for i in range(1, distance + 1)}
99+
graph = self.usage_graph()
100+
101+
if file_path not in graph:
102+
return dependencies
103+
104+
queue = deque([(file_path, 0)])
105+
visited = set()
106+
107+
while queue:
108+
current_file, current_distance = queue.popleft()
109+
110+
if current_distance >= distance:
111+
continue
112+
113+
if current_file not in visited:
114+
visited.add(current_file)
115+
116+
for entity, used_entities in graph[current_file].items():
117+
for used_entity in used_entities:
118+
if "." in used_entity:
119+
dependent_file = used_entity.split(".")[0] + ".py"
120+
if dependent_file != current_file:
121+
dependencies[current_distance + 1].add(dependent_file)
122+
queue.append((dependent_file, current_distance + 1))
123+
124+
return dependencies
125+
90126

91127
def get_module_name(code_path: Text) -> Text:
92128
module_name = os.path.basename(code_path).replace(".py", "")

codegraph/main.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
is_flag=True,
2020
help="Don't visualize code dependencies as graph",
2121
)
22-
def cli(paths, object_only):
22+
@click.option("--file-path", help="File path to start dependency search from")
23+
@click.option("--distance", type=int, help="Distance to search for dependencies")
24+
def cli(paths, object_only, file_path, distance):
2325
"""
2426
Tool that creates a graph of code to show dependencies between code entities (methods, classes, etc.).
2527
CodeGraph does not execute code, it is based only on lex and syntax parsing.
@@ -33,18 +35,30 @@ def cli(paths, object_only):
3335
)
3436
sys.exit(1)
3537

36-
args = {"paths": paths, "object_only": object_only}
38+
args = {
39+
"paths": paths,
40+
"object_only": object_only,
41+
"file_path": file_path,
42+
"distance": distance,
43+
}
3744
main(args)
3845

3946

4047
def main(args):
41-
usage_graph = core.CodeGraph(args).usage_graph()
42-
pprint.pprint(usage_graph)
43-
if not args["object_only"]:
44-
# to make more quick work if not needed to visualize
45-
import codegraph.vizualyzer as vz
48+
code_graph = core.CodeGraph(args)
49+
usage_graph = code_graph.usage_graph()
4650

47-
vz.draw_graph(usage_graph)
51+
if args.get("file_path") and args.get("distance"):
52+
dependencies = code_graph.get_dependencies(args["file_path"], args["distance"])
53+
print(f"Dependencies for {args['file_path']}:")
54+
for distance, files in dependencies.items():
55+
print(f" Distance {distance}: {', '.join(files)}")
56+
else:
57+
pprint.pprint(usage_graph)
58+
if not args["object_only"]:
59+
import codegraph.vizualyzer as vz
60+
61+
vz.draw_graph(usage_graph)
4862

4963

5064
if __name__ == "__main__":

poetry.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ classifiers = [
2121
python = "^3.12"
2222
matplotlib = "^3.9"
2323
networkx = "^3.4"
24+
click = "^8.1.7"
2425

2526
[tool.poetry.dev-dependencies]
2627
pytest = "^8.3"

0 commit comments

Comments
 (0)