Repository: best-doctor/flake8-annotations-complexity

Issue:
Forbid flat, but long annotations
This is not nested, but also not okey: `Tuple[str, str, str, int, List, Any, str, Dict, int]`.

Comments:

Patch:
diff --git a/.gitignore b/.gitignore
index 894a44c..ac3dec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -102,3 +102,6 @@ venv.bak/
 
 # mypy
 .mypy_cache/
+
+# IDE
+.idea
diff --git a/README.md b/README.md
index 7b2f875..0832f82 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ $ flake8 --max-annotations-complexity=1 test.py
 test.py:4:14: TAE002 too complex annotation (2 > 1)
 ```
 
-Tested on Python 3.5.0 and flake8 3.7.4.
+Tested on Python 3.6, 3.7, 3.8 and flake8 3.7.8.
 
 ## Contributing
 
diff --git a/flake8_annotations_complexity/ast_helpres.py b/flake8_annotations_complexity/ast_helpres.py
index f4bdc83..24a7e2a 100644
--- a/flake8_annotations_complexity/ast_helpres.py
+++ b/flake8_annotations_complexity/ast_helpres.py
@@ -18,7 +18,27 @@ def get_annotation_complexity(annotation_node, default_complexity: int = 1) -> i
     return default_complexity
 
 
-def validate_annotations_in_ast_node(node, max_annotations_complexity) -> List[Tuple[Any, int]]:
+def get_annotation_len(annotation_node) -> int:
+    if isinstance(annotation_node, ast.Str):
+        try:
+            annotation_node = ast.parse(annotation_node.s).body[0].value  # type: ignore
+        except (SyntaxError, IndexError):
+            return 0
+    if isinstance(annotation_node, ast.Subscript):
+        try:
+            if sys.version_info >= (3, 9):
+                return len(annotation_node.slice.elts)  # type: ignore
+            return len(annotation_node.slice.value.elts)  # type: ignore
+        except AttributeError:
+            return 0
+    return 0
+
+
+def validate_annotations_in_ast_node(
+    node,
+    max_annotations_complexity,
+    max_annotations_len,
+) -> List[Tuple[Any, str]]:
     too_difficult_annotations = []
     func_defs = [
         f for f in ast.walk(node)
@@ -35,6 +55,12 @@ def validate_annotations_in_ast_node(node, max_annotations_complexity) -> List[T
         if complexity > max_annotations_complexity:
             too_difficult_annotations.append((
                 annotation,
-                complexity,
+                'TAE002 too complex annotation ({0} > {1})'.format(complexity, max_annotations_complexity),
+            ))
+        annotation_len = get_annotation_len(annotation)
+        if annotation_len > 7:
+            too_difficult_annotations.append((
+                annotation,
+                'TAE003 too long annotation ({0} > {1})'.format(annotation_len, max_annotations_len),
             ))
     return too_difficult_annotations
diff --git a/flake8_annotations_complexity/checker.py b/flake8_annotations_complexity/checker.py
index 45c88ba..6f1344b 100644
--- a/flake8_annotations_complexity/checker.py
+++ b/flake8_annotations_complexity/checker.py
@@ -11,13 +11,16 @@ class AnnotationsComplexityChecker:
     max_annotations_complexity = None
     default_max_annotations_complexity = 3
 
-    _error_message_template = 'TAE002 too complex annotation ({0} > {1})'
+    max_annotations_len = None
+    default_max_annotations_len = 7
 
     def __init__(self, tree, filename: str):
         self.filename = filename
         self.tree = tree
         if AnnotationsComplexityChecker.max_annotations_complexity is None:
             AnnotationsComplexityChecker.max_annotations_complexity = self.default_max_annotations_complexity
+        if AnnotationsComplexityChecker.max_annotations_len is None:
+            AnnotationsComplexityChecker.max_annotations_len = self.default_max_annotations_len
 
     @classmethod
     def add_options(cls, parser) -> None:
@@ -27,6 +30,12 @@ class AnnotationsComplexityChecker:
             parse_from_config=True,
             default=cls.default_max_annotations_complexity,
         )
+        parser.add_option(
+            '--max-annotations-len',
+            type=int,
+            parse_from_config=True,
+            default=cls.default_max_annotations_len,
+        )
 
     @classmethod
     def parse_options(cls, options) -> None:
@@ -36,12 +45,13 @@ class AnnotationsComplexityChecker:
         too_difficult_annotations = validate_annotations_in_ast_node(
             self.tree,
             self.max_annotations_complexity,
+            self.max_annotations_len,
         )
 
-        for annotation, complexity in too_difficult_annotations:
+        for annotation, error_msg in too_difficult_annotations:
             yield (
                 annotation.lineno,
                 annotation.col_offset,
-                self._error_message_template.format(complexity, self.max_annotations_complexity),
+                error_msg,
                 type(self),
             )


Test patch:
diff --git a/tests/test_annotations_complexity.py b/tests/test_annotations_complexity.py
index b7253e1..294f0bc 100644
--- a/tests/test_annotations_complexity.py
+++ b/tests/test_annotations_complexity.py
@@ -67,3 +67,8 @@ def test_pep_585_compliance():
     assert len(errors) == 11
     errors = run_validator_for_test_file('pep_585.py', max_annotations_complexity=2)
     assert len(errors) == 2
+
+
+def test_validates_too_long_annotations():
+    errors = run_validator_for_test_file('too_long_annotation.py')
+    assert len(errors) == 4
diff --git a/tests/test_files/too_long_annotation.py b/tests/test_files/too_long_annotation.py
new file mode 100644
index 0000000..bb7c1d2
--- /dev/null
+++ b/tests/test_files/too_long_annotation.py
@@ -0,0 +1,7 @@
+from typing import Any, Dict, List, Optional, Tuple
+
+foo: Tuple[str, str, str, int, List, Any, str, Dict, int] = tuple()
+
+bar: 'Tuple[str, str, str, int, List, Any, str, Dict, int]' = tuple()
+
+egg: Tuple[str, str, str, int, List, Any, List[int], Optional[Dict[str, int]]] = tuple()