mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-03 20:03:30 +03:00
Change code with black
This commit is contained in:
parent
96361fc6e7
commit
a644d03c5e
|
@ -205,7 +205,9 @@ class DjangoConnectionField(ConnectionField):
|
||||||
class DjangoField(Field):
|
class DjangoField(Field):
|
||||||
"""Class to manage permission for fields"""
|
"""Class to manage permission for fields"""
|
||||||
|
|
||||||
def __init__(self, type, permissions=(), permissions_resolver=auth_resolver, *args, **kwargs):
|
def __init__(
|
||||||
|
self, type, permissions=(), permissions_resolver=auth_resolver, *args, **kwargs
|
||||||
|
):
|
||||||
"""Get permissions to access a field"""
|
"""Get permissions to access a field"""
|
||||||
super(DjangoField, self).__init__(type, *args, **kwargs)
|
super(DjangoField, self).__init__(type, *args, **kwargs)
|
||||||
self.permissions = permissions
|
self.permissions = permissions
|
||||||
|
@ -215,15 +217,23 @@ class DjangoField(Field):
|
||||||
"""Intercept resolver to analyse permissions"""
|
"""Intercept resolver to analyse permissions"""
|
||||||
parent_resolver = super(DjangoField, self).get_resolver(parent_resolver)
|
parent_resolver = super(DjangoField, self).get_resolver(parent_resolver)
|
||||||
if self.permissions:
|
if self.permissions:
|
||||||
return partial(get_unbound_function(self.permissions_resolver), parent_resolver, self.permissions, None,
|
return partial(
|
||||||
None, True)
|
get_unbound_function(self.permissions_resolver),
|
||||||
|
parent_resolver,
|
||||||
|
self.permissions,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
True,
|
||||||
|
)
|
||||||
return parent_resolver
|
return parent_resolver
|
||||||
|
|
||||||
|
|
||||||
class DataLoaderField(DjangoField):
|
class DataLoaderField(DjangoField):
|
||||||
"""Class to manage access to data-loader when resolve the field"""
|
"""Class to manage access to data-loader when resolve the field"""
|
||||||
|
|
||||||
def __init__(self, type, data_loader, source_loader, load_many=False, *args, **kwargs):
|
def __init__(
|
||||||
|
self, type, data_loader, source_loader, load_many=False, *args, **kwargs
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Initialization of data-loader to resolve field
|
Initialization of data-loader to resolve field
|
||||||
:param data_loader: data-loader to resolve field
|
:param data_loader: data-loader to resolve field
|
||||||
|
@ -243,7 +253,9 @@ class DataLoaderField(DjangoField):
|
||||||
def resolver_data_loader(self, root, info, *args, **kwargs):
|
def resolver_data_loader(self, root, info, *args, **kwargs):
|
||||||
"""Resolve field through dataloader"""
|
"""Resolve field through dataloader"""
|
||||||
if root:
|
if root:
|
||||||
source_loader = reduce(lambda x, y: getattr(x, y), self.source_loader.split('.'), root)
|
source_loader = reduce(
|
||||||
|
lambda x, y: getattr(x, y), self.source_loader.split("."), root
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
source_loader = kwargs.get(self.source_loader)
|
source_loader = kwargs.get(self.source_loader)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
from graphene import ID, Boolean, Float, Int, List, String, UUID, Date, DateTime, Time, Enum
|
from graphene import (
|
||||||
|
ID,
|
||||||
|
Boolean,
|
||||||
|
Float,
|
||||||
|
Int,
|
||||||
|
List,
|
||||||
|
String,
|
||||||
|
UUID,
|
||||||
|
Date,
|
||||||
|
DateTime,
|
||||||
|
Time,
|
||||||
|
Enum,
|
||||||
|
)
|
||||||
from graphene.utils.str_converters import to_camel_case
|
from graphene.utils.str_converters import to_camel_case
|
||||||
|
|
||||||
from graphene_django.converter import get_choices
|
from graphene_django.converter import get_choices
|
||||||
|
@ -87,7 +99,7 @@ def convert_form_field_to_id(field):
|
||||||
|
|
||||||
def get_form_name(form):
|
def get_form_name(form):
|
||||||
"""Get form name"""
|
"""Get form name"""
|
||||||
class_name = str(form.__class__).split('.')[-1]
|
class_name = str(form.__class__).split(".")[-1]
|
||||||
return class_name[:-2]
|
return class_name[:-2]
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,15 +111,20 @@ def convert_form_field_with_choices(field, name=None, form=None):
|
||||||
:param form: field's form
|
:param form: field's form
|
||||||
:return: graphene Field
|
:return: graphene Field
|
||||||
"""
|
"""
|
||||||
choices = getattr(field, 'choices', None)
|
choices = getattr(field, "choices", None)
|
||||||
|
|
||||||
# If is a choice field, but not depends on models
|
# If is a choice field, but not depends on models
|
||||||
if not isinstance(field, (forms.ModelMultipleChoiceField, forms.ModelChoiceField)) and choices:
|
if (
|
||||||
|
not isinstance(field, (forms.ModelMultipleChoiceField, forms.ModelChoiceField))
|
||||||
|
and choices
|
||||||
|
):
|
||||||
if form:
|
if form:
|
||||||
name = to_camel_case("{}_{}".format(get_form_name(form), field.label or name))
|
name = to_camel_case(
|
||||||
|
"{}_{}".format(get_form_name(form), field.label or name)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
name = field.label or name
|
name = field.label or name
|
||||||
name = to_camel_case(name.replace(' ', '_'))
|
name = to_camel_case(name.replace(" ", "_"))
|
||||||
choices = list(get_choices(choices))
|
choices = list(get_choices(choices))
|
||||||
named_choices = [(c[0], c[1]) for c in choices]
|
named_choices = [(c[0], c[1]) for c in choices]
|
||||||
named_choices_descriptions = {c[0]: c[2] for c in choices}
|
named_choices_descriptions = {c[0]: c[2] for c in choices}
|
||||||
|
@ -122,5 +139,7 @@ def convert_form_field_with_choices(field, name=None, form=None):
|
||||||
return named_choices_descriptions[self.name]
|
return named_choices_descriptions[self.name]
|
||||||
|
|
||||||
enum = Enum(name, list(named_choices), type=EnumWithDescriptionsType)
|
enum = Enum(name, list(named_choices), type=EnumWithDescriptionsType)
|
||||||
return enum(description=field.help_text, required=field.required) # pylint: disable=E1102
|
return enum(
|
||||||
|
description=field.help_text, required=field.required
|
||||||
|
) # pylint: disable=E1102
|
||||||
return convert_form_field(field)
|
return convert_form_field(field)
|
||||||
|
|
|
@ -22,8 +22,8 @@ def fields_for_form(form, only_fields, exclude_fields):
|
||||||
for name, field in form.fields.items():
|
for name, field in form.fields.items():
|
||||||
is_not_in_only = only_fields and name not in only_fields
|
is_not_in_only = only_fields and name not in only_fields
|
||||||
is_excluded = (
|
is_excluded = (
|
||||||
name
|
name
|
||||||
in exclude_fields # or
|
in exclude_fields # or
|
||||||
# name in already_created_fields
|
# name in already_created_fields
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,7 +46,10 @@ class BaseDjangoFormMutation(ClientIDMutation):
|
||||||
return cls.perform_mutate(form, info)
|
return cls.perform_mutate(form, info)
|
||||||
else:
|
else:
|
||||||
errors = [
|
errors = [
|
||||||
ErrorType(field=to_camel_case(key) if key != '__all__' else key, messages=value)
|
ErrorType(
|
||||||
|
field=to_camel_case(key) if key != "__all__" else key,
|
||||||
|
messages=value,
|
||||||
|
)
|
||||||
for key, value in form.errors.items()
|
for key, value in form.errors.items()
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -81,7 +84,12 @@ class DjangoFormMutation(BaseDjangoFormMutation):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __init_subclass_with_meta__(
|
def __init_subclass_with_meta__(
|
||||||
cls, form_class=None, mirror_input=False, only_fields=(), exclude_fields=(), **options
|
cls,
|
||||||
|
form_class=None,
|
||||||
|
mirror_input=False,
|
||||||
|
only_fields=(),
|
||||||
|
exclude_fields=(),
|
||||||
|
**options
|
||||||
):
|
):
|
||||||
|
|
||||||
if not form_class:
|
if not form_class:
|
||||||
|
@ -122,13 +130,13 @@ class DjangoModelFormMutation(BaseDjangoFormMutation):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __init_subclass_with_meta__(
|
def __init_subclass_with_meta__(
|
||||||
cls,
|
cls,
|
||||||
form_class=None,
|
form_class=None,
|
||||||
model=None,
|
model=None,
|
||||||
return_field_name=None,
|
return_field_name=None,
|
||||||
only_fields=(),
|
only_fields=(),
|
||||||
exclude_fields=(),
|
exclude_fields=(),
|
||||||
**options
|
**options
|
||||||
):
|
):
|
||||||
|
|
||||||
if not form_class:
|
if not form_class:
|
||||||
|
|
|
@ -115,6 +115,8 @@ def test_should_manytoone_convert_connectionorlist():
|
||||||
|
|
||||||
|
|
||||||
def test_should_typed_choice_convert_enum():
|
def test_should_typed_choice_convert_enum():
|
||||||
field = forms.TypedChoiceField(choices=(('A', 'Choice A'), ('B', 'Choice B')), label='field')
|
field = forms.TypedChoiceField(
|
||||||
graphene_type = convert_form_field_with_choices(field, name='field_name')
|
choices=(("A", "Choice A"), ("B", "Choice B")), label="field"
|
||||||
|
)
|
||||||
|
graphene_type = convert_form_field_with_choices(field, name="field_name")
|
||||||
assert isinstance(graphene_type, Enum)
|
assert isinstance(graphene_type, Enum)
|
||||||
|
|
|
@ -52,6 +52,7 @@ class FilmType(DjangoObjectType):
|
||||||
|
|
||||||
def test_needs_form_class():
|
def test_needs_form_class():
|
||||||
with raises(Exception) as exc:
|
with raises(Exception) as exc:
|
||||||
|
|
||||||
class MyMutation(DjangoFormMutation):
|
class MyMutation(DjangoFormMutation):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -180,7 +181,7 @@ class FormMutationTests(TestCase):
|
||||||
class MyMutation(DjangoFormMutation):
|
class MyMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = MyForm
|
form_class = MyForm
|
||||||
exclude_fields = ['text']
|
exclude_fields = ["text"]
|
||||||
|
|
||||||
self.assertNotIn("text", MyMutation.Input._meta.fields)
|
self.assertNotIn("text", MyMutation.Input._meta.fields)
|
||||||
self.assertIn("client_mutation_id", MyMutation.Input._meta.fields)
|
self.assertIn("client_mutation_id", MyMutation.Input._meta.fields)
|
||||||
|
@ -331,7 +332,7 @@ class ModelFormMutationTests(TestCase):
|
||||||
self.assertEqual(result.data["petMutation"]["pet"], None)
|
self.assertEqual(result.data["petMutation"]["pet"], None)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
result.data["petMutation"]["errors"],
|
result.data["petMutation"]["errors"],
|
||||||
[{"field": "age", "messages": ["Too old"], }],
|
[{"field": "age", "messages": ["Too old"],}],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(Pet.objects.count(), 0)
|
self.assertEqual(Pet.objects.count(), 0)
|
||||||
|
@ -341,7 +342,7 @@ class ModelFormMutationTests(TestCase):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
|
|
||||||
result = PetMutation.mutate_and_get_payload(None, None, test_camel='text')
|
result = PetMutation.mutate_and_get_payload(None, None, test_camel="text")
|
||||||
|
|
||||||
# A pet was not created
|
# A pet was not created
|
||||||
self.assertEqual(Pet.objects.count(), 0)
|
self.assertEqual(Pet.objects.count(), 0)
|
||||||
|
@ -349,8 +350,8 @@ class ModelFormMutationTests(TestCase):
|
||||||
fields_w_error = {e.field: e.messages for e in result.errors}
|
fields_w_error = {e.field: e.messages for e in result.errors}
|
||||||
self.assertEqual(len(result.errors), 3)
|
self.assertEqual(len(result.errors), 3)
|
||||||
self.assertIn("test_camel", fields_w_error)
|
self.assertIn("test_camel", fields_w_error)
|
||||||
self.assertEqual(fields_w_error['test_camel'], ["Enter a whole number."])
|
self.assertEqual(fields_w_error["test_camel"], ["Enter a whole number."])
|
||||||
self.assertIn("name", fields_w_error)
|
self.assertIn("name", fields_w_error)
|
||||||
self.assertEqual(fields_w_error['name'], ["This field is required."])
|
self.assertEqual(fields_w_error["name"], ["This field is required."])
|
||||||
self.assertIn("age", fields_w_error)
|
self.assertIn("age", fields_w_error)
|
||||||
self.assertEqual(fields_w_error['age'], ["This field is required."])
|
self.assertEqual(fields_w_error["age"], ["This field is required."])
|
||||||
|
|
|
@ -231,15 +231,14 @@ data_loader = DataLoader(batch_load_fn=batch_load_fn)
|
||||||
|
|
||||||
|
|
||||||
class PermissionFieldTests(TestCase):
|
class PermissionFieldTests(TestCase):
|
||||||
|
|
||||||
def test_permission_field(self):
|
def test_permission_field(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
field = DjangoField(MyType, permissions=['perm1', 'perm2'], source='resolver')
|
field = DjangoField(MyType, permissions=["perm1", "perm2"], source="resolver")
|
||||||
resolver = field.get_resolver(None)
|
resolver = field.get_resolver(None)
|
||||||
|
|
||||||
class Viewer(object):
|
class Viewer(object):
|
||||||
def has_perm(self, perm):
|
def has_perm(self, perm):
|
||||||
return perm == 'perm2'
|
return perm == "perm2"
|
||||||
|
|
||||||
info = mock.Mock(context=mock.Mock(user=Viewer()))
|
info = mock.Mock(context=mock.Mock(user=Viewer()))
|
||||||
|
|
||||||
|
@ -247,7 +246,7 @@ class PermissionFieldTests(TestCase):
|
||||||
|
|
||||||
def test_permission_field_without_permission(self):
|
def test_permission_field_without_permission(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
field = DjangoField(MyType, permissions=['perm1', 'perm2'], source='resolver')
|
field = DjangoField(MyType, permissions=["perm1", "perm2"], source="resolver")
|
||||||
resolver = field.get_resolver(field.resolver)
|
resolver = field.get_resolver(field.resolver)
|
||||||
|
|
||||||
class Viewer(object):
|
class Viewer(object):
|
||||||
|
@ -261,10 +260,11 @@ class PermissionFieldTests(TestCase):
|
||||||
|
|
||||||
|
|
||||||
class DataLoaderFieldTests(TestCase):
|
class DataLoaderFieldTests(TestCase):
|
||||||
|
|
||||||
def test_dataloaderfield(self):
|
def test_dataloaderfield(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
data_loader_field = DataLoaderField(data_loader=data_loader, source_loader='key', type=MyType)
|
data_loader_field = DataLoaderField(
|
||||||
|
data_loader=data_loader, source_loader="key", type=MyType
|
||||||
|
)
|
||||||
|
|
||||||
resolver = data_loader_field.get_resolver(None)
|
resolver = data_loader_field.get_resolver(None)
|
||||||
instance = MyInstance()
|
instance = MyInstance()
|
||||||
|
@ -273,7 +273,9 @@ class DataLoaderFieldTests(TestCase):
|
||||||
|
|
||||||
def test_dataloaderfield_many(self):
|
def test_dataloaderfield_many(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
data_loader_field = DataLoaderField(data_loader=data_loader, source_loader='keys', type=MyType, load_many=True)
|
data_loader_field = DataLoaderField(
|
||||||
|
data_loader=data_loader, source_loader="keys", type=MyType, load_many=True
|
||||||
|
)
|
||||||
|
|
||||||
resolver = data_loader_field.get_resolver(None)
|
resolver = data_loader_field.get_resolver(None)
|
||||||
instance = MyInstance()
|
instance = MyInstance()
|
||||||
|
@ -282,7 +284,9 @@ class DataLoaderFieldTests(TestCase):
|
||||||
|
|
||||||
def test_dataloaderfield_inner_prop(self):
|
def test_dataloaderfield_inner_prop(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
data_loader_field = DataLoaderField(data_loader=data_loader, source_loader='InnerClass.key', type=MyType)
|
data_loader_field = DataLoaderField(
|
||||||
|
data_loader=data_loader, source_loader="InnerClass.key", type=MyType
|
||||||
|
)
|
||||||
|
|
||||||
resolver = data_loader_field.get_resolver(None)
|
resolver = data_loader_field.get_resolver(None)
|
||||||
instance = MyInstance()
|
instance = MyInstance()
|
||||||
|
@ -291,8 +295,12 @@ class DataLoaderFieldTests(TestCase):
|
||||||
|
|
||||||
def test_dataloaderfield_many_inner_prop(self):
|
def test_dataloaderfield_many_inner_prop(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
data_loader_field = DataLoaderField(data_loader=data_loader, source_loader='InnerClass.keys', type=MyType,
|
data_loader_field = DataLoaderField(
|
||||||
load_many=True)
|
data_loader=data_loader,
|
||||||
|
source_loader="InnerClass.keys",
|
||||||
|
type=MyType,
|
||||||
|
load_many=True,
|
||||||
|
)
|
||||||
|
|
||||||
resolver = data_loader_field.get_resolver(None)
|
resolver = data_loader_field.get_resolver(None)
|
||||||
instance = MyInstance()
|
instance = MyInstance()
|
||||||
|
@ -301,15 +309,19 @@ class DataLoaderFieldTests(TestCase):
|
||||||
|
|
||||||
def test_dataloaderfield_permissions(self):
|
def test_dataloaderfield_permissions(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
data_loader_field = DataLoaderField(data_loader=data_loader, source_loader='key', type=MyType,
|
data_loader_field = DataLoaderField(
|
||||||
permissions=['perm1', 'perm2'])
|
data_loader=data_loader,
|
||||||
|
source_loader="key",
|
||||||
|
type=MyType,
|
||||||
|
permissions=["perm1", "perm2"],
|
||||||
|
)
|
||||||
|
|
||||||
resolver = data_loader_field.get_resolver(None)
|
resolver = data_loader_field.get_resolver(None)
|
||||||
instance = MyInstance()
|
instance = MyInstance()
|
||||||
|
|
||||||
class Viewer(object):
|
class Viewer(object):
|
||||||
def has_perm(self, perm):
|
def has_perm(self, perm):
|
||||||
return perm == 'perm2'
|
return perm == "perm2"
|
||||||
|
|
||||||
info = mock.Mock(context=mock.Mock(user=Viewer()))
|
info = mock.Mock(context=mock.Mock(user=Viewer()))
|
||||||
|
|
||||||
|
@ -317,8 +329,12 @@ class DataLoaderFieldTests(TestCase):
|
||||||
|
|
||||||
def test_dataloaderfield_without_permissions(self):
|
def test_dataloaderfield_without_permissions(self):
|
||||||
MyType = object()
|
MyType = object()
|
||||||
data_loader_field = DataLoaderField(data_loader=data_loader, source_loader='key', type=MyType,
|
data_loader_field = DataLoaderField(
|
||||||
permissions=['perm1', 'perm2'])
|
data_loader=data_loader,
|
||||||
|
source_loader="key",
|
||||||
|
type=MyType,
|
||||||
|
permissions=["perm1", "perm2"],
|
||||||
|
)
|
||||||
|
|
||||||
resolver = data_loader_field.get_resolver(None)
|
resolver = data_loader_field.get_resolver(None)
|
||||||
instance = MyInstance()
|
instance = MyInstance()
|
||||||
|
|
|
@ -213,6 +213,7 @@ def with_local_registry(func):
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_only_fields():
|
def test_django_objecttype_only_fields():
|
||||||
with pytest.warns(PendingDeprecationWarning):
|
with pytest.warns(PendingDeprecationWarning):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -236,6 +237,7 @@ def test_django_objecttype_fields():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_only_fields_and_fields():
|
def test_django_objecttype_only_fields_and_fields():
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -257,6 +259,7 @@ def test_django_objecttype_all_fields():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_exclude_fields():
|
def test_django_objecttype_exclude_fields():
|
||||||
with pytest.warns(PendingDeprecationWarning):
|
with pytest.warns(PendingDeprecationWarning):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -280,6 +283,7 @@ def test_django_objecttype_exclude():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_exclude_fields_and_exclude():
|
def test_django_objecttype_exclude_fields_and_exclude():
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -290,6 +294,7 @@ def test_django_objecttype_exclude_fields_and_exclude():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_exclude_and_only():
|
def test_django_objecttype_exclude_and_only():
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -300,12 +305,14 @@ def test_django_objecttype_exclude_and_only():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_fields_exclude_type_checking():
|
def test_django_objecttype_fields_exclude_type_checking():
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
fields = "foo"
|
fields = "foo"
|
||||||
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
|
|
||||||
class Reporter2(DjangoObjectType):
|
class Reporter2(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -315,15 +322,17 @@ def test_django_objecttype_fields_exclude_type_checking():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_fields_exist_on_model():
|
def test_django_objecttype_fields_exist_on_model():
|
||||||
with pytest.warns(UserWarning, match=r"Field name .* doesn't exist"):
|
with pytest.warns(UserWarning, match=r"Field name .* doesn't exist"):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
fields = ["first_name", "foo", "email"]
|
fields = ["first_name", "foo", "email"]
|
||||||
|
|
||||||
with pytest.warns(
|
with pytest.warns(
|
||||||
UserWarning,
|
UserWarning,
|
||||||
match=r"Field name .* matches an attribute on Django model .* but it's not a model field",
|
match=r"Field name .* matches an attribute on Django model .* but it's not a model field",
|
||||||
) as record:
|
) as record:
|
||||||
|
|
||||||
class Reporter2(DjangoObjectType):
|
class Reporter2(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -331,6 +340,7 @@ def test_django_objecttype_fields_exist_on_model():
|
||||||
|
|
||||||
# Don't warn if selecting a custom field
|
# Don't warn if selecting a custom field
|
||||||
with pytest.warns(None) as record:
|
with pytest.warns(None) as record:
|
||||||
|
|
||||||
class Reporter3(DjangoObjectType):
|
class Reporter3(DjangoObjectType):
|
||||||
custom_field = String()
|
custom_field = String()
|
||||||
|
|
||||||
|
@ -344,9 +354,10 @@ def test_django_objecttype_fields_exist_on_model():
|
||||||
@with_local_registry
|
@with_local_registry
|
||||||
def test_django_objecttype_exclude_fields_exist_on_model():
|
def test_django_objecttype_exclude_fields_exist_on_model():
|
||||||
with pytest.warns(
|
with pytest.warns(
|
||||||
UserWarning,
|
UserWarning,
|
||||||
match=r"Django model .* does not have a field or attribute named .*",
|
match=r"Django model .* does not have a field or attribute named .*",
|
||||||
):
|
):
|
||||||
|
|
||||||
class Reporter(DjangoObjectType):
|
class Reporter(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -354,9 +365,10 @@ def test_django_objecttype_exclude_fields_exist_on_model():
|
||||||
|
|
||||||
# Don't warn if selecting a custom field
|
# Don't warn if selecting a custom field
|
||||||
with pytest.warns(
|
with pytest.warns(
|
||||||
UserWarning,
|
UserWarning,
|
||||||
match=r"Excluding the custom field .* on DjangoObjectType .* has no effect.",
|
match=r"Excluding the custom field .* on DjangoObjectType .* has no effect.",
|
||||||
):
|
):
|
||||||
|
|
||||||
class Reporter3(DjangoObjectType):
|
class Reporter3(DjangoObjectType):
|
||||||
custom_field = String()
|
custom_field = String()
|
||||||
|
|
||||||
|
@ -366,6 +378,7 @@ def test_django_objecttype_exclude_fields_exist_on_model():
|
||||||
|
|
||||||
# Don't warn on exclude fields
|
# Don't warn on exclude fields
|
||||||
with pytest.warns(None) as record:
|
with pytest.warns(None) as record:
|
||||||
|
|
||||||
class Reporter4(DjangoObjectType):
|
class Reporter4(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
@ -562,7 +575,7 @@ class TestDjangoObjectType:
|
||||||
|
|
||||||
|
|
||||||
def extra_field_resolver(root, info, **kwargs):
|
def extra_field_resolver(root, info, **kwargs):
|
||||||
return 'extra field'
|
return "extra field"
|
||||||
|
|
||||||
|
|
||||||
class PermissionArticle(DjangoObjectType):
|
class PermissionArticle(DjangoObjectType):
|
||||||
|
@ -570,27 +583,28 @@ class PermissionArticle(DjangoObjectType):
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
"""Meta Class"""
|
"""Meta Class"""
|
||||||
|
|
||||||
field_to_permission = {
|
field_to_permission = {
|
||||||
'headline': ('content_type.permission1',),
|
"headline": ("content_type.permission1",),
|
||||||
'pub_date': ('content_type.permission2',)
|
"pub_date": ("content_type.permission2",),
|
||||||
}
|
}
|
||||||
permission_to_field = {
|
permission_to_field = {
|
||||||
'content_type.permission3': ('headline', 'reporter', 'extra_field',)
|
"content_type.permission3": ("headline", "reporter", "extra_field",)
|
||||||
}
|
}
|
||||||
model = ArticleModel
|
model = ArticleModel
|
||||||
|
|
||||||
extra_field = Field(String, resolver=extra_field_resolver)
|
extra_field = Field(String, resolver=extra_field_resolver)
|
||||||
|
|
||||||
def resolve_headline(self, info, **kwargs):
|
def resolve_headline(self, info, **kwargs):
|
||||||
return 'headline'
|
return "headline"
|
||||||
|
|
||||||
|
|
||||||
def test_django_permissions():
|
def test_django_permissions():
|
||||||
expected = {
|
expected = {
|
||||||
'headline': ('content_type.permission1', 'content_type.permission3'),
|
"headline": ("content_type.permission1", "content_type.permission3"),
|
||||||
'pub_date': ('content_type.permission2',),
|
"pub_date": ("content_type.permission2",),
|
||||||
'reporter': ('content_type.permission3',),
|
"reporter": ("content_type.permission3",),
|
||||||
'extra_field': ('content_type.permission3',),
|
"extra_field": ("content_type.permission3",),
|
||||||
}
|
}
|
||||||
assert PermissionArticle.field_permissions == expected
|
assert PermissionArticle.field_permissions == expected
|
||||||
|
|
||||||
|
@ -600,7 +614,7 @@ def test_permission_resolver():
|
||||||
|
|
||||||
class Viewer(object):
|
class Viewer(object):
|
||||||
def has_perm(self, perm):
|
def has_perm(self, perm):
|
||||||
return perm == 'content_type.permission3'
|
return perm == "content_type.permission3"
|
||||||
|
|
||||||
class Info(object):
|
class Info(object):
|
||||||
class Context(object):
|
class Context(object):
|
||||||
|
@ -609,7 +623,7 @@ def test_permission_resolver():
|
||||||
context = Context()
|
context = Context()
|
||||||
|
|
||||||
resolved = PermissionArticle.resolve_headline(MyType, Info())
|
resolved = PermissionArticle.resolve_headline(MyType, Info())
|
||||||
assert resolved == 'headline'
|
assert resolved == "headline"
|
||||||
|
|
||||||
|
|
||||||
def test_resolver_without_permission():
|
def test_resolver_without_permission():
|
||||||
|
@ -634,7 +648,7 @@ def test_permission_resolver_to_field():
|
||||||
|
|
||||||
class Viewer(object):
|
class Viewer(object):
|
||||||
def has_perm(self, perm):
|
def has_perm(self, perm):
|
||||||
return perm == 'content_type.permission3'
|
return perm == "content_type.permission3"
|
||||||
|
|
||||||
class Info(object):
|
class Info(object):
|
||||||
class Context(object):
|
class Context(object):
|
||||||
|
@ -643,7 +657,7 @@ def test_permission_resolver_to_field():
|
||||||
context = Context()
|
context = Context()
|
||||||
|
|
||||||
resolved = PermissionArticle.resolve_extra_field(MyType, Info())
|
resolved = PermissionArticle.resolve_extra_field(MyType, Info())
|
||||||
assert resolved == 'extra field'
|
assert resolved == "extra field"
|
||||||
|
|
||||||
|
|
||||||
def test_resolver_to_field_without_permission():
|
def test_resolver_to_field_without_permission():
|
||||||
|
@ -651,7 +665,7 @@ def test_resolver_to_field_without_permission():
|
||||||
|
|
||||||
class Viewer(object):
|
class Viewer(object):
|
||||||
def has_perm(self, perm):
|
def has_perm(self, perm):
|
||||||
return perm != 'content_type.permission3'
|
return perm != "content_type.permission3"
|
||||||
|
|
||||||
class Info(object):
|
class Info(object):
|
||||||
class Context(object):
|
class Context(object):
|
||||||
|
|
|
@ -3,7 +3,6 @@ from collections import OrderedDict
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from django.db.models import Model
|
|
||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
|
@ -76,7 +75,8 @@ def validate_fields(type_, model, fields, only_fields, exclude_fields):
|
||||||
(
|
(
|
||||||
'Field name "{field_name}" matches an attribute on Django model "{app_label}.{object_name}" '
|
'Field name "{field_name}" matches an attribute on Django model "{app_label}.{object_name}" '
|
||||||
"but it's not a model field so Graphene cannot determine what type it should be. "
|
"but it's not a model field so Graphene cannot determine what type it should be. "
|
||||||
'Either define the type of the field on DjangoObjectType "{type_}" or remove it from the "fields" list.'
|
'Either define the type of the field on DjangoObjectType "{type_}" or remove it from the "fields" '
|
||||||
|
"list. "
|
||||||
).format(
|
).format(
|
||||||
field_name=name,
|
field_name=name,
|
||||||
app_label=model._meta.app_label,
|
app_label=model._meta.app_label,
|
||||||
|
@ -89,7 +89,8 @@ def validate_fields(type_, model, fields, only_fields, exclude_fields):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
(
|
(
|
||||||
'Field name "{field_name}" doesn\'t exist on Django model "{app_label}.{object_name}". '
|
'Field name "{field_name}" doesn\'t exist on Django model "{app_label}.{object_name}". '
|
||||||
'Consider removing the field from the "fields" list of DjangoObjectType "{type_}" because it has no effect.'
|
'Consider removing the field from the "fields" list of DjangoObjectType "{type_}" because it has '
|
||||||
|
"no effect. "
|
||||||
).format(
|
).format(
|
||||||
field_name=name,
|
field_name=name,
|
||||||
app_label=model._meta.app_label,
|
app_label=model._meta.app_label,
|
||||||
|
@ -117,8 +118,10 @@ def validate_fields(type_, model, fields, only_fields, exclude_fields):
|
||||||
if not hasattr(model, name):
|
if not hasattr(model, name):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
(
|
(
|
||||||
'Django model "{app_label}.{object_name}" does not have a field or attribute named "{field_name}". '
|
'Django model "{app_label}.{object_name}" does not have a field or attribute named "{'
|
||||||
'Consider removing the field from the "exclude" list of DjangoObjectType "{type_}" because it has no effect'
|
'field_name}". '
|
||||||
|
'Consider removing the field from the "exclude" list of DjangoObjectType "{type_}" because it '
|
||||||
|
"has no effect "
|
||||||
).format(
|
).format(
|
||||||
field_name=name,
|
field_name=name,
|
||||||
app_label=model._meta.app_label,
|
app_label=model._meta.app_label,
|
||||||
|
@ -268,7 +271,9 @@ class DjangoObjectType(ObjectType):
|
||||||
_meta.fields = django_fields
|
_meta.fields = django_fields
|
||||||
_meta.connection = connection
|
_meta.connection = connection
|
||||||
|
|
||||||
field_permissions = cls.__get_field_permissions__(field_to_permission, permission_to_field)
|
field_permissions = cls.__get_field_permissions__(
|
||||||
|
field_to_permission, permission_to_field
|
||||||
|
)
|
||||||
if field_permissions:
|
if field_permissions:
|
||||||
cls.__set_as_nullable__(field_permissions, model, registry)
|
cls.__set_as_nullable__(field_permissions, model, registry)
|
||||||
|
|
||||||
|
@ -323,13 +328,17 @@ class DjangoObjectType(ObjectType):
|
||||||
def __set_permissions_resolvers__(cls, permissions):
|
def __set_permissions_resolvers__(cls, permissions):
|
||||||
"""Set permission resolvers"""
|
"""Set permission resolvers"""
|
||||||
for field_name, field_permissions in permissions.items():
|
for field_name, field_permissions in permissions.items():
|
||||||
attr = 'resolve_{}'.format(field_name)
|
attr = "resolve_{}".format(field_name)
|
||||||
resolver = getattr(cls._meta.fields[field_name], 'resolver', None) or getattr(cls, attr, None)
|
resolver = getattr(
|
||||||
|
cls._meta.fields[field_name], "resolver", None
|
||||||
|
) or getattr(cls, attr, None)
|
||||||
|
|
||||||
if not hasattr(field_permissions, '__iter__'):
|
if not hasattr(field_permissions, "__iter__"):
|
||||||
field_permissions = tuple(field_permissions)
|
field_permissions = tuple(field_permissions)
|
||||||
|
|
||||||
setattr(cls, attr, get_auth_resolver(field_name, field_permissions, resolver))
|
setattr(
|
||||||
|
cls, attr, get_auth_resolver(field_name, field_permissions, resolver)
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __set_as_nullable__(cls, field_permissions, model, registry):
|
def __set_as_nullable__(cls, field_permissions, model, registry):
|
||||||
|
@ -339,7 +348,7 @@ class DjangoObjectType(ObjectType):
|
||||||
_as=Field,
|
_as=Field,
|
||||||
)
|
)
|
||||||
for name, field in django_fields.items():
|
for name, field in django_fields.items():
|
||||||
if hasattr(field, '_type') and isinstance(field._type, NonNull):
|
if hasattr(field, "_type") and isinstance(field._type, NonNull):
|
||||||
field._type = field._type._of_type
|
field._type = field._type._of_type
|
||||||
setattr(cls, name, field)
|
setattr(cls, name, field)
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,16 @@ def resolve_bound_resolver(resolver, root, info, **args):
|
||||||
return resolver(root, info, **args)
|
return resolver(root, info, **args)
|
||||||
|
|
||||||
|
|
||||||
def auth_resolver(parent_resolver, permissions, attname, default_value, raise_exception, root, info, **args):
|
def auth_resolver(
|
||||||
|
parent_resolver,
|
||||||
|
permissions,
|
||||||
|
attname,
|
||||||
|
default_value,
|
||||||
|
raise_exception,
|
||||||
|
root,
|
||||||
|
info,
|
||||||
|
**args
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Middleware resolver to check viewer's permissions
|
Middleware resolver to check viewer's permissions
|
||||||
:param parent_resolver: Field resolver
|
:param parent_resolver: Field resolver
|
||||||
|
@ -146,7 +155,7 @@ def auth_resolver(parent_resolver, permissions, attname, default_value, raise_ex
|
||||||
:return: Resolved field. None if the viewer does not have permission to access the field.
|
:return: Resolved field. None if the viewer does not have permission to access the field.
|
||||||
"""
|
"""
|
||||||
# Get viewer from context
|
# Get viewer from context
|
||||||
if not hasattr(info.context, 'user'):
|
if not hasattr(info.context, "user"):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user