mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 01:47:45 +03:00 
			
		
		
		
	Merge branch 'refs/heads/features/plugins-autocamelcase' into features/django-debug
This commit is contained in:
		
						commit
						2ad5bc203a
					
				| 
						 | 
				
			
			@ -27,7 +27,7 @@ class ConnectionOrListField(Field):
 | 
			
		|||
        if not field_object_type:
 | 
			
		||||
            raise SkipField()
 | 
			
		||||
        if is_node(field_object_type):
 | 
			
		||||
            field = DjangoConnectionField(field_object_type)
 | 
			
		||||
            field = ConnectionField(field_object_type)
 | 
			
		||||
        else:
 | 
			
		||||
            field = Field(List(field_object_type))
 | 
			
		||||
        field.contribute_to_class(self.object_type, self.attname)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,8 @@
 | 
			
		|||
from django.db import models
 | 
			
		||||
from django.db.models.manager import Manager
 | 
			
		||||
from django.db.models.query import QuerySet
 | 
			
		||||
 | 
			
		||||
from graphene.utils import LazyList
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_type_for_model(schema, model):
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +22,18 @@ def get_reverse_fields(model):
 | 
			
		|||
            yield related
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class WrappedQueryset(LazyList):
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        # Dont calculate the length using len(queryset), as this will
 | 
			
		||||
        # evaluate the whole queryset and return it's length.
 | 
			
		||||
        # Use .count() instead
 | 
			
		||||
        return self._origin.count()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_queryset(value):
 | 
			
		||||
    if isinstance(value, Manager):
 | 
			
		||||
        value = value.get_queryset()
 | 
			
		||||
    if isinstance(value, QuerySet):
 | 
			
		||||
        return WrappedQueryset(value)
 | 
			
		||||
    return value
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
import copy
 | 
			
		||||
import inspect
 | 
			
		||||
from functools import partial
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
 | 
			
		||||
import six
 | 
			
		||||
 | 
			
		||||
from ..exceptions import SkipField
 | 
			
		||||
from .options import Options
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,8 +48,8 @@ class ClassTypeMeta(type):
 | 
			
		|||
 | 
			
		||||
        if not cls._meta.abstract:
 | 
			
		||||
            from ..types import List, NonNull
 | 
			
		||||
            setattr(cls, 'NonNull', NonNull(cls))
 | 
			
		||||
            setattr(cls, 'List', List(cls))
 | 
			
		||||
            setattr(cls, 'NonNull', partial(NonNull, cls))
 | 
			
		||||
            setattr(cls, 'List', partial(List, cls))
 | 
			
		||||
 | 
			
		||||
        return cls
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -81,13 +81,18 @@ class FieldsOptions(Options):
 | 
			
		|||
    def fields_map(self):
 | 
			
		||||
        return OrderedDict([(f.attname, f) for f in self.fields])
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def fields_group_type(self):
 | 
			
		||||
        from ..types.field import FieldsGroupType
 | 
			
		||||
        return FieldsGroupType(*self.local_fields)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FieldsClassTypeMeta(ClassTypeMeta):
 | 
			
		||||
    options_class = FieldsOptions
 | 
			
		||||
 | 
			
		||||
    def extend_fields(cls, bases):
 | 
			
		||||
        new_fields = cls._meta.local_fields
 | 
			
		||||
        field_names = {f.name: f for f in new_fields}
 | 
			
		||||
        field_names = {f.attname: f for f in new_fields}
 | 
			
		||||
 | 
			
		||||
        for base in bases:
 | 
			
		||||
            if not isinstance(base, FieldsClassTypeMeta):
 | 
			
		||||
