Skip to content

Using relay.node() in tests causes DeprecationWarning #3995

@davemssavage

Description

@davemssavage

Describe the Bug

When relay.node is included in a query schema the test fails with an obsure DeprecationWarning bug. The following is a contrived example to demonstrate the problem.

@pytest.mark.asyncio
async def test_node_query():
    @strawberry.type
    class Query:
        @strawberry.field
        def hello(self) -> str:
            return "Hello World"

        node: relay.Node = relay.node()

    schema = strawberry.Schema(
        query=Query,
    )
    query = """
        query Query {
            hello
        }
    """
    result = await schema.execute(query)

Generates an error:

=================================== FAILURES ===================================
_______________________________ test_node_query ________________________________

self = <GraphQLObjectType 'Query'>

    @cached_property
    def fields(self) -> GraphQLFieldMap:
        """Get provided fields, wrapping them as GraphQLFields if needed."""
        try:
>           fields = resolve_thunk(self._fields)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^

.venv/lib/python3.12/site-packages/graphql/type/definition.py:816: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
backend/.venv/lib/python3.12/site-packages/graphql/type/definition.py:300: in resolve_thunk
    return thunk() if callable(thunk) else thunk
           ^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/schema/schema_converter.py:673: in <lambda>
    fields=lambda: self.get_graphql_fields(object_type),
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/schema/schema_converter.py:477: in get_graphql_fields
    return _get_thunk_mapping(
.venv/lib/python3.12/site-packages/strawberry/schema/schema_converter.py:145: in _get_thunk_mapping
    thunk_mapping[name_converter(field)] = field_converter(
backend/.venv/lib/python3.12/site-packages/strawberry/schema/schema_converter.py:414: in from_field
    resolver = self.from_resolver(field)
               ^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/schema/schema_converter.py:772: in from_resolver
    _get_result_with_extensions = wrap_field_extensions()
                                  ^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/schema/schema_converter.py:723: in wrap_field_extensions
    extension.apply(field)
.venv/lib/python3.12/site-packages/strawberry/relay/fields.py:65: in apply
    field.base_resolver = StrawberryResolver(resolver, type_override=field.type)
    ^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/types/field.py:293: in base_resolver
    _ = resolver.arguments
        ^^^^^^^^^^^^^^^^^^
../../../.local/share/uv/python/cpython-3.12.9-macos-aarch64-none/lib/python3.12/functools.py:998: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/types/fields/resolver.py:244: in arguments
    root_parameter = self.reserved_parameters.get(ROOT_PARAMSPEC)
                     ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.local/share/uv/python/cpython-3.12.9-macos-aarch64-none/lib/python3.12/functools.py:998: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.12/site-packages/strawberry/types/fields/resolver.py:239: in reserved_parameters
    return {spec: spec.find(parameters, self) for spec in self.RESERVED_PARAMSPEC}
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = ReservedType(name='info', type=<class 'strawberry.types.info.Info'>)
parameters = (<Parameter "info: 'Info'">, <Parameter "id: "Annotated[GlobalID, argument(description='The ID of the object.')]"">)
resolver = <strawberry.types.fields.resolver.StrawberryResolver object at 0x353fe1a00>

    def find(
        self,
        parameters: tuple[inspect.Parameter, ...],
        resolver: StrawberryResolver[Any],
    ) -> Optional[inspect.Parameter]:
        # Go through all the types even after we've found one so we can
        # give a helpful error message if someone uses the type more than once.
        type_parameters = []
        for parameter in parameters:
            annotation = resolver.strawberry_annotations[parameter]
            if isinstance(annotation, StrawberryAnnotation):
                try:
                    evaled_annotation = annotation.evaluate()
                except NameError:
                    # If this is a strawberry.Parent using ForwardRef, we will fail to
                    # evaluate at this moment, but at least knowing that it is a reserved
                    # type is enough for now
                    # We might want to revisit this in the future, maybe by postponing
                    # this check to when the schema is actually being created
                    evaled_annotation = resolve_parent_forward_arg(
                        annotation.annotation
                    )
    
                if self.is_reserved_type(evaled_annotation):
                    type_parameters.append(parameter)
    
        if len(type_parameters) > 1:
            raise ConflictingArgumentsError(
                resolver, [parameter.name for parameter in type_parameters]
            )
    
        if type_parameters:
            return type_parameters[0]
    
        # Fallback to matching by name
        if not self.name:
            return None
        reserved_name = ReservedName(name=self.name).find(parameters, resolver)
        if reserved_name:
            warning = DeprecationWarning(
                f"Argument name-based matching of '{self.name}' 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')."
            )
>           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').

.venv/lib/python3.12/site-packages/strawberry/types/fields/resolver.py:152: DeprecationWarning

The above exception was the direct cause of the following exception:

    @pytest.mark.asyncio
    async def test_node_query():
        @strawberry.type
        class Query:
            @strawberry.field
            def hello(self) -> str:
                return "Hello World"
    
            node: relay.Node = relay.node()
    
>       schema = strawberry.Schema(
            query=Query,
        )

System Information

  • Operating system:
  • Python version: 3.12
  • Strawberry version (if applicable): "strawberry-graphql>=0.282.0"

Additional Context

Removing the relay.node from the above test allows it to pass

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions