mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 09:57:41 +03:00 
			
		
		
		
	Improved types as containers
This commit is contained in:
		
							parent
							
								
									2958cc18af
								
							
						
					
					
						commit
						129999d41a
					
				
							
								
								
									
										72
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								README.md
									
									
									
									
									
								
							| 
						 | 
					@ -1,10 +1,10 @@
 | 
				
			||||||
#  [Graphene](http://graphene-python.org) [](https://travis-ci.org/graphql-python/graphene) [](https://coveralls.io/github/graphql-python/graphene?branch=master)
 | 
					#  [Graphene](http://graphene-python.org) [](https://travis-ci.org/graphql-python/graphene) [](https://badge.fury.io/py/graphene) [](https://coveralls.io/github/graphql-python/graphene?branch=master)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Graphene is a Python library for building GraphQL schemas/types fast and easily.
 | 
					Graphene is a Python library for building GraphQL schemas/types fast and easily.
 | 
				
			||||||
* **Easy to use:** It maps the models/fields to internal GraphQL objects without effort.
 | 
					* **Easy to use:** It maps the models/fields to internal GraphQL objects without effort.
 | 
				
			||||||
* **Relay:** Graphene has builtin support for Relay
 | 
					* **Relay:** Graphene has builtin support for Relay
 | 
				
			||||||