| 
						 | 
				
			
			@ -95,17 +100,17 @@ class FieldsClassTypeMeta(ClassTypeMeta):
 | 
			
		|||
 | 
			
		||||
            parent_fields = base._meta.local_fields
 | 
			
		||||
            for field in parent_fields:
 | 
			
		||||
                if field.name in field_names and field.type.__class__ != field_names[
 | 
			
		||||
                        field.name].type.__class__:
 | 
			
		||||
                if field.attname in field_names and field.type.__class__ != field_names[
 | 
			
		||||
                        field.attname].type.__class__:
 | 
			
		||||
                    raise Exception(
 | 
			
		||||
                        'Local field %r in class %r (%r) clashes '
 | 
			
		||||
                        'with field with similar name from '
 | 
			
		||||
                        'Interface %s (%r)' % (
 | 
			
		||||
                            field.name,
 | 
			
		||||
                            field.attname,
 | 
			
		||||
                            cls.__name__,
 | 
			
		||||
                            field.__class__,
 | 
			
		||||
                            base.__name__,
 | 
			
		||||
                            field_names[field.name].__class__)
 | 
			
		||||
                            field_names[field.attname].__class__)
 | 
			
		||||
                    )
 | 
			
		||||
                new_field = copy.copy(field)
 | 
			
		||||
                cls.add_to_class(field.attname, new_field)
 | 
			
		||||
| 
						 | 
				
			
			@ -123,11 +128,4 @@ class FieldsClassType(six.with_metaclass(FieldsClassTypeMeta, ClassType)):
 | 
			
		|||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def fields_internal_types(cls, schema):
 | 
			
		||||
        fields = []
 | 
			
		||||
        for field in cls._meta.fields:
 | 
			
		||||
            try:
 | 
			
		||||
                fields.append((field.name, schema.T(field)))
 | 
			
		||||
            except SkipField:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
        return OrderedDict(fields)
 | 
			
		||||
        return schema.T(cls._meta.fields_group_type)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,15 +23,26 @@ def test_classtype_advanced():
 | 
			
		|||
def test_classtype_definition_list():
 | 
			
		||||
    class Character(ClassType):
 | 
			
		||||
        '''Character description'''
 | 
			
		||||
    assert isinstance(Character.List, List)
 | 
			
		||||
    assert Character.List.of_type == Character
 | 
			
		||||
    assert isinstance(Character.List(), List)
 | 
			
		||||
    assert Character.List().of_type == Character
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_classtype_definition_nonnull():
 | 
			
		||||
    class Character(ClassType):
 | 
			
		||||
        '''Character description'''
 | 
			
		||||
    assert isinstance(Character.NonNull, NonNull)
 | 
			
		||||
    assert Character.NonNull.of_type == Character
 | 
			
		||||
    assert isinstance(Character.NonNull(), NonNull)
 | 
			
		||||
    assert Character.NonNull().of_type == Character
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_fieldsclasstype_definition_order():
 | 
			
		||||
    class Character(ClassType):
 | 
			
		||||
        '''Character description'''
 | 
			
		||||
 | 
			
		||||
    class Query(FieldsClassType):
 | 
			
		||||
        name = String()
 | 
			
		||||
        char = Character.NonNull()
 | 
			
		||||
 | 
			
		||||
    assert list(Query._meta.fields_map.keys()) == ['name', 'char']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_fieldsclasstype():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,4 +24,4 @@ def test_mutation():
 | 
			
		|||
    assert list(object_type.get_fields().keys()) == ['name']
 | 
			
		||||
    assert MyMutation._meta.fields_map['name'].object_type == MyMutation
 | 
			
		||||
    assert isinstance(MyMutation.arguments, ArgumentsGroup)
 | 
			
		||||
    assert 'argName' in MyMutation.arguments
 | 
			
		||||
    assert 'argName' in schema.T(MyMutation.arguments)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ from graphene import signals
 | 
			
		|||
 | 
			
		||||
from .classtypes.base import ClassType
 | 
			
		||||
from .types.base import BaseType
 | 
			
		||||
