Added annotated resolver and context

This commit is contained in:
Syrus Akbary 2017-07-23 17:19:45 -07:00
parent f7fdc9aa3d
commit d2f1024d81
6 changed files with 89 additions and 2 deletions

View File

@ -32,6 +32,8 @@ if not __SETUP__:
Argument,
Dynamic,
Union,
Context,
ResolveInfo
)
from .relay import (
Node,
@ -74,6 +76,8 @@ if not __SETUP__:
'ConnectionField',
'PageInfo',
'lazy_import',
'Context',
'ResolveInfo',
# Deprecated
'AbstractType',

View File

@ -1,4 +1,5 @@
# flake8: noqa
from graphql.execution.base import ResolveInfo
from .objecttype import ObjectType
from .interface import Interface
@ -13,6 +14,7 @@ from .argument import Argument
from .inputobjecttype import InputObjectType
from .dynamic import Dynamic
from .union import Union
from .context import Context
# Deprecated
from .abstracttype import AbstractType
@ -38,6 +40,8 @@ __all__ = [
'Argument',
'Dynamic',
'Union',
'Context',
'ResolveInfo',
# Deprecated
'AbstractType',

View File

@ -0,0 +1,4 @@
class Context(object):
def __init__(self, **params):
for key, value in params.items():
setattr(self,key, value)

View File

@ -3,8 +3,8 @@ from functools import wraps
from ..pyutils.compat import signature
def annotate(_func=None, **annotations):
if not six.PY2:
def annotate(_func=None, _trigger_warning=True, **annotations):
if not six.PY2 and _trigger_warning:
print(
"annotate is intended for use in Python 2 only, as you can use type annotations Python 3.\n"
"Read more in https://docs.python.org/3/library/typing.html"

View File

@ -0,0 +1,36 @@
from ..pyutils.compat import signature
from functools import wraps
from ..types import Context, ResolveInfo
def annotated_resolver(func):
func_signature = signature(func)
_context_var = None
_info_var = None
for key, parameter in func_signature.parameters.items():
param_type = parameter.annotation
if param_type is Context:
_context_var = key
elif param_type is ResolveInfo:
_info_var = key
continue
# We generate different functions as it will be faster
# than calculating the args on the fly when executing
# the function resolver.
if _context_var and _info_var:
def inner(root, args, context, info):
return func(root, **dict(args, **{_info_var: info, _context_var: context}))
elif _context_var:
def inner(root, args, context, info):
return func(root, **dict(args, **{_context_var: context}))
elif _info_var:
def inner(root, args, context, info):
return func(root, **dict(args, **{_info_var: info}))
else:
def inner(root, args, context, info):
return func(root, **args)
return wraps(func)(inner)

View File

@ -0,0 +1,39 @@
import pytest
from ..annotate import annotate
from ..annotated_resolver import annotated_resolver
from ...types import Context, ResolveInfo
@annotate
def func(root, **args):
return root, args, None, None
@annotate(context=Context)
def func_with_context(root, context, **args):
return root, args, context, None
@annotate(info=ResolveInfo)
def func_with_info(root, info, **args):
return root, args, None, info
@annotate(context=Context, info=ResolveInfo)
def func_with_context_and_info(root, context, info, **args):
return root, args, context, info
root = 1
args = {
'arg': 0
}
context = 2
info = 3
@pytest.mark.parametrize("func,expected", [
(func, (1, {'arg': 0}, None, None)),
(func_with_context, (1, {'arg': 0}, 2, None)),
(func_with_info, (1, {'arg': 0}, None, 3)),
(func_with_context_and_info, (1, {'arg': 0}, 2, 3)),
])
def test_annotated_resolver(func, expected):
resolver_func = annotated_resolver(func)
resolved = resolver_func(root, args, context, info)
assert resolved == expected