We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Feature: check `lambda` functions for the number of arguments
We already have the logic to check regular an `async` functions for the number of arguments.
https://github.com/wemake-services/wemake-python-styleguide/blob/master/wemake_python_styleguide/visitors/ast/complexity/function.py#L155

But we need to check `lambda` functions as well. Since one can create a `lambda` function that receives too many arguments. 

What needs to be done:
1. We need to implement a new handler for `Lambda` node in the visitor above
2. We need to unit test this behavior here: https://github.com/wemake-services/wemake-python-styleguide/blob/master/tests/test_checkers/test_high_complexity.py

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wemake_python_styleguide/types.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 """
4 This module contains custom ``mypy`` types that we commonly use.
5 
6 Policy
7 ------
8 
9 If any of the following statements is true, move the type to this file:
10 
11 - if type is used in multiple files
12 - if type is complex enough it has to be documented
13 - if type is very important for the public API
14 
15 """
16 
17 import ast
18 from typing import TYPE_CHECKING, Tuple, Type, Union
19 
20 if TYPE_CHECKING:  # pragma: no cover
21     # TODO: use Final types to annotate all constants
22     from typing_extensions import Protocol  # noqa: Z435
23 
24     # This solves cycle imports problem:
25     from .visitors import base  # noqa: F401,Z300,Z435
26 else:
27     # We do not need to do anything if type checker is not working:
28     Protocol = object
29 
30 #: Visitor type definition:
31 VisitorClass = Type['base.BaseVisitor']
32 
33 #: In cases we need to work with both import types:
34 AnyImport = Union[ast.Import, ast.ImportFrom]
35 
36 #: In cases we need to work with both function definitions:
37 AnyFunctionDef = Union[ast.FunctionDef, ast.AsyncFunctionDef]
38 
39 #: Flake8 API format to return error messages:
40 CheckResult = Tuple[int, int, str, type]
41 
42 #: Tuple of AST node types for declarative syntax:
43 AnyNodes = Tuple[Type[ast.AST], ...]
44 
45 
46 class ConfigurationOptions(Protocol):
47     """
48     Provides structure for the options we use in our checker.
49 
50     Then this protocol is passed to each individual visitor and used there.
51     It uses structural sub-typing, and does not represent any kind of a real
52     class or structure.
53 
54     This class actually works only when running type check.
55     At other cases it is just an ``object``.
56 
57     See also:
58         https://mypy.readthedocs.io/en/latest/protocols.html
59 
60     """
61 
62     # General:
63     min_variable_length: int
64     i_control_code: bool
65 
66     # Complexity:
67     max_arguments: int
68     max_local_variables: int
69     max_returns: int
70     max_expressions: int
71     max_offset_blocks: int
72     max_elifs: int
73     max_module_members: int
74     max_methods: int
75     max_line_complexity: int
76     max_jones_score: int
77     max_imports: int
78     max_conditions: int
79 
80     # File names:
81     min_module_name_length: int
82
```

Path: `wemake_python_styleguide/visitors/ast/complexity/function.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 import ast
4 from collections import defaultdict
5 from typing import DefaultDict, List
6 
7 from wemake_python_styleguide.logics.functions import is_method
8 from wemake_python_styleguide.types import AnyFunctionDef
9 from wemake_python_styleguide.violations.complexity import (
10     TooManyArgumentsViolation,
11     TooManyElifsViolation,
12     TooManyExpressionsViolation,
13     TooManyLocalsViolation,
14     TooManyReturnsViolation,
15 )
16 from wemake_python_styleguide.visitors.base import BaseNodeVisitor
17 from wemake_python_styleguide.visitors.decorators import alias
18 
19 FunctionCounter = DefaultDict[AnyFunctionDef, int]
20 
21 
22 class _ComplexityCounter(object):
23     """Helper class to encapsulate logic from the visitor."""
24 
25     def __init__(self) -> None:
26         self.arguments: FunctionCounter = defaultdict(int)
27         self.elifs: FunctionCounter = defaultdict(int)
28         self.returns: FunctionCounter = defaultdict(int)
29         self.expressions: FunctionCounter = defaultdict(int)
30         self.variables: DefaultDict[
31             AnyFunctionDef, List[str],
32         ] = defaultdict(list)
33 
34     def _update_variables(
35         self,
36         function: AnyFunctionDef,
37         variable_name: str,
38     ) -> None:
39         """
40         Increases the counter of local variables.
41 
42         What is treated as a local variable?
43         Check ``TooManyLocalsViolation`` documentation.
44         """
45         function_variables = self.variables[function]
46         if variable_name not in function_variables and variable_name != '_':
47             function_variables.append(variable_name)
48 
49     def _update_elifs(self, node: AnyFunctionDef, sub_node: ast.If) -> None:
50         has_elif = any(
51             isinstance(if_node, ast.If) for if_node in sub_node.orelse
52         )
53 
54         if has_elif:
55             self.elifs[node] += 1
56 
57     def _check_sub_node(self, node: AnyFunctionDef, sub_node) -> None:
58         is_variable = isinstance(sub_node, ast.Name)
59         context = getattr(sub_node, 'ctx', None)
60 
61         if is_variable and isinstance(context, ast.Store):
62             self._update_variables(node, sub_node.id)
63         elif isinstance(sub_node, ast.Return):
64             self.returns[node] += 1
65         elif isinstance(sub_node, ast.Expr):
66             self.expressions[node] += 1
67         elif isinstance(sub_node, ast.If):
68             self._update_elifs(node, sub_node)
69 
70     def check_arguments_count(self, node: AnyFunctionDef) -> None:
71         """Checks the number of the arguments in a function."""
72         counter = 0
73         has_extra_arg = 0
74         if is_method(getattr(node, 'function_type', None)):
75             has_extra_arg = 1
76 
77         counter += len(node.args.args) + len(node.args.kwonlyargs)
78         if node.args.vararg:
79             counter += 1
80         if node.args.kwarg:
81             counter += 1
82 
83         self.arguments[node] = counter - has_extra_arg
84 
85     def check_function_complexity(self, node: AnyFunctionDef) -> None:
86         """
87         In this function we iterate all the internal body's node.
88 
89         We check different complexity metrics based on these internals.
90         """
91         for body_item in node.body:
92             for sub_node in ast.walk(body_item):
93                 self._check_sub_node(node, sub_node)
94 
95 
96 @alias('visit_any_function', (
97     'visit_AsyncFunctionDef',
98     'visit_FunctionDef',
99 ))
100 class FunctionComplexityVisitor(BaseNodeVisitor):
101     """
102     This class checks for complexity inside functions.
103 
104     This includes:
105 
106     1. Number of arguments
107     2. Number of `return` statements
108     3. Number of expressions
109     4. Number of local variables
110     5. Number of `elif` branches
111 
112     """
113 
114     def __init__(self, *args, **kwargs) -> None:
115         """Creates a counter for tracked metrics."""
116         super().__init__(*args, **kwargs)
117         self._counter = _ComplexityCounter()
118 
119     def _check_possible_switch(self) -> None:
120         for node, elifs in self._counter.elifs.items():
121             if elifs > self.options.max_elifs:
122                 self.add_violation(TooManyElifsViolation(node))
123 
124     def _check_function_internals(self) -> None:
125         for node, variables in self._counter.variables.items():
126             if len(variables) > self.options.max_local_variables:
127                 self.add_violation(
128                     TooManyLocalsViolation(node, text=node.name),
129                 )
130 
131         for node, expressions in self._counter.expressions.items():
132             if expressions > self.options.max_expressions:
133                 self.add_violation(
134                     TooManyExpressionsViolation(node, text=node.name),
135                 )
136 
137     def _check_function_signature(self) -> None:
138         for node, arguments in self._counter.arguments.items():
139             if arguments > self.options.max_arguments:
140                 self.add_violation(
141                     TooManyArgumentsViolation(node, text=str(arguments)),
142                 )
143 
144         for node, returns in self._counter.returns.items():
145             if returns > self.options.max_returns:
146                 self.add_violation(
147                     TooManyReturnsViolation(node, text=node.name),
148                 )
149 
150     def _post_visit(self) -> None:
151         self._check_function_signature()
152         self._check_function_internals()
153         self._check_possible_switch()
154 
155     def visit_any_function(self, node: AnyFunctionDef) -> None:
156         """
157         Checks function's internal complexity.
158 
159         Raises:
160             TooManyExpressionsViolation
161             TooManyReturnsViolation
162             TooManyLocalsViolation
163             TooManyArgumentsViolation
164             TooManyElifsViolation
165 
166         """
167         self._counter.check_arguments_count(node)
168         self._counter.check_function_complexity(node)
169         self.generic_visit(node)
170
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/wemake_python_styleguide/types.py b/wemake_python_styleguide/types.py
--- a/wemake_python_styleguide/types.py
+++ b/wemake_python_styleguide/types.py
@@ -36,6 +36,13 @@
 #: In cases we need to work with both function definitions:
 AnyFunctionDef = Union[ast.FunctionDef, ast.AsyncFunctionDef]
 