from ..plugins import Plugin, CamelCase
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GraphQLSchema(_GraphQLSchema):
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +26,7 @@ class Schema(object):
 | 
			
		|||
    _executor = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, query=None, mutation=None, subscription=None,
 | 
			
		||||
                 name='Schema', executor=None):
 | 
			
		||||
                 name='Schema', executor=None, plugins=None, auto_camelcase=True):
 | 
			
		||||
        self._types_names = {}
 | 
			
		||||
        self._types = {}
 | 
			
		||||
        self.mutation = mutation
 | 
			
		||||
| 
						 | 
				
			
			@ -33,11 +34,27 @@ class Schema(object):
 | 
			
		|||
        self.subscription = subscription
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.executor = executor
 | 
			
		||||
        self.plugins = []
 | 
			
		||||
        plugins = plugins or []
 | 
			
		||||
        if auto_camelcase:
 | 
			
		||||
            plugins.append(CamelCase())
 | 
			
		||||
        for plugin in plugins:
 | 
			
		||||
            self.add_plugin(plugin)
 | 
			
		||||
        signals.init_schema.send(self)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return '<Schema: %s (%s)>' % (str(self.name), hash(self))
 | 
			
		||||
 | 
			
		||||
    def add_plugin(self, plugin):
 | 
			
		||||
        assert isinstance(plugin, Plugin), 'A plugin need to subclass graphene.Plugin and be instantiated'
 | 
			
		||||
        plugin.contribute_to_schema(self)
 | 
			
		||||
        self.plugins.append(plugin)
 | 
			
		||||
 | 
			
		||||
    def get_internal_type(self, objecttype):
 | 
			
		||||
        for plugin in self.plugins:
 | 
			
		||||
            objecttype = plugin.transform_type(objecttype)
 | 
			
		||||
        return objecttype.internal_type(self)
 | 
			
		||||
 | 
			
		||||
    def T(self, object_type):
 | 
			
		||||
        if not object_type:
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +62,7 @@ class Schema(object):
 | 
			
		|||
                object_type, (BaseType, ClassType)) or isinstance(
 | 
			
		||||
                object_type, BaseType):
 | 
			
		||||
            if object_type not in self._types:
 | 
			
		||||
                internal_type = object_type.internal_type(self)
 | 
			
		||||
                internal_type = self.get_internal_type(object_type)
 | 
			
		||||
                self._types[object_type] = internal_type
 | 
			
		||||
                is_objecttype = inspect.isclass(
 | 
			
		||||
                    object_type) and issubclass(object_type, ClassType)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,10 +34,11 @@ def test_field_type():
 | 
			
		|||
    assert schema.T(f).type == GraphQLString
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_field_name_automatic_camelcase():
 | 
			
		||||
def test_field_name():
 | 
			
		||||
    f = Field(GraphQLString)
 | 
			
		||||
    f.contribute_to_class(MyOt, 'field_name')
 | 
			
		||||
    assert f.name == 'fieldName'
 | 
			
		||||
    assert f.name is None
 | 
			
		||||
    assert f.attname == 'field_name'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_field_name_use_name_if_exists():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,19 @@
 | 
			
		|||
from collections import OrderedDict
 | 
			
		||||
from functools import wraps
 | 
			
		||||
from itertools import chain
 | 
			
		||||
 | 
			
		||||
from graphql.core.type import GraphQLArgument
 | 
			
		||||
 | 
			
		||||
from ...utils import ProxySnakeDict, to_camel_case
 | 
			
		||||
from .base import ArgumentType, BaseType, OrderedType
 | 
			
		||||
from ...utils import ProxySnakeDict
 | 
			
		||||
from .base import ArgumentType, GroupNamedType, NamedType, OrderedType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Argument(OrderedType):
 | 
			
		||||
class Argument(NamedType, OrderedType):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, type, description=None, default=None,
 | 
			
		||||
                 name=None, _creation_counter=None):
 | 
			
		||||
        super(Argument, self).__init__(_creation_counter=_creation_counter)
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.attname = None
 | 
			
		||||
        self.type = type
 | 
			
		||||
        self.description = description
 | 
			
		||||
        self.default = default
 | 
			
		||||
| 
						 | 
				
			
			@ -27,47 +27,32 @@ class Argument(OrderedType):
 | 
			
		|||
        return self.name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ArgumentsGroup(BaseType):
 | 
			
		||||
class ArgumentsGroup(GroupNamedType):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        arguments = to_arguments(*args, **kwargs)
 | 
			
		||||
        self.arguments = OrderedDict([(arg.name, arg) for arg in arguments])
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        return OrderedDict([(arg.name, schema.T(arg))
 | 
			
		||||
                            for arg in self.arguments.values()])
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return len(self.arguments)
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return iter(self.arguments)
 | 
			
		||||
 | 
			
		||||
    def __contains__(self, *args):
 | 
			
		||||
        return self.arguments.__contains__(*args)
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, *args):
 | 
			
		||||
        return self.arguments.__getitem__(*args)
 | 
			
		||||
        super(ArgumentsGroup, self).__init__(*arguments)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def to_arguments(*args, **kwargs):
 | 
			
		||||
    arguments = {}
 | 
			
		||||
    iter_arguments = chain(kwargs.items(), [(None, a) for a in args])
 | 
			
		||||
 | 
			
		||||
    for name, arg in iter_arguments:
 | 
			
		||||
    for attname, arg in iter_arguments:
 | 
			
		||||
        if isinstance(arg, Argument):
 | 
			
		||||
            argument = arg
 | 
			
		||||
        elif isinstance(arg, ArgumentType):
 | 
			
		||||
            argument = arg.as_argument()
 | 
			
		||||
        else:
 | 
			
		||||
            raise ValueError('Unknown argument %s=%r' % (name, arg))
 | 
			
		||||
            raise ValueError('Unknown argument %s=%r' % (attname, arg))
 | 
			
		||||
 | 
			
		||||
        if name:
 | 
			
		||||
            argument.name = to_camel_case(name)
 | 
			
		||||
        assert argument.name, 'Argument in field must have a name'
 | 
			
		||||
        assert argument.name not in arguments, 'Found more than one Argument with same name {}'.format(
 | 
			
		||||
            argument.name)
 | 
			
		||||
        arguments[argument.name] = argument
 | 
			
		||||
        if attname:
 | 
			
		||||
            argument.attname = attname
 | 
			
		||||
 | 
			
		||||
        name = argument.name or argument.attname
 | 
			
		||||
        assert name, 'Argument in field must have a name'
 | 
			
		||||
        assert name not in arguments, 'Found more than one Argument with same name {}'.format(name)
 | 
			
		||||
        arguments[name] = argument
 | 
			
		||||
 | 
			
		||||
    return sorted(arguments.values())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,10 @@
 | 
			
		|||
from functools import total_ordering
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from functools import total_ordering, partial
 | 
			
		||||
 | 
			
		||||
import six
 | 
			
		||||
 | 
			
		||||
from ...utils import to_camel_case
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BaseType(object):
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,3 +129,31 @@ class FieldType(MirroredType):
 | 
			
		|||
 | 
			
		||||
class MountedType(FieldType, ArgumentType):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NamedType(BaseType):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GroupNamedType(BaseType):
 | 
			
		||||
    def __init__(self, *types):
 | 
			
		||||
        self.types = types
 | 
			
		||||
 | 
			
		||||
    def get_named_type(self, schema, type):
 | 
			
		||||
        name = type.name or type.attname
 | 
			
		||||
        return name, schema.T(type)
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        return OrderedDict(map(partial(self.get_named_type, schema), self.types))
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return len(self.types)
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return iter(self.types)
 | 
			
		||||
 | 
			
		||||
    def __contains__(self, *args):
 | 
			
		||||
        return self.types.__contains__(*args)
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, *args):
 | 
			
		||||
        return self.types.__getitem__(*args)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,16 +4,16 @@ from functools import wraps
 | 
			
		|||
