Last active
September 1, 2023 06:19
-
-
Save luqmansen/91b41f7558b4c183a8e6cdbcdedc8ce0 to your computer and use it in GitHub Desktop.
Generate Django Application Dependency Graph
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ast | |
import os | |
from random import randrange | |
from graphviz import Digraph | |
def random_color(): | |
r = randrange(255) | |
g = randrange(start=0, stop=10) | |
b = randrange(255) | |
return f'#{r:x}{g:x}{b:x}' | |
def generate_dependency_graph(root_folder): | |
dot = Digraph( | |
comment='Function Dependency Graph', | |
strict=True, | |
graph_attr={'rankdir': "BT"}, | |
) | |
dot.format = 'svg' # Output format (change to your preference) | |
parent_folder = set( | |
[ | |
folder | |
for folder in os.listdir('.') | |
if os.path.isdir(folder) | |
and not folder.startswith('.') | |
and '__init__.py' in list(os.walk(folder))[0][2] | |
] | |
) | |
for folder in parent_folder: | |
dot.node(folder, shape='box') # Add a node for each function | |
print(parent_folder) | |
# Traverse the root folder and its subfolders | |
for folder, _, files in os.walk(root_folder): | |
imported_node_per_module = {p: set() for p in parent_folder} | |
for file in files: | |
if file.endswith('.py'): # Process only Python files | |
file_path = os.path.join(folder, file) | |
curr_folder = folder.strip('./') | |
if curr_folder not in parent_folder: | |
continue | |
# module_name = os.path.splitext(file)[0] | |
# dot.subgraph( | |
# name=module_name | |
# ) # Create a subgraph for each module | |
with open(file_path, 'r') as f: | |
try: | |
tree = ast.parse(f.read()) | |
except SyntaxError: | |
continue | |
# Traverse the abstract syntax tree (AST) of the module | |
for node in ast.walk(tree): | |
if isinstance(node, ast.ImportFrom): | |
module_name = node.module | |
module_name = module_name.split('.')[0] | |
if module_name in parent_folder: | |
if module_name == curr_folder: | |
continue | |
if imported_node_per_module[module_name] is None: | |
imported_node_per_module[module_name] = set() | |
for n in node.names: | |
imported_node_per_module[module_name].add( | |
n.name | |
) | |
new_label = ',\n'.join( | |
sorted(imported_node_per_module[module_name]) | |
) | |
color = random_color() | |
dot.edge( | |
module_name, | |
curr_folder, | |
label=new_label, | |
fontcolor=color, | |
color=color, | |
) # Add an edge between module and function | |
dot.render('dependency_graph', view=True) # Render and display the graph | |
if __name__ == '__main__': | |
generate_dependency_graph('.') | |
exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment