mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-09 08:00:39 +03:00
Refactored code allowing multiple schemas at the same time.
This commit is contained in:
parent
eafc9a102e
commit
311209760d
|
@ -34,3 +34,5 @@ from graphene.core.fields import (
|
||||||
from graphene.decorators import (
|
from graphene.decorators import (
|
||||||
resolve_only_args
|
resolve_only_args
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import graphene.relay
|
||||||
|
|
|
@ -10,7 +10,6 @@ from graphql.core.type import (
|
||||||
GraphQLArgument,
|
GraphQLArgument,
|
||||||
)
|
)
|
||||||
from graphene.utils import cached_property
|
from graphene.utils import cached_property
|
||||||
from graphene.core.types import ObjectType
|
|
||||||
|
|
||||||
class Field(object):
|
class Field(object):
|
||||||
def __init__(self, field_type, resolve=None, null=True, args=None, description='', **extra_args):
|
def __init__(self, field_type, resolve=None, null=True, args=None, description='', **extra_args):
|
||||||
|
@ -45,6 +44,7 @@ class Field(object):
|
||||||
return resolve_fn(instance, args, info)
|
return resolve_fn(instance, args, info)
|
||||||
|
|
||||||
def get_object_type(self):
|
def get_object_type(self):
|
||||||
|
from graphene.core.types import ObjectType
|
||||||
field_type = self.field_type
|
field_type = self.field_type
|
||||||
_is_class = inspect.isclass(field_type)
|
_is_class = inspect.isclass(field_type)
|
||||||
if _is_class and issubclass(field_type, ObjectType):
|
if _is_class and issubclass(field_type, ObjectType):
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Options(object):
|
||||||
self.local_fields = []
|
self.local_fields = []
|
||||||
self.interface = False
|
self.interface = False
|
||||||
self.proxy = False
|
self.proxy = False
|
||||||
self.schema = schema or get_global_schema()
|
self.schema = schema
|
||||||
self.interfaces = []
|
self.interfaces = []
|
||||||
self.parents = []
|
self.parents = []
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from graphql.core.type import (
|
||||||
)
|
)
|
||||||
from graphene import signals
|
from graphene import signals
|
||||||
from graphene.utils import cached_property
|
from graphene.utils import cached_property
|
||||||
# from graphene.relay.nodes import create_node_definitions
|
|
||||||
|
|
||||||
class Schema(object):
|
class Schema(object):
|
||||||
_query = None
|
_query = None
|
||||||
|
@ -14,27 +14,15 @@ class Schema(object):
|
||||||
self.query = query
|
self.query = query
|
||||||
self.name = name
|
self.name = name
|
||||||
self._types = {}
|
self._types = {}
|
||||||
|
signals.init_schema.send(self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Schema: %s>' % str(self.name)
|
return '<Schema: %s (%s)>' % (str(self.name), hash(self))
|
||||||
|
|
||||||
# @cachedproperty
|
|
||||||
# def node_definitions(self):
|
|
||||||
# return [object, object]
|
|
||||||
# # from graphene.relay import create_node_definitions
|
|
||||||
# # return create_node_definitions(schema=self)
|
|
||||||
|
|
||||||
# @property
|
|
||||||
# def Node(self):
|
|
||||||
# return self.node_definitions[0]
|
|
||||||
|
|
||||||
# @property
|
|
||||||
# def NodeField(self):
|
|
||||||
# return self.node_definitions[1]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def query(self):
|
def query(self):
|
||||||
return self._query
|
return self._query
|
||||||
|
|
||||||
@query.setter
|
@query.setter
|
||||||
def query(self, query):
|
def query(self, query):
|
||||||
if not query:
|
if not query:
|
||||||
|
@ -69,5 +57,3 @@ def object_type_created(object_type):
|
||||||
schema = object_type._meta.schema
|
schema = object_type._meta.schema
|
||||||
if schema:
|
if schema:
|
||||||
schema.register_type(object_type)
|
schema.register_type(object_type)
|
||||||
|
|
||||||
from graphene.env import get_global_schema
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ class ObjectTypeMeta(type):
|
||||||
# Things without _meta aren't functional models, so they're
|
# Things without _meta aren't functional models, so they're
|
||||||
# uninteresting parents.
|
# uninteresting parents.
|
||||||
continue
|
continue
|
||||||
if base._meta.schema != new_class._meta.schema:
|
# if base._meta.schema != new_class._meta.schema:
|
||||||
raise Exception('The parent schema is not the same')
|
# raise Exception('The parent schema is not the same')
|
||||||
|
|
||||||
parent_fields = base._meta.local_fields
|
parent_fields = base._meta.local_fields
|
||||||
# Check for clashes between locally declared fields and those
|
# Check for clashes between locally declared fields and those
|
||||||
|
@ -135,3 +135,19 @@ class Interface(ObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
interface = True
|
interface = True
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
@signals.init_schema.connect
|
||||||
|
def add_types_to_schema(schema):
|
||||||
|
own_schema = schema
|
||||||
|
class _Interface(Interface):
|
||||||
|
class Meta:
|
||||||
|
schema = own_schema
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
class _ObjectType(ObjectType):
|
||||||
|
class Meta:
|
||||||
|
schema = own_schema
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
setattr(own_schema, 'Interface', _Interface)
|
||||||
|
setattr(own_schema, 'ObjectType', _ObjectType)
|
||||||
|
|
|
@ -2,4 +2,19 @@ from graphene.relay.nodes import (
|
||||||
create_node_definitions
|
create_node_definitions
|
||||||
)
|
)
|
||||||
|
|
||||||
from graphene.relay.relay import *
|
from graphene.relay.fields import (
|
||||||
|
ConnectionField,
|
||||||
|
)
|
||||||
|
|
||||||
|
import graphene.relay.connections
|
||||||
|
|
||||||
|
from graphene.relay.relay import (
|
||||||
|
Relay
|
||||||
|
)
|
||||||
|
|
||||||
|
from graphene.env import get_global_schema
|
||||||
|
|
||||||
|
schema = get_global_schema()
|
||||||
|
relay = schema.relay
|
||||||
|
|
||||||
|
Node, NodeField = relay.Node, relay.NodeField
|
||||||
|
|
35
graphene/relay/connections.py
Normal file
35
graphene/relay/connections.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from graphql_relay.node.node import (
|
||||||
|
globalIdField
|
||||||
|
)
|
||||||
|
from graphql_relay.connection.connection import (
|
||||||
|
connectionDefinitions
|
||||||
|
)
|
||||||
|
|
||||||
|
from graphene import signals
|
||||||
|
|
||||||
|
from graphene.core.fields import NativeField
|
||||||
|
from graphene.relay.utils import get_relay
|
||||||
|
from graphene.relay.relay import Relay
|
||||||
|
|
||||||
|
|
||||||
|
@signals.class_prepared.connect
|
||||||
|
def object_type_created(object_type):
|
||||||
|
relay = get_relay(object_type._meta.schema)
|
||||||
|
if relay and issubclass(object_type, relay.Node):
|
||||||
|
type_name = object_type._meta.type_name
|
||||||
|
# def getId(*args, **kwargs):
|
||||||
|
# print '**GET ID', args, kwargs
|
||||||
|
# return 2
|
||||||
|
field = NativeField(globalIdField(type_name))
|
||||||
|
object_type.add_to_class('id', field)
|
||||||
|
assert hasattr(object_type, 'get_node'), 'get_node classmethod not found in %s Node' % type_name
|
||||||
|
|
||||||
|
connection = connectionDefinitions(type_name, object_type._meta.type).connectionType
|
||||||
|
object_type.add_to_class('connection', connection)
|
||||||
|
|
||||||
|
|
||||||
|
@signals.init_schema.connect
|
||||||
|
def schema_created(schema):
|
||||||
|
setattr(schema, 'relay', Relay(schema))
|
30
graphene/relay/fields.py
Normal file
30
graphene/relay/fields.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from graphql_relay.connection.arrayconnection import (
|
||||||
|
connectionFromArray
|
||||||
|
)
|
||||||
|
from graphql_relay.connection.connection import (
|
||||||
|
connectionArgs
|
||||||
|
)
|
||||||
|
from graphene.core.fields import Field
|
||||||
|
from graphene.utils import cached_property
|
||||||
|
from graphene.relay.utils import get_relay
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionField(Field):
|
||||||
|
def __init__(self, field_type, resolve=None, description=''):
|
||||||
|
super(ConnectionField, self).__init__(field_type, resolve=resolve,
|
||||||
|
args=connectionArgs, description=description)
|
||||||
|
|
||||||
|
def resolve(self, instance, args, info):
|
||||||
|
resolved = super(ConnectionField, self).resolve(instance, args, info)
|
||||||
|
if resolved:
|
||||||
|
assert isinstance(resolved, collections.Iterable), 'Resolved value from the connection field have to be iterable'
|
||||||
|
return connectionFromArray(resolved, args)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def type(self):
|
||||||
|
object_type = self.get_object_type()
|
||||||
|
relay = get_relay(object_type._meta.schema)
|
||||||
|
assert issubclass(object_type, relay.Node), 'Only nodes have connections.'
|
||||||
|
return object_type.connection
|
|
@ -2,27 +2,32 @@ from graphql_relay.node.node import (
|
||||||
nodeDefinitions,
|
nodeDefinitions,
|
||||||
fromGlobalId
|
fromGlobalId
|
||||||
)
|
)
|
||||||
|
from graphene.env import get_global_schema
|
||||||
|
from graphene.core.types import Interface
|
||||||
|
from graphene.core.fields import Field, NativeField
|
||||||
|
|
||||||
def create_node_definitions(getNode=None, getNodeType=None, schema=None):
|
|
||||||
from graphene.core.types import Interface
|
def getSchemaNode(schema=None):
|
||||||
from graphene.core.fields import Field, NativeField
|
|
||||||
if not getNode:
|
|
||||||
def getNode(globalId, *args):
|
def getNode(globalId, *args):
|
||||||
from graphene.env import get_global_schema
|
|
||||||
_schema = schema or get_global_schema()
|
_schema = schema or get_global_schema()
|
||||||
resolvedGlobalId = fromGlobalId(globalId)
|
resolvedGlobalId = fromGlobalId(globalId)
|
||||||
_type, _id = resolvedGlobalId.type, resolvedGlobalId.id
|
_type, _id = resolvedGlobalId.type, resolvedGlobalId.id
|
||||||
object_type = _schema.get_type(_type)
|
object_type = schema.get_type(_type)
|
||||||
return object_type.get_node(_id)
|
return object_type.get_node(_id)
|
||||||
|
return getNode
|
||||||
|
|
||||||
if not getNodeType:
|
|
||||||
def getNodeType(obj):
|
def getNodeType(obj):
|
||||||
return obj._meta.type
|
return obj._meta.type
|
||||||
|
|
||||||
|
|
||||||
|
def create_node_definitions(getNode=None, getNodeType=getNodeType, schema=None):
|
||||||
|
getNode = getNode or getSchemaNode(schema)
|
||||||
_nodeDefinitions = nodeDefinitions(getNode, getNodeType)
|
_nodeDefinitions = nodeDefinitions(getNode, getNodeType)
|
||||||
|
|
||||||
|
_Interface = getattr(schema,'Interface', Interface)
|
||||||
|
|
||||||
class Node(Interface):
|
class Node(_Interface):
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_graphql_type(cls):
|
def get_graphql_type(cls):
|
||||||
if cls is Node:
|
if cls is Node:
|
||||||
|
|
|
@ -1,51 +1,14 @@
|
||||||
import collections
|
from graphene.relay.nodes import (
|
||||||
|
create_node_definitions
|
||||||
from graphene import signals
|
|
||||||
from graphene.utils import cached_property
|
|
||||||
|
|
||||||
from graphql_relay.node.node import (
|
|
||||||
globalIdField
|
|
||||||
)
|
)
|
||||||
from graphql_relay.connection.arrayconnection import (
|
|
||||||
connectionFromArray
|
from graphene.relay.fields import (
|
||||||
|
ConnectionField,
|
||||||
)
|
)
|
||||||
from graphql_relay.connection.connection import (
|
|
||||||
connectionArgs,
|
|
||||||
connectionDefinitions
|
|
||||||
)
|
|
||||||
from graphene.relay.nodes import create_node_definitions
|
|
||||||
from graphene.core.fields import Field, NativeField
|
|
||||||
|
|
||||||
Node, NodeField = create_node_definitions()
|
|
||||||
|
|
||||||
class ConnectionField(Field):
|
|
||||||
def __init__(self, field_type, resolve=None, description=''):
|
|
||||||
super(ConnectionField, self).__init__(field_type, resolve=resolve,
|
|
||||||
args=connectionArgs, description=description)
|
|
||||||
|
|
||||||
def resolve(self, instance, args, info):
|
|
||||||
resolved = super(ConnectionField, self).resolve(instance, args, info)
|
|
||||||
if resolved:
|
|
||||||
assert isinstance(resolved, collections.Iterable), 'Resolved value from the connection field have to be iterable'
|
|
||||||
return connectionFromArray(resolved, args)
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def type(self):
|
|
||||||
object_type = self.get_object_type()
|
|
||||||
assert issubclass(object_type, Node), 'Only nodes have connections.'
|
|
||||||
return object_type.connection
|
|
||||||
|
|
||||||
|
|
||||||
@signals.class_prepared.connect
|
class Relay(object):
|
||||||
def object_type_created(object_type):
|
def __init__(self, schema):
|
||||||
if issubclass(object_type, Node):
|
self.schema = schema
|
||||||
type_name = object_type._meta.type_name
|
self.Node, self.NodeField = create_node_definitions(schema=self.schema)
|
||||||
# def getId(*args, **kwargs):
|
self.ConnectionField = ConnectionField
|
||||||
# print '**GET ID', args, kwargs
|
|
||||||
# return 2
|
|
||||||
field = NativeField(globalIdField(type_name))
|
|
||||||
object_type.add_to_class('id', field)
|
|
||||||
assert hasattr(object_type, 'get_node'), 'get_node classmethod not found in %s Node' % type_name
|
|
||||||
|
|
||||||
connection = connectionDefinitions(type_name, object_type._meta.type).connectionType
|
|
||||||
object_type.add_to_class('connection', connection)
|
|
||||||
|
|
3
graphene/relay/utils.py
Normal file
3
graphene/relay/utils.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
def get_relay(schema):
|
||||||
|
return getattr(schema, 'relay', None)
|
|
@ -1,5 +1,6 @@
|
||||||
from blinker import Signal
|
from blinker import Signal
|
||||||
|
|
||||||
|
init_schema = Signal()
|
||||||
class_prepared = Signal()
|
class_prepared = Signal()
|
||||||
pre_init = Signal()
|
pre_init = Signal()
|
||||||
post_init = Signal()
|
post_init = Signal()
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Character(Interface):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
class Meta:
|
class Meta:
|
||||||
type_name = 'core.Character'
|
type_name = 'core.Character'
|
||||||
|
|
||||||
class Human(Character):
|
class Human(Character):
|
||||||
'''Human description'''
|
'''Human description'''
|
||||||
friends = StringField()
|
friends = StringField()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import graphene
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
|
|
||||||
schema = graphene.Schema()
|
schema = graphene.Schema()
|
||||||
|
relay = schema.relay
|
||||||
|
|
||||||
class OtherNode(relay.Node):
|
class OtherNode(relay.Node):
|
||||||
name = graphene.StringField()
|
name = graphene.StringField()
|
||||||
|
|
|
@ -8,8 +8,6 @@ from .data import (
|
||||||
getEmpire,
|
getEmpire,
|
||||||
)
|
)
|
||||||
|
|
||||||
schema = graphene.Schema()
|
|
||||||
|
|
||||||
class Ship(relay.Node):
|
class Ship(relay.Node):
|
||||||
'''A ship in the Star Wars saga'''
|
'''A ship in the Star Wars saga'''
|
||||||
name = graphene.StringField(description='The name of the ship.')
|
name = graphene.StringField(description='The name of the ship.')
|
||||||
|
@ -20,8 +18,6 @@ class Ship(relay.Node):
|
||||||
if ship:
|
if ship:
|
||||||
return Ship(ship)
|
return Ship(ship)
|
||||||
|
|
||||||
# class Meta:
|
|
||||||
# schema = schema
|
|
||||||
|
|
||||||
class Faction(relay.Node):
|
class Faction(relay.Node):
|
||||||
'''A faction in the Star Wars saga'''
|
'''A faction in the Star Wars saga'''
|
||||||
|
@ -38,9 +34,6 @@ class Faction(relay.Node):
|
||||||
if faction:
|
if faction:
|
||||||
return Faction(faction)
|
return Faction(faction)
|
||||||
|
|
||||||
# class Meta:
|
|
||||||
# schema = schema
|
|
||||||
|
|
||||||
|
|
||||||
class Query(graphene.ObjectType):
|
class Query(graphene.ObjectType):
|
||||||
rebels = graphene.Field(Faction)
|
rebels = graphene.Field(Faction)
|
||||||
|
@ -56,10 +49,4 @@ class Query(graphene.ObjectType):
|
||||||
return Faction(getEmpire())
|
return Faction(getEmpire())
|
||||||
|
|
||||||
|
|
||||||
# class Meta:
|
schema = graphene.Schema(query=Query, name='Starwars Relay Schema')
|
||||||
# schema = schema
|
|
||||||
|
|
||||||
print '*CACA', schema._types
|
|
||||||
|
|
||||||
schema.query = Query
|
|
||||||
Schema = schema
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from pytest import raises
|
from pytest import raises
|
||||||
from graphql.core import graphql
|
from graphql.core import graphql
|
||||||
|
|
||||||
from .schema import Schema
|
from .schema import schema
|
||||||
|
|
||||||
def test_correct_fetch_first_ship_rebels():
|
def test_correct_fetch_first_ship_rebels():
|
||||||
query = '''
|
query = '''
|
||||||
|
@ -32,6 +32,6 @@ def test_correct_fetch_first_ship_rebels():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = Schema.execute(query)
|
result = schema.execute(query)
|
||||||
assert result.errors == None
|
assert result.errors == None
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from pytest import raises
|
from pytest import raises
|
||||||
from graphql.core import graphql
|
from graphql.core import graphql
|
||||||
|
|
||||||
from .schema import Schema
|
from .schema import schema
|
||||||
|
|
||||||
def test_correctly_fetches_id_name_rebels():
|
def test_correctly_fetches_id_name_rebels():
|
||||||
query = '''
|
query = '''
|
||||||
|
@ -18,7 +18,7 @@ def test_correctly_fetches_id_name_rebels():
|
||||||
'name': 'Alliance to Restore the Republic'
|
'name': 'Alliance to Restore the Republic'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = Schema.execute(query)
|
result = schema.execute(query)
|
||||||
assert result.errors == None
|
assert result.errors == None
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ def test_correctly_refetches_rebels():
|
||||||
'name': 'Alliance to Restore the Republic'
|
'name': 'Alliance to Restore the Republic'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = Schema.execute(query)
|
result = schema.execute(query)
|
||||||
assert result.errors == None
|
assert result.errors == None
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ def test_correctly_fetches_id_name_empire():
|
||||||
'name': 'Galactic Empire'
|
'name': 'Galactic Empire'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = Schema.execute(query)
|
result = schema.execute(query)
|
||||||
assert result.errors == None
|
assert result.errors == None
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ def test_correctly_refetches_empire():
|
||||||
'name': 'Galactic Empire'
|
'name': 'Galactic Empire'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = Schema.execute(query)
|
result = schema.execute(query)
|
||||||
assert result.errors == None
|
assert result.errors == None
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
@ -100,6 +100,6 @@ def test_correctly_refetches_xwing():
|
||||||
'name': 'X-Wing'
|
'name': 'X-Wing'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = Schema.execute(query)
|
result = schema.execute(query)
|
||||||
assert result.errors == None
|
assert result.errors == None
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
Loading…
Reference in New Issue
Block a user