* **Django:** Automatic [Django models](#djangorelay-schema) conversion. *See an [example Django](http://github.com/graphql-python/swapi-graphene) implementation*
 | 
					* **Django:** Automatic *Django model* mapping to Graphene Types. *See an [example Django](http://github.com/graphql-python/swapi-graphene) implementation*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
| 
						 | 
					@ -16,26 +16,21 @@ pip install graphene
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Usage
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example code of a GraphQL schema using Graphene:
 | 
					Here is one example for get you started:
 | 
				
			||||||
 | 
					 | 
				
			||||||
### Schema definition
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
class Character(graphene.Interface):
 | 
					 | 
				
			||||||
    id = graphene.IDField()
 | 
					 | 
				
			||||||
    name = graphene.StringField()
 | 
					 | 
				
			||||||
    friends = graphene.ListField('self')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def resolve_friends(self, args, *_):
 | 
					 | 
				
			||||||
        return [Human(f) for f in self.instance.friends]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Human(Character):
 | 
					 | 
				
			||||||
    homePlanet = graphene.StringField()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					class Query(graphene.ObjectType):
 | 
				
			||||||
    human = graphene.Field(Human)
 | 
					    hello = graphene.StringField(description='A typical hello world')
 | 
				
			||||||
 | 
					    ping = graphene.StringField(description='Ping someone',
 | 
				
			||||||
 | 
					                                to=graphene.Argument(graphene.String))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resolve_hello(self, args, info):
 | 
				
			||||||
 | 
					        return 'World'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resolve_ping(self, args, info):
 | 
				
			||||||
 | 
					        return 'Pinging {}'.format(args.get('to'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
schema = graphene.Schema(query=Query)
 | 
					schema = graphene.Schema(query=Query)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
| 
						 | 
					@ -44,48 +39,19 @@ Then Querying `graphene.Schema` is as simple as:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					```python
 | 
				
			||||||
query = '''
 | 
					query = '''
 | 
				
			||||||
    query HeroNameQuery {
 | 
					    query SayHello {
 | 
				
			||||||
      hero {
 | 
					      hello
 | 
				
			||||||
        name
 | 
					      ping(to:'peter')
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
result = schema.execute(query)
 | 
					result = schema.execute(query)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Relay Schema
 | 
					If you want to learn even more, you can also check the following examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Graphene also supports Relay, check the [Starwars Relay example](tests/starwars_relay)!
 | 
					* Relay Schema: [Starwars Relay example](tests/starwars_relay)
 | 
				
			||||||
 | 
					* Django: [Starwars Django example](tests/starwars_django)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					 | 
				
			||||||
class Ship(relay.Node):
 | 
					 | 
				
			||||||
    name = graphene.StringField()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def get_node(cls, id):
 | 
					 | 
				
			||||||
        return Ship(your_ship_instance)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					 | 
				
			||||||
    ships = relay.ConnectionField(Ship)
 | 
					 | 
				
			||||||
    node = relay.NodeField()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Django+Relay Schema
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If you want to use graphene with your Django Models check the [Starwars Django example](tests/starwars_django)!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```python
 | 
					 | 
				
			||||||
class Ship(DjangoNode):
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = YourDjangoModelHere
 | 
					 | 
				
			||||||
        # only_fields = ('id', 'name') # Only map this fields from the model
 | 
					 | 
				
			||||||
        # exclude_fields ('field_to_exclude', ) # Exclude mapping this fields from the model
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					 | 
				
			||||||
    node = relay.NodeField()
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Contributing
 | 
					## Contributing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,11 +37,20 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
 | 
				
			||||||
            cls.add_to_class(field.name, converted_field)
 | 
					            cls.add_to_class(field.name, converted_field)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, BaseObjectType)):
 | 
					class InstanceObjectType(BaseObjectType):
 | 
				
			||||||
 | 
					    def __init__(self, instance=None):
 | 
				
			||||||
 | 
					        self.instance = instance
 | 
				
			||||||
 | 
					        super(InstanceObjectType, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __getattr__(self, attr):
 | 
				
			||||||
 | 
					        return getattr(self.instance, attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, InstanceObjectType)):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DjangoInterface(six.with_metaclass(DjangoObjectTypeMeta, BaseObjectType)):
 | 
					class DjangoInterface(six.with_metaclass(DjangoObjectTypeMeta, InstanceObjectType)):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ class Field(object):
 | 
				
			||||||
    creation_counter = 0
 | 
					    creation_counter = 0
 | 
				
			||||||
    required = False
 | 
					    required = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, field_type, name=None, resolve=None, required=False, args=None, description='', **extra_args):
 | 
					    def __init__(self, field_type, name=None, resolve=None, required=False, args=None, description='', default=None, **extra_args):
 | 
				
			||||||
        self.field_type = field_type
 | 
					        self.field_type = field_type
 | 
				
			||||||
        self.resolve_fn = resolve
 | 
					        self.resolve_fn = resolve
 | 
				
			||||||
        self.required = self.required or required
 | 
					        self.required = self.required or required
 | 
				
			||||||
| 
						 | 
					@ -38,9 +38,13 @@ class Field(object):
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        self.description = description or self.__doc__
 | 
					        self.description = description or self.__doc__
 | 
				
			||||||
        self.object_type = None
 | 
					        self.object_type = None
 | 
				
			||||||
 | 
					        self.default = default
 | 
				
			||||||
        self.creation_counter = Field.creation_counter
 | 
					        self.creation_counter = Field.creation_counter
 | 
				
			||||||
        Field.creation_counter += 1
 | 
					        Field.creation_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_default(self):
 | 
				
			||||||
 | 
					        return self.default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def contribute_to_class(self, cls, name, add=True):
 | 
					    def contribute_to_class(self, cls, name, add=True):
 | 
				
			||||||
        if not self.name:
 | 
					        if not self.name:
 | 
				
			||||||
            self.name = to_camel_case(name)
 | 
					            self.name = to_camel_case(name)
 | 
				
			||||||
| 
						 | 
					@ -57,7 +61,7 @@ class Field(object):
 | 
				
			||||||
        if resolve_fn:
 | 
					        if resolve_fn:
 | 
				
			||||||
            return resolve_fn(instance, args, info)
 | 
					            return resolve_fn(instance, args, info)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return getattr(instance, self.field_name, None)
 | 
					            return getattr(instance, self.field_name, self.get_default())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_resolve_fn(self, schema):
 | 
					    def get_resolve_fn(self, schema):
 | 
				
			||||||
        object_type = self.get_object_type(schema)
 | 
					        object_type = self.get_object_type(schema)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,29 +129,48 @@ class ObjectTypeMeta(type):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BaseObjectType(object):
 | 
					class BaseObjectType(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __new__(cls, instance=None, **kwargs):
 | 
					    def __new__(cls, *args, **kwargs):
 | 
				
			||||||
        if cls._meta.is_interface:
 | 
					        if cls._meta.is_interface:
 | 
				
			||||||
            raise Exception("An interface cannot be initialized")
 | 
					            raise Exception("An interface cannot be initialized")
 | 
				
			||||||
        if instance is None:
 | 
					        if not args and not kwargs:
 | 
				
			||||||
            if not kwargs:
 | 
					            return None
 | 
				
			||||||
                return None
 | 
					 | 
				
			||||||
        elif type(instance) is cls:
 | 
					 | 
				
			||||||
            return instance
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return super(BaseObjectType, cls).__new__(cls)
 | 
					        return super(BaseObjectType, cls).__new__(cls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, instance=None, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
        signals.pre_init.send(self.__class__, instance=instance)
 | 
					        signals.pre_init.send(self.__class__, args=args, kwargs=kwargs)
 | 
				
			||||||
        assert instance or kwargs
 | 
					        args_len = len(args)
 | 
				
			||||||
        if not instance:
 | 
					        fields = self._meta.fields
 | 
				
			||||||
            init_kwargs = dict({k: None for k in self._meta.fields_map.keys()}, **kwargs)
 | 
					        if args_len > len(fields):
 | 
				
			||||||
            instance = self._meta.object(**init_kwargs)
 | 
					            # Daft, but matches old exception sans the err msg.
 | 
				
			||||||
        self.instance = instance
 | 
					            raise IndexError("Number of args exceeds number of fields")
 | 
				
			||||||
        signals.post_init.send(self.__class__, instance=self)
 | 
					        fields_iter = iter(fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getattr__(self, name):
 | 
					        if not kwargs:
 | 
				
			||||||
        if self.instance:
 | 
					            for val, field in zip(args, fields_iter):
 | 
				
			||||||
            return getattr(self.instance, name)
 | 
					                setattr(self, field.field_name, val)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            for val, field in zip(args, fields_iter):
 | 
				
			||||||
 | 
					                setattr(self, field.field_name, val)
 | 
				
			||||||
 | 
					                kwargs.pop(field.field_name, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for field in fields_iter:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                val = kwargs.pop(field.field_name)
 | 
				
			||||||
 | 
					                setattr(self, field.field_name, val)
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if kwargs:
 | 
				
			||||||
 | 
					            for prop in list(kwargs):
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    if isinstance(getattr(self.__class__, prop), property):
 | 
				
			||||||
 | 
					                        setattr(self, prop, kwargs.pop(prop))
 | 
				
			||||||
 | 
					                except AttributeError:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					            if kwargs:
 | 
				
			||||||
 | 
					                raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signals.post_init.send(self.__class__, instance=self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def fields_as_arguments(cls, schema):
 | 
					    def fields_as_arguments(cls, schema):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,21 +32,3 @@ def test_node_should_have_same_connection_always():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_node_should_have_id_field():
 | 
					def test_node_should_have_id_field():
 | 
				
			||||||
    assert 'id' in OtherNode._meta.fields_map
 | 
					    assert 'id' in OtherNode._meta.fields_map
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# def test_field_no_contributed_raises_error():
 | 
					 | 
				
			||||||
#     with raises(Exception) as excinfo:
 | 
					 | 
				
			||||||
#         class Ship(graphene.ObjectType):
 | 
					 | 
				
			||||||
#             name = graphene.StringField()
 | 
					 | 
				
			||||||
#             class Meta:
 | 
					 | 
				
			||||||
#                 schema = schema
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#         class Faction(relay.Node):
 | 
					 | 
				
			||||||
#             name = graphene.StringField()
 | 
					 | 
				
			||||||
#             ships = relay.ConnectionField(Ship)
 | 
					 | 
				
			||||||
#             @classmethod
 | 
					 | 
				
			||||||
#             def get_node(cls):
 | 
					 | 
				
			||||||
#                 pass
 | 
					 | 
				
			||||||
#             class Meta:
 | 
					 | 
				
			||||||
#                 schema = schema
 | 
					 | 
				
			||||||
#     assert 'same type_name' in str(excinfo.value)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,3 @@
 | 
				
			||||||
from pytest import raises
 | 
					 | 
				
			||||||
from graphql.core.type import (
 | 
					from graphql.core.type import (
 | 
				
			||||||
    GraphQLNonNull,
 | 
					    GraphQLNonNull,
 | 
				
			||||||
    GraphQLID
 | 
					    GraphQLID
 | 
				
			||||||
| 
						 | 
					@ -10,11 +9,6 @@ from graphene import relay
 | 
				
			||||||
schema = graphene.Schema()
 | 
					schema = graphene.Schema()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MyType(object):
 | 
					 | 
				
			||||||
    name = 'my'
 | 
					 | 
				
			||||||
    arg = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class MyConnection(relay.Connection):
 | 
					class MyConnection(relay.Connection):
 | 
				
			||||||
    my_custom_field = graphene.StringField(resolve=lambda instance, *_: 'Custom')
 | 
					    my_custom_field = graphene.StringField(resolve=lambda instance, *_: 'Custom')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +18,7 @@ class MyNode(relay.Node):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_node(cls, id):
 | 
					    def get_node(cls, id):
 | 
				
			||||||
        return MyNode(MyType())
 | 
					        return MyNode(name='mo')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					class Query(graphene.ObjectType):
 | 
				
			||||||
| 
						 | 
					@ -32,10 +26,9 @@ class Query(graphene.ObjectType):
 | 
				
			||||||
    all_my_nodes = relay.ConnectionField(MyNode, connection_type=MyConnection, customArg=graphene.Argument(graphene.String))
 | 
					    all_my_nodes = relay.ConnectionField(MyNode, connection_type=MyConnection, customArg=graphene.Argument(graphene.String))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def resolve_all_my_nodes(self, args, info):
 | 
					    def resolve_all_my_nodes(self, args, info):
 | 
				
			||||||
        t = MyType()
 | 
					 | 
				
			||||||
        custom_arg = args.get('customArg')
 | 
					        custom_arg = args.get('customArg')
 | 
				
			||||||
        assert custom_arg == "1"
 | 
					        assert custom_arg == "1"
 | 
				
			||||||
        return [MyNode(t)]
 | 
					        return [MyNode(name='my')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
schema.query = Query
 | 
					schema.query = Query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,7 +54,7 @@ def test_nodefield_query():
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    expected = {
 | 
					    expected = {
 | 
				
			||||||
        'myNode': {
 | 
					        'myNode': {
 | 
				
			||||||
            'name': 'my'
 | 
					            'name': 'mo'
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'allMyNodes': {
 | 
					        'allMyNodes': {
 | 
				
			||||||
            'edges': [{
 | 
					            'edges': [{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,77 +1,78 @@
 | 
				
			||||||
from collections import namedtuple
 | 
					humanData = {}
 | 
				
			||||||
 | 
					droidData = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Human = namedtuple('Human', 'id name friends appearsIn homePlanet')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
luke = Human(
 | 
					def setup():
 | 
				
			||||||
    id='1000',
 | 
					    from .schema import Human, Droid
 | 
				
			||||||
    name='Luke Skywalker',
 | 
					    global humanData, droidData
 | 
				
			||||||
    friends=['1002', '1003', '2000', '2001'],
 | 
					    luke = Human(
 | 
				
			||||||
    appearsIn=[4, 5, 6],
 | 
					        id='1000',
 | 
				
			||||||
    homePlanet='Tatooine',
 | 
					        name='Luke Skywalker',
 | 
				
			||||||
)
 | 
					        friends=['1002', '1003', '2000', '2001'],
 | 
				
			||||||
 | 
					        appears_in=[4, 5, 6],
 | 
				
			||||||
 | 
					        home_planet='Tatooine',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vader = Human(
 | 
					    vader = Human(
 | 
				
			||||||
    id='1001',
 | 
					        id='1001',
 | 
				
			||||||
    name='Darth Vader',
 | 
					        name='Darth Vader',
 | 
				
			||||||
    friends=['1004'],
 | 
					        friends=['1004'],
 | 
				
			||||||
    appearsIn=[4, 5, 6],
 | 
					        appears_in=[4, 5, 6],
 | 
				
			||||||
    homePlanet='Tatooine',
 | 
					        home_planet='Tatooine',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
han = Human(
 | 
					    han = Human(
 | 
				
			||||||
    id='1002',
 | 
					        id='1002',
 | 
				
			||||||
    name='Han Solo',
 | 
					        name='Han Solo',
 | 
				
			||||||
    friends=['1000', '1003', '2001'],
 | 
					        friends=['1000', '1003', '2001'],
 | 
				
			||||||
    appearsIn=[4, 5, 6],
 | 
					        appears_in=[4, 5, 6],
 | 
				
			||||||
    homePlanet=None,
 | 
					        home_planet=None,
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
leia = Human(
 | 
					    leia = Human(
 | 
				
			||||||
    id='1003',
 | 
					        id='1003',
 | 
				
			||||||
    name='Leia Organa',
 | 
					        name='Leia Organa',
 | 
				
			||||||
    friends=['1000', '1002', '2000', '2001'],
 | 
					        friends=['1000', '1002', '2000', '2001'],
 | 
				
			||||||
    appearsIn=[4, 5, 6],
 | 
					        appears_in=[4, 5, 6],
 | 
				
			||||||
    homePlanet='Alderaan',
 | 
					        home_planet='Alderaan',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tarkin = Human(
 | 
					    tarkin = Human(
 | 
				
			||||||
    id='1004',
 | 
					        id='1004',
 | 
				
			||||||
    name='Wilhuff Tarkin',
 | 
					        name='Wilhuff Tarkin',
 | 
				
			||||||
    friends=['1001'],
 | 
					        friends=['1001'],
 | 
				
			||||||
    appearsIn=[4],
 | 
					        appears_in=[4],
 | 
				
			||||||
    homePlanet=None,
 | 
					        home_planet=None,
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
humanData = {
 | 
					    humanData = {
 | 
				
			||||||
    '1000': luke,
 | 
					        '1000': luke,
 | 
				
			||||||
    '1001': vader,
 | 
					        '1001': vader,
 | 
				
			||||||
    '1002': han,
 | 
					        '1002': han,
 | 
				
			||||||
    '1003': leia,
 | 
					        '1003': leia,
 | 
				
			||||||
    '1004': tarkin,
 | 
					        '1004': tarkin,
 | 
				
			||||||
}
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Droid = namedtuple('Droid', 'id name friends appearsIn primaryFunction')
 | 
					    threepio = Droid(
 | 
				
			||||||
 | 
					        id='2000',
 | 
				
			||||||
 | 
					        name='C-3PO',
 | 
				
			||||||
 | 
					        friends=['1000', '1002', '1003', '2001'],
 | 
				
			||||||
 | 
					        appears_in=[4, 5, 6],
 | 
				
			||||||
 | 
					        primary_function='Protocol',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
threepio = Droid(
 | 
					    artoo = Droid(
 | 
				
			||||||
    id='2000',
 | 
					        id='2001',
 | 
				
			||||||
    name='C-3PO',
 | 
					        name='R2-D2',
 | 
				
			||||||
    friends=['1000', '1002', '1003', '2001'],
 | 
					        friends=['1000', '1002', '1003'],
 | 
				
			||||||
    appearsIn=[4, 5, 6],
 | 
					        appears_in=[4, 5, 6],
 | 
				
			||||||
    primaryFunction='Protocol',
 | 
					        primary_function='Astromech',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
artoo = Droid(
 | 
					    droidData = {
 | 
				
			||||||
    id='2001',
 | 
					        '2000': threepio,
 | 
				
			||||||
    name='R2-D2',
 | 
					        '2001': artoo,
 | 
				
			||||||
    friends=['1000', '1002', '1003'],
 | 
					    }
 | 
				
			||||||
    appearsIn=[4, 5, 6],
 | 
					 | 
				
			||||||
    primaryFunction='Astromech',
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
droidData = {
 | 
					 | 
				
			||||||
    '2000': threepio,
 | 
					 | 
				
			||||||
    '2001': artoo,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getCharacter(id):
 | 
					def getCharacter(id):
 | 
				
			||||||
| 
						 | 
					@ -84,8 +85,8 @@ def getFriends(character):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getHero(episode):
 | 
					def getHero(episode):
 | 
				
			||||||
    if episode == 5:
 | 
					    if episode == 5:
 | 
				
			||||||
        return luke
 | 
					        return humanData['1000']
 | 
				
			||||||
    return artoo
 | 
					    return droidData['2001']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getHuman(id):
 | 
					def getHuman(id):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ from graphql.core.type import GraphQLEnumValue
 | 
				
			||||||
import graphene
 | 
					import graphene
 | 
				
			||||||
from graphene import resolve_only_args
 | 
					from graphene import resolve_only_args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .data import getHero, getHuman, getCharacter, getDroid, Human as _Human, Droid as _Droid
 | 
					from .data import getHero, getHuman, getCharacter, getDroid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Episode = graphene.Enum('Episode', dict(
 | 
					Episode = graphene.Enum('Episode', dict(
 | 
				
			||||||
    NEWHOPE=GraphQLEnumValue(4),
 | 
					    NEWHOPE=GraphQLEnumValue(4),
 | 
				
			||||||
| 
						 | 
					@ -11,29 +11,23 @@ Episode = graphene.Enum('Episode', dict(
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def wrap_character(character):
 | 
					 | 
				
			||||||
    if isinstance(character, _Human):
 | 
					 | 
				
			||||||
        return Human(character)
 | 
					 | 
				
			||||||
    elif isinstance(character, _Droid):
 | 
					 | 
				
			||||||
        return Droid(character)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Character(graphene.Interface):
 | 
					class Character(graphene.Interface):
 | 
				
			||||||
    id = graphene.IDField()
 | 
					    id = graphene.IDField()
 | 
				
			||||||
    name = graphene.StringField()
 | 
					    name = graphene.StringField()
 | 
				
			||||||
    friends = graphene.ListField('self')
 | 
					    friends = graphene.ListField('self')
 | 
				
			||||||
    appearsIn = graphene.ListField(Episode)
 | 
					    appears_in = graphene.ListField(Episode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def resolve_friends(self, args, *_):
 | 
					    def resolve_friends(self, args, *_):
 | 
				
			||||||
        return [wrap_character(getCharacter(f)) for f in self.instance.friends]
 | 
					        # The character friends is a list of strings
 | 
				
			||||||
 | 
					        return [getCharacter(f) for f in self.friends]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Human(Character):
 | 
					class Human(Character):
 | 
				
			||||||
    homePlanet = graphene.StringField()
 | 
					    home_planet = graphene.StringField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Droid(Character):
 | 
					class Droid(Character):
 | 
				
			||||||
    primaryFunction = graphene.StringField()
 | 
					    primary_function = graphene.StringField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					class Query(graphene.ObjectType):
 | 
				
			||||||
| 
						 | 
					@ -52,15 +46,15 @@ class Query(graphene.ObjectType):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @resolve_only_args
 | 
					    @resolve_only_args
 | 
				
			||||||
    def resolve_hero(self, episode=None):
 | 
					    def resolve_hero(self, episode=None):
 | 
				
			||||||
        return wrap_character(getHero(episode))
 | 
					        return getHero(episode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @resolve_only_args
 | 
					    @resolve_only_args
 | 
				
			||||||
    def resolve_human(self, id):
 | 
					    def resolve_human(self, id):
 | 
				
			||||||
        return wrap_character(getHuman(id))
 | 
					        return getHuman(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @resolve_only_args
 | 
					    @resolve_only_args
 | 
				
			||||||
    def resolve_droid(self, id):
 | 
					    def resolve_droid(self, id):
 | 
				
			||||||
        return wrap_character(getDroid(id))
 | 
					        return getDroid(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Schema = graphene.Schema(query=Query)
 | 
					Schema = graphene.Schema(query=Query)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
from .schema import Schema, Query
 | 
					from .schema import Schema, Query
 | 
				
			||||||
from graphql.core import graphql
 | 
					from graphql.core import graphql
 | 
				
			||||||
 | 
					from .data import setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_hero_name_query():
 | 
					def test_hero_name_query():
 | 
				
			||||||
    query = '''
 | 
					    query = '''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ class Ship(DjangoNode):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@schema.register
 | 
					@schema.register
 | 
				
			||||||
class CharacterModel(DjangoObjectType):
 | 
					class Character(DjangoObjectType):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = CharacterModel
 | 
					        model = CharacterModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,78 +1,80 @@
 | 
				
			||||||
from collections import namedtuple
 | 
					data = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ship = namedtuple('Ship', ['id', 'name'])
 | 
					 | 
				
			||||||
Faction = namedtuple('Faction', ['id', 'name', 'ships'])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
xwing = Ship(
 | 
					def setup():
 | 
				
			||||||
    id='1',
 | 
					    global data
 | 
				
			||||||
    name='X-Wing',
 | 
					    
 | 
				
			||||||
)
 | 
					    from .schema import Ship, Faction
 | 
				
			||||||
 | 
					    xwing = Ship(
 | 
				
			||||||
 | 
					        id='1',
 | 
				
			||||||
 | 
					        name='X-Wing',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ywing = Ship(
 | 
					    ywing = Ship(
 | 
				
			||||||
    id='2',
 | 
					        id='2',
 | 
				
			||||||
    name='Y-Wing',
 | 
					        name='Y-Wing',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
awing = Ship(
 | 
					    awing = Ship(
 | 
				
			||||||
    id='3',
 | 
					        id='3',
 | 
				
			||||||
    name='A-Wing',
 | 
					        name='A-Wing',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Yeah, technically it's Corellian. But it flew in the service of the rebels,
 | 
					    # Yeah, technically it's Corellian. But it flew in the service of the rebels,
 | 
				
			||||||
# so for the purposes of this demo it's a rebel ship.
 | 
					    # so for the purposes of this demo it's a rebel ship.
 | 
				
			||||||
falcon = Ship(
 | 
					    falcon = Ship(
 | 
				
			||||||
    id='4',
 | 
					        id='4',
 | 
				
			||||||
    name='Millenium Falcon',
 | 
					        name='Millenium Falcon',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
homeOne = Ship(
 | 
					    homeOne = Ship(
 | 
				
			||||||
    id='5',
 | 
					        id='5',
 | 
				
			||||||
    name='Home One',
 | 
					        name='Home One',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tieFighter = Ship(
 | 
					    tieFighter = Ship(
 | 
				
			||||||
    id='6',
 | 
					        id='6',
 | 
				
			||||||
    name='TIE Fighter',
 | 
					        name='TIE Fighter',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tieInterceptor = Ship(
 | 
					    tieInterceptor = Ship(
 | 
				
			||||||
    id='7',
 | 
					        id='7',
 | 
				
			||||||
    name='TIE Interceptor',
 | 
					        name='TIE Interceptor',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
executor = Ship(
 | 
					    executor = Ship(
 | 
				
			||||||
    id='8',
 | 
					        id='8',
 | 
				
			||||||
    name='Executor',
 | 
					        name='Executor',
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rebels = Faction(
 | 
					    rebels = Faction(
 | 
				
			||||||
    id='1',
 | 
					        id='1',
 | 
				
			||||||
    name='Alliance to Restore the Republic',
 | 
					        name='Alliance to Restore the Republic',
 | 
				
			||||||
    ships=['1', '2', '3', '4', '5']
 | 
					        ships=['1', '2', '3', '4', '5']
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
empire = Faction(
 | 
					    empire = Faction(
 | 
				
			||||||
    id='2',
 | 
					        id='2',
 | 
				
			||||||
    name='Galactic Empire',
 | 
					        name='Galactic Empire',
 | 
				
			||||||
    ships=['6', '7', '8']
 | 
					        ships=['6', '7', '8']
 | 
				
			||||||
)
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data = {
 | 
					    data = {
 | 
				
			||||||
    'Faction': {
 | 
					        'Faction': {
 | 
				
			||||||
        '1': rebels,
 | 
					            '1': rebels,
 | 
				
			||||||
        '2': empire
 | 
					            '2': empire
 | 
				
			||||||
    },
 | 
					        },
 | 
				
			||||||
    'Ship': {
 | 
					        'Ship': {
 | 
				
			||||||
        '1': xwing,
 | 
					            '1': xwing,
 | 
				
			||||||
        '2': ywing,
 | 
					            '2': ywing,
 | 
				
			||||||
        '3': awing,
 | 
					            '3': awing,
 | 
				
			||||||
        '4': falcon,
 | 
					            '4': falcon,
 | 
				
			||||||
        '5': homeOne,
 | 
					            '5': homeOne,
 | 
				
			||||||
        '6': tieFighter,
 | 
					            '6': tieFighter,
 | 
				
			||||||
        '7': tieInterceptor,
 | 
					            '7': tieInterceptor,
 | 
				
			||||||
        '8': executor
 | 
					            '8': executor
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def createShip(shipName, factionId):
 | 
					def createShip(shipName, factionId):
 | 
				
			||||||
| 
						 | 
					@ -95,8 +97,8 @@ def getFaction(_id):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getRebels():
 | 
					def getRebels():
 | 
				
			||||||
    return rebels
 | 
					    return getFaction('1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getEmpire():
 | 
					def getEmpire():
 | 
				
			||||||
    return empire
 | 
					    return getFaction('2')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,29 +12,28 @@ schema = graphene.Schema(name='Starwars Relay 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.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_node(cls, id):
 | 
					    def get_node(cls, id):
 | 
				
			||||||
        return Ship(getShip(id))
 | 
					        return getShip(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Faction(relay.Node):
 | 
					class Faction(relay.Node):
 | 
				
			||||||
 | 
					 | 
				
			||||||
    '''A faction in the Star Wars saga'''
 | 
					    '''A faction in the Star Wars saga'''
 | 
				
			||||||
    name = graphene.StringField(description='The name of the faction.')
 | 
					    name = graphene.StringField(description='The name of the faction.')
 | 
				
			||||||
    ships = relay.ConnectionField(
 | 
					    ships = relay.ConnectionField(
 | 
				
			||||||
        Ship, description='The ships used by the faction.')
 | 
					        Ship, description='The ships used by the faction.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @resolve_only_args
 | 
					    @resolve_only_args
 | 
				
			||||||
    def resolve_ships(self, **kwargs):
 | 
					    def resolve_ships(self, **args):
 | 
				
			||||||
        return [Ship(getShip(ship)) for ship in self.instance.ships]
 | 
					        # Transform the instance ship_ids into real instances
 | 
				
			||||||
 | 
					        return [getShip(ship_id) for ship_id in self.ships]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_node(cls, id):
 | 
					    def get_node(cls, id):
 | 
				
			||||||
        return Faction(getFaction(id))
 | 
					        return getFaction(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					class Query(graphene.ObjectType):
 | 
				
			||||||
| 
						 | 
					@ -44,11 +43,11 @@ class Query(graphene.ObjectType):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @resolve_only_args
 | 
					    @resolve_only_args
 | 
				
			||||||
    def resolve_rebels(self):
 | 
					    def resolve_rebels(self):
 | 
				
			||||||
        return Faction(getRebels())
 | 
					        return getRebels()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @resolve_only_args
 | 
					    @resolve_only_args
 | 
				
			||||||
    def resolve_empire(self):
 | 
					    def resolve_empire(self):
 | 
				
			||||||
        return Faction(getEmpire())
 | 
					        return getEmpire()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
schema.query = Query
 | 
					schema.query = Query
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,61 +0,0 @@
 | 
				
			||||||
import graphene
 | 
					 | 
				
			||||||
from graphene import resolve_only_args, relay
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .data import (
 | 
					 | 
				
			||||||
    getHero, getHuman, getCharacter, getDroid,
 | 
					 | 
				
			||||||
    Human as _Human, Droid as _Droid)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Episode = graphene.Enum('Episode', dict(
 | 
					 | 
				
			||||||
    NEWHOPE=4,
 | 
					 | 
				
			||||||
    EMPIRE=5,
 | 
					 | 
				
			||||||
    JEDI=6
 | 
					 | 
				
			||||||
))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def wrap_character(character):
 | 
					 | 
				
			||||||
    if isinstance(character, _Human):
 | 
					 | 
				
			||||||
        return Human(character)
 | 
					 | 
				
			||||||
    elif isinstance(character, _Droid):
 | 
					 | 
				
			||||||
        return Droid(character)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Character(graphene.Interface):
 | 
					 | 
				
			||||||
    name = graphene.StringField()
 | 
					 | 
				
			||||||
    friends = relay.Connection('Character')
 | 
					 | 
				
			||||||
    appearsIn = graphene.ListField(Episode)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def resolve_friends(self, args, *_):
 | 
					 | 
				
			||||||
        return [wrap_character(getCharacter(f)) for f in self.instance.friends]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Human(relay.Node, Character):
 | 
					 | 
				
			||||||
    homePlanet = graphene.StringField()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Droid(relay.Node, Character):
 | 
					 | 
				
			||||||
    primaryFunction = graphene.StringField()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Query(graphene.ObjectType):
 | 
					 | 
				
			||||||
    hero = graphene.Field(Character,
 | 
					 | 
				
			||||||
                          episode=graphene.Argument(Episode))
 | 
					 | 
				
			||||||
    human = graphene.Field(Human,
 | 
					 | 
				
			||||||
                           id=graphene.Argument(graphene.String))
 | 
					 | 
				
			||||||
    droid = graphene.Field(Droid,
 | 
					 | 
				
			||||||
                           id=graphene.Argument(graphene.String))
 | 
					 | 
				
			||||||
    node = relay.NodeField()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @resolve_only_args
 | 
					 | 
				
			||||||
    def resolve_hero(self, episode):
 | 
					 | 
				
			||||||
        return wrap_character(getHero(episode))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @resolve_only_args
 | 
					 | 
				
			||||||
    def resolve_human(self, id):
 | 
					 | 
				
			||||||
        return wrap_character(getHuman(id))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @resolve_only_args
 | 
					 | 
				
			||||||
    def resolve_droid(self, id):
 | 
					 | 
				
			||||||
        return wrap_character(getDroid(id))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Schema = graphene.Schema(query=Query)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
from pytest import raises
 | 
					 | 
				
			||||||
from graphql.core import graphql
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .schema import schema
 | 
					from .schema import schema
 | 
				
			||||||
 | 
					from .data import setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_correct_fetch_first_ship_rebels():
 | 
					def test_correct_fetch_first_ship_rebels():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
from pytest import raises
 | 
					 | 
				
			||||||
from graphql.core import graphql
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .schema import schema
 | 
					from .schema import schema
 | 
				
			||||||
 | 
					from .data import setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_correctly_fetches_id_name_rebels():
 | 
					def test_correctly_fetches_id_name_rebels():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user