Repository: Melevir/cognitive_complexity

Issue:
Not increment nesting for decorators
> Python’s decorator idiom allows additional behavior to be added to an existing function
without modifying the function itself. This addition is accomplished with the use of nested
functions in the decorator providing the additional behavior. In order not to penalize Python
coders for the use of a common feature of their language, an exception has been added.
However, an attempt has been made to define the exception narrowly. Specifically, to be
eligible for the exception, a function may contain only a nested function and a return
statement.

This is valid after #3 is done.

Comments:

Patch:
diff --git a/cognitive_complexity/api.py b/cognitive_complexity/api.py
index 9a36850..392ca66 100644
--- a/cognitive_complexity/api.py
+++ b/cognitive_complexity/api.py
@@ -2,11 +2,14 @@ import ast
 
 from cognitive_complexity.common_types import AnyFuncdef
 from cognitive_complexity.utils.ast import (
-    has_recursive_calls, process_child_nodes, process_node_itself,
+    has_recursive_calls, is_decorator, process_child_nodes, process_node_itself,
 )
 
 
 def get_cognitive_complexity(funcdef: AnyFuncdef) -> int:
+    if is_decorator(funcdef):
+        return get_cognitive_complexity(funcdef.body[0])  # type: ignore
+
     complexity = 0
     for node in funcdef.body:
         complexity += get_cognitive_complexity_for_node(node)
@@ -18,7 +21,7 @@ def get_cognitive_complexity(funcdef: AnyFuncdef) -> int:
 def get_cognitive_complexity_for_node(
         node: ast.AST,
         increment_by: int = 0,
-        verbose: bool = True,
+        verbose: bool = False,
 ) -> int:
 
     increment_by, base_complexity, should_iter_children = process_node_itself(node, increment_by)
diff --git a/cognitive_complexity/utils/ast.py b/cognitive_complexity/utils/ast.py
index 815bc05..19db71d 100644
--- a/cognitive_complexity/utils/ast.py
+++ b/cognitive_complexity/utils/ast.py
@@ -16,6 +16,15 @@ def has_recursive_calls(funcdef: AnyFuncdef) -> bool:
     ])
 
 
+def is_decorator(funcdef: AnyFuncdef) -> bool:
+    return (
+        isinstance(funcdef, ast.FunctionDef)
+        and len(funcdef.body) == 2
+        and isinstance(funcdef.body[0], ast.FunctionDef)
+        and isinstance(funcdef.body[1], ast.Return)
+    )
+
+
 def process_child_nodes(
     node: ast.AST,
     increment_by: int,


Test patch:
diff --git a/tests/test_cognitive_complexity.py b/tests/test_cognitive_complexity.py
index 6bf7d66..40cdf71 100644
--- a/tests/test_cognitive_complexity.py
+++ b/tests/test_cognitive_complexity.py
@@ -218,3 +218,39 @@ def test_while_else_complexity():
         else:  # +1
             return 5
     """) == 6
+
+
+def test_a_decorator_complexity():
+    assert get_code_snippet_compexity("""
+    def a_decorator(a, b):
+        def inner(func):  # nesting = 0
+            if condition:  # +1
+                print(b)
+            func()
+        return inner
+    """) == 1
+
+
+def test_not_a_decorator_complexity():
+    assert get_code_snippet_compexity("""
+    def not_a_decorator(a, b):
+        my_var = a*b
+        def inner(func):  # nesting = 1
+            if condition:  # +1 structure, +1 nesting
+                print(b)
+            func()
+        return inner
+    """) == 2
+
+
+def test_decorator_generator_complexity():
+    assert get_code_snippet_compexity("""
+    def decorator_generator(a):
+        def generator(func):
+            def decorator(func): # nesting = 0
+                if condition: # +1
+                    print(b)
+                return func()
+            return decorator
+        return generator
+    """) == 1