Skip to content

Instantly share code, notes, and snippets.

@luqmansen
Last active September 1, 2023 06:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luqmansen/91b41f7558b4c183a8e6cdbcdedc8ce0 to your computer and use it in GitHub Desktop.
Save luqmansen/91b41f7558b4c183a8e6cdbcdedc8ce0 to your computer and use it in GitHub Desktop.
Generate Django Application Dependency Graph
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