Cognitive complexity and python
Install dependencies
pip install cognitive_complexity astunparse tabulate
Import and define utils
import ast
import astunparse
from inspect import getsource
from tabulate import tabulate
from cognitive_complexity.api import get_cognitive_complexity_for_node
from cognitive_complexity.utils.ast import has_recursive_calls, is_decorator, process_child_nodes, process_node_itself
def get_cognitive_complexity(func):
func = func if isinstance(func, str) else getsource(func)
funcdef = ast.parse(func).body[0]
if is_decorator(funcdef):
return get_cognitive_complexity(funcdef.body[0])
details = []
complexity = 0
for node in funcdef.body:
node_complexity = get_cognitive_complexity_for_node(node)
complexity += node_complexity
node_code = astunparse.unparse(node)
if f"{funcdef.name}(" in node_code: # +1 for recursion
node_complexity += 1
complexity += 1
details.append([node_complexity, node_code])
details.append([complexity, "Total"])
return complexity, details
Introduction
Formulated in a Fortran environment in 1976, Cyclomatic Complexity has long been the standard for measuring the complexity of a methodβs control flow. It was originally intended βto identify software modules that will be difficult to test or maintainβ, but while it accurately calculates the minimum number of test cases required to fully cover a method, it is not a satisfactory measure of understandability and it also doesnβt include modern language structures like try/catch, and lambdas.
-- Cognitive Complexity:A new way of measuring understandability, white paper by G. Ann Campbell
Basic criteria and methodology
As a remedy for these problems, Cognitive Complexity has been formulated to address modern language structures, and to produce values that are meaningful at the class and application levels. A Cognitive Complexity score is assessed according to three basic rules:
- Ignore structures that allow multiple statements to be readably shorthanded into one
- Increment (add one) for each break in the linear flow of the code
Increment when flow-breaking structures are nested Additionally, a complexity score is made up of four different types of increments:
A. Nesting - assessed for nesting control flow structures inside each other
B. Structural - assessed on control flow structures that are subject to a nesting increment, and that increase the nesting count
C. Fundamental - assessed on statements not subject to a nesting increment
D. Hybrid - assessed on control flow structures that are not subject to a nesting increment, but which do increase the nesting count
-- Cognitive Complexity: A new way of measuring understandability, white paper by G. Ann Campbell
def f(n):
if n > 10:
return True
if n < 5:
return 20
else:
return 2
return f(n)
total, details = get_cognitive_complexity(f)
print(tabulate(details, headers=["Complexity", "Node"], tablefmt="fancy_grid"))