Last active
September 13, 2020 00:00
-
-
Save adrianherrera/6791bd9afaeb78d53d0d92e89d73f28b to your computer and use it in GitHub Desktop.
Calculate the cyclomatic complexity of a DOT file
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
#!/usr/bin/env python3 | |
""" | |
Calculate the cyclomatic complexity of a graph in a DOT file. | |
Author: Adrian Herrera | |
""" | |
from argparse import ArgumentParser | |
import networkx as nx | |
from networkx.drawing.nx_pydot import read_dot | |
def parse_args(): | |
"""Parse the command-line arguments.""" | |
parser = ArgumentParser(description='Calculate the cyclomatic complexity ' | |
'of a DOT file') | |
parser.add_argument('-o', '--output', required=True, help='Output CSV') | |
parser.add_argument('dot', nargs='+', metavar='DOT', | |
help='Path to DOT file') | |
return parser.parse_args() | |
def main(): | |
"""The main function.""" | |
args = parse_args() | |
dot_paths = args.dot | |
csv_rows = [] | |
for dot_path in dot_paths: | |
# Read the graph | |
graph = read_dot(dot_path) | |
# Find the entry node | |
entry_node = None | |
for node, in_degree in graph.in_degree(): | |
if in_degree == 0: | |
entry_node = node | |
break | |
if not entry_node: | |
raise Exception('Failed to find entry node in `%s`' % dot_path) | |
# Find the exit node(s) and connect them to the entry node (making the | |
# graph strongly connected) | |
for node, out_degree in graph.out_degree(): | |
if out_degree == 0: | |
graph.add_edge(node, entry_node) | |
num_edges = graph.number_of_edges() | |
num_nodes = graph.number_of_nodes() | |
num_scc = nx.components.number_strongly_connected_components(graph) | |
cyclomatic_complexity = num_edges - num_nodes + num_scc | |
csv_rows.append(dict(path=dot_path, cyclomatic=cyclomatic_complexity)) | |
# Write CSV | |
with open(args.output, 'w') as outf: | |
writer = CsvDictWriter(outf, fieldnames=('path', 'cyclomatic')) | |
writer.writeheader() | |
writer.writerows(csv_rows) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment