Repository: wemake-services/wemake-python-styleguide

Issue:
Annotation complexity should not fail on expressions
# Bug report

This code:

```python
def some() -> 'test expression':
    ...
```

Makes `flake8-annotation-complexity` to fail. We need to ignore this case silently.

Related: #1170 

Demo: https://asciinema.org/a/IIjIfkVKytmZ1F5c2YufMORdi
Annotation complexity should not fail on expressions
# Bug report

This code:

```python
def some() -> 'test expression':
    ...
```

Makes `flake8-annotation-complexity` to fail. We need to ignore this case silently.

Related: #1170 

Demo: https://asciinema.org/a/IIjIfkVKytmZ1F5c2YufMORdi


Discussion:
Hello! 

Can I ask you about resolving this issue? 
This fail happens because of ast can't parse string which is not ast-compatible. Why we parse string to get ast nodes? This is non-standard use. Is it for backward compatibility? Maybe just remove this condition statement?

If we still need to handle this case, is try-except with pass will resolve the problem? I'm trying make this, but received a lint errors: WPS420 and S110. I know that try-except-pass is a bad practice, but how to silently ignore this exception?

Sorry for my newbie questions )
It is ok to learn new things! Do not ever stop doing this 🙂 

We use `ast.parse` because sometime people write annotations as strings. This happens due to how `python` evaluates names. Here's an example:

```python
>>> class Some(object):
...      def test(self) -> Some: ...
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in Some
NameError: name 'Some' is not defined
``` 

And the same with strings:

```python
>>> class Some(object):
...      def test(self) -> 'Some': ...
... 
>>> 
```

So, we have to parse these stings. But, on the other hand we should skip situations like: 
```python
>>> import ast
>>> ast.parse('some invalid type')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/sobolev/.pyenv/versions/3.8.0/lib/python3.8/ast.py", line 47, in parse
    return compile(source, filename, mode, flags,
  File "<unknown>", line 1
    some invalid type
         ^
SyntaxError: invalid syntax
```

I suggest to return `1` in this case of `SyntaxError`. 

@leksuss is my description good enough? Will you fix this bug? 🙂 
Nikita, thank you for your answer. In function `get_annotation_compexity` we just count complexity of annotation. And this is make sense with the annotation as strings if it looks like:
```
>>> class Some(object):
...      def test(self) -> '[list[list[list[int, str]]]]': ...
```
In which cases somebody would write like this (difficult annotation inside string)? Sorry if my question irrelevant of resolving.

And yes, I'll fix it. This would my first pull request, so I just need some time to understand the procedure.
@leksuss we cannot control why people would do that. But, we know that they will. And our goal is to help them not to make this mistake. 

I appreciate your help! Thanks a lot! Since this one is the first PR for you, here are the steps:

1. You fork this repository: https://help.github.com/en/github/getting-started-with-github/fork-a-repo
2. Then (inside your fork) you add new failing tests here: https://github.com/wemake-services/wemake-python-styleguide/blob/master/tests/test_visitors/test_ast/test_complexity/test_annotation_complexity/test_annotation_complexity_nesting.py You goal at this point is to make sure that you can reproduce the bug. It is called [ATDD](https://en.wikipedia.org/wiki/Acceptance_test%E2%80%93driven_development)
3. Then (inside your fork) you edit https://github.com/wemake-services/wemake-python-styleguide/blob/master/wemake_python_styleguide/logic/complexity/annotations.py and fix the bug.
3. Then you run your tests again and they should pass this time!
4. You submit a PR: https://opensource.com/article/19/7/create-pull-request-github
5. Done!

You can find the information about running tests here: https://github.com/wemake-services/wemake-python-styleguide/blob/master/CONTRIBUTING.md
@sobolevn thank you for so useful answer! 
Hello! 

Can I ask you about resolving this issue? 
This fail happens because of ast can't parse string which is not ast-compatible. Why we parse string to get ast nodes? This is non-standard use. Is it for backward compatibility? Maybe just remove this condition statement?

If we still need to handle this case, is try-except with pass will resolve the problem? I'm trying make this, but received a lint errors: WPS420 and S110. I know that try-except-pass is a bad practice, but how to silently ignore this exception?