import six
 | 
			
		||||
from graphql.core.type import GraphQLField, GraphQLInputObjectField
 | 
			
		||||
 | 
			
		||||
from ...utils import to_camel_case
 | 
			
		||||
from ..classtypes.base import FieldsClassType
 | 
			
		||||
from ..classtypes.inputobjecttype import InputObjectType
 | 
			
		||||
from ..classtypes.mutation import Mutation
 | 
			
		||||
from ..exceptions import SkipField
 | 
			
		||||
from .argument import ArgumentsGroup, snake_case_args
 | 
			
		||||
from .base import LazyType, MountType, OrderedType
 | 
			
		||||
from .base import LazyType, NamedType, MountType, OrderedType, GroupNamedType
 | 
			
		||||
from .definitions import NonNull
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Field(OrderedType):
 | 
			
		||||
class Field(NamedType, OrderedType):
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
            self, type, description=None, args=None, name=None, resolver=None,
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +36,6 @@ class Field(OrderedType):
 | 
			
		|||
        assert issubclass(
 | 
			
		||||
            cls, (FieldsClassType)), 'Field {} cannot be mounted in {}'.format(
 | 
			
		||||
            self, cls)
 | 
			
		||||
        if not self.name:
 | 
			
		||||
            self.name = to_camel_case(attname)
 | 
			
		||||
        self.attname = attname
 | 
			
		||||
        self.object_type = cls
 | 
			
		||||
        self.mount(cls)
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +61,9 @@ class Field(OrderedType):
 | 
			
		|||
            return NonNull(self.type)
 | 
			
		||||
        return self.type
 | 
			
		||||
 | 
			
		||||
    def decorate_resolver(self, resolver):
 | 
			
		||||
        return snake_case_args(resolver)
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        resolver = self.resolver
 | 
			
		||||
        description = self.description
 | 
			
		||||
| 
						 | 
				
			
			@ -85,9 +86,9 @@ class Field(OrderedType):
 | 
			
		|||
                return my_resolver(instance, args, info)
 | 
			
		||||
            resolver = wrapped_func
 | 
			
		||||
 | 
			
		||||
        resolver = snake_case_args(resolver)
 | 
			
		||||
        assert type, 'Internal type for field %s is None' % str(self)
 | 
			
		||||
        return GraphQLField(type, args=schema.T(arguments), resolver=resolver,
 | 
			
		||||
        return GraphQLField(type, args=schema.T(arguments),
 | 
			
		||||
                            resolver=self.decorate_resolver(resolver),
 | 
			
		||||
                            description=description,)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +115,7 @@ class Field(OrderedType):
 | 
			
		|||
        return hash((self.creation_counter, self.object_type))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InputField(OrderedType):
 | 
			
		||||
class InputField(NamedType, OrderedType):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, type, description=None, default=None,
 | 
			
		||||
                 name=None, _creation_counter=None, required=False):
 | 
			
		||||
| 
						 | 
				
			
			@ -130,8 +131,6 @@ class InputField(OrderedType):
 | 
			
		|||
        assert issubclass(
 | 
			
		||||
            cls, (InputObjectType)), 'InputField {} cannot be mounted in {}'.format(
 | 
			
		||||
            self, cls)
 | 
			
		||||
        if not self.name:
 | 
			
		||||
            self.name = to_camel_case(attname)
 | 
			
		||||
        self.attname = attname
 | 
			
		||||
        self.object_type = cls
 | 
			
		||||
        self.mount(cls)
 | 
			
		||||
