We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
StrawberryResolver.annotation removed in release 0.115.0
I, and possibly others, am relying on the annotations of the resolver in order to "inherit" resolvers.
It would be great if we could have that information returned in a future release.  

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `strawberry/types/fields/resolver.py`
Content:
```
1 from __future__ import annotations as _
2 
3 import builtins
4 import inspect
5 import sys
6 import warnings
7 from inspect import isasyncgenfunction, iscoroutinefunction
8 from typing import (  # type: ignore[attr-defined]
9     Any,
10     Callable,
11     Dict,
12     ForwardRef,
13     Generic,
14     List,
15     Mapping,
16     NamedTuple,
17     Optional,
18     Tuple,
19     Type,
20     TypeVar,
21     Union,
22     _eval_type,
23 )
24 
25 from backports.cached_property import cached_property
26 from typing_extensions import Annotated, Protocol, get_args, get_origin
27 
28 from strawberry.annotation import StrawberryAnnotation
29 from strawberry.arguments import StrawberryArgument
30 from strawberry.exceptions import MissingArgumentsAnnotationsError
31 from strawberry.type import StrawberryType
32 from strawberry.types.info import Info
33 
34 
35 class ReservedParameterSpecification(Protocol):
36     def find(
37         self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver
38     ) -> Optional[inspect.Parameter]:
39         """Finds the reserved parameter from ``parameters``."""
40 
41 
42 class ReservedName(NamedTuple):
43     name: str
44 
45     def find(
46         self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver
47     ) -> Optional[inspect.Parameter]:
48         return next((p for p in parameters if p.name == self.name), None)
49 
50 
51 class ReservedNameBoundParameter(NamedTuple):
52     name: str
53 
54     def find(
55         self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver
56     ) -> Optional[inspect.Parameter]:
57         if parameters:  # Add compatibility for resolvers with no arguments
58             first_parameter = parameters[0]
59             return first_parameter if first_parameter.name == self.name else None
60         else:
61             return None
62 
63 
64 class ReservedType(NamedTuple):
65     """Define a reserved type by name or by type.
66 
67     To preserve backwards-comaptibility, if an annotation was defined but does not match
68     :attr:`type`, then the name is used as a fallback.
69     """
70 
71     name: str
72     type: Type
73 
74     def find(
75         self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver
76     ) -> Optional[inspect.Parameter]:
77         for parameter in parameters:
78             annotation = parameter.annotation
79             try:
80                 resolved_annotation = _eval_type(
81                     ForwardRef(annotation)
82                     if isinstance(annotation, str)
83                     else annotation,
84                     resolver._namespace,
85                     None,
86                 )
87                 resolver._resolved_annotations[parameter] = resolved_annotation
88             except NameError:
89                 # Type-annotation could not be resolved
90                 resolved_annotation = annotation
91             if self.is_reserved_type(resolved_annotation):
92                 return parameter
93 
94         # Fallback to matching by name
95         reserved_name = ReservedName(name=self.name).find(parameters, resolver)
96         if reserved_name:
97             warning = DeprecationWarning(
98                 f"Argument name-based matching of '{self.name}' is deprecated and will "
99                 "be removed in v1.0. Ensure that reserved arguments are annotated "
100                 "their respective types (i.e. use value: 'DirectiveValue[str]' instead "
101                 "of 'value: str' and 'info: Info' instead of a plain 'info')."
102             )
103             warnings.warn(warning)
104             return reserved_name
105         else:
106             return None
107 
108     def is_reserved_type(self, other: Type) -> bool:
109         if get_origin(other) is Annotated:
110             # Handle annotated arguments such as Private[str] and DirectiveValue[str]
111             return any(isinstance(argument, self.type) for argument in get_args(other))
112         else:
113             # Handle both concrete and generic types (i.e Info, and Info[Any, Any])
114             return other is self.type or get_origin(other) is self.type
115 
116 
117 SELF_PARAMSPEC = ReservedNameBoundParameter("self")
118 CLS_PARAMSPEC = ReservedNameBoundParameter("cls")
119 ROOT_PARAMSPEC = ReservedName("root")
120 INFO_PARAMSPEC = ReservedType("info", Info)
121 
122 T = TypeVar("T")
123 
124 
125 class StrawberryResolver(Generic[T]):
126 
127     RESERVED_PARAMSPEC: Tuple[ReservedParameterSpecification, ...] = (
128         SELF_PARAMSPEC,
129         CLS_PARAMSPEC,
130         ROOT_PARAMSPEC,
131         INFO_PARAMSPEC,
132     )
133 
134     def __init__(
135         self,
136         func: Union[Callable[..., T], staticmethod, classmethod],
137         *,
138         description: Optional[str] = None,
139         type_override: Optional[Union[StrawberryType, type]] = None,
140     ):
141         self.wrapped_func = func
142         self._description = description
143         self._type_override = type_override
144         """Specify the type manually instead of calculating from wrapped func
145 
146         This is used when creating copies of types w/ generics
147         """
148         self._resolved_annotations: Dict[inspect.Parameter, Any] = {}
149         """Populated during reserved parameter determination.
150 
151         Caching resolved annotations this way prevents evaling them repeatedly.
152         """
153 
154     # TODO: Use this when doing the actual resolving? How to deal with async resolvers?
155     def __call__(self, *args, **kwargs) -> T:
156         if not callable(self.wrapped_func):
157             raise UncallableResolverError(self)
158         return self.wrapped_func(*args, **kwargs)
159 
160     @cached_property
161     def signature(self) -> inspect.Signature:
162         return inspect.signature(self._unbound_wrapped_func)
163 
164     @cached_property
165     def reserved_parameters(
166         self,
167     ) -> Dict[ReservedParameterSpecification, Optional[inspect.Parameter]]:
168         """Mapping of reserved parameter specification to parameter."""
169         parameters = tuple(self.signature.parameters.values())
170         return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}
171 
172     @cached_property
173     def arguments(self) -> List[StrawberryArgument]:
174         """Resolver arguments exposed in the GraphQL Schema."""
175         parameters = self.signature.parameters.values()
176         reserved_parameters = set(self.reserved_parameters.values())
177 
178         missing_annotations = set()
179         arguments = []
180         user_parameters = (p for p in parameters if p not in reserved_parameters)
181         for param in user_parameters:
182             annotation = self._resolved_annotations.get(param, param.annotation)
183             if annotation is inspect.Signature.empty:
184                 missing_annotations.add(param.name)
185             else:
186                 argument = StrawberryArgument(
187                     python_name=param.name,
188                     graphql_name=None,
189                     type_annotation=StrawberryAnnotation(
190                         annotation=annotation, namespace=self._namespace
191                     ),
192                     default=param.default,
193                 )
194                 arguments.append(argument)
195         if missing_annotations:
196             raise MissingArgumentsAnnotationsError(self.name, missing_annotations)
197         return arguments
198 
199     @cached_property
200     def info_parameter(self) -> Optional[inspect.Parameter]:
201         return self.reserved_parameters.get(INFO_PARAMSPEC)
202 
203     @cached_property
204     def root_parameter(self) -> Optional[inspect.Parameter]:
205         return self.reserved_parameters.get(ROOT_PARAMSPEC)
206 
207     @cached_property
208     def self_parameter(self) -> Optional[inspect.Parameter]:
209         return self.reserved_parameters.get(SELF_PARAMSPEC)
210 
211     @cached_property
212     def name(self) -> str:
213         # TODO: What to do if resolver is a lambda?
214         return self._unbound_wrapped_func.__name__
215 
216     @cached_property
217     def type_annotation(self) -> Optional[StrawberryAnnotation]:
218         return_annotation = self.signature.return_annotation
219         if return_annotation is inspect.Signature.empty:
220             return None
221         else:
222             type_annotation = StrawberryAnnotation(
223                 annotation=return_annotation, namespace=self._namespace
224             )
225         return type_annotation
226 
227     @property
228     def type(self) -> Optional[Union[StrawberryType, type]]:
229         if self._type_override:
230             return self._type_override
231         if self.type_annotation is None:
232             return None
233         return self.type_annotation.resolve()
234 
235     @cached_property
236     def is_async(self) -> bool:
237         return iscoroutinefunction(self._unbound_wrapped_func) or isasyncgenfunction(
238             self._unbound_wrapped_func
239         )
240 
241     def copy_with(
242         self, type_var_map: Mapping[TypeVar, Union[StrawberryType, builtins.type]]
243     ) -> StrawberryResolver:
244         type_override = None
245 
246         if self.type:
247             if isinstance(self.type, StrawberryType):
248                 type_override = self.type.copy_with(type_var_map)
249             else:
250                 type_override = self.type._type_definition.copy_with(  # type: ignore
251                     type_var_map,
252                 )
253 
254         return type(self)(
255             func=self.wrapped_func,
256             description=self._description,
257             type_override=type_override,
258         )
259 
260     @cached_property
261     def _namespace(self) -> Dict[str, Any]:
262         return sys.modules[self._unbound_wrapped_func.__module__].__dict__
263 
264     @cached_property
265     def _unbound_wrapped_func(self) -> Callable[..., T]:
266         if isinstance(self.wrapped_func, (staticmethod, classmethod)):
267             return self.wrapped_func.__func__
268 
269         return self.wrapped_func
270 
271 
272 class UncallableResolverError(Exception):
273     def __init__(self, resolver: "StrawberryResolver"):
274         message = (
275             f"Attempted to call resolver {resolver} with uncallable function "
276             f"{resolver.wrapped_func}"
277         )
278         super().__init__(message)
279 
280 
281 __all__ = ["StrawberryResolver"]
282
```
--- 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/strawberry/types/fields/resolver.py b/strawberry/types/fields/resolver.py
--- a/strawberry/types/fields/resolver.py
+++ b/strawberry/types/fields/resolver.py
@@ -213,6 +213,25 @@
         # TODO: What to do if resolver is a lambda?
         return self._unbound_wrapped_func.__name__
 
