Repository: strawberry-graphql/strawberry

Issue:
Tests failing from DeprecationWarnings in strawberry code
<!-- Provide a general summary of the bug in the title above. -->

<!--- This template is entirely optional and can be removed, but is here to help both you and us. -->
<!--- Anything on lines wrapped in comments like these will not show up in the final text. -->

## Describe the Bug

Our tests have started failing with a later release of Strawberry (0.183.6) because of deprecation warnings. They fail the moment they try to import a strawberry module. We run our tests to error on warnings and we do not ignore deprecation warnings. 

```
../xxx/strawberry/types/fields/resolver.py:199: in reserved_parameters
    return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}
../xxx/strawberry/types/fields/resolver.py:199: in <dictcomp>
    return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}
../xxx/strawberry/types/fields/resolver.py:128: in find
    warnings.warn(warning, stacklevel=3)
E   DeprecationWarning: Argument name-based matching of 'info' is deprecated and will be removed in v1.0. Ensure that reserved arguments are annotated their respective types (i.e. use value: 'DirectiveValue[str]' instead of 'value: str' and 'info: Info' instead of a plain 'info').

```

I've tracked this down and it seems that some strawberry code is actually triggering the deprecation warning. This is happening in `strawberry/relay/types.py:365`. 
https://github.com/strawberry-graphql/strawberry/blob/d4ae4a5f4504c34fd5c7234f0bb7266e8cfbe674/strawberry/relay/types.py#L365
The `info:Info` parameter looks like it is being declared in the recommended way (given the warning above), however it still triggers the warning. If I change the `info` variable to be named `info2` for example, the warning goes away.

As a test, I've also run the strawberry test locally but have removed the `ignore:DeprecationWarning:strawberry.*.resolver` flag (i.e. https://github.com/strawberry-graphql/strawberry/blob/d4ae4a5f4504c34fd5c7234f0bb7266e8cfbe674/pyproject.toml#LL164C1-L164C56) and also set to error on warning. In this case I get the same failures due to deprecation warnings in the strawberry tests.

## System Information

 - Operating system: Centos 7 
 - Strawberry version (if applicable): 0.183.6 (have not tested exactly which release introduced this issue). It is still present in 0.186.0
## Additional Context

<!-- Add any other relevant information about the problem here. -->


<!-- POLAR PLEDGE BADGE START -->
## Upvote & Fund

- We're using [Polar.sh](https://polar.sh/strawberry-graphql) so you can upvote and help fund this issue.
- We receive the funding once the issue is completed & confirmed by you.
- Thank you in advance for helping prioritize & fund our backlog.

<a href="https://polar.sh/strawberry-graphql/strawberry/issues/2857">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/api/github/strawberry-graphql/strawberry/issues/2857/pledge.svg?darkmode=1">
  <img alt="Fund with Polar" src="https://polar.sh/api/github/strawberry-graphql/strawberry/issues/2857/pledge.svg">
</picture>
</a>
<!-- POLAR PLEDGE BADGE END -->



Discussion:
on it! :D

Resolving patch:
diff --git a/strawberry/relay/types.py b/strawberry/relay/types.py
--- a/strawberry/relay/types.py
+++ b/strawberry/relay/types.py
@@ -38,6 +38,7 @@
 from strawberry.private import StrawberryPrivate
 from strawberry.relay.exceptions import NodeIDAnnotationError
 from strawberry.type import StrawberryContainer, get_object_definition
+from strawberry.types.info import Info  # noqa: TCH001
 from strawberry.types.types import StrawberryObjectDefinition
 from strawberry.utils.aio import aenumerate, aislice, resolve_awaitable
 from strawberry.utils.inspect import in_async_context
@@ -47,7 +48,6 @@
 
 if TYPE_CHECKING:
     from strawberry.scalars import ID
-    from strawberry.types.info import Info
     from strawberry.utils.await_maybe import AwaitableOrValue
 
 _T = TypeVar("_T")


Test patch:
diff --git a/tests/relay/schema.py b/tests/relay/schema.py
--- a/tests/relay/schema.py
+++ b/tests/relay/schema.py
@@ -31,7 +31,7 @@ class Fruit(relay.Node):
     def resolve_nodes(
         cls,
         *,
-        info: Info,
+        info: Info[None, None],
         node_ids: Iterable[str],
         required: bool = False,
     ) -> Iterable[Optional[Self]]:
