diff --git a/examples/django_test_settings.py b/examples/django_test_settings.py index dcb1f6c8..4b5689e9 100644 --- a/examples/django_test_settings.py +++ b/examples/django_test_settings.py @@ -28,3 +28,5 @@ GRAPHENE = {"SCHEMA": "graphene_django.tests.schema_view.schema"} ROOT_URLCONF = "graphene_django.tests.urls" + +USE_TZ = True diff --git a/examples/starwars/schema.py b/examples/starwars/schema.py index 07bf9d28..e81c8b2b 100644 --- a/examples/starwars/schema.py +++ b/examples/starwars/schema.py @@ -1,5 +1,5 @@ import graphene -from graphene import Schema, relay, resolve_only_args +from graphene import Schema, relay from graphene_django import DjangoConnectionField, DjangoObjectType from .data import create_ship, get_empire, get_faction, get_rebels, get_ship, get_ships @@ -62,16 +62,13 @@ class Query(graphene.ObjectType): node = relay.Node.Field() ships = DjangoConnectionField(Ship, description="All the ships.") - @resolve_only_args - def resolve_ships(self): + def resolve_ships(self, info): return get_ships() - @resolve_only_args - def resolve_rebels(self): + def resolve_rebels(self, info): return get_rebels() - @resolve_only_args - def resolve_empire(self): + def resolve_empire(self, info): return get_empire() diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 7eba22a1..4ff832b9 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -190,19 +190,13 @@ def convert_field_to_string(field, registry=None): ) -@convert_django_field.register(models.BigAutoField) @convert_django_field.register(models.AutoField) +@convert_django_field.register(models.BigAutoField) +@convert_django_field.register(models.SmallAutoField) def convert_field_to_id(field, registry=None): return ID(description=get_django_field_description(field), required=not field.null) -if hasattr(models, "SmallAutoField"): - - @convert_django_field.register(models.SmallAutoField) - def convert_field_small_to_id(field, registry=None): - return convert_field_to_id(field, registry) - - @convert_django_field.register(models.UUIDField) def convert_field_to_uuid(field, registry=None): return UUID( diff --git a/graphene_django/fields.py b/graphene_django/fields.py index 1bbe1f3d..9e9f4572 100644 --- a/graphene_django/fields.py +++ b/graphene_django/fields.py @@ -247,7 +247,7 @@ def connection_resolver( def wrap_resolve(self, parent_resolver): return partial( self.connection_resolver, - parent_resolver, + self.resolver or parent_resolver, self.connection_type, self.get_manager(), self.get_queryset_resolver(), diff --git a/graphene_django/forms/tests/test_converter.py b/graphene_django/forms/tests/test_converter.py index 7e2a6d34..64fa8507 100644 --- a/graphene_django/forms/tests/test_converter.py +++ b/graphene_django/forms/tests/test_converter.py @@ -1,4 +1,4 @@ -from django import forms +from django import VERSION as DJANGO_VERSION, forms from pytest import raises from graphene import ( @@ -19,12 +19,16 @@ from ..converter import convert_form_field -def assert_conversion(django_field, graphene_field, *args): - field = django_field(*args, help_text="Custom Help Text") +def assert_conversion(django_field, graphene_field, *args, **kwargs): + # Arrange + help_text = kwargs.setdefault("help_text", "Custom Help Text") + field = django_field(*args, **kwargs) + # Act graphene_type = convert_form_field(field) + # Assert assert isinstance(graphene_type, graphene_field) field = graphene_type.Field() - assert field.description == "Custom Help Text" + assert field.description == help_text return field @@ -59,7 +63,12 @@ def test_should_slug_convert_string(): def test_should_url_convert_string(): - assert_conversion(forms.URLField, String) + kwargs = {} + if DJANGO_VERSION >= (5, 0): + # silence RemovedInDjango60Warning + kwargs["assume_scheme"] = "https" + + assert_conversion(forms.URLField, String, **kwargs) def test_should_choice_convert_string(): @@ -75,8 +84,7 @@ def test_should_regex_convert_string(): def test_should_uuid_convert_string(): - if hasattr(forms, "UUIDField"): - assert_conversion(forms.UUIDField, UUID) + assert_conversion(forms.UUIDField, UUID) def test_should_integer_convert_int(): diff --git a/graphene_django/rest_framework/tests/test_field_converter.py b/graphene_django/rest_framework/tests/test_field_converter.py index b0d7a6d6..7eb907ac 100644 --- a/graphene_django/rest_framework/tests/test_field_converter.py +++ b/graphene_django/rest_framework/tests/test_field_converter.py @@ -96,8 +96,7 @@ def test_should_regex_convert_string(): def test_should_uuid_convert_string(): - if hasattr(serializers, "UUIDField"): - assert_conversion(serializers.UUIDField, graphene.String) + assert_conversion(serializers.UUIDField, graphene.String) def test_should_model_convert_field(): diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index 2f8b1d51..5609c0c2 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -53,9 +53,8 @@ def assert_conversion(django_field, graphene_field, *args, **kwargs): def test_should_unknown_django_field_raise_exception(): - with raises(Exception) as excinfo: + with raises(Exception, match="Don't know how to convert the Django field"): convert_django_field(None) - assert "Don't know how to convert the Django field" in str(excinfo.value) def test_should_date_time_convert_string(): @@ -115,8 +114,7 @@ def test_should_big_auto_convert_id(): def test_should_small_auto_convert_id(): - if hasattr(models, "SmallAutoField"): - assert_conversion(models.SmallAutoField, graphene.ID, primary_key=True) + assert_conversion(models.SmallAutoField, graphene.ID, primary_key=True) def test_should_uuid_convert_id(): @@ -166,14 +164,14 @@ def test_field_with_choices_convert_enum(): help_text="Language", choices=(("es", "Spanish"), ("en", "English")) ) - class TranslatedModel(models.Model): + class ChoicesModel(models.Model): language = field class Meta: app_label = "test" graphene_type = convert_django_field_with_choices(field).type.of_type - assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices" + assert graphene_type._meta.name == "TestChoicesModelLanguageChoices" assert graphene_type._meta.enum.__members__["ES"].value == "es" assert graphene_type._meta.enum.__members__["ES"].description == "Spanish" assert graphene_type._meta.enum.__members__["EN"].value == "en" @@ -186,14 +184,14 @@ def get_choices(): field = models.CharField(help_text="Language", choices=get_choices) - class TranslatedModel(models.Model): + class CallableChoicesModel(models.Model): language = field class Meta: app_label = "test" graphene_type = convert_django_field_with_choices(field).type.of_type - assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices" + assert graphene_type._meta.name == "TestCallableChoicesModelLanguageChoices" assert graphene_type._meta.enum.__members__["ES"].value == "es" assert graphene_type._meta.enum.__members__["ES"].description == "Spanish" assert graphene_type._meta.enum.__members__["EN"].value == "en" diff --git a/graphene_django/tests/test_get_queryset.py b/graphene_django/tests/test_get_queryset.py index d5b1d938..d0930e4a 100644 --- a/graphene_django/tests/test_get_queryset.py +++ b/graphene_django/tests/test_get_queryset.py @@ -26,6 +26,7 @@ def setup_schema(self): class ReporterType(DjangoObjectType): class Meta: model = Reporter + fields = "__all__" @classmethod def get_queryset(cls, queryset, info): @@ -36,6 +37,7 @@ def get_queryset(cls, queryset, info): class ArticleType(DjangoObjectType): class Meta: model = Article + fields = "__all__" @classmethod def get_queryset(cls, queryset, info): @@ -200,6 +202,7 @@ def setup_schema(self): class ReporterType(DjangoObjectType): class Meta: model = Reporter + fields = "__all__" interfaces = (Node,) @classmethod @@ -211,6 +214,7 @@ def get_queryset(cls, queryset, info): class ArticleType(DjangoObjectType): class Meta: model = Article + fields = "__all__" interfaces = (Node,) @classmethod @@ -370,6 +374,7 @@ def setup_schema(self): class FilmDetailsType(DjangoObjectType): class Meta: model = FilmDetails + fields = "__all__" @classmethod def get_queryset(cls, queryset, info): @@ -380,6 +385,7 @@ def get_queryset(cls, queryset, info): class FilmType(DjangoObjectType): class Meta: model = Film + fields = "__all__" @classmethod def get_queryset(cls, queryset, info): diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 42394c20..85ea1452 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -1,5 +1,6 @@ import base64 import datetime +from unittest.mock import ANY, Mock import pytest from django.db import models @@ -2000,14 +2001,62 @@ class Query(graphene.ObjectType): assert result.data == expected +def test_connection_should_call_resolver_function(): + resolver_mock = Mock( + name="resolver", + return_value=[ + Reporter(first_name="Some", last_name="One"), + Reporter(first_name="John", last_name="Doe"), + ], + ) + + class ReporterType(DjangoObjectType): + class Meta: + model = Reporter + fields = "__all__" + interfaces = [Node] + + class Query(graphene.ObjectType): + reporters = DjangoConnectionField(ReporterType, resolver=resolver_mock) + + schema = graphene.Schema(query=Query) + result = schema.execute( + """ + query { + reporters { + edges { + node { + firstName + lastName + } + } + } + } + """ + ) + + resolver_mock.assert_called_once_with(None, ANY) + assert not result.errors + assert result.data == { + "reporters": { + "edges": [ + {"node": {"firstName": "Some", "lastName": "One"}}, + {"node": {"firstName": "John", "lastName": "Doe"}}, + ], + }, + } + + def test_should_query_nullable_foreign_key(): class PetType(DjangoObjectType): class Meta: model = Pet + fields = "__all__" class PersonType(DjangoObjectType): class Meta: model = Person + fields = "__all__" class Query(graphene.ObjectType): pet = graphene.Field(PetType, name=graphene.String(required=True)) @@ -2022,10 +2071,8 @@ def resolve_person(self, info, name): schema = graphene.Schema(query=Query) person = Person.objects.create(name="Jane") - [ - Pet.objects.create(name="Stray dog", age=1), - Pet.objects.create(name="Jane's dog", owner=person, age=1), - ] + Pet.objects.create(name="Stray dog", age=1) + Pet.objects.create(name="Jane's dog", owner=person, age=1) query_pet = """ query getPet($name: String!) { @@ -2068,6 +2115,7 @@ def test_should_query_nullable_one_to_one_relation_with_custom_resolver(): class FilmType(DjangoObjectType): class Meta: model = Film + fields = "__all__" @classmethod def get_queryset(cls, queryset, info): @@ -2076,6 +2124,7 @@ def get_queryset(cls, queryset, info): class FilmDetailsType(DjangoObjectType): class Meta: model = FilmDetails + fields = "__all__" @classmethod def get_queryset(cls, queryset, info): diff --git a/setup.cfg b/setup.cfg index bd6d271f..09dcf69c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,3 +10,7 @@ omit = */tests/* [tool:pytest] DJANGO_SETTINGS_MODULE = examples.django_test_settings addopts = --random-order +filterwarnings = + error + # we can't do anything about the DeprecationWarning about typing.ByteString in graphql + default:'typing\.ByteString' is deprecated:DeprecationWarning:graphql\.pyutils\.is_iterable