Repository: wemake-services/wemake-python-styleguide

Issue:
TypeError: 'NoneType' object is not iterable
# Bug report
When I run `flake8` with `wemake-python-styleguide 0.6.1`, I see exception traceback.
(move from #112)
## System information
### flake8 information
```
{
  "dependencies": [
    {
      "dependency": "setuptools",
      "version": "39.1.0"
    }
  ],
  "platform": {
    "python_implementation": "CPython",
    "python_version": "3.6.5",
    "system": "Darwin"
  },
  "plugins": [
    {
      "is_local": false,
      "plugin": "flake8-bandit",
      "version": "v1.0.2"
    },
    {
      "is_local": false,
      "plugin": "flake8-broken-line",
      "version": "0.1.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-bugbear",
      "version": "18.8.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-comprehensions",
      "version": "1.4.1"
    },
    {
      "is_local": false,
      "plugin": "flake8-debugger",
      "version": "3.1.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-django",
      "version": "0.0.3"
    },
    {
      "is_local": false,
      "plugin": "flake8-docstrings",
      "version": "1.3.0, pydocstyle: 3.0.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-eradicate",
      "version": "0.1.1"
    },
    {
      "is_local": false,
      "plugin": "flake8-print",
      "version": "3.1.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-string-format",
      "version": "0.2.3"
    },
    {
      "is_local": false,
      "plugin": "flake8-type-annotations",
      "version": "0.1.0"
    },
    {
      "is_local": false,
      "plugin": "flake8_builtins",
      "version": "1.4.1"
    },
    {
      "is_local": false,
      "plugin": "flake8_coding",
      "version": "1.3.1"
    },
    {
      "is_local": false,
      "plugin": "flake8_commas",
      "version": "2.0.0"
    },
    {
      "is_local": false,
      "plugin": "flake8_isort",
      "version": "2.3"
    },
    {
      "is_local": false,
      "plugin": "flake8_pep3101",
      "version": "1.2.1"
    },
    {
      "is_local": false,
      "plugin": "flake8_quotes",
      "version": "1.0.0"
    },
    {
      "is_local": false,
      "plugin": "logging-format",
      "version": "0.5.0"
    },
    {
      "is_local": false,
      "plugin": "mccabe",
      "version": "0.6.1"
    },
    {
      "is_local": false,
      "plugin": "naming",
      "version": "0.7.0"
    },
    {
      "is_local": false,
      "plugin": "per-file-ignores",
      "version": "0.6"
    },
    {
      "is_local": false,
      "plugin": "pycodestyle",
      "version": "2.4.0"
    },
    {
      "is_local": false,
      "plugin": "pyflakes",
      "version": "2.0.0"
    },
    {
      "is_local": false,
      "plugin": "wemake-python-styleguide",
      "version": "0.6.1"
    }
  ],
  "version": "3.6.0"
}
```
### traceback
```
multiprocessing.pool.RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/checker.py", line 682, in _run_checks
    return checker.run_checks()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/checker.py", line 612, in run_checks
    self.run_ast_checks()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/checker.py", line 520, in run_ast_checks
    for (line_number, offset, text, check) in runner:
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/wemake_python_styleguide/checker.py", line 178, in run
    yield from self._run_checks(self.visitors)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/wemake_python_styleguide/checker.py", line 166, in _run_checks
    visitor.run()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/wemake_python_styleguide/visitors/base.py", line 140, in run
    self.visit(self.tree)
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ast.py", line 253, in visit
    return visitor(node)
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ast.py", line 261, in generic_visit
    self.visit(item)
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ast.py", line 253, in visit
    return visitor(node)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/wemake_python_styleguide/visitors/ast/naming.py", line 154, in visit_ClassDef
    self._validator.check_attribute_name(node)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/wemake_python_styleguide/visitors/ast/naming.py", line 117, in check_attribute_name
    if logical.is_upper_case_name(name):
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/wemake_python_styleguide/logics/naming/logical.py", line 70, in is_upper_case_name
    return any(character.isupper() for character in name)
TypeError: 'NoneType' object is not iterable
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/__main__.py", line 4, in <module>
    cli.main()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/main/cli.py", line 16, in main
    app.run(argv)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/main/application.py", line 412, in run
    self._run(argv)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/main/application.py", line 400, in _run
    self.run_checks()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/main/application.py", line 318, in run_checks
    self.file_checker_manager.run()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8_per_file_ignores.py", line 33, in run
    orig_run(self)
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/checker.py", line 338, in run
    self.run_parallel()
  File "/Users/boger/virtualvenvs/myproject-backend-v3/lib/python3.6/site-packages/flake8/checker.py", line 302, in run_parallel
    for ret in pool_map:
  File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py", line 735, in next
    raise value
TypeError: 'NoneType' object is not iterable
```


Discussion:
@b0g3r can you please provide a code sample that causes this issue?
If you tell me how can I get them. Because I try to use wps on big project (22466 lines)
You can use this script:

```sh
for file in $(find YOUR_SOURCE_FOLDER -name '*.py'); do
   echo "Checking now: $file"
   flake8 "$file"
done
```

Then you will see which file is failing. And then you can reduce the problem to the specific snippet. 
Yay, this code:
```python
class MyClass:
    def action_method(self, request, object):
        pass
    action_method.label = 'Do action'
```

Resolving patch:
diff --git a/wemake_python_styleguide/visitors/ast/naming.py b/wemake_python_styleguide/visitors/ast/naming.py
--- a/wemake_python_styleguide/visitors/ast/naming.py
+++ b/wemake_python_styleguide/visitors/ast/naming.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 import ast
-from typing import Callable, List, Tuple, Union
+from typing import Callable, List, Optional, Tuple, Union
 
 from wemake_python_styleguide.constants import (
     MODULE_METADATA_VARIABLES_BLACKLIST,
@@ -113,8 +113,11 @@ def check_attribute_name(self, node: ast.ClassDef) -> None:
 
         for assignment in top_level_assigns:
             for target in assignment.targets:
-                name = getattr(target, 'id', None)
-                if logical.is_upper_case_name(name):
+                if not isinstance(target, ast.Name):
+                    continue
+
+                name: Optional[str] = getattr(target, 'id', None)
+                if name and logical.is_upper_case_name(name):
                     self._error_callback(
                         naming.UpperCaseAttributeViolation(target, text=name),
                     )


Test patch:
diff --git a/tests/test_visitors/test_ast/test_naming/test_class_attributes.py b/tests/test_visitors/test_ast/test_naming/test_class_attributes.py
--- a/tests/test_visitors/test_ast/test_naming/test_class_attributes.py
+++ b/tests/test_visitors/test_ast/test_naming/test_class_attributes.py
@@ -12,6 +12,14 @@ class Test(object):
     {0} = None
 """
 
+regression423 = """
+class MyClass(object):
+    def action_method(self, request, object):
+        ...
+
+    action_method.label = 'Do action'
+"""
+
 
 @pytest.mark.parametrize('non_snake_case_name', [
     'Abc',
@@ -60,3 +68,21 @@ def test_snake_case_class_attributes(
     visitor.run()
 
     assert_errors(visitor, [])
+
+
+def test_regression423(
+    assert_errors,
+    parse_ast_tree,
+    default_options,
+):
+    """
+    Tests that this issue-423 won't happen again.
+
+    See: https://github.com/wemake-services/wemake-python-styleguide/issues/423
+    """
+    tree = parse_ast_tree(regression423)
+
+    visitor = WrongNameVisitor(default_options, tree=tree)
+    visitor.run()
+
+    assert_errors(visitor, [])