mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-11 12:16:58 +03:00
Added annotated resolver and context
This commit is contained in:
parent
f7fdc9aa3d
commit
d2f1024d81
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
4
graphene/types/context.py
Normal file
4
graphene/types/context.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
class Context(object):
|
||||
def __init__(self, **params):
|
||||
for key, value in params.items():
|
||||
setattr(self,key, value)
|
|
@ -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"
|
||||
|
|
36
graphene/utils/annotated_resolver.py
Normal file
36
graphene/utils/annotated_resolver.py
Normal 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)
|
39
graphene/utils/tests/test_annotated_resolver.py
Normal file
39
graphene/utils/tests/test_annotated_resolver.py
Normal 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
|
Loading…
Reference in New Issue
Block a user