Improved plugins

This commit is contained in:
Syrus Akbary 2016-05-20 00:16:34 -07:00
parent b431bfe477
commit 25fd60d1ff
6 changed files with 52 additions and 41 deletions

View File

@ -1,6 +1,7 @@
from contextlib import contextmanager from contextlib import contextmanager
from django.db import connections from django.db import connections
from graphene import with_context
from ....core.schema import GraphQLSchema from ....core.schema import GraphQLSchema
from ....core.types import Field from ....core.types import Field
@ -10,11 +11,14 @@ from .sql.types import DjangoDebugSQL
from .types import DjangoDebug from .types import DjangoDebug
class WrappedRoot(object): class EmptyContext(object):
pass
def __init__(self, root):
class DjangoDebugContext(object):
def __init__(self):
self._recorded = [] self._recorded = []
self._root = root
def record(self, **log): def record(self, **log):
self._recorded.append(DjangoDebugSQL(**log)) self._recorded.append(DjangoDebugSQL(**log))
@ -24,17 +28,9 @@ class WrappedRoot(object):
class WrapRoot(object): class WrapRoot(object):
@with_context
@property def resolve_debug(self, args, context, info):
def _root(self): return context.django_debug.debug()
return self._wrapped_root.root
@_root.setter
def _root(self, value):
self._wrapped_root = value
def resolve_debug(self, args, info):
return self._wrapped_root.debug()
def debug_objecttype(objecttype): def debug_objecttype(objecttype):
@ -72,8 +68,10 @@ class DjangoDebugPlugin(Plugin):
@contextmanager @contextmanager
def context_execution(self, executor): def context_execution(self, executor):
executor['root_value'] = WrappedRoot(root=executor.get('root_value')) context_value = executor.get('context_value') or EmptyContext()
context_value.django_debug = DjangoDebugContext()
executor['context_value'] = context_value
executor['schema'] = self.wrap_schema(executor['schema']) executor['schema'] = self.wrap_schema(executor['schema'])
self.enable_instrumentation(executor['root_value']) self.enable_instrumentation(context_value.django_debug)
yield executor yield executor
self.disable_instrumentation() self.disable_instrumentation()

View File

@ -12,6 +12,16 @@ from .classtypes.base import ClassType
from .types.base import InstanceType from .types.base import InstanceType
class ACI(object):
def __init__(self, args, context, info):
self.args = args
self.context = context
self.info = info
def __repr__(self):
return "ACI(args={}, context={}, info={})".format(repr(self.args), repr(self.context), repr(self.info))
class GraphQLSchema(_GraphQLSchema): class GraphQLSchema(_GraphQLSchema):
def __init__(self, schema, *args, **kwargs): def __init__(self, schema, *args, **kwargs):
@ -111,6 +121,26 @@ class Schema(object):
raise KeyError('Type %r not found in %r' % (type_name, self)) raise KeyError('Type %r not found in %r' % (type_name, self))
return self._types_names[type_name] return self._types_names[type_name]
def resolve(self, resolver, root, args, context, info):
aci = ACI(args, context, info)
plugins_process_aci = self.plugins.get_plugin_functions('process_aci')
plugins_process_response = self.plugins.get_plugin_functions('process_response')
for process_aci in plugins_process_aci:
processed_aci = process_aci(aci)
if processed_aci is None:
continue
return processed_aci
response = resolver(root, aci.args, aci.context, aci.info)
for process_response in plugins_process_response:
processed_response = process_response(response, aci)
if processed_response is None:
continue
return processed_response
return response
@property @property
def types(self): def types(self):
return self._types_names return self._types_names

View File

@ -1,9 +1,7 @@
from functools import wraps
from itertools import chain from itertools import chain
from graphql.type import GraphQLArgument from graphql.type import GraphQLArgument
from ...utils import ProxySnakeDict
from .base import ArgumentType, GroupNamedType, NamedType, OrderedType from .base import ArgumentType, GroupNamedType, NamedType, OrderedType
@ -53,11 +51,3 @@ def to_arguments(*args, **kwargs):
arguments[name] = argument arguments[name] = argument
return sorted(arguments.values()) return sorted(arguments.values())
def snake_case_args(resolver):
@wraps(resolver)
def wrapped_resolver(instance, args, context, info):
return resolver(instance, ProxySnakeDict(args), context, info)
return wrapped_resolver

View File

@ -1,5 +1,5 @@
from collections import OrderedDict from collections import OrderedDict
from functools import wraps from functools import wraps, partial
import six import six
from graphql.type import GraphQLField, GraphQLInputObjectField from graphql.type import GraphQLField, GraphQLInputObjectField
@ -10,7 +10,7 @@ from ..classtypes.base import FieldsClassType
from ..classtypes.inputobjecttype import InputObjectType from ..classtypes.inputobjecttype import InputObjectType
from ..classtypes.mutation import Mutation from ..classtypes.mutation import Mutation
from ..exceptions import SkipField from ..exceptions import SkipField
from .argument import Argument, ArgumentsGroup, snake_case_args from .argument import Argument, ArgumentsGroup
from .base import (ArgumentType, GroupNamedType, LazyType, MountType, from .base import (ArgumentType, GroupNamedType, LazyType, MountType,
NamedType, OrderedType) NamedType, OrderedType)
from .definitions import NonNull from .definitions import NonNull
@ -89,9 +89,6 @@ class Field(NamedType, OrderedType):
return NonNull(self.type) return NonNull(self.type)
return self.type return self.type
def decorate_resolver(self, resolver):
return snake_case_args(resolver)
def internal_type(self, schema): def internal_type(self, schema):
if not self.object_type: if not self.object_type:
raise Exception('The field is not mounted in any ClassType') raise Exception('The field is not mounted in any ClassType')
@ -119,7 +116,7 @@ class Field(NamedType, OrderedType):
assert type, 'Internal type for field %s is None' % str(self) assert type, 'Internal type for field %s is None' % str(self)
return GraphQLField(type, args=schema.T(arguments), return GraphQLField(type, args=schema.T(arguments),
resolver=self.decorate_resolver(resolver), resolver=partial(schema.resolve, resolver),
deprecation_reason=self.deprecation_reason, deprecation_reason=self.deprecation_reason,
description=description,) description=description,)

View File

@ -4,7 +4,7 @@ from pytest import raises
from graphene.core.schema import Schema from graphene.core.schema import Schema
from graphene.core.types import ObjectType from graphene.core.types import ObjectType
from ..argument import Argument, snake_case_args, to_arguments from ..argument import Argument, to_arguments
from ..scalars import String from ..scalars import String
@ -45,10 +45,3 @@ def test_to_arguments_wrong_type():
p=3 p=3
) )
assert 'Unknown argument p=3' == str(excinfo.value) assert 'Unknown argument p=3' == str(excinfo.value)
def test_snake_case_args():
def resolver(instance, args, context, info):
return args['my_arg']['inner_arg']
r = snake_case_args(resolver)
assert r(None, {'myArg': {'innerArg': 3}}, None, None) == 3

View File

@ -1,7 +1,10 @@
from ..utils import to_camel_case from ..utils import to_camel_case, ProxySnakeDict
class CamelCase(object): class CamelCase(object):
def get_default_namedtype_name(self, value): def get_default_namedtype_name(self, value):
return to_camel_case(value) return to_camel_case(value)
def process_aci(self, aci):
aci.args = ProxySnakeDict(aci.args)