Repository: Melevir/cognitive_complexity

Issue:
Document try complexity computation
Hi, thanks for this great tool :smile: I was scratching my head when adding/removing any lines from `try` block was influencing cognitive complexity and searched in your documentation and then code why is that and found this line in code:

https://github.com/Melevir/cognitive_complexity/blob/1df07df7adf88bc2c002e4bf85da28c18bfbd086/cognitive_complexity/utils/ast.py#L40

It means that any line added inside try block will increment complexity (code below gives complexity 4)

```python
def a(b, c):
    try:
        print(1)
        print(2)
        print(3)
        print(4)
    except Exception:
        raise
```

This behavior is unexpected as it was not mentioned in SonarSource links provided, can we document it here or in flake8 extension? Thanks

Comments:

Patch:
diff --git a/cognitive_complexity/utils/ast.py b/cognitive_complexity/utils/ast.py
index 19db71d..43625fd 100644
--- a/cognitive_complexity/utils/ast.py
+++ b/cognitive_complexity/utils/ast.py
@@ -33,14 +33,7 @@ def process_child_nodes(
 ) -> int:
     child_complexity = 0
     child_nodes = ast.iter_child_nodes(node)
-
-    for node_num, child_node in enumerate(child_nodes):
-        if isinstance(node, ast.Try):
-            if node_num == 1:
-                # add +1 for all try nodes except body
-                increment_by += 1
-            if node_num:
-                child_complexity += max(1, increment_by)
+    for child_node in child_nodes:
         child_complexity += complexity_calculator(
             child_node,
             increment_by=increment_by,
@@ -50,7 +43,7 @@ def process_child_nodes(
 
 
 def process_control_flow_breaker(
-    node: Union[ast.If, ast.For, ast.While, ast.IfExp],
+    node: Union[ast.If, ast.For, ast.While, ast.IfExp, ast.ExceptHandler],
     increment_by: int,
 ) -> Tuple[int, int, bool]:
     if isinstance(node, ast.IfExp):
@@ -60,6 +53,10 @@ def process_control_flow_breaker(
     elif isinstance(node, ast.If) and len(node.orelse) == 1 and isinstance(node.orelse[0], ast.If):
         # node is an elif; the increment will be counted on the ast.If
         increment = 0
+    elif isinstance(node, ast.ExceptHandler):
+        # +1 for the catch/except-handler
+        increment = 0
+        increment_by += 1
     elif node.orelse:
         # +1 for the else and add a nesting level
         increment = 1
@@ -80,6 +77,7 @@ def process_node_itself(
         ast.For,
         ast.While,
         ast.IfExp,
+        ast.ExceptHandler,
     )
     incrementers_nodes = (
         ast.FunctionDef,


Test patch:
diff --git a/tests/test_cognitive_complexity.py b/tests/test_cognitive_complexity.py
index 40cdf71..f4a01cf 100644
--- a/tests/test_cognitive_complexity.py
+++ b/tests/test_cognitive_complexity.py
@@ -9,6 +9,14 @@ def test_simple_if_simple_condition_complexity():
     """) == 1
 
 
+def test_simple_if_simple_condition_complexity_with_print():
+    assert get_code_snippet_compexity("""
+    def f(a, b):
+        if a:  # +1
+            print('1')
+    """) == 1
+
+
 def test_simple_if_serial_condition_complexity():
     assert get_code_snippet_compexity("""
     def f(a, b):
@@ -87,16 +95,41 @@ def test_very_nested_structure_condition_complexity():
     """) == 6
 
 
-def test_try_condition_complexity():
+def test_try_condition_complexity_simple():
+    assert get_code_snippet_compexity("""
+    def f():
+        try:
+            print('hello1')
+        except Exception:  # +1
+            print('goodbye')
+    """) == 1
+
+
+def test_try_condition_complexity_with_multiple_lines():
+    assert get_code_snippet_compexity("""
+    def f(a, b):
+        try:
+            print('hello1')
+            print('hello2')
+            print('hello3')
+            print('hello4')
+            print('hello5')
+        except Exception:  # +1
+            print('goodbye')
+    """) == 1
+
+
+def test_try_condition_complexity_with_nesting():
     assert get_code_snippet_compexity("""
     def f(a, b):
         try:
             for foo in bar:  # +1
-                return a
+                if a > 0:  # +2
+                    return a
         except Exception:  # +1
             if a < 0:  # +2
                 return a
-    """) == 4
+    """) == 6
 
 
 def test_recursion_complexity():
@@ -125,6 +158,28 @@ def test_real_function():
     """) == 9
 
 
+def test_real_function_with_try():
+    assert get_code_snippet_compexity("""
+    def process_raw_constant(constant, min_word_length):
+        try:
+            processed_words = []
+            raw_camelcase_words = []
+            for raw_word in re.findall(r'[a-z]+', constant):  # +1
+                word = raw_word.strip()
+                if (  # +2 (nesting = 1)
+                    len(word) >= min_word_length  # +2 (2 bool operator sequences)
+                    and not (word.startswith('-') or word.endswith('-'))
+                ):
+                    if is_camel_case_word(word):  # +3 (nesting=2)
+                        raw_camelcase_words.append(word)
+                    else:  # +1
+                        processed_words.append(word.lower())
+            return processed_words, raw_camelcase_words
+        except Exception as exp:  # +1
+            return 1
+    """) == 9 + 1
+
+
 def test_break_and_continue():
     assert get_code_snippet_compexity("""
     def f(a):