We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Subclassing `Info`
Subclassing `strawberry.types.Info` raises a warning when using it in resolvers.
`"Argument name-based matching of 'info' is deprecated and will be removed in v1.0."`
But it gets injected into resolvers without any problems, in my use case i only change `Info.context` to provide my custom `Context` class and original `Info` gets injected: `strawberry.types.info.Info`

## System Information

 - Strawberry version: 0.126.2

## Additional Context

Repository with bug reproduction: https://gitlab.com/ThirVondukr/strawberry-info-warning
Strawberry code where warning originates from: https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/types/fields/resolver.py#L126

Subclassing `Info`
Subclassing `strawberry.types.Info` raises a warning when using it in resolvers.
`"Argument name-based matching of 'info' is deprecated and will be removed in v1.0."`
But it gets injected into resolvers without any problems, in my use case i only change `Info.context` to provide my custom `Context` class and original `Info` gets injected: `strawberry.types.info.Info`

## System Information

 - Strawberry version: 0.126.2

## Additional Context

Repository with bug reproduction: https://gitlab.com/ThirVondukr/strawberry-info-warning
Strawberry code where warning originates from: https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/types/fields/resolver.py#L126


--- 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 typing_extensions import Annotated, Protocol, get_args, get_origin
26 
27 from strawberry.annotation import StrawberryAnnotation
28 from strawberry.arguments import StrawberryArgument
29 from strawberry.exceptions import MissingArgumentsAnnotationsError
30 from strawberry.type import StrawberryType
31 from strawberry.types.info import Info
32 from strawberry.utils.cached_property import cached_property
33 
34 
35 class Parameter(inspect.Parameter):
36     def __hash__(self):
37         """Override to exclude default value from hash.
38 
39         This adds compatibility for using unhashable default values in resolvers such as
40         list and dict. The present use-case is limited to analyzing parameters from one
41         resolver. Therefore, the name, kind, and annotation combination are guaranteed
42         to be unique since two arguments cannot have the same name in a callable.
43 
44         Furthermore, even though it is not currently a use-case to collect parameters
45         from different resolvers, the likelihood of collision from having the same hash
46         value but different defaults is mitigated by Python invoking the
47         :py:meth:`__eq__` method if two items have the same hash. See the verification
48         of this behavior in the `test_parameter_hash_collision` test.
49         """
50         return hash((self.name, self.kind, self.annotation))
51 
52 
53 class Signature(inspect.Signature):
54 
55     _parameter_cls = Parameter
56 
57 
58 class ReservedParameterSpecification(Protocol):
59     def find(
60         self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver
61     ) -> Optional[inspect.Parameter]:
62         """Finds the reserved parameter from ``parameters``."""
63 
64 
65 class ReservedName(NamedTuple):
66     name: str
67 
68     def find(
69         self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver
70     ) -> Optional[inspect.Parameter]:
71         return next((p for p in parameters if p.name == self.name), None)
72 
73 
74 class ReservedNameBoundParameter(NamedTuple):
75     name: str
76 
77     def find(
78         self, parameters: Tuple[inspect.Parameter, ...], _: StrawberryResolver
79     ) -> Optional[inspect.Parameter]:
80         if parameters:  # Add compatibility for resolvers with no arguments
81             first_parameter = parameters[0]
82             return first_parameter if first_parameter.name == self.name else None
83         else:
84             return None
85 
86 
87 class ReservedType(NamedTuple):
88     """Define a reserved type by name or by type.
89 
90     To preserve backwards-comaptibility, if an annotation was defined but does not match
91     :attr:`type`, then the name is used as a fallback.
92     """
93 
94     name: str
95     type: Type
96 
97     def find(
98         self, parameters: Tuple[inspect.Parameter, ...], resolver: StrawberryResolver
99     ) -> Optional[inspect.Parameter]:
100         for parameter in parameters:
101             annotation = parameter.annotation
102             try:
103                 resolved_annotation = _eval_type(
104                     ForwardRef(annotation)
105                     if isinstance(annotation, str)
106                     else annotation,
107                     resolver._namespace,
108                     None,
109                 )
110                 resolver._resolved_annotations[parameter] = resolved_annotation
111             except NameError:
112                 # Type-annotation could not be resolved
113                 resolved_annotation = annotation
114             if self.is_reserved_type(resolved_annotation):
115                 return parameter
116 
117         # Fallback to matching by name
118         reserved_name = ReservedName(name=self.name).find(parameters, resolver)
119         if reserved_name:
120             warning = DeprecationWarning(
121                 f"Argument name-based matching of '{self.name}' is deprecated and will "
122                 "be removed in v1.0. Ensure that reserved arguments are annotated "
123                 "their respective types (i.e. use value: 'DirectiveValue[str]' instead "
124                 "of 'value: str' and 'info: Info' instead of a plain 'info')."
125             )
126             warnings.warn(warning)
127             return reserved_name
128         else:
129             return None
130 
131     def is_reserved_type(self, other: Type) -> bool:
132         if get_origin(other) is Annotated:
133             # Handle annotated arguments such as Private[str] and DirectiveValue[str]
134             return any(isinstance(argument, self.type) for argument in get_args(other))
135         else:
136             # Handle both concrete and generic types (i.e Info, and Info[Any, Any])
137             return other is self.type or get_origin(other) is self.type
138 
139 
140 SELF_PARAMSPEC = ReservedNameBoundParameter("self")
141 CLS_PARAMSPEC = ReservedNameBoundParameter("cls")
142 ROOT_PARAMSPEC = ReservedName("root")
143 INFO_PARAMSPEC = ReservedType("info", Info)
144 
145 T = TypeVar("T")
146 
147 
148 class StrawberryResolver(Generic[T]):
149 
150     RESERVED_PARAMSPEC: Tuple[ReservedParameterSpecification, ...] = (
151         SELF_PARAMSPEC,
152         CLS_PARAMSPEC,
153         ROOT_PARAMSPEC,
154         INFO_PARAMSPEC,
155     )
156 
157     def __init__(
158         self,
159         func: Union[Callable[..., T], staticmethod, classmethod],
160         *,
161         description: Optional[str] = None,
162         type_override: Optional[Union[StrawberryType, type]] = None,
163     ):
164         self.wrapped_func = func
165         self._description = description
166         self._type_override = type_override
167         """Specify the type manually instead of calculating from wrapped func
168 
169         This is used when creating copies of types w/ generics
170         """
171         self._resolved_annotations: Dict[inspect.Parameter, Any] = {}
172         """Populated during reserved parameter determination.
173 
174         Caching resolved annotations this way prevents evaling them repeatedly.
175         """
176 
177     # TODO: Use this when doing the actual resolving? How to deal with async resolvers?
178     def __call__(self, *args, **kwargs) -> T:
179         if not callable(self.wrapped_func):
180             raise UncallableResolverError(self)
181         return self.wrapped_func(*args, **kwargs)
182 
183     @cached_property
184     def signature(self) -> inspect.Signature:
185         return Signature.from_callable(self._unbound_wrapped_func, follow_wrapped=True)
186 
187     @cached_property
188     def reserved_parameters(
189         self,
190     ) -> Dict[ReservedParameterSpecification, Optional[inspect.Parameter]]:
191         """Mapping of reserved parameter specification to parameter."""
192         parameters = tuple(self.signature.parameters.values())
193         return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}
194 
195     @cached_property
196     def arguments(self) -> List[StrawberryArgument]:
197         """Resolver arguments exposed in the GraphQL Schema."""
198         parameters = self.signature.parameters.values()
199         reserved_parameters = set(self.reserved_parameters.values())
200 
201         missing_annotations = set()
202         arguments = []
203         user_parameters = (p for p in parameters if p not in reserved_parameters)
204         for param in user_parameters:
205             annotation = self._resolved_annotations.get(param, param.annotation)
206             if annotation is inspect.Signature.empty:
207                 missing_annotations.add(param.name)
208             else:
209                 argument = StrawberryArgument(
210                     python_name=param.name,
211                     graphql_name=None,
212                     type_annotation=StrawberryAnnotation(
213                         annotation=annotation, namespace=self._namespace
214                     ),
215                     default=param.default,
216                 )
217                 arguments.append(argument)
218         if missing_annotations:
219             raise MissingArgumentsAnnotationsError(self.name, missing_annotations)
220         return arguments
221 
222     @cached_property
223     def info_parameter(self) -> Optional[inspect.Parameter]:
224         return self.reserved_parameters.get(INFO_PARAMSPEC)
225 
226     @cached_property
227     def root_parameter(self) -> Optional[inspect.Parameter]:
228         return self.reserved_parameters.get(ROOT_PARAMSPEC)
229 
230     @cached_property
231     def self_parameter(self) -> Optional[inspect.Parameter]:
232         return self.reserved_parameters.get(SELF_PARAMSPEC)
233 
234     @cached_property
235     def name(self) -> str:
236         # TODO: What to do if resolver is a lambda?
237         return self._unbound_wrapped_func.__name__
238 
239     @cached_property
240     def annotations(self) -> Dict[str, object]:
241         """Annotations for the resolver.
242 
243         Does not include special args defined in `RESERVED_PARAMSPEC` (e.g. self, root,
244         info)
245         """
246         reserved_parameters = self.reserved_parameters
247         reserved_names = {p.name for p in reserved_parameters.values() if p is not None}
248 
249         annotations = self._unbound_wrapped_func.__annotations__
250         annotations = {
251             name: annotation
252             for name, annotation in annotations.items()
253             if name not in reserved_names
254         }
255 
256         return annotations
257 
258     @cached_property
259     def type_annotation(self) -> Optional[StrawberryAnnotation]:
260         return_annotation = self.signature.return_annotation
261         if return_annotation is inspect.Signature.empty:
262             return None
263         else:
264             type_annotation = StrawberryAnnotation(
265                 annotation=return_annotation, namespace=self._namespace
266             )
267         return type_annotation
268 
269     @property
270     def type(self) -> Optional[Union[StrawberryType, type]]:
271         if self._type_override:
272             return self._type_override
273         if self.type_annotation is None:
274             return None
275         return self.type_annotation.resolve()
276 
277     @cached_property
278     def is_async(self) -> bool:
279         return iscoroutinefunction(self._unbound_wrapped_func) or isasyncgenfunction(
280             self._unbound_wrapped_func
281         )
282 
283     def copy_with(
284         self, type_var_map: Mapping[TypeVar, Union[StrawberryType, builtins.type]]
285     ) -> StrawberryResolver:
286         type_override = None
287 
288         if self.type:
289             if isinstance(self.type, StrawberryType):
290                 type_override = self.type.copy_with(type_var_map)
291             else:
292                 type_override = self.type._type_definition.copy_with(  # type: ignore
293                     type_var_map,
294                 )
295 
296         return type(self)(
297             func=self.wrapped_func,
298             description=self._description,
299             type_override=type_override,
300         )
301 
302     @cached_property
303     def _namespace(self) -> Dict[str, Any]:
304         return sys.modules[self._unbound_wrapped_func.__module__].__dict__
305 
306     @cached_property
307     def _unbound_wrapped_func(self) -> Callable[..., T]:
308         if isinstance(self.wrapped_func, (staticmethod, classmethod)):
309             return self.wrapped_func.__func__
310 
311         return self.wrapped_func
312 
313 
314 class UncallableResolverError(Exception):
315     def __init__(self, resolver: "StrawberryResolver"):
316         message = (
317             f"Attempted to call resolver {resolver} with uncallable function "
318             f"{resolver.wrapped_func}"
319         )
320         super().__init__(message)
321 
322 
323 __all__ = ["StrawberryResolver"]
324
```
--- 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
@@ -20,6 +20,7 @@
     TypeVar,
     Union,
     _eval_type,
+    cast,
 )
 
 from typing_extensions import Annotated, Protocol, get_args, get_origin
@@ -129,12 +130,17 @@
             return None
 
     def is_reserved_type(self, other: Type) -> bool:
-        if get_origin(other) is Annotated:
+        origin = cast(type, get_origin(other)) or other
+        if origin is Annotated:
             # Handle annotated arguments such as Private[str] and DirectiveValue[str]
             return any(isinstance(argument, self.type) for argument in get_args(other))
         else:
             # Handle both concrete and generic types (i.e Info, and Info[Any, Any])
-            return other is self.type or get_origin(other) is self.type
+            return (
+                issubclass(origin, self.type)
+                if isinstance(origin, type)
+                else origin is self.type
+            )
 
 
 SELF_PARAMSPEC = ReservedNameBoundParameter("self")

{"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@@ -20,6 +20,7 @@\n     TypeVar,\n     Union,\n     _eval_type,\n+    cast,\n )\n \n from typing_extensions import Annotated, Protocol, get_args, get_origin\n@@ -129,12 +130,17 @@\n             return None\n \n     def is_reserved_type(self, other: Type) -> bool:\n-        if get_origin(other) is Annotated:\n+        origin = cast(type, get_origin(other)) or other\n+        if origin 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+            return (\n+                issubclass(origin, self.type)\n+                if isinstance(origin, type)\n+                else origin is self.type\n+            )\n \n \n SELF_PARAMSPEC = ReservedNameBoundParameter(\"self\")\n", "issue": "Subclassing `Info`\nSubclassing `strawberry.types.Info` raises a warning when using it in resolvers.\r\n`\"Argument name-based matching of 'info' is deprecated and will be removed in v1.0.\"`\r\nBut it gets injected into resolvers without any problems, in my use case i only change `Info.context` to provide my custom `Context` class and original `Info` gets injected: `strawberry.types.info.Info`\r\n\r\n## System Information\r\n\r\n - Strawberry version: 0.126.2\r\n\r\n## Additional Context\r\n\r\nRepository with bug reproduction: https://gitlab.com/ThirVondukr/strawberry-info-warning\r\nStrawberry code where warning originates from: https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/types/fields/resolver.py#L126\r\n\nSubclassing `Info`\nSubclassing `strawberry.types.Info` raises a warning when using it in resolvers.\r\n`\"Argument name-based matching of 'info' is deprecated and will be removed in v1.0.\"`\r\nBut it gets injected into resolvers without any problems, in my use case i only change `Info.context` to provide my custom `Context` class and original `Info` gets injected: `strawberry.types.info.Info`\r\n\r\n## System Information\r\n\r\n - Strawberry version: 0.126.2\r\n\r\n## Additional Context\r\n\r\nRepository with bug reproduction: https://gitlab.com/ThirVondukr/strawberry-info-warning\r\nStrawberry code where warning originates from: https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/types/fields/resolver.py#L126\r\n\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 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\nfrom strawberry.utils.cached_property import cached_property\n\n\nclass Parameter(inspect.Parameter):\n    def __hash__(self):\n        \"\"\"Override to exclude default value from hash.\n\n        This adds compatibility for using unhashable default values in resolvers such as\n        list and dict. The present use-case is limited to analyzing parameters from one\n        resolver. Therefore, the name, kind, and annotation combination are guaranteed\n        to be unique since two arguments cannot have the same name in a callable.\n\n        Furthermore, even though it is not currently a use-case to collect parameters\n        from different resolvers, the likelihood of collision from having the same hash\n        value but different defaults is mitigated by Python invoking the\n        :py:meth:`__eq__` method if two items have the same hash. See the verification\n        of this behavior in the `test_parameter_hash_collision` test.\n        \"\"\"\n        return hash((self.name, self.kind, self.annotation))\n\n\nclass Signature(inspect.Signature):\n\n    _parameter_cls = Parameter\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 Signature.from_callable(self._unbound_wrapped_func, follow_wrapped=True)\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"}], "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    cast,\n)\n\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\nfrom strawberry.utils.cached_property import cached_property\n\n\nclass Parameter(inspect.Parameter):\n    def __hash__(self):\n        \"\"\"Override to exclude default value from hash.\n\n        This adds compatibility for using unhashable default values in resolvers such as\n        list and dict. The present use-case is limited to analyzing parameters from one\n        resolver. Therefore, the name, kind, and annotation combination are guaranteed\n        to be unique since two arguments cannot have the same name in a callable.\n\n        Furthermore, even though it is not currently a use-case to collect parameters\n        from different resolvers, the likelihood of collision from having the same hash\n        value but different defaults is mitigated by Python invoking the\n        :py:meth:`__eq__` method if two items have the same hash. See the verification\n        of this behavior in the `test_parameter_hash_collision` test.\n        \"\"\"\n        return hash((self.name, self.kind, self.annotation))\n\n\nclass Signature(inspect.Signature):\n\n    _parameter_cls = Parameter\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        origin = cast(type, get_origin(other)) or other\n        if origin 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 (\n                issubclass(origin, self.type)\n                if isinstance(origin, type)\n                else origin is self.type\n            )\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 Signature.from_callable(self._unbound_wrapped_func, follow_wrapped=True)\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"}]}