prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  609: Allow __enter__() inside an __enter__()
  ### What's wrong
  
  One design pattern is to wrap a context manager. It would be nice to avoid WPS609 errors with this code, which seems to require accessing the direct magic methods.
  
  ### How it should be
  
  Allow code like:
  ```
  class Foo:
      ...
  
      def __enter__(self):
          self._conn.__enter__()
          return self
  
      def __exit__(self, exc_type, exc_value, traceback):
          self._conn.__exit__(exc_type, exc_value, traceback)
  ```
  
  I guess the same for aenter/aexit as well.
  
  --- 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/attributes.py`
  Content:
  ```
  1 import ast
  2 from typing import ClassVar, FrozenSet
  3 
  4 from typing_extensions import final
  5 
  6 from wemake_python_styleguide.constants import ALL_MAGIC_METHODS
  7 from wemake_python_styleguide.logic.naming import access
  8 from wemake_python_styleguide.violations.best_practices import (
  9     ProtectedAttributeViolation,
  10 )
  11 from wemake_python_styleguide.violations.oop import (
  12     DirectMagicAttributeAccessViolation,
  13 )
  14 from wemake_python_styleguide.visitors.base import BaseNodeVisitor
  15 
  16 
  17 @final
  18 class WrongAttributeVisitor(BaseNodeVisitor):
  19     """Ensures that attributes are used correctly."""
  20 
  21     _allowed_to_use_protected: ClassVar[FrozenSet[str]] = frozenset((
  22         'self',
  23         'cls',
  24         'mcs',
  25     ))
  26 
  27     def visit_Attribute(self, node: ast.Attribute) -> None:
  28         """Checks the `Attribute` node."""
  29         self._check_protected_attribute(node)
  30         self._check_magic_attribute(node)
  31         self.generic_visit(node)
  32 
  33     def _is_super_called(self, node: ast.Call) -> bool:
  34         return isinstance(node.func, ast.Name) and node.func.id == 'super'
  35 
  36     def _ensure_attribute_type(self, node: ast.Attribute, exception) -> None:
  37         if isinstance(node.value, ast.Name):
  38             if node.value.id in self._allowed_to_use_protected:
  39                 return
  40 
  41         if isinstance(node.value, ast.Call):
  42             if self._is_super_called(node.value):
  43                 return
  44 
  45         self.add_violation(exception(node, text=node.attr))
  46 
  47     def _check_protected_attribute(self, node: ast.Attribute) -> None:
  48         if access.is_protected(node.attr):
  49             self._ensure_attribute_type(node, ProtectedAttributeViolation)
  50 
  51     def _check_magic_attribute(self, node: ast.Attribute) -> None:
  52         if access.is_magic(node.attr):
  53             if node.attr in ALL_MAGIC_METHODS:
  54                 self._ensure_attribute_type(
  55                     node, DirectMagicAttributeAccessViolation,
  56                 )
  57
  ```
  --- 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/attributes.py b/wemake_python_styleguide/visitors/ast/attributes.py
  --- a/wemake_python_styleguide/visitors/ast/attributes.py
  +++ b/wemake_python_styleguide/visitors/ast/attributes.py
  @@ -3,7 +3,9 @@
   
   from typing_extensions import final
   
  +from wemake_python_styleguide.compat.aliases import FunctionNodes
   from wemake_python_styleguide.constants import ALL_MAGIC_METHODS
  +from wemake_python_styleguide.logic import nodes
   from wemake_python_styleguide.logic.naming import access
   from wemake_python_styleguide.violations.best_practices import (
       ProtectedAttributeViolation,
  @@ -50,6 +52,15 @@
   
       def _check_magic_attribute(self, node: ast.Attribute) -> None:
           if access.is_magic(node.attr):
  +            # If "magic" method being called has the same name as
  +            # the enclosing function, then it is a "wrapper" and thus
  +            # a "false positive".
  +
  +            ctx = nodes.get_context(node)
  +            if isinstance(ctx, FunctionNodes):
  +                if node.attr == ctx.name:
  +                    return
  +
               if node.attr in ALL_MAGIC_METHODS:
                   self._ensure_attribute_type(
                       node, DirectMagicAttributeAccessViolation,
  
verification_info: {"golden_diff": "diff --git a/wemake_python_styleguide/visitors/ast/attributes.py b/wemake_python_styleguide/visitors/ast/attributes.py\n--- a/wemake_python_styleguide/visitors/ast/attributes.py\n+++ b/wemake_python_styleguide/visitors/ast/attributes.py\n@@ -3,7 +3,9 @@\n \n from typing_extensions import final\n \n+from wemake_python_styleguide.compat.aliases import FunctionNodes\n from wemake_python_styleguide.constants import ALL_MAGIC_METHODS\n+from wemake_python_styleguide.logic import nodes\n from wemake_python_styleguide.logic.naming import access\n from wemake_python_styleguide.violations.best_practices import (\n     ProtectedAttributeViolation,\n@@ -50,6 +52,15 @@\n \n     def _check_magic_attribute(self, node: ast.Attribute) -> None:\n         if access.is_magic(node.attr):\n+            # If \"magic\" method being called has the same name as\n+            # the enclosing function, then it is a \"wrapper\" and thus\n+            # a \"false positive\".\n+\n+            ctx = nodes.get_context(node)\n+            if isinstance(ctx, FunctionNodes):\n+                if node.attr == ctx.name:\n+                    return\n+\n             if node.attr in ALL_MAGIC_METHODS:\n                 self._ensure_attribute_type(\n                     node, DirectMagicAttributeAccessViolation,\n", "issue": "609: Allow __enter__() inside an __enter__()\n### What's wrong\r\n\r\nOne design pattern is to wrap a context manager. It would be nice to avoid WPS609 errors with this code, which seems to require accessing the direct magic methods.\r\n\r\n### How it should be\r\n\r\nAllow code like:\r\n```\r\nclass Foo:\r\n    ...\r\n\r\n    def __enter__(self):\r\n        self._conn.__enter__()\r\n        return self\r\n\r\n    def __exit__(self, exc_type, exc_value, traceback):\r\n        self._conn.__exit__(exc_type, exc_value, traceback)\r\n```\r\n\r\nI guess the same for aenter/aexit as well.\n", "before_files": [{"content": "import ast\nfrom typing import ClassVar, FrozenSet\n\nfrom typing_extensions import final\n\nfrom wemake_python_styleguide.constants import ALL_MAGIC_METHODS\nfrom wemake_python_styleguide.logic.naming import access\nfrom wemake_python_styleguide.violations.best_practices import (\n    ProtectedAttributeViolation,\n)\nfrom wemake_python_styleguide.violations.oop import (\n    DirectMagicAttributeAccessViolation,\n)\nfrom wemake_python_styleguide.visitors.base import BaseNodeVisitor\n\n\n@final\nclass WrongAttributeVisitor(BaseNodeVisitor):\n    \"\"\"Ensures that attributes are used correctly.\"\"\"\n\n    _allowed_to_use_protected: ClassVar[FrozenSet[str]] = frozenset((\n        'self',\n        'cls',\n        'mcs',\n    ))\n\n    def visit_Attribute(self, node: ast.Attribute) -> None:\n        \"\"\"Checks the `Attribute` node.\"\"\"\n        self._check_protected_attribute(node)\n        self._check_magic_attribute(node)\n        self.generic_visit(node)\n\n    def _is_super_called(self, node: ast.Call) -> bool:\n        return isinstance(node.func, ast.Name) and node.func.id == 'super'\n\n    def _ensure_attribute_type(self, node: ast.Attribute, exception) -> None:\n        if isinstance(node.value, ast.Name):\n            if node.value.id in self._allowed_to_use_protected:\n                return\n\n        if isinstance(node.value, ast.Call):\n            if self._is_super_called(node.value):\n                return\n\n        self.add_violation(exception(node, text=node.attr))\n\n    def _check_protected_attribute(self, node: ast.Attribute) -> None:\n        if access.is_protected(node.attr):\n            self._ensure_attribute_type(node, ProtectedAttributeViolation)\n\n    def _check_magic_attribute(self, node: ast.Attribute) -> None:\n        if access.is_magic(node.attr):\n            if node.attr in ALL_MAGIC_METHODS:\n                self._ensure_attribute_type(\n                    node, DirectMagicAttributeAccessViolation,\n                )\n", "path": "wemake_python_styleguide/visitors/ast/attributes.py"}], "after_files": [{"content": "import ast\nfrom typing import ClassVar, FrozenSet\n\nfrom typing_extensions import final\n\nfrom wemake_python_styleguide.compat.aliases import FunctionNodes\nfrom wemake_python_styleguide.constants import ALL_MAGIC_METHODS\nfrom wemake_python_styleguide.logic import nodes\nfrom wemake_python_styleguide.logic.naming import access\nfrom wemake_python_styleguide.violations.best_practices import (\n    ProtectedAttributeViolation,\n)\nfrom wemake_python_styleguide.violations.oop import (\n    DirectMagicAttributeAccessViolation,\n)\nfrom wemake_python_styleguide.visitors.base import BaseNodeVisitor\n\n\n@final\nclass WrongAttributeVisitor(BaseNodeVisitor):\n    \"\"\"Ensures that attributes are used correctly.\"\"\"\n\n    _allowed_to_use_protected: ClassVar[FrozenSet[str]] = frozenset((\n        'self',\n        'cls',\n        'mcs',\n    ))\n\n    def visit_Attribute(self, node: ast.Attribute) -> None:\n        \"\"\"Checks the `Attribute` node.\"\"\"\n        self._check_protected_attribute(node)\n        self._check_magic_attribute(node)\n        self.generic_visit(node)\n\n    def _is_super_called(self, node: ast.Call) -> bool:\n        return isinstance(node.func, ast.Name) and node.func.id == 'super'\n\n    def _ensure_attribute_type(self, node: ast.Attribute, exception) -> None:\n        if isinstance(node.value, ast.Name):\n            if node.value.id in self._allowed_to_use_protected:\n                return\n\n        if isinstance(node.value, ast.Call):\n            if self._is_super_called(node.value):\n                return\n\n        self.add_violation(exception(node, text=node.attr))\n\n    def _check_protected_attribute(self, node: ast.Attribute) -> None:\n        if access.is_protected(node.attr):\n            self._ensure_attribute_type(node, ProtectedAttributeViolation)\n\n    def _check_magic_attribute(self, node: ast.Attribute) -> None:\n        if access.is_magic(node.attr):\n            # If \"magic\" method being called has the same name as\n            # the enclosing function, then it is a \"wrapper\" and thus\n            # a \"false positive\".\n\n            ctx = nodes.get_context(node)\n            if isinstance(ctx, FunctionNodes):\n                if node.attr == ctx.name:\n                    return\n\n            if node.attr in ALL_MAGIC_METHODS:\n                self._ensure_attribute_type(\n                    node, DirectMagicAttributeAccessViolation,\n                )\n", "path": "wemake_python_styleguide/visitors/ast/attributes.py"}]}