First stage separate interfaces

This commit is contained in:
Syrus Akbary 2016-08-07 19:20:40 -07:00
parent ff3968faea
commit 04492600e5
7 changed files with 51 additions and 33 deletions

View File

@ -4,7 +4,9 @@ from graphene import relay, resolve_only_args
from .data import create_ship, get_empire, get_faction, get_rebels, get_ship
class Ship(relay.Node, graphene.ObjectType):
class Ship(graphene.ObjectType):
class Meta:
interfaces = [relay.Node]
'''A ship in the Star Wars saga'''
name = graphene.String(description='The name of the ship.')

View File

@ -96,8 +96,8 @@ class IterableConnectionField(Field):
@property
def connection(self):
from .node import Node
if issubclass(self._type, Node):
connection_type = self._type.get_default_connection()
if Node in self._type._meta.interfaces:
connection_type = self._type.Connection
else:
connection_type = self._type
assert issubclass(connection_type, Connection), '{} type have to be a subclass of Connection'.format(str(self))

View File

@ -12,6 +12,15 @@ from ..utils.copy_fields import copy_fields
from .connection import Connection
def get_default_connection(cls):
assert issubclass(cls, ObjectType), 'Can only get connection type on implemented Nodes.'
class Meta:
node = cls
return type('{}Connection'.format(cls.__name__), (Connection,), {'Meta': Meta})
# We inherit from ObjectTypeMeta as we want to allow
# inheriting from Node, and also ObjectType.
# Like class MyNode(Node): pass
@ -24,17 +33,6 @@ class NodeMeta(ObjectTypeMeta):
meta,
)
@staticmethod
def _create_objecttype(cls, name, bases, attrs):
cls = super(NodeMeta, cls)._create_objecttype(cls, name, bases, attrs)
require_get_node = Node._meta.graphql_type in cls._meta.graphql_type._provided_interfaces
if require_get_node:
assert hasattr(
cls, 'get_node'), '{}.get_node method is required by the Node interface.'.format(
cls.__name__)
return cls
@staticmethod
def _create_interface(cls, name, bases, attrs):
options = cls._get_interface_options(attrs.pop('Meta', None))
@ -95,10 +93,14 @@ class Node(six.with_metaclass(NodeMeta, Interface)):
return graphql_type.graphene_type.get_node(_id, context, info)
@classmethod
def get_default_connection(cls):
assert issubclass(cls, ObjectType), 'Can only get connection type on implemented Nodes.'
if not cls._connection:
class Meta:
node = cls
cls._connection = type('{}Connection'.format(cls.__name__), (Connection,), {'Meta': Meta})
return cls._connection
def implements(cls, objecttype):
require_get_node = Node._meta.graphql_type in objecttype._meta.get_interfaces
get_connection = getattr(objecttype, 'get_connection', None)
if not get_connection:
get_connection = partial(get_default_connection, objecttype)
objecttype.Connection = get_connection()
if require_get_node:
assert hasattr(
objecttype, 'get_node'), '{}.get_node method is required by the Node interface.'.format(
objecttype.__name__)

View File

@ -6,7 +6,9 @@ from ..connection import Connection
from ..node import Node
class MyObject(Node, ObjectType):
class MyObject(ObjectType):
class Meta:
interfaces = [Node]
field = String()
@classmethod

View File

@ -8,8 +8,9 @@ from ..connection import Connection
from ..node import Node
class MyNode(Node, ObjectType):
class MyNode(ObjectType):
class Meta:
interfaces = [Node]
name = String()
@staticmethod
@ -46,12 +47,12 @@ def test_node_good():
def test_node_get_connection():
connection = MyNode.get_default_connection()
connection = MyNode.Connection
assert issubclass(connection, Connection)
def test_node_get_connection_dont_duplicate():
assert MyNode.get_default_connection() == MyNode.get_default_connection()
assert MyNode.Connection == MyNode.Connection
def test_node_query():

View File

@ -24,12 +24,15 @@ class BasePhoto(Interface):
width = Int()
class User(CustomNode, ObjectType):
class User(ObjectType):
class Meta:
interfaces = [CustomNode]
name = String()
class Photo(CustomNode, BasePhoto, ObjectType):
pass
class Photo(ObjectType):
class Meta:
interfaces = [CustomNode, BasePhoto]
user_data = {
@ -50,7 +53,6 @@ schema = Schema(query=RootQuery, types=[User, Photo])
def test_str_schema_correct():
print str(schema)
assert str(schema) == '''schema {
query: RootQuery
}

View File

@ -1,4 +1,4 @@
import inspect
import six
from ..utils.copy_fields import copy_fields
@ -97,12 +97,17 @@ class ObjectTypeMeta(type):
if not options.graphql_type:
fields = copy_fields(Field, fields, parent=cls)
base_interfaces = tuple(b for b in bases if issubclass(b, Interface))
inherited_interfaces = tuple(b for b in bases if issubclass(b, Interface))
options.get_fields = lambda: fields
options.get_interfaces = tuple(get_interfaces(interfaces + base_interfaces))
options.interfaces = interfaces + inherited_interfaces
options.get_interfaces = tuple(get_interfaces(options.interfaces))
options.graphql_type = generate_objecttype(cls)
for i in options.interfaces:
if inspect.isclass(i) and issubclass(i, Interface):
i.implements(cls)
else:
assert not fields, "Can't mount Fields in an ObjectType with a defined graphql_type"
assert not interfaces, "Can't have extra interfaces with a defined graphql_type"
fields = copy_fields(Field, options.graphql_type.get_fields(), parent=cls)
options.get_fields = lambda: fields
@ -175,3 +180,7 @@ class Interface(six.with_metaclass(ObjectTypeMeta)):
if not isinstance(self, ObjectType):
raise Exception("An interface cannot be intitialized")
super(Interface, self).__init__(*args, **kwargs)
@classmethod
def implements(cls, objecttype):
pass