@@ -41,7 +41,7 @@ def resolve_nodes(
         return fruits.values()
 
     @classmethod
-    def is_type_of(cls, obj, _info) -> bool:
+    def is_type_of(cls, obj: Any, _info: Info[None, None]) -> bool:
         # This is here to support FruitConcrete, which is mimicing an integration
         # object which would return an object alike Fruit (e.g. the django integration)
         return isinstance(obj, (cls, FruitConcrete))
@@ -64,7 +64,7 @@ class FruitAsync(relay.Node):
     async def resolve_nodes(
         cls,
         *,
-        info: Optional[Info] = None,
+        info: Optional[Info[None, None]] = None,
         node_ids: Iterable[str],
         required: bool = False,
     ) -> Iterable[Optional[Self]]:
@@ -77,7 +77,7 @@ async def resolve_nodes(
         return fruits_async.values()
 
     @classmethod
-    async def resolve_id(cls, root: Self, *, info: Info) -> str:
+    async def resolve_id(cls, root: Self, *, info: Info[None, None]) -> str:
         return str(root.id)
 
 
@@ -92,7 +92,7 @@ def resolve_connection(
         cls,
         nodes: Iterable[Fruit],
         *,
-        info: Optional[Info] = None,
+        info: Optional[Info[None, None]] = None,
         total_count: Optional[int] = None,
         before: Optional[str] = None,
         after: Optional[str] = None,
@@ -161,7 +161,9 @@ def resolve_connection(
 @strawberry.type
 class FruitAlikeConnection(relay.ListConnection[Fruit]):
     @classmethod
-    def resolve_node(cls, node: FruitAlike, *, info: Info, **kwargs: Any) -> Fruit:
+    def resolve_node(
+        cls, node: FruitAlike, *, info: Info[None, None], **kwargs: Any
+    ) -> Fruit:
         return Fruit(
             id=node.id,
             name=node.name,
@@ -207,7 +209,7 @@ class Query:
     @relay.connection(relay.ListConnection[Fruit])
     def fruits_concrete_resolver(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> List[Fruit]:
         # This is mimicing integrations, like Django
@@ -227,7 +229,7 @@ def fruits_concrete_resolver(
     @relay.connection(relay.ListConnection[Fruit])
     def fruits_custom_resolver(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> List[Fruit]:
         return [
@@ -239,7 +241,7 @@ def fruits_custom_resolver(
     @relay.connection(relay.ListConnection[Fruit])
     def fruits_custom_resolver_lazy(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> List[Annotated["Fruit", strawberry.lazy("tests.relay.schema")]]:
         return [
@@ -251,7 +253,7 @@ def fruits_custom_resolver_lazy(
     @relay.connection(relay.ListConnection[Fruit])
     def fruits_custom_resolver_iterator(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> Iterator[Fruit]:
         for f in fruits.values():
@@ -261,7 +263,7 @@ def fruits_custom_resolver_iterator(
     @relay.connection(relay.ListConnection[Fruit])
     def fruits_custom_resolver_iterable(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> Iterator[Fruit]:
         for f in fruits.values():
@@ -271,7 +273,7 @@ def fruits_custom_resolver_iterable(
     @relay.connection(relay.ListConnection[Fruit])
     def fruits_custom_resolver_generator(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> Generator[Fruit, None, None]:
         for f in fruits.values():
@@ -281,7 +283,7 @@ def fruits_custom_resolver_generator(
     @relay.connection(relay.ListConnection[Fruit])
     async def fruits_custom_resolver_async_iterable(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> AsyncIterable[Fruit]:
         for f in fruits.values():
@@ -291,7 +293,7 @@ async def fruits_custom_resolver_async_iterable(
     @relay.connection(relay.ListConnection[Fruit])
     async def fruits_custom_resolver_async_iterator(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> AsyncIterator[Fruit]:
         for f in fruits.values():
@@ -301,7 +303,7 @@ async def fruits_custom_resolver_async_iterator(
     @relay.connection(relay.ListConnection[Fruit])
     async def fruits_custom_resolver_async_generator(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> AsyncGenerator[Fruit, None]:
         for f in fruits.values():
@@ -311,7 +313,7 @@ async def fruits_custom_resolver_async_generator(
     @relay.connection(FruitAlikeConnection)
     def fruit_alike_connection_custom_resolver(
         self,
-        info: Info,
+        info: Info[None, None],
         name_endswith: Optional[str] = None,
     ) -> List[FruitAlike]:
         return [
@@ -331,7 +333,7 @@ class Mutation:
     @strawberry.mutation
     def create_fruit(
         self,
-        info: Info,
+        info: Info[None, None],
         name: str,
         color: str,
     ) -> CreateFruitPayload:
diff --git a/tests/relay/test_schema.py b/tests/relay/test_schema.py
--- a/tests/relay/test_schema.py
+++ b/tests/relay/test_schema.py
@@ -16,11 +16,9 @@ def test_schema():
     schema_output = str(schema).strip("\n").strip(" ")
     output = pathlib.Path(__file__).parent / "schema.gql"
     if not output.exists():
-        with output.open("w") as f:
-            f.write(schema_output + "\n")
+        output.write_text(schema_output + "\n")
 
-    with output.open() as f:
-        expected = f.read().strip("\n").strip(" ")
+    expected = output.read_text().strip("\n").strip(" ")
 
     assert schema_output == expected