Skip to content

Commit e69e4a0

Browse files
authored
Bugfix: call resolver function in DjangoConnectionField as documented (#1529)
* treat warnings as errors when running the tests * silence warnings * bugfix: let DjangoConnectionField call its resolver function that is, the one specified using DjangoConnectionField(..., resolver=some_func) * ignore the DeprecationWarning about typing.ByteString in graphql
1 parent 97deb76 commit e69e4a0

File tree

10 files changed

+94
-37
lines changed

10 files changed

+94
-37
lines changed

examples/django_test_settings.py

+2
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@
2828
GRAPHENE = {"SCHEMA": "graphene_django.tests.schema_view.schema"}
2929

3030
ROOT_URLCONF = "graphene_django.tests.urls"
31+
32+
USE_TZ = True

examples/starwars/schema.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import graphene
2-
from graphene import Schema, relay, resolve_only_args
2+
from graphene import Schema, relay
33
from graphene_django import DjangoConnectionField, DjangoObjectType
44

55
from .data import create_ship, get_empire, get_faction, get_rebels, get_ship, get_ships
@@ -62,16 +62,13 @@ class Query(graphene.ObjectType):
6262
node = relay.Node.Field()
6363
ships = DjangoConnectionField(Ship, description="All the ships.")
6464

65-
@resolve_only_args
66-
def resolve_ships(self):
65+
def resolve_ships(self, info):
6766
return get_ships()
6867

69-
@resolve_only_args
70-
def resolve_rebels(self):
68+
def resolve_rebels(self, info):
7169
return get_rebels()
7270

73-
@resolve_only_args
74-
def resolve_empire(self):
71+
def resolve_empire(self, info):
7572
return get_empire()
7673

7774

graphene_django/converter.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -199,19 +199,13 @@ def convert_field_to_string(field, registry=None):
199199
)
200200

201201

202-
@convert_django_field.register(models.BigAutoField)
203202
@convert_django_field.register(models.AutoField)
203+
@convert_django_field.register(models.BigAutoField)
204+
@convert_django_field.register(models.SmallAutoField)
204205
def convert_field_to_id(field, registry=None):
205206
return ID(description=get_django_field_description(field), required=not field.null)
206207

207208