+#: In cases we need to work with all function definitions (including Lambda)
+AnyFunctionDefAndLambda = Union[
+    ast.FunctionDef,
+    ast.AsyncFunctionDef,
+    ast.Lambda,
+]
+
 #: Flake8 API format to return error messages:
 CheckResult = Tuple[int, int, str, type]
 
diff --git a/wemake_python_styleguide/visitors/ast/complexity/function.py b/wemake_python_styleguide/visitors/ast/complexity/function.py
--- a/wemake_python_styleguide/visitors/ast/complexity/function.py
+++ b/wemake_python_styleguide/visitors/ast/complexity/function.py
@@ -5,7 +5,10 @@
 from typing import DefaultDict, List
 
 from wemake_python_styleguide.logics.functions import is_method
-from wemake_python_styleguide.types import AnyFunctionDef
+from wemake_python_styleguide.types import (
+    AnyFunctionDef,
+    AnyFunctionDefAndLambda,
+)
 from wemake_python_styleguide.violations.complexity import (
     TooManyArgumentsViolation,
     TooManyElifsViolation,
@@ -17,13 +20,14 @@
 from wemake_python_styleguide.visitors.decorators import alias
 
 FunctionCounter = DefaultDict[AnyFunctionDef, int]
+FunctionCounterWithLambda = DefaultDict[AnyFunctionDefAndLambda, int]
 
 
 class _ComplexityCounter(object):
     """Helper class to encapsulate logic from the visitor."""
 
     def __init__(self) -> None:
-        self.arguments: FunctionCounter = defaultdict(int)
+        self.arguments: FunctionCounterWithLambda = defaultdict(int)
         self.elifs: FunctionCounter = defaultdict(int)
         self.returns: FunctionCounter = defaultdict(int)
         self.expressions: FunctionCounter = defaultdict(int)
@@ -67,7 +71,7 @@
         elif isinstance(sub_node, ast.If):
             self._update_elifs(node, sub_node)
 
-    def check_arguments_count(self, node: AnyFunctionDef) -> None:
+    def check_arguments_count(self, node: AnyFunctionDefAndLambda) -> None:
         """Checks the number of the arguments in a function."""
         counter = 0
         has_extra_arg = 0
@@ -167,3 +171,14 @@
         self._counter.check_arguments_count(node)
         self._counter.check_function_complexity(node)
         self.generic_visit(node)
+
+    def visit_Lambda(self, node: ast.Lambda) -> None:
+        """
+        Checks lambda function's internal complexity.
+
+        Raises:
+            TooManyArgumentsViolation
+
+        """
+        self._counter.check_arguments_count(node)
+        self.generic_visit(node)

{"golden_diff": "diff --git a/wemake_python_styleguide/types.py b/wemake_python_styleguide/types.py\n--- a/wemake_python_styleguide/types.py\n+++ b/wemake_python_styleguide/types.py\n@@ -36,6 +36,13 @@\n #: In cases we need to work with both function definitions:\n AnyFunctionDef = Union[ast.FunctionDef, ast.AsyncFunctionDef]\n \n+#: In cases we need to work with all function definitions (including Lambda)\n+AnyFunctionDefAndLambda = Union[\n+    ast.FunctionDef,\n+    ast.AsyncFunctionDef,\n+    ast.Lambda,\n+]\n+\n #: Flake8 API format to return error messages:\n CheckResult = Tuple[int, int, str, type]\n \ndiff --git a/wemake_python_styleguide/visitors/ast/complexity/function.py b/wemake_python_styleguide/visitors/ast/complexity/function.py\n--- a/wemake_python_styleguide/visitors/ast/complexity/function.py\n+++ b/wemake_python_styleguide/visitors/ast/complexity/function.py\n@@ -5,7 +5,10 @@\n from typing import DefaultDict, List\n \n from wemake_python_styleguide.logics.functions import is_method\n-from wemake_python_styleguide.types import AnyFunctionDef\n+from wemake_python_styleguide.types import (\n+    AnyFunctionDef,\n+    AnyFunctionDefAndLambda,\n+)\n from wemake_python_styleguide.violations.complexity import (\n     TooManyArgumentsViolation,\n     TooManyElifsViolation,\n@@ -17,13 +20,14 @@\n from wemake_python_styleguide.visitors.decorators import alias\n \n FunctionCounter = DefaultDict[AnyFunctionDef, int]\n+FunctionCounterWithLambda = DefaultDict[AnyFunctionDefAndLambda, int]\n \n \n class _ComplexityCounter(object):\n     \"\"\"Helper class to encapsulate logic from the visitor.\"\"\"\n \n     def __init__(self) -> None:\n-        self.arguments: FunctionCounter = defaultdict(int)\n+        self.arguments: FunctionCounterWithLambda = defaultdict(int)\n         self.elifs: FunctionCounter = defaultdict(int)\n         self.returns: FunctionCounter = defaultdict(int)\n         self.expressions: FunctionCounter = defaultdict(int)\n@@ -67,7 +71,7 @@\n         elif isinstance(sub_node, ast.If):\n             self._update_elifs(node, sub_node)\n \n-    def check_arguments_count(self, node: AnyFunctionDef) -> None:\n+    def check_arguments_count(self, node: AnyFunctionDefAndLambda) -> None:\n         \"\"\"Checks the number of the arguments in a function.\"\"\"\n         counter = 0\n         has_extra_arg = 0\n@@ -167,3 +171,14 @@\n         self._counter.check_arguments_count(node)\n         self._counter.check_function_complexity(node)\n         self.generic_visit(node)\n+\n+    def visit_Lambda(self, node: ast.Lambda) -> None:\n+        \"\"\"\n+        Checks lambda function's internal complexity.\n+\n+        Raises:\n+            TooManyArgumentsViolation\n+\n+        \"\"\"\n+        self._counter.check_arguments_count(node)\n+        self.generic_visit(node)\n", "issue": "Feature: check `lambda` functions for the number of arguments\nWe already have the logic to check regular an `async` functions for the number of arguments.\r\nhttps://github.com/wemake-services/wemake-python-styleguide/blob/master/wemake_python_styleguide/visitors/ast/complexity/function.py#L155\r\n\r\nBut we need to check `lambda` functions as well. Since one can create a `lambda` function that receives too many arguments. \r\n\r\nWhat needs to be done:\r\n1. We need to implement a new handler for `Lambda` node in the visitor above\r\n2. We need to unit test this behavior here: https://github.com/wemake-services/wemake-python-styleguide/blob/master/tests/test_checkers/test_high_complexity.py\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"\nThis module contains custom ``mypy`` types that we commonly use.\n\nPolicy\n------\n\nIf any of the following statements is true, move the type to this file:\n\n- if type is used in multiple files\n- if type is complex enough it has to be documented\n- if type is very important for the public API\n\n\"\"\"\n\nimport ast\nfrom typing import TYPE_CHECKING, Tuple, Type, Union\n\nif TYPE_CHECKING:  # pragma: no cover\n    # TODO: use Final types to annotate all constants\n    from typing_extensions import Protocol  # noqa: Z435\n\n    # This solves cycle imports problem:\n    from .visitors import base  # noqa: F401,Z300,Z435\nelse:\n    # We do not need to do anything if type checker is not working:\n    Protocol = object\n\n#: Visitor type definition:\nVisitorClass = Type['base.BaseVisitor']\n\n#: In cases we need to work with both import types:\nAnyImport = Union[ast.Import, ast.ImportFrom]\n\n#: In cases we need to work with both function definitions:\nAnyFunctionDef = Union[ast.FunctionDef, ast.AsyncFunctionDef]\n\n#: Flake8 API format to return error messages:\nCheckResult = Tuple[int, int, str, type]\n\n#: Tuple of AST node types for declarative syntax:\nAnyNodes = Tuple[Type[ast.AST], ...]\n\n\nclass ConfigurationOptions(Protocol):\n    \"\"\"\n    Provides structure for the options we use in our checker.\n\n    Then this protocol is passed to each individual visitor and used there.\n    It uses structural sub-typing, and does not represent any kind of a real\n    class or structure.\n\n    This class actually works only when running type check.\n    At other cases it is just an ``object``.\n\n    See also:\n        https://mypy.readthedocs.io/en/latest/protocols.html\n\n    \"\"\"\n\n    # General:\n    min_variable_length: int\n    i_control_code: bool\n\n    # Complexity:\n    max_arguments: int\n    max_local_variables: int\n    max_returns: int\n    max_expressions: int\n    max_offset_blocks: int\n    max_elifs: int\n    max_module_members: int\n    max_methods: int\n    max_line_complexity: int\n    max_jones_score: int\n    max_imports: int\n    max_conditions: int\n\n    # File names:\n    min_module_name_length: int\n", "path": "wemake_python_styleguide/types.py"}, {"content": "# -*- coding: utf-8 -*-\n\nimport ast\nfrom collections import defaultdict\nfrom typing import DefaultDict, List\n\nfrom wemake_python_styleguide.logics.functions import is_method\nfrom wemake_python_styleguide.types import AnyFunctionDef\nfrom wemake_python_styleguide.violations.complexity import (\n    TooManyArgumentsViolation,\n    TooManyElifsViolation,\n    TooManyExpressionsViolation,\n    TooManyLocalsViolation,\n    TooManyReturnsViolation,\n)\nfrom wemake_python_styleguide.visitors.base import BaseNodeVisitor\nfrom wemake_python_styleguide.visitors.decorators import alias\n\nFunctionCounter = DefaultDict[AnyFunctionDef, int]\n\n\nclass _ComplexityCounter(object):\n    \"\"\"Helper class to encapsulate logic from the visitor.\"\"\"\n\n    def __init__(self) -> None:\n        self.arguments: FunctionCounter = defaultdict(int)\n        self.elifs: FunctionCounter = defaultdict(int)\n        self.returns: FunctionCounter = defaultdict(int)\n        self.expressions: FunctionCounter = defaultdict(int)\n        self.variables: DefaultDict[\n            AnyFunctionDef, List[str],\n        ] = defaultdict(list)\n\n    def _update_variables(\n        self,\n        function: AnyFunctionDef,\n        variable_name: str,\n    ) -> None:\n        \"\"\"\n        Increases the counter of local variables.\n\n        What is treated as a local variable?\n        Check ``TooManyLocalsViolation`` documentation.\n        \"\"\"\n        function_variables = self.variables[function]\n        if variable_name not in function_variables and variable_name != '_':\n            function_variables.append(variable_name)\n\n    def _update_elifs(self, node: AnyFunctionDef, sub_node: ast.If) -> None:\n        has_elif = any(\n            isinstance(if_node, ast.If) for if_node in sub_node.orelse\n        )\n\n        if has_elif:\n            self.elifs[node] += 1\n\n    def _check_sub_node(self, node: AnyFunctionDef, sub_node) -> None:\n        is_variable = isinstance(sub_node, ast.Name)\n        context = getattr(sub_node, 'ctx', None)\n\n        if is_variable and isinstance(context, ast.Store):\n            self._update_variables(node, sub_node.id)\n        elif isinstance(sub_node, ast.Return):\n            self.returns[node] += 1\n        elif isinstance(sub_node, ast.Expr):\n            self.expressions[node] += 1\n        elif isinstance(sub_node, ast.If):\n            self._update_elifs(node, sub_node)\n\n    def check_arguments_count(self, node: AnyFunctionDef) -> None:\n        \"\"\"Checks the number of the arguments in a function.\"\"\"\n        counter = 0\n        has_extra_arg = 0\n        if is_method(getattr(node, 'function_type', None)):\n            has_extra_arg = 1\n\n        counter += len(node.args.args) + len(node.args.kwonlyargs)\n        if node.args.vararg:\n            counter += 1\n        if node.args.kwarg:\n            counter += 1\n\n        self.arguments[node] = counter - has_extra_arg\n\n    def check_function_complexity(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        In this function we iterate all the internal body's node.\n\n        We check different complexity metrics based on these internals.\n        \"\"\"\n        for body_item in node.body:\n            for sub_node in ast.walk(body_item):\n                self._check_sub_node(node, sub_node)\n\n\n@alias('visit_any_function', (\n    'visit_AsyncFunctionDef',\n    'visit_FunctionDef',\n))\nclass FunctionComplexityVisitor(BaseNodeVisitor):\n    \"\"\"\n    This class checks for complexity inside functions.\n\n    This includes:\n\n    1. Number of arguments\n    2. Number of `return` statements\n    3. Number of expressions\n    4. Number of local variables\n    5. Number of `elif` branches\n\n    \"\"\"\n\n    def __init__(self, *args, **kwargs) -> None:\n        \"\"\"Creates a counter for tracked metrics.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._counter = _ComplexityCounter()\n\n    def _check_possible_switch(self) -> None:\n        for node, elifs in self._counter.elifs.items():\n            if elifs > self.options.max_elifs:\n                self.add_violation(TooManyElifsViolation(node))\n\n    def _check_function_internals(self) -> None:\n        for node, variables in self._counter.variables.items():\n            if len(variables) > self.options.max_local_variables:\n                self.add_violation(\n                    TooManyLocalsViolation(node, text=node.name),\n                )\n\n        for node, expressions in self._counter.expressions.items():\n            if expressions > self.options.max_expressions:\n                self.add_violation(\n                    TooManyExpressionsViolation(node, text=node.name),\n                )\n\n    def _check_function_signature(self) -> None:\n        for node, arguments in self._counter.arguments.items():\n            if arguments > self.options.max_arguments:\n                self.add_violation(\n                    TooManyArgumentsViolation(node, text=str(arguments)),\n                )\n\n        for node, returns in self._counter.returns.items():\n            if returns > self.options.max_returns:\n                self.add_violation(\n                    TooManyReturnsViolation(node, text=node.name),\n                )\n\n    def _post_visit(self) -> None:\n        self._check_function_signature()\n        self._check_function_internals()\n        self._check_possible_switch()\n\n    def visit_any_function(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        Checks function's internal complexity.\n\n        Raises:\n            TooManyExpressionsViolation\n            TooManyReturnsViolation\n            TooManyLocalsViolation\n            TooManyArgumentsViolation\n            TooManyElifsViolation\n\n        \"\"\"\n        self._counter.check_arguments_count(node)\n        self._counter.check_function_complexity(node)\n        self.generic_visit(node)\n", "path": "wemake_python_styleguide/visitors/ast/complexity/function.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"\nThis module contains custom ``mypy`` types that we commonly use.\n\nPolicy\n------\n\nIf any of the following statements is true, move the type to this file:\n\n- if type is used in multiple files\n- if type is complex enough it has to be documented\n- if type is very important for the public API\n\n\"\"\"\n\nimport ast\nfrom typing import TYPE_CHECKING, Tuple, Type, Union\n\nif TYPE_CHECKING:  # pragma: no cover\n    # TODO: use Final types to annotate all constants\n    from typing_extensions import Protocol  # noqa: Z435\n\n    # This solves cycle imports problem:\n    from .visitors import base  # noqa: F401,Z300,Z435\nelse:\n    # We do not need to do anything if type checker is not working:\n    Protocol = object\n\n#: Visitor type definition:\nVisitorClass = Type['base.BaseVisitor']\n\n#: In cases we need to work with both import types:\nAnyImport = Union[ast.Import, ast.ImportFrom]\n\n#: In cases we need to work with both function definitions:\nAnyFunctionDef = Union[ast.FunctionDef, ast.AsyncFunctionDef]\n\n#: In cases we need to work with all function definitions (including Lambda)\nAnyFunctionDefAndLambda = Union[\n    ast.FunctionDef,\n    ast.AsyncFunctionDef,\n    ast.Lambda,\n]\n\n#: Flake8 API format to return error messages:\nCheckResult = Tuple[int, int, str, type]\n\n#: Tuple of AST node types for declarative syntax:\nAnyNodes = Tuple[Type[ast.AST], ...]\n\n\nclass ConfigurationOptions(Protocol):\n    \"\"\"\n    Provides structure for the options we use in our checker.\n\n    Then this protocol is passed to each individual visitor and used there.\n    It uses structural sub-typing, and does not represent any kind of a real\n    class or structure.\n\n    This class actually works only when running type check.\n    At other cases it is just an ``object``.\n\n    See also:\n        https://mypy.readthedocs.io/en/latest/protocols.html\n\n    \"\"\"\n\n    # General:\n    min_variable_length: int\n    i_control_code: bool\n\n    # Complexity:\n    max_arguments: int\n    max_local_variables: int\n    max_returns: int\n    max_expressions: int\n    max_offset_blocks: int\n    max_elifs: int\n    max_module_members: int\n    max_methods: int\n    max_line_complexity: int\n    max_jones_score: int\n    max_imports: int\n    max_conditions: int\n\n    # File names:\n    min_module_name_length: int\n", "path": "wemake_python_styleguide/types.py"}, {"content": "# -*- coding: utf-8 -*-\n\nimport ast\nfrom collections import defaultdict\nfrom typing import DefaultDict, List\n\nfrom wemake_python_styleguide.logics.functions import is_method\nfrom wemake_python_styleguide.types import (\n    AnyFunctionDef,\n    AnyFunctionDefAndLambda,\n)\nfrom wemake_python_styleguide.violations.complexity import (\n    TooManyArgumentsViolation,\n    TooManyElifsViolation,\n    TooManyExpressionsViolation,\n    TooManyLocalsViolation,\n    TooManyReturnsViolation,\n)\nfrom wemake_python_styleguide.visitors.base import BaseNodeVisitor\nfrom wemake_python_styleguide.visitors.decorators import alias\n\nFunctionCounter = DefaultDict[AnyFunctionDef, int]\nFunctionCounterWithLambda = DefaultDict[AnyFunctionDefAndLambda, int]\n\n\nclass _ComplexityCounter(object):\n    \"\"\"Helper class to encapsulate logic from the visitor.\"\"\"\n\n    def __init__(self) -> None:\n        self.arguments: FunctionCounterWithLambda = defaultdict(int)\n        self.elifs: FunctionCounter = defaultdict(int)\n        self.returns: FunctionCounter = defaultdict(int)\n        self.expressions: FunctionCounter = defaultdict(int)\n        self.variables: DefaultDict[\n            AnyFunctionDef, List[str],\n        ] = defaultdict(list)\n\n    def _update_variables(\n        self,\n        function: AnyFunctionDef,\n        variable_name: str,\n    ) -> None:\n        \"\"\"\n        Increases the counter of local variables.\n\n        What is treated as a local variable?\n        Check ``TooManyLocalsViolation`` documentation.\n        \"\"\"\n        function_variables = self.variables[function]\n        if variable_name not in function_variables and variable_name != '_':\n            function_variables.append(variable_name)\n\n    def _update_elifs(self, node: AnyFunctionDef, sub_node: ast.If) -> None:\n        has_elif = any(\n            isinstance(if_node, ast.If) for if_node in sub_node.orelse\n        )\n\n        if has_elif:\n            self.elifs[node] += 1\n\n    def _check_sub_node(self, node: AnyFunctionDef, sub_node) -> None:\n        is_variable = isinstance(sub_node, ast.Name)\n        context = getattr(sub_node, 'ctx', None)\n\n        if is_variable and isinstance(context, ast.Store):\n            self._update_variables(node, sub_node.id)\n        elif isinstance(sub_node, ast.Return):\n            self.returns[node] += 1\n        elif isinstance(sub_node, ast.Expr):\n            self.expressions[node] += 1\n        elif isinstance(sub_node, ast.If):\n            self._update_elifs(node, sub_node)\n\n    def check_arguments_count(self, node: AnyFunctionDefAndLambda) -> None:\n        \"\"\"Checks the number of the arguments in a function.\"\"\"\n        counter = 0\n        has_extra_arg = 0\n        if is_method(getattr(node, 'function_type', None)):\n            has_extra_arg = 1\n\n        counter += len(node.args.args) + len(node.args.kwonlyargs)\n        if node.args.vararg:\n            counter += 1\n        if node.args.kwarg:\n            counter += 1\n\n        self.arguments[node] = counter - has_extra_arg\n\n    def check_function_complexity(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        In this function we iterate all the internal body's node.\n\n        We check different complexity metrics based on these internals.\n        \"\"\"\n        for body_item in node.body:\n            for sub_node in ast.walk(body_item):\n                self._check_sub_node(node, sub_node)\n\n\n@alias('visit_any_function', (\n    'visit_AsyncFunctionDef',\n    'visit_FunctionDef',\n))\nclass FunctionComplexityVisitor(BaseNodeVisitor):\n    \"\"\"\n    This class checks for complexity inside functions.\n\n    This includes:\n\n    1. Number of arguments\n    2. Number of `return` statements\n    3. Number of expressions\n    4. Number of local variables\n    5. Number of `elif` branches\n\n    \"\"\"\n\n    def __init__(self, *args, **kwargs) -> None:\n        \"\"\"Creates a counter for tracked metrics.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._counter = _ComplexityCounter()\n\n    def _check_possible_switch(self) -> None:\n        for node, elifs in self._counter.elifs.items():\n            if elifs > self.options.max_elifs:\n                self.add_violation(TooManyElifsViolation(node))\n\n    def _check_function_internals(self) -> None:\n        for node, variables in self._counter.variables.items():\n            if len(variables) > self.options.max_local_variables:\n                self.add_violation(\n                    TooManyLocalsViolation(node, text=node.name),\n                )\n\n        for node, expressions in self._counter.expressions.items():\n            if expressions > self.options.max_expressions:\n                self.add_violation(\n                    TooManyExpressionsViolation(node, text=node.name),\n                )\n\n    def _check_function_signature(self) -> None:\n        for node, arguments in self._counter.arguments.items():\n            if arguments > self.options.max_arguments:\n                self.add_violation(\n                    TooManyArgumentsViolation(node, text=str(arguments)),\n                )\n\n        for node, returns in self._counter.returns.items():\n            if returns > self.options.max_returns:\n                self.add_violation(\n                    TooManyReturnsViolation(node, text=node.name),\n                )\n\n    def _post_visit(self) -> None:\n        self._check_function_signature()\n        self._check_function_internals()\n        self._check_possible_switch()\n\n    def visit_any_function(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        Checks function's internal complexity.\n\n        Raises:\n            TooManyExpressionsViolation\n            TooManyReturnsViolation\n            TooManyLocalsViolation\n            TooManyArgumentsViolation\n            TooManyElifsViolation\n\n        \"\"\"\n        self._counter.check_arguments_count(node)\n        self._counter.check_function_complexity(node)\n        self.generic_visit(node)\n\n    def visit_Lambda(self, node: ast.Lambda) -> None:\n        \"\"\"\n        Checks lambda function's internal complexity.\n\n        Raises:\n            TooManyArgumentsViolation\n\n        \"\"\"\n        self._counter.check_arguments_count(node)\n        self.generic_visit(node)\n", "path": "wemake_python_styleguide/visitors/ast/complexity/function.py"}]}