+    @cached_property
+    def annotations(self) -> Dict[str, object]:
+        """Annotations for the resolver.
+
+        Does not include special args defined in `RESERVED_PARAMSPEC` (e.g. self, root,
+        info)
+        """
+        reserved_parameters = self.reserved_parameters
+        reserved_names = {p.name for p in reserved_parameters.values() if p is not None}
+
+        annotations = self._unbound_wrapped_func.__annotations__
+        annotations = {
+            name: annotation
+            for name, annotation in annotations.items()
+            if name not in reserved_names
+        }
+
+        return annotations
+
     @cached_property
     def type_annotation(self) -> Optional[StrawberryAnnotation]:
         return_annotation = self.signature.return_annotation

{"golden_diff": "diff --git a/strawberry/types/fields/resolver.py b/strawberry/types/fields/resolver.py\n--- a/strawberry/types/fields/resolver.py\n+++ b/strawberry/types/fields/resolver.py\n@@ -213,6 +213,25 @@\n         # TODO: What to do if resolver is a lambda?\n         return self._unbound_wrapped_func.__name__\n \n+    @cached_property\n+    def annotations(self) -> Dict[str, object]:\n+        \"\"\"Annotations for the resolver.\n+\n+        Does not include special args defined in `RESERVED_PARAMSPEC` (e.g. self, root,\n+        info)\n+        \"\"\"\n+        reserved_parameters = self.reserved_parameters\n+        reserved_names = {p.name for p in reserved_parameters.values() if p is not None}\n+\n+        annotations = self._unbound_wrapped_func.__annotations__\n+        annotations = {\n+            name: annotation\n+            for name, annotation in annotations.items()\n+            if name not in reserved_names\n+        }\n+\n+        return annotations\n+\n     @cached_property\n     def type_annotation(self) -> Optional[StrawberryAnnotation]:\n         return_annotation = self.signature.return_annotation\n", "issue": "StrawberryResolver.annotation removed in release 0.115.0\nI, and possibly others, am relying on the annotations of the resolver in order to \"inherit\" resolvers.\r\nIt would be great if we could have that information returned in a future release.  \n", "before_files": [{"content": "from __future__ import annotations as _\n\nimport builtins\nimport inspect\nimport sys\nimport warnings\nfrom inspect import isasyncgenfunction, iscoroutinefunction\nfrom typing import (  # type: ignore[attr-defined]\n    Any,\n    Callable,\n    Dict,\n    ForwardRef,\n    Generic,\n    List,\n    Mapping,\n    NamedTuple,\n    Optional,\n    Tuple,\n    Type,\n    TypeVar,\n    Union,\n    _eval_type,\n)\n\nfrom backports.cached_property import cached_property\nfrom typing_extensions import Annotated, Protocol, get_args, get_origin\n\nfrom strawberry.annotation import StrawberryAnnotation\nfrom strawberry.arguments import StrawberryArgument\nfrom strawberry.exceptions import MissingArgumentsAnnotationsError\nfrom strawberry.type import StrawberryType\nfrom strawberry.types.info import Info\n\n\nclass ReservedParameterSpecification(Protocol):\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        \"\"\"Finds the reserved parameter from ``parameters``.\"\"\"\n\n\nclass ReservedName(NamedTuple):\n    name: str\n\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        return next((p for p in parameters if p.name == self.name), None)\n\n\nclass ReservedNameBoundParameter(NamedTuple):\n    name: str\n\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        if parameters:  # Add compatibility for resolvers with no arguments\n            first_parameter = parameters[0]\n            return first_parameter if first_parameter.name == self.name else None\n        else:\n            return None\n\n\nclass ReservedType(NamedTuple):\n    \"\"\"Define a reserved type by name or by type.\n\n    To preserve backwards-comaptibility, if an annotation was defined but does not match\n    :attr:`type`, then the name is used as a fallback.\n    \"\"\"\n\n    name: str\n    type: Type\n\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        for parameter in parameters:\n            annotation = parameter.annotation\n            try:\n                resolved_annotation = _eval_type(\n                    ForwardRef(annotation)\n                    if isinstance(annotation, str)\n                    else annotation,\n                    resolver._namespace,\n                    None,\n                )\n                resolver._resolved_annotations[parameter] = resolved_annotation\n            except NameError:\n                # Type-annotation could not be resolved\n                resolved_annotation = annotation\n            if self.is_reserved_type(resolved_annotation):\n                return parameter\n\n        # Fallback to matching by name\n        reserved_name = ReservedName(name=self.name).find(parameters, resolver)\n        if reserved_name:\n            warning = DeprecationWarning(\n                f\"Argument name-based matching of '{self.name}' is deprecated and will \"\n                \"be removed in v1.0. Ensure that reserved arguments are annotated \"\n                \"their respective types (i.e. use value: 'DirectiveValue[str]' instead \"\n                \"of 'value: str' and 'info: Info' instead of a plain 'info').\"\n            )\n            warnings.warn(warning)\n            return reserved_name\n        else:\n            return None\n\n    def is_reserved_type(self, other: Type) -> bool:\n        if get_origin(other) is Annotated:\n            # Handle annotated arguments such as Private[str] and DirectiveValue[str]\n            return any(isinstance(argument, self.type) for argument in get_args(other))\n        else:\n            # Handle both concrete and generic types (i.e Info, and Info[Any, Any])\n            return other is self.type or get_origin(other) is self.type\n\n\nSELF_PARAMSPEC = ReservedNameBoundParameter(\"self\")\nCLS_PARAMSPEC = ReservedNameBoundParameter(\"cls\")\nROOT_PARAMSPEC = ReservedName(\"root\")\nINFO_PARAMSPEC = ReservedType(\"info\", Info)\n\nT = TypeVar(\"T\")\n\n\nclass StrawberryResolver(Generic[T]):\n\n    RESERVED_PARAMSPEC: Tuple[ReservedParameterSpecification, ...] = (\n        SELF_PARAMSPEC,\n        CLS_PARAMSPEC,\n        ROOT_PARAMSPEC,\n        INFO_PARAMSPEC,\n    )\n\n    def __init__(\n        self,\n        func: Union[Callable[..., T], staticmethod, classmethod],\n        *,\n        description: Optional[str] = None,\n        type_override: Optional[Union[StrawberryType, type]] = None,\n    ):\n        self.wrapped_func = func\n        self._description = description\n        self._type_override = type_override\n        \"\"\"Specify the type manually instead of calculating from wrapped func\n\n        This is used when creating copies of types w/ generics\n        \"\"\"\n        self._resolved_annotations: Dict[inspect.Parameter, Any] = {}\n        \"\"\"Populated during reserved parameter determination.\n\n        Caching resolved annotations this way prevents evaling them repeatedly.\n        \"\"\"\n\n    # TODO: Use this when doing the actual resolving? How to deal with async resolvers?\n    def __call__(self, *args, **kwargs) -> T:\n        if not callable(self.wrapped_func):\n            raise UncallableResolverError(self)\n        return self.wrapped_func(*args, **kwargs)\n\n    @cached_property\n    def signature(self) -> inspect.Signature:\n        return inspect.signature(self._unbound_wrapped_func)\n\n    @cached_property\n    def reserved_parameters(\n        self,\n    ) -> Dict[ReservedParameterSpecification, Optional[inspect.Parameter]]:\n        \"\"\"Mapping of reserved parameter specification to parameter.\"\"\"\n        parameters = tuple(self.signature.parameters.values())\n        return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}\n\n    @cached_property\n    def arguments(self) -> List[StrawberryArgument]:\n        \"\"\"Resolver arguments exposed in the GraphQL Schema.\"\"\"\n        parameters = self.signature.parameters.values()\n        reserved_parameters = set(self.reserved_parameters.values())\n\n        missing_annotations = set()\n        arguments = []\n        user_parameters = (p for p in parameters if p not in reserved_parameters)\n        for param in user_parameters:\n            annotation = self._resolved_annotations.get(param, param.annotation)\n            if annotation is inspect.Signature.empty:\n                missing_annotations.add(param.name)\n            else:\n                argument = StrawberryArgument(\n                    python_name=param.name,\n                    graphql_name=None,\n                    type_annotation=StrawberryAnnotation(\n                        annotation=annotation, namespace=self._namespace\n                    ),\n                    default=param.default,\n                )\n                arguments.append(argument)\n        if missing_annotations:\n            raise MissingArgumentsAnnotationsError(self.name, missing_annotations)\n        return arguments\n\n    @cached_property\n    def info_parameter(self) -> Optional[inspect.Parameter]:\n        return self.reserved_parameters.get(INFO_PARAMSPEC)\n\n    @cached_property\n    def root_parameter(self) -> Optional[inspect.Parameter]:\n        return self.reserved_parameters.get(ROOT_PARAMSPEC)\n\n    @cached_property\n    def self_parameter(self) -> Optional[inspect.Parameter]:\n        return self.reserved_parameters.get(SELF_PARAMSPEC)\n\n    @cached_property\n    def name(self) -> str:\n        # TODO: What to do if resolver is a lambda?\n        return self._unbound_wrapped_func.__name__\n\n    @cached_property\n    def type_annotation(self) -> Optional[StrawberryAnnotation]:\n        return_annotation = self.signature.return_annotation\n        if return_annotation is inspect.Signature.empty:\n            return None\n        else:\n            type_annotation = StrawberryAnnotation(\n                annotation=return_annotation, namespace=self._namespace\n            )\n        return type_annotation\n\n    @property\n    def type(self) -> Optional[Union[StrawberryType, type]]:\n        if self._type_override:\n            return self._type_override\n        if self.type_annotation is None:\n            return None\n        return self.type_annotation.resolve()\n\n    @cached_property\n    def is_async(self) -> bool:\n        return iscoroutinefunction(self._unbound_wrapped_func) or isasyncgenfunction(\n            self._unbound_wrapped_func\n        )\n\n    def copy_with(\n        self, type_var_map: Mapping[TypeVar, Union[StrawberryType, builtins.type]]\n    ) -> StrawberryResolver:\n        type_override = None\n\n        if self.type:\n            if isinstance(self.type, StrawberryType):\n                type_override = self.type.copy_with(type_var_map)\n            else:\n                type_override = self.type._type_definition.copy_with(  # type: ignore\n                    type_var_map,\n                )\n\n        return type(self)(\n            func=self.wrapped_func,\n            description=self._description,\n            type_override=type_override,\n        )\n\n    @cached_property\n    def _namespace(self) -> Dict[str, Any]:\n        return sys.modules[self._unbound_wrapped_func.__module__].__dict__\n\n    @cached_property\n    def _unbound_wrapped_func(self) -> Callable[..., T]:\n        if isinstance(self.wrapped_func, (staticmethod, classmethod)):\n            return self.wrapped_func.__func__\n\n        return self.wrapped_func\n\n\nclass UncallableResolverError(Exception):\n    def __init__(self, resolver: \"StrawberryResolver\"):\n        message = (\n            f\"Attempted to call resolver {resolver} with uncallable function \"\n            f\"{resolver.wrapped_func}\"\n        )\n        super().__init__(message)\n\n\n__all__ = [\"StrawberryResolver\"]\n", "path": "strawberry/types/fields/resolver.py"}], "after_files": [{"content": "from __future__ import annotations as _\n\nimport builtins\nimport inspect\nimport sys\nimport warnings\nfrom inspect import isasyncgenfunction, iscoroutinefunction\nfrom typing import (  # type: ignore[attr-defined]\n    Any,\n    Callable,\n    Dict,\n    ForwardRef,\n    Generic,\n    List,\n    Mapping,\n    NamedTuple,\n    Optional,\n    Tuple,\n    Type,\n    TypeVar,\n    Union,\n    _eval_type,\n)\n\nfrom backports.cached_property import cached_property\nfrom typing_extensions import Annotated, Protocol, get_args, get_origin\n\nfrom strawberry.annotation import StrawberryAnnotation\nfrom strawberry.arguments import StrawberryArgument\nfrom strawberry.exceptions import MissingArgumentsAnnotationsError\nfrom strawberry.type import StrawberryType\nfrom strawberry.types.info import Info\n\n\nclass ReservedParameterSpecification(Protocol):\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        \"\"\"Finds the reserved parameter from ``parameters``.\"\"\"\n\n\nclass ReservedName(NamedTuple):\n    name: str\n\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        return next((p for p in parameters if p.name == self.name), None)\n\n\nclass ReservedNameBoundParameter(NamedTuple):\n    name: str\n\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        if parameters:  # Add compatibility for resolvers with no arguments\n            first_parameter = parameters[0]\n            return first_parameter if first_parameter.name == self.name else None\n        else:\n            return None\n\n\nclass ReservedType(NamedTuple):\n    \"\"\"Define a reserved type by name or by type.\n\n    To preserve backwards-comaptibility, if an annotation was defined but does not match\n    :attr:`type`, then the name is used as a fallback.\n    \"\"\"\n\n    name: str\n    type: Type\n\n    def find(\n        self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver\n    ) -> Optional[inspect.Parameter]:\n        for parameter in parameters:\n            annotation = parameter.annotation\n            try:\n                resolved_annotation = _eval_type(\n                    ForwardRef(annotation)\n                    if isinstance(annotation, str)\n                    else annotation,\n                    resolver._namespace,\n                    None,\n                )\n                resolver._resolved_annotations[parameter] = resolved_annotation\n            except NameError:\n                # Type-annotation could not be resolved\n                resolved_annotation = annotation\n            if self.is_reserved_type(resolved_annotation):\n                return parameter\n\n        # Fallback to matching by name\n        reserved_name = ReservedName(name=self.name).find(parameters, resolver)\n        if reserved_name:\n            warning = DeprecationWarning(\n                f\"Argument name-based matching of '{self.name}' is deprecated and will \"\n                \"be removed in v1.0. Ensure that reserved arguments are annotated \"\n                \"their respective types (i.e. use value: 'DirectiveValue[str]' instead \"\n                \"of 'value: str' and 'info: Info' instead of a plain 'info').\"\n            )\n            warnings.warn(warning)\n            return reserved_name\n        else:\n            return None\n\n    def is_reserved_type(self, other: Type) -> bool:\n        if get_origin(other) is Annotated:\n            # Handle annotated arguments such as Private[str] and DirectiveValue[str]\n            return any(isinstance(argument, self.type) for argument in get_args(other))\n        else:\n            # Handle both concrete and generic types (i.e Info, and Info[Any, Any])\n            return other is self.type or get_origin(other) is self.type\n\n\nSELF_PARAMSPEC = ReservedNameBoundParameter(\"self\")\nCLS_PARAMSPEC = ReservedNameBoundParameter(\"cls\")\nROOT_PARAMSPEC = ReservedName(\"root\")\nINFO_PARAMSPEC = ReservedType(\"info\", Info)\n\nT = TypeVar(\"T\")\n\n\nclass StrawberryResolver(Generic[T]):\n\n    RESERVED_PARAMSPEC: Tuple[ReservedParameterSpecification, ...] = (\n        SELF_PARAMSPEC,\n        CLS_PARAMSPEC,\n        ROOT_PARAMSPEC,\n        INFO_PARAMSPEC,\n    )\n\n    def __init__(\n        self,\n        func: Union[Callable[..., T], staticmethod, classmethod],\n        *,\n        description: Optional[str] = None,\n        type_override: Optional[Union[StrawberryType, type]] = None,\n    ):\n        self.wrapped_func = func\n        self._description = description\n        self._type_override = type_override\n        \"\"\"Specify the type manually instead of calculating from wrapped func\n\n        This is used when creating copies of types w/ generics\n        \"\"\"\n        self._resolved_annotations: Dict[inspect.Parameter, Any] = {}\n        \"\"\"Populated during reserved parameter determination.\n\n        Caching resolved annotations this way prevents evaling them repeatedly.\n        \"\"\"\n\n    # TODO: Use this when doing the actual resolving? How to deal with async resolvers?\n    def __call__(self, *args, **kwargs) -> T:\n        if not callable(self.wrapped_func):\n            raise UncallableResolverError(self)\n        return self.wrapped_func(*args, **kwargs)\n\n    @cached_property\n    def signature(self) -> inspect.Signature:\n        return inspect.signature(self._unbound_wrapped_func)\n\n    @cached_property\n    def reserved_parameters(\n        self,\n    ) -> Dict[ReservedParameterSpecification, Optional[inspect.Parameter]]:\n        \"\"\"Mapping of reserved parameter specification to parameter.\"\"\"\n        parameters = tuple(self.signature.parameters.values())\n        return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}\n\n    @cached_property\n    def arguments(self) -> List[StrawberryArgument]:\n        \"\"\"Resolver arguments exposed in the GraphQL Schema.\"\"\"\n        parameters = self.signature.parameters.values()\n        reserved_parameters = set(self.reserved_parameters.values())\n\n        missing_annotations = set()\n        arguments = []\n        user_parameters = (p for p in parameters if p not in reserved_parameters)\n        for param in user_parameters:\n            annotation = self._resolved_annotations.get(param, param.annotation)\n            if annotation is inspect.Signature.empty:\n                missing_annotations.add(param.name)\n            else:\n                argument = StrawberryArgument(\n                    python_name=param.name,\n                    graphql_name=None,\n                    type_annotation=StrawberryAnnotation(\n                        annotation=annotation, namespace=self._namespace\n                    ),\n                    default=param.default,\n                )\n                arguments.append(argument)\n        if missing_annotations:\n            raise MissingArgumentsAnnotationsError(self.name, missing_annotations)\n        return arguments\n\n    @cached_property\n    def info_parameter(self) -> Optional[inspect.Parameter]:\n        return self.reserved_parameters.get(INFO_PARAMSPEC)\n\n    @cached_property\n    def root_parameter(self) -> Optional[inspect.Parameter]:\n        return self.reserved_parameters.get(ROOT_PARAMSPEC)\n\n    @cached_property\n    def self_parameter(self) -> Optional[inspect.Parameter]:\n        return self.reserved_parameters.get(SELF_PARAMSPEC)\n\n    @cached_property\n    def name(self) -> str:\n        # TODO: What to do if resolver is a lambda?\n        return self._unbound_wrapped_func.__name__\n\n    @cached_property\n    def annotations(self) -> Dict[str, object]:\n        \"\"\"Annotations for the resolver.\n\n        Does not include special args defined in `RESERVED_PARAMSPEC` (e.g. self, root,\n        info)\n        \"\"\"\n        reserved_parameters = self.reserved_parameters\n        reserved_names = {p.name for p in reserved_parameters.values() if p is not None}\n\n        annotations = self._unbound_wrapped_func.__annotations__\n        annotations = {\n            name: annotation\n            for name, annotation in annotations.items()\n            if name not in reserved_names\n        }\n\n        return annotations\n\n    @cached_property\n    def type_annotation(self) -> Optional[StrawberryAnnotation]:\n        return_annotation = self.signature.return_annotation\n        if return_annotation is inspect.Signature.empty:\n            return None\n        else:\n            type_annotation = StrawberryAnnotation(\n                annotation=return_annotation, namespace=self._namespace\n            )\n        return type_annotation\n\n    @property\n    def type(self) -> Optional[Union[StrawberryType, type]]:\n        if self._type_override:\n            return self._type_override\n        if self.type_annotation is None:\n            return None\n        return self.type_annotation.resolve()\n\n    @cached_property\n    def is_async(self) -> bool:\n        return iscoroutinefunction(self._unbound_wrapped_func) or isasyncgenfunction(\n            self._unbound_wrapped_func\n        )\n\n    def copy_with(\n        self, type_var_map: Mapping[TypeVar, Union[StrawberryType, builtins.type]]\n    ) -> StrawberryResolver:\n        type_override = None\n\n        if self.type:\n            if isinstance(self.type, StrawberryType):\n                type_override = self.type.copy_with(type_var_map)\n            else:\n                type_override = self.type._type_definition.copy_with(  # type: ignore\n                    type_var_map,\n                )\n\n        return type(self)(\n            func=self.wrapped_func,\n            description=self._description,\n            type_override=type_override,\n        )\n\n    @cached_property\n    def _namespace(self) -> Dict[str, Any]:\n        return sys.modules[self._unbound_wrapped_func.__module__].__dict__\n\n    @cached_property\n    def _unbound_wrapped_func(self) -> Callable[..., T]:\n        if isinstance(self.wrapped_func, (staticmethod, classmethod)):\n            return self.wrapped_func.__func__\n\n        return self.wrapped_func\n\n\nclass UncallableResolverError(Exception):\n    def __init__(self, resolver: \"StrawberryResolver\"):\n        message = (\n            f\"Attempted to call resolver {resolver} with uncallable function \"\n            f\"{resolver.wrapped_func}\"\n        )\n        super().__init__(message)\n\n\n__all__ = [\"StrawberryResolver\"]\n", "path": "strawberry/types/fields/resolver.py"}]}