From 3ec03a740bd7de29167c8678007ac9047677786b Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 15 Dec 2024 15:22:37 +0100 Subject: [PATCH] Fix deprecation warnings caused by tests (#3727) * Fix passing types to union is deprecated * Fix `is_unset` deprecation warnings in tests * Fix `asserts_errors` deprecation warnings in tests * Fix `info.field_nodes` deprecation warnings * Fix `graphiql` deprecation warnings in tests * Fix `listen_to_channel` deprecation warnings * Fix name-based matching of `value` deprecations * Test directives still work as expected --- tests/channels/test_layers.py | 5 ++- tests/fastapi/test_openapi.py | 2 +- tests/federation/test_entities.py | 4 +- tests/fields/test_arguments.py | 13 +++++-- tests/litestar/schema.py | 10 +++-- tests/schema/test_arguments.py | 2 +- tests/schema/test_directives.py | 57 +++++++++++++++++++++-------- tests/schema/test_extensions.py | 3 +- tests/schema/test_get_extensions.py | 4 +- tests/schema/test_info.py | 10 +++-- tests/schema/test_permission.py | 4 +- tests/schema/test_resolvers.py | 24 +++++++----- tests/test/test_client.py | 16 ++++---- tests/tools/test_create_type.py | 6 +-- tests/types/test_lazy_types.py | 6 +-- tests/views/schema.py | 7 ++-- 16 files changed, 113 insertions(+), 60 deletions(-) diff --git a/tests/channels/test_layers.py b/tests/channels/test_layers.py index a9c325f8e8..ffc7108703 100644 --- a/tests/channels/test_layers.py +++ b/tests/channels/test_layers.py @@ -50,8 +50,9 @@ async def test_no_layers(): "Check https://channels.readthedocs.io/en/stable/topics/channel_layers.html " "for more information" ) - with pytest.raises(RuntimeError, match=msg): - await consumer.channel_listen("foobar").__anext__() + with pytest.deprecated_call(match="Use listen_to_channel instead"): + with pytest.raises(RuntimeError, match=msg): + await consumer.channel_listen("foobar").__anext__() with pytest.raises(RuntimeError, match=msg): async with consumer.listen_to_channel("foobar"): diff --git a/tests/fastapi/test_openapi.py b/tests/fastapi/test_openapi.py index d30f88abe9..1552d7310c 100644 --- a/tests/fastapi/test_openapi.py +++ b/tests/fastapi/test_openapi.py @@ -26,7 +26,7 @@ def test_disable_graphiql_view_and_allow_queries_via_get(): app = FastAPI() schema = strawberry.Schema(query=Query) graphql_app = GraphQLRouter[None, None]( - schema, graphiql=False, allow_queries_via_get=False + schema, graphql_ide=None, allow_queries_via_get=False ) app.include_router(graphql_app, prefix="/graphql") diff --git a/tests/federation/test_entities.py b/tests/federation/test_entities.py index 4793c0aeb0..ad79aeade8 100644 --- a/tests/federation/test_entities.py +++ b/tests/federation/test_entities.py @@ -375,7 +375,9 @@ def resolve_reference(cls, info: Info, id: strawberry.ID) -> "Product": exception = Exception("Foo bar") exception.extensions = {"baz": "qux"} raise located_error( - exception, nodes=info.field_nodes[0], path=["_entities_override", 0] + exception, + nodes=info._raw_info.field_nodes[0], + path=["_entities_override", 0], ) @strawberry.federation.type(extend=True) diff --git a/tests/fields/test_arguments.py b/tests/fields/test_arguments.py index f8c911806b..f0d8a4991d 100644 --- a/tests/fields/test_arguments.py +++ b/tests/fields/test_arguments.py @@ -1,5 +1,4 @@ import sys -import warnings from typing import List, Optional, Union from typing_extensions import Annotated @@ -488,11 +487,19 @@ def test_unset_deprecation_warning(): def test_deprecated_unset(): - with pytest.deprecated_call(): + warning = "`is_unset` is deprecated use `value is UNSET` instead" + + with pytest.deprecated_call(match=warning): from strawberry.types.unset import is_unset - with warnings.catch_warnings(record=False): + with pytest.deprecated_call(match=warning): assert is_unset(UNSET) + + with pytest.deprecated_call(match=warning): assert not is_unset(None) + + with pytest.deprecated_call(match=warning): assert not is_unset(False) + + with pytest.deprecated_call(match=warning): assert not is_unset("hello world") diff --git a/tests/litestar/schema.py b/tests/litestar/schema.py index 5f00b1a2ee..71b69ad464 100644 --- a/tests/litestar/schema.py +++ b/tests/litestar/schema.py @@ -99,7 +99,9 @@ async def echo( yield message @strawberry.subscription - async def request_ping(self, info) -> typing.AsyncGenerator[bool, None]: + async def request_ping( + self, info: strawberry.Info + ) -> typing.AsyncGenerator[bool, None]: ws = info.context["ws"] await ws.send_json(PingMessage().as_dict()) yield True @@ -111,7 +113,7 @@ async def infinity(self, message: str) -> typing.AsyncGenerator[str, None]: await asyncio.sleep(1) @strawberry.subscription - async def context(self, info) -> typing.AsyncGenerator[str, None]: + async def context(self, info: strawberry.Info) -> typing.AsyncGenerator[str, None]: yield info.context["custom_value"] @strawberry.subscription @@ -132,7 +134,9 @@ async def flavors(self) -> typing.AsyncGenerator[Flavor, None]: yield Flavor.CHOCOLATE @strawberry.subscription - async def debug(self, info) -> typing.AsyncGenerator[DebugInfo, None]: + async def debug( + self, info: strawberry.Info + ) -> typing.AsyncGenerator[DebugInfo, None]: active_result_handlers = [ task for task in info.context["get_tasks"]() if not task.done() ] diff --git a/tests/schema/test_arguments.py b/tests/schema/test_arguments.py index 7c1f2e32f9..6020fd5a68 100644 --- a/tests/schema/test_arguments.py +++ b/tests/schema/test_arguments.py @@ -177,7 +177,7 @@ class Query: @strawberry.field def hello( self, - info, + info: strawberry.Info, input: Annotated[str, strawberry.argument(metadata={"test": "foo"})], ) -> str: nonlocal field_definition diff --git a/tests/schema/test_directives.py b/tests/schema/test_directives.py index 3b31e97258..adfcd29f6b 100644 --- a/tests/schema/test_directives.py +++ b/tests/schema/test_directives.py @@ -40,6 +40,7 @@ def person(self) -> Person: ) assert not result.errors + assert result.data assert result.data["person"] == {"name": "Jess"} query = """query ($skipPoints: Boolean!){ @@ -53,6 +54,7 @@ def person(self) -> Person: result = schema.execute_sync(query, variable_values={"skipPoints": False}) assert not result.errors + assert result.data assert result.data["person"] == {"name": "Jess", "points": 2000} @@ -80,6 +82,7 @@ def person(self) -> Person: result = await schema.execute(query, variable_values={"includePoints": False}) assert not result.errors + assert result.data assert result.data["person"] == {"name": "Jess"} query = """query ($skipPoints: Boolean!){ @@ -93,18 +96,21 @@ def person(self) -> Person: result = await schema.execute(query, variable_values={"skipPoints": False}) assert not result.errors + assert result.data assert result.data["person"] == {"name": "Jess", "points": 2000} def test_can_declare_directives(): @strawberry.type class Query: - cake: str = "made_in_switzerland" + @strawberry.field + def cake(self) -> str: + return "made_in_switzerland" @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def uppercase(value: str, example: str): + def uppercase(value: DirectiveValue[str], example: str): return value.upper() schema = strawberry.Schema(query=Query, directives=[uppercase]) @@ -120,6 +126,10 @@ def uppercase(value: str, example: str): assert schema.as_str() == textwrap.dedent(expected_schema).strip() + result = schema.execute_sync('query { cake @uppercase(example: "foo") }') + assert result.errors is None + assert result.data == {"cake": "MADE_IN_SWITZERLAND"} + def test_directive_arguments_without_value_param(): """Regression test for Strawberry Issue #1666. @@ -171,11 +181,11 @@ def person(self) -> Person: @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def turn_uppercase(value: str): + def turn_uppercase(value: DirectiveValue[str]): return value.upper() @strawberry.directive(locations=[DirectiveLocation.FIELD]) - def replace(value: str, old: str, new: str): + def replace(value: DirectiveValue[str], old: str, new: str): return value.replace(old, new) schema = strawberry.Schema(query=Query, directives=[turn_uppercase, replace]) @@ -195,6 +205,7 @@ def replace(value: str, old: str, new: str): result = schema.execute_sync(query, variable_values={"identified": False}) assert not result.errors + assert result.data assert result.data["person"]["name"] == "JESS" assert result.data["jess"]["name"] == "Jessica" assert result.data["johnDoe"].get("name") is None @@ -214,11 +225,11 @@ def person(self) -> Person: @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def turn_uppercase(value: str): + def turn_uppercase(value: DirectiveValue[str]): return value.upper() @strawberry.directive(locations=[DirectiveLocation.FIELD]) - def replace(value: str, old: str, new: str): + def replace(value: DirectiveValue[str], old: str, new: str): return value.replace(old, new) schema = strawberry.Schema( @@ -242,6 +253,7 @@ def replace(value: str, old: str, new: str): result = schema.execute_sync(query, variable_values={"identified": False}) assert not result.errors + assert result.data assert result.data["person"]["name"] == "JESS" assert result.data["jess"]["name"] == "Jessica" assert result.data["johnDoe"].get("name") is None @@ -262,7 +274,7 @@ def person(self) -> Person: @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - async def uppercase(value: str): + async def uppercase(value: DirectiveValue[str]): return value.upper() schema = strawberry.Schema(query=Query, directives=[uppercase]) @@ -293,7 +305,7 @@ def person(self) -> Person: return Person() @strawberry.directive(locations=[DirectiveLocation.FIELD]) - def replace(value: str, old_list: List[str], new: str): + def replace(value: DirectiveValue[str], old_list: List[str], new: str): for old in old_list: value = value.replace(old, new) @@ -310,6 +322,7 @@ def replace(value: str, old_list: List[str], new: str): result = schema.execute_sync(query, variable_values={"identified": False}) assert not result.errors + assert result.data assert result.data["person"]["name"] == "JESS" @@ -327,7 +340,7 @@ def person(self) -> Person: @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def uppercase(value: str): + def uppercase(value: DirectiveValue[str]): return value.upper() class ExampleExtension(SchemaExtension): @@ -366,7 +379,7 @@ async def person(self) -> Person: @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def uppercase(value: str): + def uppercase(value: DirectiveValue[str]): return value.upper() class ExampleExtension(SchemaExtension): @@ -416,7 +429,7 @@ def greetingTemplate(self, locale: Locale = Locale.EN) -> str: locations=[DirectiveLocation.FIELD], description="Interpolate string on the server from context data", ) - def interpolate(value: str, info: strawberry.Info): + def interpolate(value: DirectiveValue[str], info: strawberry.Info): try: assert isinstance(info, strawberry.Info) assert info._field is field @@ -592,6 +605,7 @@ def append_names(value: DirectiveValue[str], names: List[str]): ) assert result.errors is None + assert result.data assert result.data["greeting"] == "Hi foo, bar" @@ -602,12 +616,14 @@ class DirectiveInput: @strawberry.type class Query: - cake: str = "made_in_switzerland" + @strawberry.field + def cake(self) -> str: + return "made_in_switzerland" @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def uppercase(value: str, input: DirectiveInput): + def uppercase(value: DirectiveValue[str], input: DirectiveInput): return value.upper() schema = strawberry.Schema(query=Query, directives=[uppercase]) @@ -627,18 +643,24 @@ def uppercase(value: str, input: DirectiveInput): assert schema.as_str() == textwrap.dedent(expected_schema).strip() + result = schema.execute_sync('query { cake @uppercase(input: { example: "foo" }) }') + assert result.errors is None + assert result.data == {"cake": "MADE_IN_SWITZERLAND"} + def test_directives_with_scalar(): DirectiveInput = strawberry.scalar(str, name="DirectiveInput") @strawberry.type class Query: - cake: str = "made_in_switzerland" + @strawberry.field + def cake(self) -> str: + return "made_in_switzerland" @strawberry.directive( locations=[DirectiveLocation.FIELD], description="Make string uppercase" ) - def uppercase(value: str, input: DirectiveInput): + def uppercase(value: DirectiveValue[str], input: DirectiveInput): return value.upper() schema = strawberry.Schema(query=Query, directives=[uppercase]) @@ -656,6 +678,10 @@ def uppercase(value: str, input: DirectiveInput): assert schema.as_str() == textwrap.dedent(expected_schema).strip() + result = schema.execute_sync('query { cake @uppercase(input: "foo") }') + assert result.errors is None + assert result.data == {"cake": "MADE_IN_SWITZERLAND"} + @pytest.mark.asyncio async def test_directive_with_custom_info_class() -> NoReturn: @@ -687,4 +713,5 @@ def append_names(value: DirectiveValue[str], names: List[str], info: CustomInfo) ) assert result.errors is None + assert result.data assert result.data["greeting"] == "Hi foo, bar" diff --git a/tests/schema/test_extensions.py b/tests/schema/test_extensions.py index 131864142c..6f54719669 100644 --- a/tests/schema/test_extensions.py +++ b/tests/schema/test_extensions.py @@ -11,6 +11,7 @@ ) import strawberry +from strawberry.directive import DirectiveValue from strawberry.scalars import JSON from strawberry.schema.schema_converter import GraphQLCoreConverter from strawberry.schema_directive import Location @@ -52,7 +53,7 @@ class Query: def test_directive(): @strawberry.directive(locations=[DirectiveLocation.FIELD]) - def uppercase(value: str, foo: str): + def uppercase(value: DirectiveValue[str], foo: str): return value.upper() @strawberry.type() diff --git a/tests/schema/test_get_extensions.py b/tests/schema/test_get_extensions.py index aeabab3ec7..5a91f79001 100644 --- a/tests/schema/test_get_extensions.py +++ b/tests/schema/test_get_extensions.py @@ -1,5 +1,5 @@ import strawberry -from strawberry.directive import DirectiveLocation +from strawberry.directive import DirectiveLocation, DirectiveValue from strawberry.extensions import SchemaExtension from strawberry.extensions.directives import ( DirectivesExtension, @@ -13,7 +13,7 @@ class Query: @strawberry.directive(locations=[DirectiveLocation.FIELD]) -def uppercase(value: str) -> str: +def uppercase(value: DirectiveValue[str]) -> str: return value.upper() diff --git a/tests/schema/test_info.py b/tests/schema/test_info.py index 3869d0d61d..70fddea56d 100644 --- a/tests/schema/test_info.py +++ b/tests/schema/test_info.py @@ -65,6 +65,7 @@ def hello_world(self, info: strawberry.Info[str, str]) -> Result: result = schema.execute_sync(query, context_value=my_context, root_value=root_value) assert not result.errors + assert result.data info = result.data["helloWorld"] assert info.pop("operation").startswith("OperationDefinitionNode at") field = json.loads(info.pop("selectedField")) @@ -315,11 +316,12 @@ def field(self, info: strawberry.Info) -> return_type: result = schema.execute_sync("{ field }") assert not result.errors + assert result.data assert result.data["field"] == return_value def test_return_type_from_field(): - def resolver(info): + def resolver(info: strawberry.Info): assert info.return_type is int return 0 @@ -332,11 +334,12 @@ class Query: result = schema.execute_sync("{ field }") assert not result.errors + assert result.data assert result.data["field"] == 0 def test_field_nodes_deprecation(): - def resolver(info): + def resolver(info: strawberry.Info): info.field_nodes return 0 @@ -350,6 +353,7 @@ class Query: result = schema.execute_sync("{ field }") assert not result.errors + assert result.data assert result.data["field"] == 0 @@ -367,7 +371,7 @@ class Query: @strawberry.field def field( self, - info, + info: strawberry.Info, arg_1: Annotated[str, strawberry.argument(description="Some description")], arg_2: Optional[TestInput] = None, ) -> str: diff --git a/tests/schema/test_permission.py b/tests/schema/test_permission.py index 23e54230d0..f041dac6b6 100644 --- a/tests/schema/test_permission.py +++ b/tests/schema/test_permission.py @@ -71,9 +71,7 @@ class Query: @strawberry.type class Subscription: @strawberry.subscription(permission_classes=[IsAdmin]) - async def user( - self, info - ) -> typing.AsyncGenerator[str, None]: # pragma: no cover + async def user(self) -> typing.AsyncGenerator[str, None]: # pragma: no cover yield "Hello" schema = strawberry.Schema(query=Query, subscription=Subscription) diff --git a/tests/schema/test_resolvers.py b/tests/schema/test_resolvers.py index 574955a954..8a81626320 100644 --- a/tests/schema/test_resolvers.py +++ b/tests/schema/test_resolvers.py @@ -1,5 +1,6 @@ # type: ignore import typing +from contextlib import nullcontext from typing import Any, Generic, List, NamedTuple, Optional, Type, TypeVar, Union import pytest @@ -512,18 +513,23 @@ def arbitrarily_named_info(icon: str, info_argument: Info) -> str: @pytest.mark.parametrize( - "resolver", + ("resolver", "deprecation"), ( - pytest.param(name_based_info), - pytest.param(type_based_info), - pytest.param(generic_type_based_info), - pytest.param(arbitrarily_named_info), + pytest.param( + name_based_info, + pytest.deprecated_call(match="Argument name-based matching of"), + ), + pytest.param(type_based_info, nullcontext()), + pytest.param(generic_type_based_info, nullcontext()), + pytest.param(arbitrarily_named_info, nullcontext()), ), ) -def test_info_argument(resolver): - @strawberry.type - class ResolverGreeting: - hello: str = strawberry.field(resolver=resolver) +def test_info_argument(resolver, deprecation): + with deprecation: + + @strawberry.type + class ResolverGreeting: + hello: str = strawberry.field(resolver=resolver) schema = strawberry.Schema(query=ResolverGreeting) result = schema.execute_sync('{ hello(icon: "🍓") }') diff --git a/tests/test/test_client.py b/tests/test/test_client.py index 0e03d12f77..1cac370d01 100644 --- a/tests/test/test_client.py +++ b/tests/test/test_client.py @@ -9,26 +9,28 @@ async def test_query_asserts_errors_option_is_deprecated( graphql_client, asserts_errors ): - with pytest.warns( - DeprecationWarning, - match="The `asserts_errors` argument has been renamed to `assert_no_errors`", + with pytest.deprecated_call( + match="The `asserts_errors` argument has been renamed to `assert_no_errors`" ): await await_maybe( graphql_client.query("{ hello }", asserts_errors=asserts_errors) ) -@pytest.mark.parametrize("option_name", ["asserts_errors", "assert_no_errors"]) @pytest.mark.parametrize( - ("assert_no_errors", "expectation"), + ("option_name", "expectation1"), + [("asserts_errors", pytest.deprecated_call()), ("assert_no_errors", nullcontext())], +) +@pytest.mark.parametrize( + ("assert_no_errors", "expectation2"), [(True, pytest.raises(AssertionError)), (False, nullcontext())], ) async def test_query_with_assert_no_errors_option( - graphql_client, option_name, assert_no_errors, expectation + graphql_client, option_name, assert_no_errors, expectation1, expectation2 ): query = "{ ThisIsNotAValidQuery }" - with expectation: + with expectation1, expectation2: await await_maybe( graphql_client.query(query, **{option_name: assert_no_errors}) ) diff --git a/tests/tools/test_create_type.py b/tests/tools/test_create_type.py index f483df8e49..4d49d1b0d3 100644 --- a/tests/tools/test_create_type.py +++ b/tests/tools/test_create_type.py @@ -137,7 +137,7 @@ class User: username: str @strawberry.mutation - def make_user(info, username: str) -> User: + def make_user(username: str) -> User: return User(username=username) Mutation = create_type("Mutation", [make_user]) @@ -156,7 +156,7 @@ class User: username: str @strawberry.mutation(name="makeNewUser", description="Make a new user") - def make_user(info, username: str) -> User: + def make_user(username: str) -> User: return User(username=username) Mutation = create_type("Mutation", [make_user]) @@ -176,7 +176,7 @@ class User: id: strawberry.ID @strawberry.field - def get_user_by_id(info, id: strawberry.ID) -> User: + def get_user_by_id(id: strawberry.ID) -> User: return User(id=id) Query = create_type("Query", [get_user_by_id]) diff --git a/tests/types/test_lazy_types.py b/tests/types/test_lazy_types.py index 429a2b7a2c..3dfc55bcc5 100644 --- a/tests/types/test_lazy_types.py +++ b/tests/types/test_lazy_types.py @@ -2,7 +2,7 @@ import enum import sys import textwrap -from typing import Generic, TypeVar +from typing import Generic, TypeVar, Union from typing_extensions import Annotated, TypeAlias import pytest @@ -173,7 +173,7 @@ def test_lazy_type_in_union(): ActiveType = LazyType("LaziestType", "test_lazy_types") ActiveEnum = LazyType("LazyEnum", "test_lazy_types") - something = union(name="CoolUnion", types=(ActiveType, ActiveEnum)) + something = Annotated[Union[ActiveType, ActiveEnum], union(name="CoolUnion")] annotation = StrawberryAnnotation(something) resolved = annotation.resolve() @@ -190,7 +190,7 @@ def test_lazy_function_in_union(): ActiveType = Annotated["LaziestType", strawberry.lazy("test_lazy_types")] ActiveEnum = Annotated["LazyEnum", strawberry.lazy("test_lazy_types")] - something = union(name="CoolUnion", types=(ActiveType, ActiveEnum)) + something = Annotated[Union[ActiveType, ActiveEnum], union(name="CoolUnion")] annotation = StrawberryAnnotation(something) resolved = annotation.resolve() diff --git a/tests/views/schema.py b/tests/views/schema.py index cb5d9959ef..311fccbb5f 100644 --- a/tests/views/schema.py +++ b/tests/views/schema.py @@ -221,12 +221,13 @@ async def listener( ) -> AsyncGenerator[str, None]: yield info.context["request"].channel_name - async for message in info.context["request"].channel_listen( + async with info.context["request"].listen_to_channel( type="test.message", timeout=timeout, groups=[group] if group is not None else [], - ): - yield message["text"] + ) as cm: + async for message in cm: + yield message["text"] @strawberry.subscription async def listener_with_confirmation(