mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 12:44:15 +03:00
Merge pull request #514 from graphql-python/2.0-newresolvers
Use the new resolvers API
This commit is contained in:
commit
a4bcb94958
|
@ -48,7 +48,7 @@ Here is one example for you to get started:
|
|||
class Query(graphene.ObjectType):
|
||||
hello = graphene.String(description='A typical hello world')
|
||||
|
||||
def resolve_hello(self):
|
||||
def resolve_hello(self, info):
|
||||
return 'World'
|
||||
|
||||
schema = graphene.Schema(query=Query)
|
||||
|
|
|
@ -65,7 +65,7 @@ Here is one example for you to get started:
|
|||
class Query(graphene.ObjectType):
|
||||
hello = graphene.String(description='A typical hello world')
|
||||
|
||||
def resolve_hello(self):
|
||||
def resolve_hello(self, info):
|
||||
return 'World'
|
||||
|
||||
schema = graphene.Schema(query=Query)
|
||||
|
|
|
@ -25,6 +25,42 @@ developer have to write to use them.
|
|||
|
||||
## Deprecations
|
||||
|
||||
### Simpler resolvers
|
||||
|
||||
All the resolvers in graphene have been simplified. If before resolvers must had received
|
||||
four arguments `root`, `args`, `context` and `info`, now the `args` are passed as keyword arguments
|
||||
and `context` and `info` will only be passed if the function is annotated with it.
|
||||
|
||||
Before:
|
||||
|
||||
```python
|
||||
my_field = graphene.String(my_arg=graphene.String())
|
||||
|
||||
def resolve_my_field(self, args, context, info):
|
||||
my_arg = args.get('my_arg')
|
||||
return ...
|
||||
```
|
||||
|
||||
With 2.0:
|
||||
|
||||
```python
|
||||
my_field = graphene.String(my_arg=graphene.String())
|
||||
|
||||
def resolve_my_field(self, info, my_arg):
|
||||
return ...
|
||||
```
|
||||
|
||||
And, if you need the context in the resolver, you can use `info.context`:
|
||||
|
||||
```python
|
||||
my_field = graphene.String(my_arg=graphene.String())
|
||||
|
||||
def resolve_my_field(self, info, my_arg):
|
||||
context = info.context
|
||||
return ...
|
||||
```
|
||||
|
||||
|
||||
### AbstractType deprecated
|
||||
|
||||
AbstractType is deprecated in graphene 2.0, you can now use normal inheritance instead.
|
||||
|
@ -51,7 +87,7 @@ class Pet(CommonFields, Interface):
|
|||
|
||||
### resolve\_only\_args
|
||||
|
||||
`resolve_only_args` is now deprecated in favor of type annotations (using the polyfill `@graphene.annotate` in Python 2 in case is necessary for accessing `context` or `info`).
|
||||
`resolve_only_args` is now deprecated as the resolver API has been simplified.
|
||||
|
||||
Before:
|
||||
|
||||
|
@ -70,7 +106,7 @@ With 2.0:
|
|||
class User(ObjectType):
|
||||
name = String()
|
||||
|
||||
def resolve_name(self):
|
||||
def resolve_name(self, info):
|
||||
return self.name
|
||||
```
|
||||
|
||||
|
@ -174,6 +210,42 @@ class Query(ObjectType):
|
|||
user_connection = relay.ConnectionField(UserConnection)
|
||||
```
|
||||
|
||||
## Node.get_node
|
||||
|
||||
The method `get_node` in `ObjectTypes` that have `Node` as interface, changes it's api.
|
||||
From `def get_node(cls, id, context, info)` to `def get_node(cls, info, id)`.
|
||||
|
||||
```python
|
||||
class MyObject(ObjectType):
|
||||
class Meta:
|
||||
interfaces = (Node, )
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, context, info):
|
||||
return ...
|
||||
```
|
||||
|
||||
To:
|
||||
```python
|
||||
class MyObject(ObjectType):
|
||||
class Meta:
|
||||
interfaces = (Node, )
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, info, id):
|
||||
return ...
|
||||
```
|
||||
|
||||
## Mutation.mutate
|
||||
|
||||
Now only receives (`root`, `info`, `**args`)
|
||||
|
||||
|
||||
## ClientIDMutation.mutate_and_get_payload
|
||||
|
||||
Now only receives (`root`, `info`, `**input`)
|
||||
|
||||
|
||||
## New Features
|
||||
|
||||
### InputObjectType
|
||||
|
@ -216,10 +288,9 @@ class UserInput(InputObjectType):
|
|||
class Query(ObjectType):
|
||||
user = graphene.Field(User, input=UserInput())
|
||||
|
||||
def resolve_user(self, input):
|
||||
def resolve_user(self, info, input):
|
||||
if input.is_valid:
|
||||
return get_user(input.id)
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
@ -255,7 +326,7 @@ class Base(ObjectType):
|
|||
|
||||
id = ID()
|
||||
|
||||
def resolve_id(self):
|
||||
def resolve_id(self, info):
|
||||
return "{type}_{id}".format(
|
||||
type=self.__class__.__name__,
|
||||
id=self.id
|
||||
|
|
|
@ -99,8 +99,8 @@ leaner code and at most 4 database requests, and possibly fewer if there are cac
|
|||
best_friend = graphene.Field(lambda: User)
|
||||
friends = graphene.List(lambda: User)
|
||||
|
||||
def resolve_best_friend(self):
|
||||
def resolve_best_friend(self, info):
|
||||
return user_loader.load(self.best_friend_id)
|
||||
|
||||
def resolve_friends(self):
|
||||
def resolve_friends(self, info):
|
||||
return user_loader.load_many(self.friend_ids)
|
||||
|
|
|
@ -24,9 +24,8 @@ You can pass context to a query via ``context_value``.
|
|||
class Query(graphene.ObjectType):
|
||||
name = graphene.String()
|
||||
|
||||
@graphene.annotate(context=graphene.Context)
|
||||
def resolve_name(self, context):
|
||||
return context.get('name')
|
||||
def resolve_name(self, info):
|
||||
return info.context.get('name')
|
||||
|
||||
schema = graphene.Schema(Query)
|
||||
result = schema.execute('{ name }', context_value={'name': 'Syrus'})
|
||||
|
@ -44,8 +43,8 @@ You can pass variables to a query via ``variable_values``.
|
|||
class Query(graphene.ObjectType):
|
||||
user = graphene.Field(User)
|
||||
|
||||
def resolve_user(self, args, context, info):
|
||||
return context.get('user')
|
||||
def resolve_user(self, info):
|
||||
return info.context.get('user')
|
||||
|
||||
schema = graphene.Schema(Query)
|
||||
result = schema.execute(
|
||||
|
|
|
@ -31,10 +31,10 @@ This middleware only continues evaluation if the ``field_name`` is not ``'user'`
|
|||
.. code:: python
|
||||
|
||||
class AuthorizationMiddleware(object):
|
||||
def resolve(self, next, root, args, context, info):
|
||||
def resolve(self, next, root, info, **args):
|
||||
if info.field_name == 'user':
|
||||
return None
|
||||
return next(root, args, context, info)
|
||||
return next(root, info, **args)
|
||||
|
||||
|
||||
And then execute it with:
|
||||
|
|
|
@ -39,7 +39,7 @@ one field: ``hello`` and an input name. And when we query it, it should return `
|
|||
class Query(graphene.ObjectType):
|
||||
hello = graphene.String(name=graphene.String(default_value="stranger"))
|
||||
|
||||
def resolve_hello(self, name):
|
||||
def resolve_hello(self, info, name):
|
||||
return 'Hello ' + name
|
||||
|
||||
schema = graphene.Schema(query=Query)
|
||||
|
|
|
@ -41,5 +41,5 @@ that implements ``Node`` will have a default Connection.
|
|||
name = graphene.String()
|
||||
ships = relay.ConnectionField(ShipConnection)
|
||||
|
||||
def resolve_ships(self):
|
||||
def resolve_ships(self, info):
|
||||
return []
|
||||
|
|
|
@ -21,7 +21,7 @@ subclass of ``relay.ClientIDMutation``.
|
|||
faction = graphene.Field(Faction)
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, input, context, info):
|
||||
def mutate_and_get_payload(cls, root, info, **input):
|
||||
ship_name = input.ship_name
|
||||
faction_id = input.faction_id
|
||||
ship = create_ship(ship_name, faction_id)
|
||||
|
@ -46,7 +46,7 @@ Mutations can also accept files, that's how it will work with different integrat
|
|||
success = graphene.String()
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, input, context, info):
|
||||
def mutate_and_get_payload(cls, root, info, **input):
|
||||
# When using it in Django, context will be the request
|
||||
files = context.FILES
|
||||
# Or, if used in Flask, context will be the flask global request
|
||||
|
|
|
@ -22,7 +22,7 @@ Example usage (taken from the `Starwars Relay example`_):
|
|||
name = graphene.String(description='The name of the ship.')
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, context, info):
|
||||
def get_node(cls, info, id):
|
||||
return get_ship(id)
|
||||
|
||||
The ``id`` returned by the ``Ship`` type when you query it will be a
|
||||
|
@ -55,7 +55,7 @@ Example of a custom node:
|
|||
return '{}:{}'.format(type, id)
|
||||
|
||||
@staticmethod
|
||||
def get_node_from_global_id(global_id, context, info, only_type=None):
|
||||
def get_node_from_global_id(info global_id, only_type=None):
|
||||
type, id = global_id.split(':')
|
||||
if only_node:
|
||||
# We assure that the node type that we want to retrieve
|
||||
|
|
|
@ -25,7 +25,7 @@ This example model defines a Person, with a first and a last name:
|
|||
last_name = graphene.String()
|
||||
full_name = graphene.String()
|
||||
|
||||
def resolve_full_name(self):
|
||||
def resolve_full_name(self, info):
|
||||
return '{} {}'.format(self.first_name, self.last_name)
|
||||
|
||||
**first\_name** and **last\_name** are fields of the ObjectType. Each
|
||||
|
@ -71,7 +71,7 @@ method in the class.
|
|||
class Query(graphene.ObjectType):
|
||||
reverse = graphene.String(word=graphene.String())
|
||||
|
||||
def resolve_reverse(self, word):
|
||||
def resolve_reverse(self, info, word):
|
||||
return word[::-1]
|
||||
|
||||
Resolvers outside the class
|
||||
|
@ -83,7 +83,7 @@ A field can use a custom resolver from outside the class:
|
|||
|
||||
import graphene
|
||||
|
||||
def reverse(root, word):
|
||||
def reverse(root, info, word):
|
||||
return word[::-1]
|
||||
|
||||
class Query(graphene.ObjectType):
|
||||
|
|
|
@ -11,10 +11,9 @@ class Address(graphene.ObjectType):
|
|||
|
||||
|
||||
class Query(graphene.ObjectType):
|
||||
address = graphene.Field(Address, geo=GeoInput())
|
||||
address = graphene.Field(Address, geo=GeoInput(required=True))
|
||||
|
||||
def resolve_address(self, args, context, info):
|
||||
geo = args.get('geo')
|
||||
def resolve_address(self, info, geo):
|
||||
return Address(latlng="({},{})".format(geo.get('lat'), geo.get('lng')))
|
||||
|
||||
|
||||
|
|
|
@ -9,9 +9,8 @@ class User(graphene.ObjectType):
|
|||
class Query(graphene.ObjectType):
|
||||
me = graphene.Field(User)
|
||||
|
||||
@graphene.annotate(context=graphene.Context)
|
||||
def resolve_me(self, context):
|
||||
return context['user']
|
||||
def resolve_me(self, info):
|
||||
return info.context['user']
|
||||
|
||||
|
||||
schema = graphene.Schema(query=Query)
|
||||
|
|
|
@ -11,7 +11,7 @@ class Query(graphene.ObjectType):
|
|||
|
||||
patron = graphene.Field(Patron)
|
||||
|
||||
def resolve_patron(self):
|
||||
def resolve_patron(self, info):
|
||||
return Patron(id=1, name='Syrus', age=27)
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class Character(graphene.Interface):
|
|||
friends = graphene.List(lambda: Character)
|
||||
appears_in = graphene.List(Episode)
|
||||
|
||||
def resolve_friends(self):
|
||||
def resolve_friends(self, info):
|
||||
# The character friends is a list of strings
|
||||
return [get_character(f) for f in self.friends]
|
||||
|
||||
|
@ -45,13 +45,13 @@ class Query(graphene.ObjectType):
|
|||
id=graphene.String()
|
||||
)
|
||||
|
||||
def resolve_hero(self, episode=None):
|
||||
def resolve_hero(self, info, episode=None):
|
||||
return get_hero(episode)
|
||||
|
||||
def resolve_human(self, id):
|
||||
def resolve_human(self, info, id):
|
||||
return get_human(id)
|
||||
|
||||
def resolve_droid(self, id):
|
||||
def resolve_droid(self, info, id):
|
||||
return get_droid(id)
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import graphene
|
||||
from graphene import annotate, relay, annotate
|
||||
from graphene import relay
|
||||
|
||||
from .data import create_ship, get_empire, get_faction, get_rebels, get_ship
|
||||
|
||||
|
@ -13,7 +13,7 @@ class Ship(graphene.ObjectType):
|
|||
name = graphene.String(description='The name of the ship.')
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, context, info):
|
||||
def get_node(cls, info, id):
|
||||
return get_ship(id)
|
||||
|
||||
|
||||
|
@ -32,12 +32,12 @@ class Faction(graphene.ObjectType):
|
|||
name = graphene.String(description='The name of the faction.')
|
||||
ships = relay.ConnectionField(ShipConnection, description='The ships used by the faction.')
|
||||
|
||||
def resolve_ships(self, **args):
|
||||
def resolve_ships(self, info, **args):
|
||||
# Transform the instance ship_ids into real instances
|
||||
return [get_ship(ship_id) for ship_id in self.ships]
|
||||
|
||||
@classmethod
|
||||
def get_node(cls, id, context, info):
|
||||
def get_node(cls, info, id):
|
||||
return get_faction(id)
|
||||
|
||||
|
||||
|
@ -51,9 +51,7 @@ class IntroduceShip(relay.ClientIDMutation):
|
|||
faction = graphene.Field(Faction)
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, input, context, info):
|
||||
ship_name = input.get('ship_name')
|
||||
faction_id = input.get('faction_id')
|
||||
def mutate_and_get_payload(cls, root, info, ship_name, faction_id, client_mutation_id=None):
|
||||
ship = create_ship(ship_name, faction_id)
|
||||
faction = get_faction(faction_id)
|
||||
return IntroduceShip(ship=ship, faction=faction)
|
||||
|
@ -64,10 +62,10 @@ class Query(graphene.ObjectType):
|
|||
empire = graphene.Field(Faction)
|
||||
node = relay.Node.Field()
|
||||
|
||||
def resolve_rebels(self):
|
||||
def resolve_rebels(self, info):
|
||||
return get_rebels()
|
||||
|
||||
def resolve_empire(self):
|
||||
def resolve_empire(self, info):
|
||||
return get_empire()
|
||||
|
||||
|
||||
|
|
|
@ -48,8 +48,6 @@ if not __SETUP__:
|
|||
)
|
||||
from .utils.resolve_only_args import resolve_only_args
|
||||
from .utils.module_loading import lazy_import
|
||||
from .utils.annotate import annotate
|
||||
from .utils.auto_resolver import final_resolver, is_final_resolver
|
||||
|
||||
__all__ = [
|
||||
'ObjectType',
|
||||
|
@ -82,11 +80,8 @@ if not __SETUP__:
|
|||
'ConnectionField',
|
||||
'PageInfo',
|
||||
'lazy_import',
|
||||
'annotate',
|
||||
'Context',
|
||||
'ResolveInfo',
|
||||
'final_resolver',
|
||||
'is_final_resolver',
|
||||
|
||||
# Deprecated
|
||||
'AbstractType',
|
||||
|
|
|
@ -10,7 +10,6 @@ from ..types import (Boolean, Enum, Int, Interface, List, NonNull, Scalar,
|
|||
from ..types.field import Field
|
||||
from ..types.objecttype import ObjectType, ObjectTypeOptions
|
||||
from ..utils.deprecated import warn_deprecation
|
||||
from ..utils.auto_resolver import final_resolver
|
||||
from .node import is_node
|
||||
|
||||
|
||||
|
@ -132,8 +131,8 @@ class IterableConnectionField(Field):
|
|||
return connection
|
||||
|
||||
@classmethod
|
||||
def connection_resolver(cls, resolver, connection_type, root, args, context, info):
|
||||
resolved = resolver(root, args, context, info)
|
||||
def connection_resolver(cls, resolver, connection_type, root, info, **args):
|
||||
resolved = resolver(root, info, **args)
|
||||
|
||||
on_resolve = partial(cls.resolve_connection, connection_type, args)
|
||||
if is_thenable(resolved):
|
||||
|
@ -143,7 +142,7 @@ class IterableConnectionField(Field):
|
|||
|
||||
def get_resolver(self, parent_resolver):
|
||||
resolver = super(IterableConnectionField, self).get_resolver(parent_resolver)
|
||||
return final_resolver(partial(self.connection_resolver, resolver, self.type))
|
||||
return partial(self.connection_resolver, resolver, self.type)
|
||||
|
||||
|
||||
ConnectionField = IterableConnectionField
|
||||
|
|
|
@ -3,9 +3,8 @@ from collections import OrderedDict
|
|||
|
||||
from promise import Promise, is_thenable
|
||||
|
||||
from ..types import Field, InputObjectType, String, Context, ResolveInfo
|
||||
from ..types import Field, InputObjectType, String
|
||||
from ..types.mutation import Mutation
|
||||
from ..utils.annotate import annotate
|
||||
|
||||
|
||||
class ClientIDMutation(Mutation):
|
||||
|
@ -58,18 +57,17 @@ class ClientIDMutation(Mutation):
|
|||
)
|
||||
|
||||
@classmethod
|
||||
@annotate(context=Context, info=ResolveInfo, _trigger_warning=False)
|
||||
def mutate(cls, root, input, context, info):
|
||||
def mutate(cls, root, info, input):
|
||||
def on_resolve(payload):
|
||||
try:
|
||||
payload.client_mutation_id = input.get('clientMutationId')
|
||||
payload.client_mutation_id = input.get('client_mutation_id')
|
||||
except:
|
||||
raise Exception(
|
||||
('Cannot set client_mutation_id in the payload object {}'
|
||||
).format(repr(payload)))
|
||||
return payload
|
||||
|
||||
result = cls.mutate_and_get_payload(input, context, info)
|
||||
result = cls.mutate_and_get_payload(root, info, **input)
|
||||
if is_thenable(result):
|
||||
return Promise.resolve(result).then(on_resolve)
|
||||
|
||||
|
|
|
@ -3,11 +3,9 @@ from functools import partial
|
|||
|
||||
from graphql_relay import from_global_id, to_global_id
|
||||
|
||||
from ..types import ID, Field, Interface, ObjectType, Context, ResolveInfo
|
||||
from ..types import ID, Field, Interface, ObjectType
|
||||
from ..types.interface import InterfaceOptions
|
||||
from ..types.utils import get_type
|
||||
from ..utils.annotate import annotate
|
||||
from ..utils.auto_resolver import final_resolver
|
||||
|
||||
|
||||
def is_node(objecttype):
|
||||
|
@ -31,15 +29,15 @@ class GlobalID(Field):
|
|||
self.parent_type_name = parent_type._meta.name if parent_type else None
|
||||
|
||||
@staticmethod
|
||||
def id_resolver(parent_resolver, node, root, args, context, info, parent_type_name=None):
|
||||
type_id = parent_resolver(root, args, context, info)
|
||||
def id_resolver(parent_resolver, node, root, info, parent_type_name=None, **args):
|
||||
type_id = parent_resolver(root, info, **args)
|
||||
parent_type_name = parent_type_name or info.parent_type.name
|
||||
return node.to_global_id(parent_type_name, type_id) # root._meta.name
|
||||
|
||||
def get_resolver(self, parent_resolver):
|
||||
return final_resolver(partial(
|
||||
return partial(
|
||||
self.id_resolver, parent_resolver, self.node, parent_type_name=self.parent_type_name
|
||||
))
|
||||
)
|
||||
|
||||
|
||||
class NodeField(Field):
|
||||
|
@ -58,7 +56,7 @@ class NodeField(Field):
|
|||
)
|
||||
|
||||
def get_resolver(self, parent_resolver):
|
||||
return partial(self.node_type.node_resolver, only_type=get_type(self.field_type))
|
||||
return partial(self.node_type.node_resolver, get_type(self.field_type))
|
||||
|
||||
|
||||
class AbstractNode(Interface):
|
||||
|
@ -83,12 +81,11 @@ class Node(AbstractNode):
|
|||
return NodeField(cls, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
@annotate(context=Context, info=ResolveInfo, _trigger_warning=False)
|
||||
def node_resolver(cls, root, id, context, info, only_type=None):
|
||||
return cls.get_node_from_global_id(id, context, info, only_type)
|
||||
def node_resolver(cls, only_type, root, info, id):
|
||||
return cls.get_node_from_global_id(info, id, only_type=only_type)
|
||||
|
||||
@classmethod
|
||||
def get_node_from_global_id(cls, global_id, context, info, only_type=None):
|
||||
def get_node_from_global_id(cls, info, global_id, only_type=None):
|
||||
try:
|
||||
_type, _id = cls.from_global_id(global_id)
|
||||
graphene_type = info.schema.get_type(_type).graphene_type
|
||||
|
@ -106,7 +103,7 @@ class Node(AbstractNode):
|
|||
|
||||
get_node = getattr(graphene_type, 'get_node', None)
|
||||
if get_node:
|
||||
return get_node(_id, context, info)
|
||||
return get_node(info, _id)
|
||||
|
||||
@classmethod
|
||||
def from_global_id(cls, global_id):
|
||||
|
|
|
@ -31,13 +31,13 @@ class Query(ObjectType):
|
|||
|
||||
node = Node.Field()
|
||||
|
||||
def resolve_letters(self, **args):
|
||||
def resolve_letters(self, info, **args):
|
||||
return list(letters.values())
|
||||
|
||||
def resolve_promise_letters(self, **args):
|
||||
def resolve_promise_letters(self, info, **args):
|
||||
return Promise.resolve(list(letters.values()))
|
||||
|
||||
def resolve_connection_letters(self, **args):
|
||||
def resolve_connection_letters(self, info, **args):
|
||||
return LetterConnection(
|
||||
page_info=PageInfo(
|
||||
has_next_page=True,
|
||||
|
|
|
@ -48,7 +48,7 @@ def test_global_id_defaults_to_info_parent_type():
|
|||
my_id = '1'
|
||||
gid = GlobalID()
|
||||
id_resolver = gid.get_resolver(lambda *_: my_id)
|
||||
my_global_id = id_resolver(None, None, None, Info(User))
|
||||
my_global_id = id_resolver(None, Info(User))
|
||||
assert my_global_id == to_global_id(User._meta.name, my_id)
|
||||
|
||||
|
||||
|
@ -56,5 +56,5 @@ def test_global_id_allows_setting_customer_parent_type():
|
|||
my_id = '1'
|
||||
gid = GlobalID(parent_type=User)
|
||||
id_resolver = gid.get_resolver(lambda *_: my_id)
|
||||
my_global_id = id_resolver(None, None, None, None)
|
||||
my_global_id = id_resolver(None, None)
|
||||
assert my_global_id == to_global_id(User._meta.name, my_id)
|
||||
|
|
|
@ -27,8 +27,7 @@ class SaySomething(ClientIDMutation):
|
|||
phrase = String()
|
||||
|
||||
@staticmethod
|
||||
def mutate_and_get_payload(args, context, info):
|
||||
what = args.get('what')
|
||||
def mutate_and_get_payload(self, info, what, client_mutation_id=None):
|
||||
return SaySomething(phrase=str(what))
|
||||
|
||||
|
||||
|
@ -40,8 +39,7 @@ class SaySomethingPromise(ClientIDMutation):
|
|||
phrase = String()
|
||||
|
||||
@staticmethod
|
||||
def mutate_and_get_payload(args, context, info):
|
||||
what = args.get('what')
|
||||
def mutate_and_get_payload(self, info, what, client_mutation_id=None):
|
||||
return Promise.resolve(SaySomething(phrase=str(what)))
|
||||
|
||||
|
||||
|
@ -59,13 +57,11 @@ class OtherMutation(ClientIDMutation):
|
|||
name = String()
|
||||
my_node_edge = Field(MyEdge)
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, args, context, info):
|
||||
shared = args.get('shared', '')
|
||||
additionalField = args.get('additionalField', '')
|
||||
@staticmethod
|
||||
def mutate_and_get_payload(self, info, shared='', additional_field='', client_mutation_id=None):
|
||||
edge_type = MyEdge
|
||||
return OtherMutation(
|
||||
name=shared + additionalField,
|
||||
name=shared + additional_field,
|
||||
my_node_edge=edge_type(cursor='1', node=MyNode(name='name')))
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class MyNode(ObjectType):
|
|||
name = String()
|
||||
|
||||
@staticmethod
|
||||
def get_node(id, *_):
|
||||
def get_node(info, id):
|
||||
return MyNode(name=str(id))
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ class MyOtherNode(SharedNodeFields, ObjectType):
|
|||
return 'extra field info.'
|
||||
|
||||
@staticmethod
|
||||
def get_node(id, *_):
|
||||
def get_node(info, id):
|
||||
return MyOtherNode(shared=str(id))
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class CustomNode(Node):
|
|||
return id
|
||||
|
||||
@staticmethod
|
||||
def get_node_from_global_id(id, context, info, only_type=None):
|
||||
def get_node_from_global_id(info, id, only_type=None):
|
||||
assert info.schema == schema
|
||||
if id in user_data:
|
||||
return user_data.get(id)
|
||||
|
|
|
@ -29,7 +29,7 @@ class CreatePost(graphene.Mutation):
|
|||
|
||||
result = graphene.Field(CreatePostResult)
|
||||
|
||||
def mutate(self, text):
|
||||
def mutate(self, info, text):
|
||||
result = Success(yeah='yeah')
|
||||
|
||||
return CreatePost(result=result)
|
||||
|
|
|
@ -6,7 +6,7 @@ import graphene
|
|||
class Query(graphene.ObjectType):
|
||||
some_field = graphene.String(from_=graphene.String(name="from"))
|
||||
|
||||
def resolve_some_field(self, from_=None):
|
||||
def resolve_some_field(self, info, from_=None):
|
||||
return from_
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,20 @@ class InputObjectTypeOptions(BaseOptions):
|
|||
create_container = None # type: Callable
|
||||
|
||||
|
||||
class InputObjectType(dict, UnmountedType, BaseType):
|
||||
class InputObjectTypeContainer(dict, BaseType):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
dict.__init__(self, *args, **kwargs)
|
||||
for key, value in self.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def __init_subclass__(cls, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class InputObjectType(UnmountedType, BaseType):
|
||||
'''
|
||||
Input Object Type Definition
|
||||
|
||||
|
@ -20,30 +33,9 @@ class InputObjectType(dict, UnmountedType, BaseType):
|
|||
|
||||
Using `NonNull` will ensure that a value must be provided by the query
|
||||
'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
as_container = kwargs.pop('_as_container', False)
|
||||
if as_container:
|
||||
# Is inited as container for the input args
|
||||
self.__init_container__(*args, **kwargs)
|
||||
else:
|
||||
# Is inited as UnmountedType, e.g.
|
||||
#
|
||||
# class MyObjectType(graphene.ObjectType):
|
||||
# my_input = MyInputType(required=True)
|
||||
#
|
||||
UnmountedType.__init__(self, *args, **kwargs)
|
||||
|
||||
def __init_container__(self, *args, **kwargs):
|
||||
dict.__init__(self, *args, **kwargs)
|
||||
for key, value in self.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
@classmethod
|
||||
def create_container(cls, data):
|
||||
return cls(data, _as_container=True)
|
||||
|
||||
@classmethod
|
||||
def __init_subclass_with_meta__(cls, create_container=None, **options):
|
||||
def __init_subclass_with_meta__(cls, container=None, **options):
|
||||
_meta = InputObjectTypeOptions(cls)
|
||||
|
||||
fields = OrderedDict()
|
||||
|
@ -53,9 +45,9 @@ class InputObjectType(dict, UnmountedType, BaseType):
|
|||
)
|
||||
|
||||
_meta.fields = fields
|
||||
if create_container is None:
|
||||
create_container = cls.create_container
|
||||
_meta.create_container = create_container
|
||||
if container is None:
|
||||
container = type(cls.__name__, (InputObjectTypeContainer, cls), {})
|
||||
_meta.container = container
|
||||
super(InputObjectType, cls).__init_subclass_with_meta__(_meta=_meta, **options)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -37,14 +37,10 @@ class Interface(BaseType):
|
|||
super(Interface, cls).__init_subclass_with_meta__(_meta=_meta, **options)
|
||||
|
||||
@classmethod
|
||||
def resolve_type(cls, instance, context, info):
|
||||
def resolve_type(cls, instance, info):
|
||||
from .objecttype import ObjectType
|
||||
if isinstance(instance, ObjectType):
|
||||
return type(instance)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
raise Exception("An Interface cannot be intitialized")
|
||||
|
||||
@classmethod
|
||||
def implements(cls, objecttype):
|
||||
pass
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
def attr_resolver(attname, default_value, root, args, context, info):
|
||||
def attr_resolver(attname, default_value, root, info, **args):
|
||||
return getattr(root, attname, default_value)
|
||||
|
||||
|
||||
def dict_resolver(attname, default_value, root, args, context, info):
|
||||
def dict_resolver(attname, default_value, root, info, **args):
|
||||
return root.get(attname, default_value)
|
||||
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ class Query(ObjectType):
|
|||
datetime = DateTime(_in=DateTime(name='in'))
|
||||
time = Time(_at=Time(name='at'))
|
||||
|
||||
def resolve_datetime(self, _in=None):
|
||||
def resolve_datetime(self, info, _in=None):
|
||||
return _in
|
||||
|
||||
def resolve_time(self, _at=None):
|
||||
def resolve_time(self, info, _at=None):
|
||||
return _at
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from ..schema import Schema
|
|||
class Query(ObjectType):
|
||||
generic = GenericScalar(input=GenericScalar())
|
||||
|
||||
def resolve_generic(self, input=None):
|
||||
def resolve_generic(self, info, input=None):
|
||||
return input
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ from ..schema import Schema
|
|||
class Query(ObjectType):
|
||||
json = JSONString(input=JSONString())
|
||||
|
||||
def resolve_json(self, input):
|
||||
def resolve_json(self, info, input):
|
||||
return input
|
||||
|
||||
schema = Schema(query=Query)
|
||||
|
|
|
@ -12,13 +12,13 @@ def test_generate_mutation_no_args():
|
|||
class MyMutation(Mutation):
|
||||
'''Documentation'''
|
||||
|
||||
def mutate(self, **args):
|
||||
def mutate(self, info, **args):
|
||||
return args
|
||||
|
||||
assert issubclass(MyMutation, ObjectType)
|
||||
assert MyMutation._meta.name == "MyMutation"
|
||||
assert MyMutation._meta.description == "Documentation"
|
||||
resolved = MyMutation.Field().resolver(None, name='Peter')
|
||||
resolved = MyMutation.Field().resolver(None, None, name='Peter')
|
||||
assert resolved == {'name': 'Peter'}
|
||||
|
||||
|
||||
|
@ -29,12 +29,12 @@ def test_generate_mutation_with_meta():
|
|||
name = 'MyOtherMutation'
|
||||
description = 'Documentation'
|
||||
|
||||
def mutate(self, **args):
|
||||
def mutate(self, info, **args):
|
||||
return args
|
||||
|
||||
assert MyMutation._meta.name == "MyOtherMutation"
|
||||
assert MyMutation._meta.description == "Documentation"
|
||||
resolved = MyMutation.Field().resolver(None, name='Peter')
|
||||
resolved = MyMutation.Field().resolver(None, None, name='Peter')
|
||||
assert resolved == {'name': 'Peter'}
|
||||
|
||||
|
||||
|
@ -59,13 +59,13 @@ def test_mutation_custom_output_type():
|
|||
|
||||
Output = User
|
||||
|
||||
def mutate(self, name):
|
||||
def mutate(self, info, name):
|
||||
return User(name=name)
|
||||
|
||||
field = CreateUser.Field()
|
||||
assert field.type == User
|
||||
assert field.args == {'name': Argument(String)}
|
||||
resolved = field.resolver(None, name='Peter')
|
||||
resolved = field.resolver(None, None, name='Peter')
|
||||
assert isinstance(resolved, User)
|
||||
assert resolved.name == 'Peter'
|
||||
|
||||
|
@ -81,7 +81,7 @@ def test_mutation_execution():
|
|||
name = String()
|
||||
dynamic = Dynamic(lambda: String())
|
||||
|
||||
def mutate(self, name, dynamic):
|
||||
def mutate(self, info, name, dynamic):
|
||||
return CreateUser(name=name, dynamic=dynamic)
|
||||
|
||||
class Query(ObjectType):
|
||||
|
|
|
@ -14,7 +14,6 @@ from ..schema import Schema
|
|||
from ..structures import List
|
||||
from ..union import Union
|
||||
from ..context import Context
|
||||
from ...utils.annotate import annotate
|
||||
|
||||
|
||||
def test_query():
|
||||
|
@ -39,14 +38,14 @@ def test_query_union():
|
|||
one = String()
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, root, context, info):
|
||||
def is_type_of(cls, root, info):
|
||||
return isinstance(root, one_object)
|
||||
|
||||
class Two(ObjectType):
|
||||
two = String()
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, root, context, info):
|
||||
def is_type_of(cls, root, info):
|
||||
return isinstance(root, two_object)
|
||||
|
||||
class MyUnion(Union):
|
||||
|
@ -57,7 +56,7 @@ def test_query_union():
|
|||
class Query(ObjectType):
|
||||
unions = List(MyUnion)
|
||||
|
||||
def resolve_unions(self):
|
||||
def resolve_unions(self, info):
|
||||
return [one_object(), two_object()]
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -91,7 +90,7 @@ def test_query_interface():
|
|||
one = String()
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, root, context, info):
|
||||
def is_type_of(cls, root, info):
|
||||
return isinstance(root, one_object)
|
||||
|
||||
class Two(ObjectType):
|
||||
|
@ -102,13 +101,13 @@ def test_query_interface():
|
|||
two = String()
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, root, context, info):
|
||||
def is_type_of(cls, root, info):
|
||||
return isinstance(root, two_object)
|
||||
|
||||
class Query(ObjectType):
|
||||
interfaces = List(MyInterface)
|
||||
|
||||
def resolve_interfaces(self):
|
||||
def resolve_interfaces(self, info):
|
||||
return [one_object(), two_object()]
|
||||
|
||||
hello_schema = Schema(Query, types=[One, Two])
|
||||
|
@ -156,7 +155,7 @@ def test_query_wrong_default_value():
|
|||
field = String()
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, root, context, info):
|
||||
def is_type_of(cls, root, info):
|
||||
return isinstance(root, MyType)
|
||||
|
||||
class Query(ObjectType):
|
||||
|
@ -188,7 +187,7 @@ def test_query_resolve_function():
|
|||
class Query(ObjectType):
|
||||
hello = String()
|
||||
|
||||
def resolve_hello(self):
|
||||
def resolve_hello(self, info):
|
||||
return 'World'
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -202,7 +201,7 @@ def test_query_arguments():
|
|||
class Query(ObjectType):
|
||||
test = String(a_str=String(), a_int=Int())
|
||||
|
||||
def resolve_test(self, **args):
|
||||
def resolve_test(self, info, **args):
|
||||
return json.dumps([self, args], separators=(',', ':'))
|
||||
|
||||
test_schema = Schema(Query)
|
||||
|
@ -231,7 +230,7 @@ def test_query_input_field():
|
|||
class Query(ObjectType):
|
||||
test = String(a_input=Input())
|
||||
|
||||
def resolve_test(self, **args):
|
||||
def resolve_test(self, info, **args):
|
||||
return json.dumps([self, args], separators=(',', ':'))
|
||||
|
||||
test_schema = Schema(Query)
|
||||
|
@ -254,10 +253,10 @@ def test_query_middlewares():
|
|||
hello = String()
|
||||
other = String()
|
||||
|
||||
def resolve_hello(self):
|
||||
def resolve_hello(self, info):
|
||||
return 'World'
|
||||
|
||||
def resolve_other(self):
|
||||
def resolve_other(self, info):
|
||||
return 'other'
|
||||
|
||||
def reversed_middleware(next, *args, **kwargs):
|
||||
|
@ -280,14 +279,14 @@ def test_objecttype_on_instances():
|
|||
class ShipType(ObjectType):
|
||||
name = String(description="Ship name", required=True)
|
||||
|
||||
def resolve_name(self):
|
||||
def resolve_name(self, info):
|
||||
# Here self will be the Ship instance returned in resolve_ship
|
||||
return self.name
|
||||
|
||||
class Query(ObjectType):
|
||||
ship = Field(ShipType)
|
||||
|
||||
def resolve_ship(self):
|
||||
def resolve_ship(self, info):
|
||||
return Ship(name='xwing')
|
||||
|
||||
schema = Schema(query=Query)
|
||||
|
@ -302,7 +301,7 @@ def test_big_list_query_benchmark(benchmark):
|
|||
class Query(ObjectType):
|
||||
all_ints = List(Int)
|
||||
|
||||
def resolve_all_ints(self):
|
||||
def resolve_all_ints(self, info):
|
||||
return big_list
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -319,7 +318,7 @@ def test_big_list_query_compiled_query_benchmark(benchmark):
|
|||
class Query(ObjectType):
|
||||
all_ints = List(Int)
|
||||
|
||||
def resolve_all_ints(self):
|
||||
def resolve_all_ints(self, info):
|
||||
return big_list
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -341,7 +340,7 @@ def test_big_list_of_containers_query_benchmark(benchmark):
|
|||
class Query(ObjectType):
|
||||
all_containers = List(Container)
|
||||
|
||||
def resolve_all_containers(self):
|
||||
def resolve_all_containers(self, info):
|
||||
return big_container_list
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -364,7 +363,7 @@ def test_big_list_of_containers_multiple_fields_query_benchmark(benchmark):
|
|||
class Query(ObjectType):
|
||||
all_containers = List(Container)
|
||||
|
||||
def resolve_all_containers(self):
|
||||
def resolve_all_containers(self, info):
|
||||
return big_container_list
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -382,16 +381,16 @@ def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark
|
|||
z = Int()
|
||||
o = Int()
|
||||
|
||||
def resolve_x(self):
|
||||
def resolve_x(self, info):
|
||||
return self.x
|
||||
|
||||
def resolve_y(self):
|
||||
def resolve_y(self, info):
|
||||
return self.y
|
||||
|
||||
def resolve_z(self):
|
||||
def resolve_z(self, info):
|
||||
return self.z
|
||||
|
||||
def resolve_o(self):
|
||||
def resolve_o(self, info):
|
||||
return self.o
|
||||
|
||||
big_container_list = [Container(x=x, y=x, z=x, o=x) for x in range(1000)]
|
||||
|
@ -399,7 +398,7 @@ def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark
|
|||
class Query(ObjectType):
|
||||
all_containers = List(Container)
|
||||
|
||||
def resolve_all_containers(self):
|
||||
def resolve_all_containers(self, info):
|
||||
return big_container_list
|
||||
|
||||
hello_schema = Schema(Query)
|
||||
|
@ -420,15 +419,13 @@ def test_query_annotated_resolvers():
|
|||
context = String()
|
||||
info = String()
|
||||
|
||||
def resolve_annotated(self, id):
|
||||
def resolve_annotated(self, info, id):
|
||||
return "{}-{}".format(self, id)
|
||||
|
||||
@annotate(context=Context, _trigger_warning=False)
|
||||
def resolve_context(self, context):
|
||||
assert isinstance(context, Context)
|
||||
return "{}-{}".format(self, context.key)
|
||||
def resolve_context(self, info):
|
||||
assert isinstance(info.context, Context)
|
||||
return "{}-{}".format(self, info.context.key)
|
||||
|
||||
@annotate(info=ResolveInfo, _trigger_warning=False)
|
||||
def resolve_info(self, info):
|
||||
assert isinstance(info, ResolveInfo)
|
||||
return "{}-{}".format(self, info.field_name)
|
||||
|
|
|
@ -16,22 +16,22 @@ class demo_obj(object):
|
|||
|
||||
|
||||
def test_attr_resolver():
|
||||
resolved = attr_resolver('attr', None, demo_obj, args, context, info)
|
||||
resolved = attr_resolver('attr', None, demo_obj, info, **args)
|
||||
assert resolved == 'value'
|
||||
|
||||
|
||||
def test_attr_resolver_default_value():
|
||||
resolved = attr_resolver('attr2', 'default', demo_obj, args, context, info)
|
||||
resolved = attr_resolver('attr2', 'default', demo_obj, info, **args)
|
||||
assert resolved == 'default'
|
||||
|
||||
|
||||
def test_dict_resolver():
|
||||
resolved = dict_resolver('attr', None, demo_dict, args, context, info)
|
||||
resolved = dict_resolver('attr', None, demo_dict, info, **args)
|
||||
assert resolved == 'value'
|
||||
|
||||
|
||||
def test_dict_resolver_default_value():
|
||||
resolved = dict_resolver('attr2', 'default', demo_dict, args, context, info)
|
||||
resolved = dict_resolver('attr2', 'default', demo_dict, info, **args)
|
||||
assert resolved == 'default'
|
||||
|
||||
|
||||
|
|
|
@ -204,5 +204,5 @@ def test_objecttype_with_possible_types():
|
|||
typemap = TypeMap([MyObjectType])
|
||||
graphql_type = typemap['MyObjectType']
|
||||
assert graphql_type.is_type_of
|
||||
assert graphql_type.is_type_of({}, None, None) is True
|
||||
assert graphql_type.is_type_of(MyObjectType(), None, None) is False
|
||||
assert graphql_type.is_type_of({}, None) is True
|
||||
assert graphql_type.is_type_of(MyObjectType(), None) is False
|
||||
|
|
|
@ -6,7 +6,7 @@ from ..schema import Schema
|
|||
class Query(ObjectType):
|
||||
uuid = UUID(input=UUID())
|
||||
|
||||
def resolve_uuid(self, input):
|
||||
def resolve_uuid(self, info, input):
|
||||
return input
|
||||
|
||||
schema = Schema(query=Query)
|
||||
|
|
|
@ -11,7 +11,6 @@ from graphql.type.typemap import GraphQLTypeMap
|
|||
|
||||
from ..utils.get_unbound_function import get_unbound_function
|
||||
from ..utils.str_converters import to_camel_case
|
||||
from ..utils.auto_resolver import auto_resolver, final_resolver
|
||||
from .definitions import (GrapheneEnumType, GrapheneGraphQLType,
|
||||
GrapheneInputObjectType, GrapheneInterfaceType,
|
||||
GrapheneObjectType, GrapheneScalarType,
|
||||
|
@ -38,12 +37,12 @@ def is_graphene_type(_type):
|
|||
return True
|
||||
|
||||
|
||||
def resolve_type(resolve_type_func, map, type_name, root, context, info):
|
||||
_type = resolve_type_func(root, context, info)
|
||||
def resolve_type(resolve_type_func, map, type_name, root, info):
|
||||
_type = resolve_type_func(root, info)
|
||||
|
||||
if not _type:
|
||||
return_type = map[type_name]
|
||||
return get_default_resolve_type_fn(root, context, info, return_type)
|
||||
return get_default_resolve_type_fn(root, info, return_type)
|
||||
|
||||
if inspect.isclass(_type) and issubclass(_type, ObjectType):
|
||||
graphql_type = map.get(_type._meta.name)
|
||||
|
@ -55,7 +54,7 @@ def resolve_type(resolve_type_func, map, type_name, root, context, info):
|
|||
return _type
|
||||
|
||||
|
||||
def is_type_of_from_possible_types(possible_types, root, context, info):
|
||||
def is_type_of_from_possible_types(possible_types, root, info):
|
||||
return isinstance(root, possible_types)
|
||||
|
||||
|
||||
|
@ -196,7 +195,7 @@ class TypeMap(GraphQLTypeMap):
|
|||
graphene_type=type,
|
||||
name=type._meta.name,
|
||||
description=type._meta.description,
|
||||
container_type=type._meta.create_container,
|
||||
container_type=type._meta.container,
|
||||
fields=partial(
|
||||
self.construct_fields_for_type, map, type, is_input_type=True),
|
||||
)
|
||||
|
@ -240,7 +239,7 @@ class TypeMap(GraphQLTypeMap):
|
|||
_field = GraphQLInputObjectField(
|
||||
field_type,
|
||||
default_value=field.default_value,
|
||||
out_name=field.name or name,
|
||||
out_name=name,
|
||||
description=field.description)
|
||||
else:
|
||||
args = OrderedDict()
|
||||
|
@ -256,13 +255,13 @@ class TypeMap(GraphQLTypeMap):
|
|||
_field = GraphQLField(
|
||||
field_type,
|
||||
args=args,
|
||||
resolver=auto_resolver(field.get_resolver(
|
||||
auto_resolver(self.get_resolver_for_type(
|
||||
resolver=field.get_resolver(
|
||||
self.get_resolver_for_type(
|
||||
type,
|
||||
name,
|
||||
field.default_value
|
||||
))
|
||||
)),
|
||||
)
|
||||
),
|
||||
deprecation_reason=field.deprecation_reason,
|
||||
description=field.description)
|
||||
field_name = field.name or self.get_name(name)
|
||||
|
@ -292,7 +291,7 @@ class TypeMap(GraphQLTypeMap):
|
|||
|
||||
default_resolver = type._meta.default_resolver or get_default_resolver(
|
||||
)
|
||||
return final_resolver(partial(default_resolver, name, default_value))
|
||||
return partial(default_resolver, name, default_value)
|
||||
|
||||
def get_field_type(self, map, type):
|
||||
if isinstance(type, List):
|
||||
|
|
|
@ -34,7 +34,7 @@ class Union(UnmountedType, BaseType):
|
|||
return cls
|
||||
|
||||
@classmethod
|
||||
def resolve_type(cls, instance, context, info):
|
||||
def resolve_type(cls, instance, info):
|
||||
from .objecttype import ObjectType
|
||||
if isinstance(instance, ObjectType):
|
||||
return type(instance)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
from .resolver_from_annotations import resolver_from_annotations
|
||||
|
||||
|
||||
def final_resolver(func):
|
||||
func._is_final_resolver = True
|
||||
return func
|
||||
|
||||
|
||||
def auto_resolver(func=None):
|
||||
if not func:
|
||||
return
|
||||
|
||||
if not is_final_resolver(func):
|
||||
# Is a Graphene 2.0 resolver function
|
||||
return final_resolver(resolver_from_annotations(func))
|
||||
else:
|
||||
return func
|
||||
|
||||
|
||||
def is_final_resolver(func):
|
||||
return getattr(func, '_is_final_resolver', False)
|
|
@ -1,18 +1,11 @@
|
|||
from six import PY2
|
||||
from .annotate import annotate
|
||||
from functools import wraps
|
||||
from .deprecated import deprecated
|
||||
|
||||
if PY2:
|
||||
deprecation_reason = (
|
||||
'Please use @annotate instead.'
|
||||
)
|
||||
else:
|
||||
deprecation_reason = (
|
||||
'Please use Python 3 type annotations instead. Read more: '
|
||||
'https://docs.python.org/3/library/typing.html'
|
||||
)
|
||||
|
||||
|
||||
@deprecated(deprecation_reason)
|
||||
@deprecated('This function is deprecated')
|
||||
def resolve_only_args(func):
|
||||
return annotate(func)
|
||||
@wraps(func)
|
||||
def wrapped_func(root, info, **args):
|
||||
return func(root, **args)
|
||||
|
||||
return wrapped_func
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
import pytest
|
||||
from ..annotate import annotate
|
||||
from ..auto_resolver import auto_resolver, final_resolver
|
||||
|
||||
from ...types import Context, ResolveInfo
|
||||
|
||||
|
||||
@final_resolver
|
||||
def resolver(root, args, context, info):
|
||||
return root, args, context, info
|
||||
|
||||
|
||||
def resolver_annotated(root, **args):
|
||||
return root, args, None, None
|
||||
|
||||
|
||||
@annotate(context=Context, info=ResolveInfo, _trigger_warning=False)
|
||||
def resolver_with_context_and_info(root, context, info, **args):
|
||||
return root, args, context, info
|
||||
|
||||
|
||||
def test_auto_resolver_non_annotated():
|
||||
decorated_resolver = auto_resolver(resolver)
|
||||
# We make sure the function is not wrapped
|
||||
assert decorated_resolver == resolver
|
||||
assert decorated_resolver(1, {}, 2, 3) == (1, {}, 2, 3)
|
||||
|
||||
|
||||
def test_auto_resolver_annotated():
|
||||
decorated_resolver = auto_resolver(resolver_annotated)
|
||||
assert decorated_resolver(1, {}, 2, 3) == (1, {}, None, None)
|
||||
|
||||
|
||||
def test_auto_resolver_annotated_with_context_and_info():
|
||||
decorated_resolver = auto_resolver(resolver_with_context_and_info)
|
||||
assert decorated_resolver(1, {}, 2, 3) == (1, {}, 2, 3)
|
|
@ -1,44 +0,0 @@
|
|||
import pytest
|
||||
from ..annotate import annotate
|
||||
from ..resolver_from_annotations import resolver_from_annotations
|
||||
|
||||
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_resolver_from_annotations(func, expected):
|
||||
resolver_func = resolver_from_annotations(func)
|
||||
resolved = resolver_func(root, args, context, info)
|
||||
assert resolved == expected
|
Loading…
Reference in New Issue
Block a user