Sorry for my newbie questions )
It is ok to learn new things! Do not ever stop doing this 🙂 

We use `ast.parse` because sometime people write annotations as strings. This happens due to how `python` evaluates names. Here's an example:

```python
>>> class Some(object):
...      def test(self) -> Some: ...
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in Some
NameError: name 'Some' is not defined
``` 

And the same with strings:

```python
>>> class Some(object):
...      def test(self) -> 'Some': ...
... 
>>> 
```

So, we have to parse these stings. But, on the other hand we should skip situations like: 
```python
>>> import ast
>>> ast.parse('some invalid type')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/sobolev/.pyenv/versions/3.8.0/lib/python3.8/ast.py", line 47, in parse
    return compile(source, filename, mode, flags,
  File "<unknown>", line 1
    some invalid type
         ^
SyntaxError: invalid syntax
```

I suggest to return `1` in this case of `SyntaxError`. 

@leksuss is my description good enough? Will you fix this bug? 🙂 
Nikita, thank you for your answer. In function `get_annotation_compexity` we just count complexity of annotation. And this is make sense with the annotation as strings if it looks like:
```
>>> class Some(object):
...      def test(self) -> '[list[list[list[int, str]]]]': ...
```
In which cases somebody would write like this (difficult annotation inside string)? Sorry if my question irrelevant of resolving.

And yes, I'll fix it. This would my first pull request, so I just need some time to understand the procedure.
@leksuss we cannot control why people would do that. But, we know that they will. And our goal is to help them not to make this mistake. 

I appreciate your help! Thanks a lot! Since this one is the first PR for you, here are the steps:

1. You fork this repository: https://help.github.com/en/github/getting-started-with-github/fork-a-repo
2. Then (inside your fork) you add new failing tests here: https://github.com/wemake-services/wemake-python-styleguide/blob/master/tests/test_visitors/test_ast/test_complexity/test_annotation_complexity/test_annotation_complexity_nesting.py You goal at this point is to make sure that you can reproduce the bug. It is called [ATDD](https://en.wikipedia.org/wiki/Acceptance_test%E2%80%93driven_development)
3. Then (inside your fork) you edit https://github.com/wemake-services/wemake-python-styleguide/blob/master/wemake_python_styleguide/logic/complexity/annotations.py and fix the bug.
3. Then you run your tests again and they should pass this time!
4. You submit a PR: https://opensource.com/article/19/7/create-pull-request-github
5. Done!

You can find the information about running tests here: https://github.com/wemake-services/wemake-python-styleguide/blob/master/CONTRIBUTING.md
@sobolevn thank you for so useful answer! 

Resolving patch:
diff --git a/wemake_python_styleguide/logic/complexity/annotations.py b/wemake_python_styleguide/logic/complexity/annotations.py
--- a/wemake_python_styleguide/logic/complexity/annotations.py
+++ b/wemake_python_styleguide/logic/complexity/annotations.py
@@ -24,9 +24,12 @@ def get_annotation_compexity(annotation_node: _Annotation) -> int:
     we additionally parse them to ``ast`` nodes.
     """
     if isinstance(annotation_node, ast.Str):
-        annotation_node = ast.parse(  # type: ignore
-            annotation_node.s,
-        ).body[0].value
+        try:
+            annotation_node = ast.parse(  # type: ignore
+                annotation_node.s,
+            ).body[0].value
+        except SyntaxError:
+            return 1
 
     if isinstance(annotation_node, ast.Subscript):
         return 1 + get_annotation_compexity(


Test patch:
diff --git a/tests/test_visitors/test_ast/test_complexity/test_annotation_complexity/test_annotation_complexity_nesting.py b/tests/test_visitors/test_ast/test_complexity/test_annotation_complexity/test_annotation_complexity_nesting.py
--- a/tests/test_visitors/test_ast/test_complexity/test_annotation_complexity/test_annotation_complexity_nesting.py
+++ b/tests/test_visitors/test_ast/test_complexity/test_annotation_complexity/test_annotation_complexity_nesting.py
@@ -68,6 +68,7 @@ class Test(object):
     'Dict[int, str]',
     'Callable[[str, int], int]',
     'List[List[int]]',
+    '"String Annontation"',
 ])
 def test_correct_annotations(
     assert_errors,