| 
						 | 
				
			
			@ -143,3 +142,14 @@ class InputField(OrderedType):
 | 
			
		|||
        return GraphQLInputObjectField(
 | 
			
		||||
            schema.T(self.type),
 | 
			
		||||
            default_value=self.default, description=self.description)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FieldsGroupType(GroupNamedType):
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        fields = []
 | 
			
		||||
        for field in sorted(self.types):
 | 
			
		||||
            try:
 | 
			
		||||
                fields.append(self.get_named_type(schema, field))
 | 
			
		||||
            except SkipField:
 | 
			
		||||
                continue
 | 
			
		||||
        return OrderedDict(fields)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,8 +27,8 @@ def test_to_arguments():
 | 
			
		|||
        other_kwarg=String(),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    assert [a.name for a in arguments] == [
 | 
			
		||||
        'myArg', 'otherArg', 'myKwarg', 'otherKwarg']
 | 
			
		||||
    assert [a.name or a.attname for a in arguments] == [
 | 
			
		||||
        'myArg', 'otherArg', 'my_kwarg', 'other_kwarg']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_to_arguments_no_name():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ def test_field_internal_type():
 | 
			
		|||
    schema = Schema(query=Query)
 | 
			
		||||
 | 
			
		||||
    type = schema.T(field)
 | 
			
		||||
    assert field.name == 'myField'
 | 
			
		||||
    assert field.name is None
 | 
			
		||||
    assert field.attname == 'my_field'
 | 
			
		||||
    assert isinstance(type, GraphQLField)
 | 
			
		||||
    assert type.description == 'My argument'
 | 
			
		||||
| 
						 | 
				
			
			@ -98,9 +98,10 @@ def test_field_string_reference():
 | 
			
		|||
 | 
			
		||||
def test_field_custom_arguments():
 | 
			
		||||
    field = Field(None, name='my_customName', p=String())
 | 
			
		||||
    schema = Schema()
 | 
			
		||||
 | 
			
		||||
    args = field.arguments
 | 
			
		||||
    assert 'p' in args
 | 
			
		||||
    assert 'p' in schema.T(args)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_inputfield_internal_type():
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +116,7 @@ def test_inputfield_internal_type():
 | 
			
		|||
    schema = Schema(query=MyObjectType)
 | 
			
		||||
 | 
			
		||||
    type = schema.T(field)
 | 
			
		||||
    assert field.name == 'myField'
 | 
			
		||||
    assert field.name is None
 | 
			
		||||
    assert field.attname == 'my_field'
 | 
			
		||||
    assert isinstance(type, GraphQLInputObjectField)
 | 
			
		||||
    assert type.description == 'My input field'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								graphene/plugins/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								graphene/plugins/__init__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
from .base import Plugin
 | 
			
		||||
from .camel_case import CamelCase
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    'Plugin', 'CamelCase'
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										6
									
								
								graphene/plugins/base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								graphene/plugins/base.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
class Plugin(object):
 | 
			
		||||
    def contribute_to_schema(self, schema):
 | 
			
		||||
        self.schema = schema
 | 
			
		||||
 | 
			
		||||
    def transform_type(self, objecttype):
 | 
			
		||||
        return objecttype
 | 
			
		||||
							
								
								
									
										22
									
								
								graphene/plugins/camel_case.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								graphene/plugins/camel_case.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
from .base import Plugin
 | 
			
		||||
 | 
			
		||||
from ..core.types.base import GroupNamedType
 | 
			
		||||
from ..utils import memoize, to_camel_case
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def camelcase_named_type(schema, type):
 | 
			
		||||
    name = type.name or to_camel_case(type.attname)
 | 
			
		||||
    return name, schema.T(type)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CamelCase(Plugin):
 | 
			
		||||
    @memoize
 | 
			
		||||
    def transform_group(self, _type):
 | 
			
		||||
        new_type = _type.__class__(*_type.types)
 | 
			
		||||
        setattr(new_type, 'get_named_type', camelcase_named_type)
 | 
			
		||||
        return new_type
 | 
			
		||||
 | 
			
		||||
    def transform_type(self, _type):
 | 
			
		||||
        if isinstance(_type, GroupNamedType):
 | 
			
		||||
            return self.transform_group(_type)
 | 
			
		||||
        return _type
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +34,7 @@ schema = Schema(query=Query, mutation=MyResultMutation)
 | 
			
		|||
 | 
			
		||||
