prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add Exceptions for String Constant Overuse
  # Rule request
  
  I feel it would be good to be able to declare exceptions for WPS226
  
  ## Thesis / Reasoning
  
  In a file on a current project, I tend to use `" ".join(iterable)` a lot.
  It feels unnatural to declare a CONSTANT for that.
  Also, I don't think it is good in this case to disable WPS226 for the entire file as there could be other common string constants.
  
  Alternative: Excluse `" "`, `""`, "`\n"` & friends from this by default.
  
  --- 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/visitors/ast/complexity/overuses.py`
  Content:
  ```
  1 import ast
  2 from collections import defaultdict
  3 from typing import Callable, ClassVar, DefaultDict, List, Tuple
  4 
  5 from typing_extensions import final
  6 
  7 from wemake_python_styleguide.compat.aliases import FunctionNodes
  8 from wemake_python_styleguide.logic import source, walk
  9 from wemake_python_styleguide.logic.complexity import overuses
  10 from wemake_python_styleguide.types import AnyNodes, AnyText, AnyTextPrimitive
  11 from wemake_python_styleguide.violations import complexity
  12 from wemake_python_styleguide.visitors import base, decorators
  13 
  14 #: We use these types to store the number of nodes usage in different contexts.
  15 _Expressions = DefaultDict[str, List[ast.AST]]
  16 _FunctionExpressions = DefaultDict[ast.AST, _Expressions]
  17 
  18 
  19 @final
  20 @decorators.alias('visit_any_string', (
  21     'visit_Str',
  22     'visit_Bytes',
  23 ))
  24 class StringOveruseVisitor(base.BaseNodeVisitor):
  25     """Restricts several string usages."""
  26 
  27     def __init__(self, *args, **kwargs) -> None:
  28         """Inits the counter for constants."""
  29         super().__init__(*args, **kwargs)
  30         self._string_constants: DefaultDict[
  31             AnyTextPrimitive, int,
  32         ] = defaultdict(int)
  33 
  34     def visit_any_string(self, node: AnyText) -> None:
  35         """
  36         Restricts to over-use string constants.
  37 
  38         Raises:
  39             OverusedStringViolation
  40 
  41         """
  42         self._check_string_constant(node)
  43         self.generic_visit(node)
  44 
  45     def _check_string_constant(self, node: AnyText) -> None:
  46         if overuses.is_annotation(node):
  47             return
  48 
  49         self._string_constants[node.s] += 1
  50 
  51     def _post_visit(self) -> None:
  52         for string, usage_count in self._string_constants.items():
  53             if usage_count > self.options.max_string_usages:
  54                 self.add_violation(
  55                     complexity.OverusedStringViolation(
  56                         text=source.render_string(string) or "''",
  57                         baseline=self.options.max_string_usages,
  58                     ),
  59                 )
  60 
  61 
  62 @final
  63 class ExpressionOveruseVisitor(base.BaseNodeVisitor):
  64     """Finds overused expressions."""
  65 
  66     _expressions: ClassVar[AnyNodes] = (
  67         # We do not treat `ast.Attribute`s as expressions
  68         # because they are too widely used. That's a compromise.
  69         ast.Assert,
  70         ast.BoolOp,
  71         ast.BinOp,
  72         ast.Call,
  73         ast.Compare,
  74         ast.Subscript,
  75         ast.UnaryOp,
  76         ast.Lambda,
  77 
  78         ast.DictComp,
  79         ast.Dict,
  80         ast.List,
  81         ast.ListComp,
  82         ast.Tuple,
  83         ast.GeneratorExp,
  84         ast.Set,
  85         ast.SetComp,
  86     )
  87 
  88     _ignore_predicates: Tuple[Callable[[ast.AST], bool], ...] = (
  89         overuses.is_decorator,
  90         overuses.is_self,
  91         overuses.is_annotation,
  92         overuses.is_class_context,
  93         overuses.is_super_call,
  94         overuses.is_primitive,
  95     )
  96 
  97     _msg: ClassVar[str] = '{0}; used {1}'
  98 
  99     def __init__(self, *args, **kwargs) -> None:
  100         """We need to track expression usage in functions and modules."""
  101         super().__init__(*args, **kwargs)
  102         self._module_expressions: _Expressions = defaultdict(list)
  103         self._function_expressions: _FunctionExpressions = defaultdict(
  104             lambda: defaultdict(list),
  105         )
  106 
  107     def visit(self, node: ast.AST) -> None:
  108         """
  109         Visits all nodes in a module to find overused values.
  110 
  111         Raises:
  112             OverusedExpressionViolation
  113 
  114         """
  115         if isinstance(node, self._expressions):
  116             self._add_expression(node)
  117         self.generic_visit(node)
  118 
  119     def _add_expression(self, node: ast.AST) -> None:
  120         if any(ignore(node) for ignore in self._ignore_predicates):
  121             return
  122 
  123         source_code = source.node_to_string(node)
  124         self._module_expressions[source_code].append(node)
  125 
  126         maybe_function = walk.get_closest_parent(node, FunctionNodes)
  127         if maybe_function is not None:
  128             self._function_expressions[maybe_function][source_code].append(
  129                 node,
  130             )
  131 
  132     def _post_visit(self) -> None:
  133         for mod_source, module_nodes in self._module_expressions.items():
  134             if len(module_nodes) > self.options.max_module_expressions:
  135                 self.add_violation(
  136                     complexity.OverusedExpressionViolation(
  137                         module_nodes[0],
  138                         text=self._msg.format(mod_source, len(module_nodes)),
  139                         baseline=self.options.max_module_expressions,
  140                     ),
  141                 )
  142 
  143         for function_contexts in self._function_expressions.values():
  144             for src, function_nodes in function_contexts.items():
  145                 if len(function_nodes) > self.options.max_function_expressions:
  146                     self.add_violation(
  147                         complexity.OverusedExpressionViolation(
  148                             function_nodes[0],
  149                             text=self._msg.format(src, len(function_nodes)),
  150                             baseline=self.options.max_function_expressions,
  151                         ),
  152                     )
  153
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/wemake_python_styleguide/visitors/ast/complexity/overuses.py b/wemake_python_styleguide/visitors/ast/complexity/overuses.py
  --- a/wemake_python_styleguide/visitors/ast/complexity/overuses.py
  +++ b/wemake_python_styleguide/visitors/ast/complexity/overuses.py
  @@ -22,7 +22,25 @@
       'visit_Bytes',
   ))
   class StringOveruseVisitor(base.BaseNodeVisitor):
  -    """Restricts several string usages."""
  +    """
  +    Restricts repeated usage of the same string constant.
  +
  +    NB: Some short strings are ignored, as their use is very common and
  +    forcing assignment would not make much sense (i.e. newlines or "").
  +    """
  +
  +    _ignored_string_constants = frozenset((
  +        ' ',
  +        '',
  +        '\n',
  +        '\r\n',
  +        '\t',
  +        b' ',
  +        b'',
  +        b'\n',
  +        b'\r\n',
  +        b'\t',
  +    ))
   
       def __init__(self, *args, **kwargs) -> None:
           """Inits the counter for constants."""
  @@ -46,6 +64,11 @@
           if overuses.is_annotation(node):
               return
   
  +        # Some strings are so common, that it makes no sense to check if
  +        # they are overused.
  +        if node.s in self._ignored_string_constants:
  +            return
  +
           self._string_constants[node.s] += 1
   
       def _post_visit(self) -> None:
  
verification_info: {"golden_diff": "diff --git a/wemake_python_styleguide/visitors/ast/complexity/overuses.py b/wemake_python_styleguide/visitors/ast/complexity/overuses.py\n--- a/wemake_python_styleguide/visitors/ast/complexity/overuses.py\n+++ b/wemake_python_styleguide/visitors/ast/complexity/overuses.py\n@@ -22,7 +22,25 @@\n     'visit_Bytes',\n ))\n class StringOveruseVisitor(base.BaseNodeVisitor):\n-    \"\"\"Restricts several string usages.\"\"\"\n+    \"\"\"\n+    Restricts repeated usage of the same string constant.\n+\n+    NB: Some short strings are ignored, as their use is very common and\n+    forcing assignment would not make much sense (i.e. newlines or \"\").\n+    \"\"\"\n+\n+    _ignored_string_constants = frozenset((\n+        ' ',\n+        '',\n+        '\\n',\n+        '\\r\\n',\n+        '\\t',\n+        b' ',\n+        b'',\n+        b'\\n',\n+        b'\\r\\n',\n+        b'\\t',\n+    ))\n \n     def __init__(self, *args, **kwargs) -> None:\n         \"\"\"Inits the counter for constants.\"\"\"\n@@ -46,6 +64,11 @@\n         if overuses.is_annotation(node):\n             return\n \n+        # Some strings are so common, that it makes no sense to check if\n+        # they are overused.\n+        if node.s in self._ignored_string_constants:\n+            return\n+\n         self._string_constants[node.s] += 1\n \n     def _post_visit(self) -> None:\n", "issue": "Add Exceptions for String Constant Overuse\n# Rule request\r\n\r\nI feel it would be good to be able to declare exceptions for WPS226\r\n\r\n## Thesis / Reasoning\r\n\r\nIn a file on a current project, I tend to use `\" \".join(iterable)` a lot.\r\nIt feels unnatural to declare a CONSTANT for that.\r\nAlso, I don't think it is good in this case to disable WPS226 for the entire file as there could be other common string constants.\r\n\r\nAlternative: Excluse `\" \"`, `\"\"`, \"`\\n\"` & friends from this by default.\n", "before_files": [{"content": "import ast\nfrom collections import defaultdict\nfrom typing import Callable, ClassVar, DefaultDict, List, Tuple\n\nfrom typing_extensions import final\n\nfrom wemake_python_styleguide.compat.aliases import FunctionNodes\nfrom wemake_python_styleguide.logic import source, walk\nfrom wemake_python_styleguide.logic.complexity import overuses\nfrom wemake_python_styleguide.types import AnyNodes, AnyText, AnyTextPrimitive\nfrom wemake_python_styleguide.violations import complexity\nfrom wemake_python_styleguide.visitors import base, decorators\n\n#: We use these types to store the number of nodes usage in different contexts.\n_Expressions = DefaultDict[str, List[ast.AST]]\n_FunctionExpressions = DefaultDict[ast.AST, _Expressions]\n\n\n@final\n@decorators.alias('visit_any_string', (\n    'visit_Str',\n    'visit_Bytes',\n))\nclass StringOveruseVisitor(base.BaseNodeVisitor):\n    \"\"\"Restricts several string usages.\"\"\"\n\n    def __init__(self, *args, **kwargs) -> None:\n        \"\"\"Inits the counter for constants.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._string_constants: DefaultDict[\n            AnyTextPrimitive, int,\n        ] = defaultdict(int)\n\n    def visit_any_string(self, node: AnyText) -> None:\n        \"\"\"\n        Restricts to over-use string constants.\n\n        Raises:\n            OverusedStringViolation\n\n        \"\"\"\n        self._check_string_constant(node)\n        self.generic_visit(node)\n\n    def _check_string_constant(self, node: AnyText) -> None:\n        if overuses.is_annotation(node):\n            return\n\n        self._string_constants[node.s] += 1\n\n    def _post_visit(self) -> None:\n        for string, usage_count in self._string_constants.items():\n            if usage_count > self.options.max_string_usages:\n                self.add_violation(\n                    complexity.OverusedStringViolation(\n                        text=source.render_string(string) or \"''\",\n                        baseline=self.options.max_string_usages,\n                    ),\n                )\n\n\n@final\nclass ExpressionOveruseVisitor(base.BaseNodeVisitor):\n    \"\"\"Finds overused expressions.\"\"\"\n\n    _expressions: ClassVar[AnyNodes] = (\n        # We do not treat `ast.Attribute`s as expressions\n        # because they are too widely used. That's a compromise.\n        ast.Assert,\n        ast.BoolOp,\n        ast.BinOp,\n        ast.Call,\n        ast.Compare,\n        ast.Subscript,\n        ast.UnaryOp,\n        ast.Lambda,\n\n        ast.DictComp,\n        ast.Dict,\n        ast.List,\n        ast.ListComp,\n        ast.Tuple,\n        ast.GeneratorExp,\n        ast.Set,\n        ast.SetComp,\n    )\n\n    _ignore_predicates: Tuple[Callable[[ast.AST], bool], ...] = (\n        overuses.is_decorator,\n        overuses.is_self,\n        overuses.is_annotation,\n        overuses.is_class_context,\n        overuses.is_super_call,\n        overuses.is_primitive,\n    )\n\n    _msg: ClassVar[str] = '{0}; used {1}'\n\n    def __init__(self, *args, **kwargs) -> None:\n        \"\"\"We need to track expression usage in functions and modules.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._module_expressions: _Expressions = defaultdict(list)\n        self._function_expressions: _FunctionExpressions = defaultdict(\n            lambda: defaultdict(list),\n        )\n\n    def visit(self, node: ast.AST) -> None:\n        \"\"\"\n        Visits all nodes in a module to find overused values.\n\n        Raises:\n            OverusedExpressionViolation\n\n        \"\"\"\n        if isinstance(node, self._expressions):\n            self._add_expression(node)\n        self.generic_visit(node)\n\n    def _add_expression(self, node: ast.AST) -> None:\n        if any(ignore(node) for ignore in self._ignore_predicates):\n            return\n\n        source_code = source.node_to_string(node)\n        self._module_expressions[source_code].append(node)\n\n        maybe_function = walk.get_closest_parent(node, FunctionNodes)\n        if maybe_function is not None:\n            self._function_expressions[maybe_function][source_code].append(\n                node,\n            )\n\n    def _post_visit(self) -> None:\n        for mod_source, module_nodes in self._module_expressions.items():\n            if len(module_nodes) > self.options.max_module_expressions:\n                self.add_violation(\n                    complexity.OverusedExpressionViolation(\n                        module_nodes[0],\n                        text=self._msg.format(mod_source, len(module_nodes)),\n                        baseline=self.options.max_module_expressions,\n                    ),\n                )\n\n        for function_contexts in self._function_expressions.values():\n            for src, function_nodes in function_contexts.items():\n                if len(function_nodes) > self.options.max_function_expressions:\n                    self.add_violation(\n                        complexity.OverusedExpressionViolation(\n                            function_nodes[0],\n                            text=self._msg.format(src, len(function_nodes)),\n                            baseline=self.options.max_function_expressions,\n                        ),\n                    )\n", "path": "wemake_python_styleguide/visitors/ast/complexity/overuses.py"}], "after_files": [{"content": "import ast\nfrom collections import defaultdict\nfrom typing import Callable, ClassVar, DefaultDict, List, Tuple\n\nfrom typing_extensions import final\n\nfrom wemake_python_styleguide.compat.aliases import FunctionNodes\nfrom wemake_python_styleguide.logic import source, walk\nfrom wemake_python_styleguide.logic.complexity import overuses\nfrom wemake_python_styleguide.types import AnyNodes, AnyText, AnyTextPrimitive\nfrom wemake_python_styleguide.violations import complexity\nfrom wemake_python_styleguide.visitors import base, decorators\n\n#: We use these types to store the number of nodes usage in different contexts.\n_Expressions = DefaultDict[str, List[ast.AST]]\n_FunctionExpressions = DefaultDict[ast.AST, _Expressions]\n\n\n@final\n@decorators.alias('visit_any_string', (\n    'visit_Str',\n    'visit_Bytes',\n))\nclass StringOveruseVisitor(base.BaseNodeVisitor):\n    \"\"\"\n    Restricts repeated usage of the same string constant.\n\n    NB: Some short strings are ignored, as their use is very common and\n    forcing assignment would not make much sense (i.e. newlines or \"\").\n    \"\"\"\n\n    _ignored_string_constants = frozenset((\n        ' ',\n        '',\n        '\\n',\n        '\\r\\n',\n        '\\t',\n        b' ',\n        b'',\n        b'\\n',\n        b'\\r\\n',\n        b'\\t',\n    ))\n\n    def __init__(self, *args, **kwargs) -> None:\n        \"\"\"Inits the counter for constants.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._string_constants: DefaultDict[\n            AnyTextPrimitive, int,\n        ] = defaultdict(int)\n\n    def visit_any_string(self, node: AnyText) -> None:\n        \"\"\"\n        Restricts to over-use string constants.\n\n        Raises:\n            OverusedStringViolation\n\n        \"\"\"\n        self._check_string_constant(node)\n        self.generic_visit(node)\n\n    def _check_string_constant(self, node: AnyText) -> None:\n        if overuses.is_annotation(node):\n            return\n\n        # Some strings are so common, that it makes no sense to check if\n        # they are overused.\n        if node.s in self._ignored_string_constants:\n            return\n\n        self._string_constants[node.s] += 1\n\n    def _post_visit(self) -> None:\n        for string, usage_count in self._string_constants.items():\n            if usage_count > self.options.max_string_usages:\n                self.add_violation(\n                    complexity.OverusedStringViolation(\n                        text=source.render_string(string) or \"''\",\n                        baseline=self.options.max_string_usages,\n                    ),\n                )\n\n\n@final\nclass ExpressionOveruseVisitor(base.BaseNodeVisitor):\n    \"\"\"Finds overused expressions.\"\"\"\n\n    _expressions: ClassVar[AnyNodes] = (\n        # We do not treat `ast.Attribute`s as expressions\n        # because they are too widely used. That's a compromise.\n        ast.Assert,\n        ast.BoolOp,\n        ast.BinOp,\n        ast.Call,\n        ast.Compare,\n        ast.Subscript,\n        ast.UnaryOp,\n        ast.Lambda,\n\n        ast.DictComp,\n        ast.Dict,\n        ast.List,\n        ast.ListComp,\n        ast.Tuple,\n        ast.GeneratorExp,\n        ast.Set,\n        ast.SetComp,\n    )\n\n    _ignore_predicates: Tuple[Callable[[ast.AST], bool], ...] = (\n        overuses.is_decorator,\n        overuses.is_self,\n        overuses.is_annotation,\n        overuses.is_class_context,\n        overuses.is_super_call,\n        overuses.is_primitive,\n    )\n\n    _msg: ClassVar[str] = '{0}; used {1}'\n\n    def __init__(self, *args, **kwargs) -> None:\n        \"\"\"We need to track expression usage in functions and modules.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._module_expressions: _Expressions = defaultdict(list)\n        self._function_expressions: _FunctionExpressions = defaultdict(\n            lambda: defaultdict(list),\n        )\n\n    def visit(self, node: ast.AST) -> None:\n        \"\"\"\n        Visits all nodes in a module to find overused values.\n\n        Raises:\n            OverusedExpressionViolation\n\n        \"\"\"\n        if isinstance(node, self._expressions):\n            self._add_expression(node)\n        self.generic_visit(node)\n\n    def _add_expression(self, node: ast.AST) -> None:\n        if any(ignore(node) for ignore in self._ignore_predicates):\n            return\n\n        source_code = source.node_to_string(node)\n        self._module_expressions[source_code].append(node)\n\n        maybe_function = walk.get_closest_parent(node, FunctionNodes)\n        if maybe_function is not None:\n            self._function_expressions[maybe_function][source_code].append(\n                node,\n            )\n\n    def _post_visit(self) -> None:\n        for mod_source, module_nodes in self._module_expressions.items():\n            if len(module_nodes) > self.options.max_module_expressions:\n                self.add_violation(\n                    complexity.OverusedExpressionViolation(\n                        module_nodes[0],\n                        text=self._msg.format(mod_source, len(module_nodes)),\n                        baseline=self.options.max_module_expressions,\n                    ),\n                )\n\n        for function_contexts in self._function_expressions.values():\n            for src, function_nodes in function_contexts.items():\n                if len(function_nodes) > self.options.max_function_expressions:\n                    self.add_violation(\n                        complexity.OverusedExpressionViolation(\n                            function_nodes[0],\n                            text=self._msg.format(src, len(function_nodes)),\n                            baseline=self.options.max_function_expressions,\n                        ),\n                    )\n", "path": "wemake_python_styleguide/visitors/ast/complexity/overuses.py"}]}