208-
if hasattr(models, "SmallAutoField"):
209-
210-
@convert_django_field.register(models.SmallAutoField)
211-
def convert_field_small_to_id(field, registry=None):
212-
return convert_field_to_id(field, registry)
213-
214-
215209
@convert_django_field.register(models.UUIDField)
216210
def convert_field_to_uuid(field, registry=None):
217211
return UUID(

graphene_django/fields.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ def connection_resolver(
247247
def wrap_resolve(self, parent_resolver):
248248
return partial(
249249
self.connection_resolver,
250-
parent_resolver,
250+
self.resolver or parent_resolver,
251251
self.connection_type,
252252
self.get_manager(),
253253
self.get_queryset_resolver(),

graphene_django/forms/tests/test_converter.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from django import forms
1+
from django import VERSION as DJANGO_VERSION, forms
22
from pytest import raises
33

44
from graphene import (
@@ -19,12 +19,16 @@
1919
from ..converter import convert_form_field
2020

2121

22-
def assert_conversion(django_field, graphene_field, *args):
23-
field = django_field(*args, help_text="Custom Help Text")
22+
def assert_conversion(django_field, graphene_field, *args, **kwargs):
23+
# Arrange
24+
help_text = kwargs.setdefault("help_text", "Custom Help Text")
25+
field = django_field(*args, **kwargs)
26+
# Act
2427
graphene_type = convert_form_field(field)
28+
# Assert
2529
assert isinstance(graphene_type, graphene_field)
2630
field = graphene_type.Field()
27-
assert field.description == "Custom Help Text"
31+
assert field.description == help_text
2832
return field
2933

3034

@@ -59,7 +63,12 @@ def test_should_slug_convert_string():
5963

6064

6165
def test_should_url_convert_string():
62-
assert_conversion(forms.URLField, String)
66+
kwargs = {}
67+
if DJANGO_VERSION >= (5, 0):
68+
# silence RemovedInDjango60Warning
69+
kwargs["assume_scheme"] = "https"
70+
71+
assert_conversion(forms.URLField, String, **kwargs)
6372

6473

6574
def test_should_choice_convert_string():
@@ -75,8 +84,7 @@ def test_should_regex_convert_string():
7584

7685

7786
def test_should_uuid_convert_string():
78-
if hasattr(forms, "UUIDField"):
79-
assert_conversion(forms.UUIDField, UUID)
87+
assert_conversion(forms.UUIDField, UUID)
8088

8189

8290
def test_should_integer_convert_int():

graphene_django/rest_framework/tests/test_field_converter.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ def test_should_regex_convert_string():
9696

9797

9898
def test_should_uuid_convert_string():
99-
if hasattr(serializers, "UUIDField"):
100-
assert_conversion(serializers.UUIDField, graphene.String)
99+
assert_conversion(serializers.UUIDField, graphene.String)
101100

102101

103102
def test_should_model_convert_field():

graphene_django/tests/test_converter.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@ def assert_conversion(django_field, graphene_field, *args, **kwargs):
5353

5454

5555
def test_should_unknown_django_field_raise_exception():
56-
with raises(Exception) as excinfo:
56+
with raises(Exception, match="Don't know how to convert the Django field"):
5757
convert_django_field(None)
58-
assert "Don't know how to convert the Django field" in str(excinfo.value)
5958

6059

6160
def test_should_date_time_convert_string():
@@ -115,8 +114,7 @@ def test_should_big_auto_convert_id():
115114

116115

117116
def test_should_small_auto_convert_id():
118-
if hasattr(models, "SmallAutoField"):
119-
assert_conversion(models.SmallAutoField, graphene.ID, primary_key=True)
117+
assert_conversion(models.SmallAutoField, graphene.ID, primary_key=True)
120118

121119

122120
def test_should_uuid_convert_id():
@@ -166,14 +164,14 @@ def test_field_with_choices_convert_enum():
166164
help_text="Language", choices=(("es", "Spanish"), ("en", "English"))
167165
)
168166

169-
class TranslatedModel(models.Model):
167+
class ChoicesModel(models.Model):
170168
language = field
171169

172170
class Meta:
173171
app_label = "test"
174172

175173
graphene_type = convert_django_field_with_choices(field).type.of_type
176-
assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices"
174+
assert graphene_type._meta.name == "TestChoicesModelLanguageChoices"
177175
assert graphene_type._meta.enum.__members__["ES"].value == "es"
178176
assert graphene_type._meta.enum.__members__["ES"].description == "Spanish"
179177
assert graphene_type._meta.enum.__members__["EN"].value == "en"
@@ -186,14 +184,14 @@ def get_choices():
186184

187185
field = models.CharField(help_text="Language", choices=get_choices)
188186

189-
class TranslatedModel(models.Model):
187+
class CallableChoicesModel(models.Model):
190188
language = field
191189

192190
class Meta:
193191
app_label = "test"
194192

195193
graphene_type = convert_django_field_with_choices(field).type.of_type
196-
assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices"
194+
assert graphene_type._meta.name == "TestCallableChoicesModelLanguageChoices"
197195
assert graphene_type._meta.enum.__members__["ES"].value == "es"
198196
assert graphene_type._meta.enum.__members__["ES"].description == "Spanish"
199197
assert graphene_type._meta.enum.__members__["EN"].value == "en"

graphene_django/tests/test_get_queryset.py

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def setup_schema(self):
2626
class ReporterType(DjangoObjectType):
2727
class Meta:
2828
model = Reporter
29+
fields = "__all__"
2930

3031
@classmethod
3132
def get_queryset(cls, queryset, info):
@@ -36,6 +37,7 @@ def get_queryset(cls, queryset, info):
3637
class ArticleType(DjangoObjectType):
3738
class Meta:
3839
model = Article
40+
fields = "__all__"
3941

4042
@classmethod
4143
def get_queryset(cls, queryset, info):
@@ -200,6 +202,7 @@ def setup_schema(self):
200202
class ReporterType(DjangoObjectType):
201203
class Meta:
202204
model = Reporter
205+
fields = "__all__"
203206
interfaces = (Node,)
204207

205208
@classmethod
@@ -211,6 +214,7 @@ def get_queryset(cls, queryset, info):
211214
class ArticleType(DjangoObjectType):
212215
class Meta:
213216
model = Article
217+
fields = "__all__"
214218
interfaces = (Node,)
215219

216220
@classmethod
@@ -370,6 +374,7 @@ def setup_schema(self):
370374
class FilmDetailsType(DjangoObjectType):
371375
class Meta:
372376
model = FilmDetails
377+
fields = "__all__"
373378

374379
@classmethod
375380
def get_queryset(cls, queryset, info):
@@ -380,6 +385,7 @@ def get_queryset(cls, queryset, info):
380385
class FilmType(DjangoObjectType):
381386
class Meta:
382387
model = Film
388+
fields = "__all__"
383389

384390
@classmethod
385391
def get_queryset(cls, queryset, info):

graphene_django/tests/test_query.py

+53-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import base64
22
import datetime
3+
from unittest.mock import ANY, Mock
34

45
import pytest
56
from django.db import models
@@ -2000,14 +2001,62 @@ class Query(graphene.ObjectType):
20002001
assert result.data == expected
20012002

20022003

2004+
def test_connection_should_call_resolver_function():
2005+
resolver_mock = Mock(
2006+
name="resolver",
2007+
return_value=[
2008+
Reporter(first_name="Some", last_name="One"),
2009+
Reporter(first_name="John", last_name="Doe"),
2010+
],
2011+
)
2012+
2013+
class ReporterType(DjangoObjectType):
2014+
class Meta:
2015+
model = Reporter
2016+
fields = "__all__"
2017+
interfaces = [Node]
2018+
2019+
class Query(graphene.ObjectType):
2020+
reporters = DjangoConnectionField(ReporterType, resolver=resolver_mock)
2021+
2022+
schema = graphene.Schema(query=Query)
2023+
result = schema.execute(
2024+
"""
2025+
query {
2026+
reporters {
2027+
edges {
2028+
node {
2029+
firstName
2030+
lastName
2031+
}
2032+
}
2033+
}
2034+
}
2035+
"""
2036+
)
2037+
2038+
resolver_mock.assert_called_once_with(None, ANY)
2039+
assert not result.errors
2040+
assert result.data == {
2041+
"reporters": {
2042+
"edges": [
2043+
{"node": {"firstName": "Some", "lastName": "One"}},
2044+
{"node": {"firstName": "John", "lastName": "Doe"}},
2045+
],
2046+
},
2047+
}
2048+
2049+
20032050
def test_should_query_nullable_foreign_key():
20042051
class PetType(DjangoObjectType):
20052052
class Meta:
20062053
model = Pet
2054+
fields = "__all__"
20072055

20082056
class PersonType(DjangoObjectType):
20092057
class Meta:
20102058
model = Person
2059+
fields = "__all__"
20112060

20122061
class Query(graphene.ObjectType):
20132062
pet = graphene.Field(PetType, name=graphene.String(required=True))
@@ -2022,10 +2071,8 @@ def resolve_person(self, info, name):
20222071
schema = graphene.Schema(query=Query)
20232072

20242073
person = Person.objects.create(name="Jane")
2025-
[
2026-
Pet.objects.create(name="Stray dog", age=1),
2027-
Pet.objects.create(name="Jane's dog", owner=person, age=1),
2028-
]
2074+
Pet.objects.create(name="Stray dog", age=1)
2075+
Pet.objects.create(name="Jane's dog", owner=person, age=1)
20292076

20302077
query_pet = """
20312078
query getPet($name: String!) {
@@ -2068,6 +2115,7 @@ def test_should_query_nullable_one_to_one_relation_with_custom_resolver():
20682115
class FilmType(DjangoObjectType):
20692116
class Meta:
20702117
model = Film
2118+
fields = "__all__"
20712119

20722120
@classmethod
20732121
def get_queryset(cls, queryset, info):
@@ -2076,6 +2124,7 @@ def get_queryset(cls, queryset, info):
20762124
class FilmDetailsType(DjangoObjectType):
20772125
class Meta:
20782126
model = FilmDetails
2127+
fields = "__all__"
20792128

20802129
@classmethod
20812130
def get_queryset(cls, queryset, info):

setup.cfg

+4
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ omit = */tests/*
1010
[tool:pytest]
1111
DJANGO_SETTINGS_MODULE = examples.django_test_settings
1212
addopts = --random-order
13+
filterwarnings =
14+
error
15+
# we can't do anything about the DeprecationWarning about typing.ByteString in graphql
16+
default:'typing\.ByteString' is deprecated:DeprecationWarning:graphql\.pyutils\.is_iterable

0 commit comments

Comments
 (0)