def test_mutation_arguments():
 | 
			
		||||
    assert ChangeNumber.arguments
 | 
			
		||||
    assert list(ChangeNumber.arguments) == ['input']
 | 
			
		||||
    assert 'input' in ChangeNumber.arguments
 | 
			
		||||
    assert 'input' in schema.T(ChangeNumber.arguments)
 | 
			
		||||
    inner_type = ChangeNumber.input_type
 | 
			
		||||
    client_mutation_id_field = inner_type._meta.fields_map[
 | 
			
		||||
        'client_mutation_id']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,9 @@ from .proxy_snake_dict import ProxySnakeDict
 | 
			
		|||
from .caching import cached_property, memoize
 | 
			
		||||
from .misc import enum_to_graphql_enum
 | 
			
		||||
from .resolve_only_args import resolve_only_args
 | 
			
		||||
from .lazylist import LazyList
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict',
 | 
			
		||||
           'cached_property', 'memoize', 'enum_to_graphql_enum',
 | 
			
		||||
           'resolve_only_args']
 | 
			
		||||
           'resolve_only_args', 'LazyList']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										43
									
								
								graphene/utils/lazylist.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								graphene/utils/lazylist.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
class LazyList(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, origin, state=None):
 | 
			
		||||
        self._origin = origin
 | 
			
		||||
        self._state = state or []
 | 
			
		||||
        self._origin_iter = None
 | 
			
		||||
        self._finished = False
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self if not self._finished else iter(self._state)
 | 
			
		||||
 | 
			
		||||
    def iter(self):
 | 
			
		||||
        return self.__iter__()
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return self._origin.__len__()
 | 
			
		||||
 | 
			
		||||
    def __next__(self):
 | 
			
		||||
        try:
 | 
			
		||||
            if not self._origin_iter:
 | 
			
		||||
                self._origin_iter = self._origin.__iter__()
 | 
			
		||||
            n = next(self._origin_iter)
 | 
			
		||||
        except StopIteration as e:
 | 
			
		||||
            self._finished = True
 | 
			
		||||
            raise e
 | 
			
		||||
        else:
 | 
			
		||||
            self._state.append(n)
 | 
			
		||||
            return n
 | 
			
		||||
 | 
			
		||||
    def next(self):
 | 
			
		||||
        return self.__next__()
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        item = self._origin[key]
 | 
			
		||||
        if isinstance(key, slice):
 | 
			
		||||
            return self.__class__(item)
 | 
			
		||||
        return item
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, name):
 | 
			
		||||
        return getattr(self._origin, name)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<{} {}>".format(self.__class__.__name__, repr(self._origin))
 | 
			
		||||
							
								
								
									
										23
									
								
								graphene/utils/tests/test_lazylist.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								graphene/utils/tests/test_lazylist.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
from py.test import raises
 | 
			
		||||
 | 
			
		||||
from ..lazylist import LazyList
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_lazymap():
 | 
			
		||||
    data = list(range(10))
 | 
			
		||||
    lm = LazyList(data)
 | 
			
		||||
    assert len(lm) == 10
 | 
			
		||||
    assert lm[1] == 1
 | 
			
		||||
    assert isinstance(lm[1:4], LazyList)
 | 
			
		||||
    assert lm.append == data.append
 | 
			
		||||
    assert repr(lm) == '<LazyList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_lazymap_iter():
 | 
			
		||||
    data = list(range(2))
 | 
			
		||||
    lm = LazyList(data)
 | 
			
		||||
    iter_lm = iter(lm)
 | 
			
		||||
    assert iter_lm.next() == 0
 | 
			
		||||
    assert iter_lm.next() == 1
 | 
			
		||||
    with raises(StopIteration):
 | 
			
		||||
        iter_lm.next()
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user