Initial work refactoring class Meta to class arguments.

Initial work refactoring class Meta to class arguments.

Refactoring firehose imports to explicit imports.
More blackening of example code.
More refactoring of `class Meta` into class arguments.
This commit is contained in:
changeling 2019-06-02 17:55:35 -05:00
parent 67c4310c78
commit eefcf40360
26 changed files with 319 additions and 317 deletions

View File

@ -106,10 +106,10 @@ leaner code and at most 4 database requests, and possibly fewer if there are cac
.. code:: python .. code:: python
class User(graphene.ObjectType): class User(ObjectType):
name = graphene.String() name = String()
best_friend = graphene.Field(lambda: User) best_friend = Field(lambda: User)
friends = graphene.List(lambda: User) friends = List(lambda: User)
def resolve_best_friend(self, info): def resolve_best_friend(self, info):
return user_loader.load(self.best_friend_id) return user_loader.load(self.best_friend_id)

View File

@ -7,8 +7,8 @@ For executing a query a schema, you can directly call the ``execute`` method on
.. code:: python .. code:: python
schema = graphene.Schema(...) schema = Schema(...)
result = schema.execute('{ name }') result = schema.execute("{ name }")
``result`` represents the result of execution. ``result.data`` is the result of executing the query, ``result.errors`` is ``None`` if no errors occurred, and is a non-empty list if an error occurred. ``result`` represents the result of execution. ``result.data`` is the result of executing the query, ``result.errors`` is ``None`` if no errors occurred, and is a non-empty list if an error occurred.
@ -21,14 +21,15 @@ You can pass context to a query via ``context``.
.. code:: python .. code:: python
class Query(graphene.ObjectType): class Query(ObjectType):
name = graphene.String() name = String()
def resolve_name(root, info): def resolve_name(root, info):
return info.context.get('name') return info.context.get("name")
schema = graphene.Schema(Query)
result = schema.execute('{ name }', context={'name': 'Syrus'}) schema = Schema(Query)
result = schema.execute("{ name }", context={"name": "Syrus"})
@ -40,22 +41,23 @@ You can pass variables to a query via ``variables``.
.. code:: python .. code:: python
class Query(graphene.ObjectType): class Query(ObjectType):
user = graphene.Field(User, id=graphene.ID(required=True)) user = Field(User, id=ID(required=True))
def resolve_user(root, info, id): def resolve_user(root, info, id):
return get_user_by_id(id) return get_user_by_id(id)
schema = graphene.Schema(Query)
schema = Schema(Query)
result = schema.execute( result = schema.execute(
''' """
query getUser($id: ID) { query getUser($id: ID) {
user(id: $id) { user(id: $id) {
id id
firstName firstName
lastName lastName
} }
} }
''', """,
variables={'id': 12}, variables={"id": 12},
) )

View File

@ -12,7 +12,7 @@ Lets build a basic GraphQL schema from scratch.
Requirements Requirements
------------ ------------
- Python (2.7, 3.4, 3.5, 3.6, pypy) - Python (3.6+, pypy)
- Graphene (2.0) - Graphene (2.0)
Project setup Project setup
@ -35,15 +35,17 @@ one field: ``hello`` and an input name. And when we query it, it should return `
.. code:: python .. code:: python
import graphene from graphene import ObjectType, Schema, String
class Query(graphene.ObjectType):
hello = graphene.String(argument=graphene.String(default_value="stranger")) class Query(ObjectType):
hello = String(argument=String(default_value="stranger"))
def resolve_hello(self, info, argument): def resolve_hello(self, info, argument):
return 'Hello ' + argument return f"Hello {argument}"
schema = graphene.Schema(query=Query)
schema = Schema(query=Query)
Querying Querying
-------- --------
@ -52,11 +54,11 @@ Then we can start querying our schema:
.. code:: python .. code:: python
result = schema.execute('{ hello }') result = schema.execute("{ hello }")
print(result.data['hello']) # "Hello stranger" print(result.data["hello"]) # "Hello stranger"
# or passing the argument in the query # or passing the argument in the query
result = schema.execute('{ hello (argument: "graph") }') result = schema.execute('{ hello (argument: "graph") }')
print(result.data['hello']) # "Hello graph" print(result.data["hello"]) # "Hello graph"
Congrats! You got your first graphene schema working! Congrats! You got your first graphene schema working!

View File

@ -16,12 +16,9 @@ and ``other`` an extra field in the Connection Edge.
.. code:: python .. code:: python
class ShipConnection(Connection): class ShipConnection(Connection, node=Ship):
extra = String() extra = String()
class Meta:
node = Ship
class Edge: class Edge:
other = String() other = String()
@ -37,8 +34,8 @@ that implements ``Node`` will have a default Connection.
.. code:: python .. code:: python
class Faction(graphene.ObjectType): class Faction(ObjectType):
name = graphene.String() name = String()
ships = relay.ConnectionField(ShipConnection) ships = relay.ConnectionField(ShipConnection)
def resolve_ships(self, info): def resolve_ships(self, info):

View File

@ -12,13 +12,12 @@ subclass of ``relay.ClientIDMutation``.
.. code:: python .. code:: python
class IntroduceShip(relay.ClientIDMutation): class IntroduceShip(relay.ClientIDMutation):
class Input: class Input:
ship_name = graphene.String(required=True) ship_name = String(required=True)
faction_id = graphene.String(required=True) faction_id = String(required=True)
ship = graphene.Field(Ship) ship = Field(Ship)
faction = graphene.Field(Faction) faction = Field(Faction)
@classmethod @classmethod
def mutate_and_get_payload(cls, root, info, **input): def mutate_and_get_payload(cls, root, info, **input):
@ -28,8 +27,6 @@ subclass of ``relay.ClientIDMutation``.
faction = get_faction(faction_id) faction = get_faction(faction_id)
return IntroduceShip(ship=ship, faction=faction) return IntroduceShip(ship=ship, faction=faction)
Accepting Files Accepting Files
--------------- ---------------
@ -37,13 +34,13 @@ Mutations can also accept files, that's how it will work with different integrat
.. code:: python .. code:: python
class UploadFile(graphene.ClientIDMutation): class UploadFile(ClientIDMutation):
class Input: class Input:
pass pass
# nothing needed for uploading file # nothing needed for uploading file
# your return fields # your return fields
success = graphene.String() success = String()
@classmethod @classmethod
def mutate_and_get_payload(cls, root, info, **input): def mutate_and_get_payload(cls, root, info, **input):

View File

@ -14,12 +14,10 @@ Example usage (taken from the `Starwars Relay example`_):
.. code:: python .. code:: python
class Ship(graphene.ObjectType): class Ship(ObjectType, interfaces=(relay.Node,)):
'''A ship in the Star Wars saga''' """A ship in the Star Wars saga"""
class Meta:
interfaces = (relay.Node, )
name = graphene.String(description='The name of the ship.') name = String(description="The name of the ship.")
@classmethod @classmethod
def get_node(cls, info, id): def get_node(cls, info, id):
@ -45,26 +43,22 @@ Example of a custom node:
.. code:: python .. code:: python
class CustomNode(Node): class CustomNode(Node, name="Node"):
class Meta:
name = 'Node'
@staticmethod @staticmethod
def to_global_id(type, id): def to_global_id(type, id):
return '{}:{}'.format(type, id) return "{}:{}".format(type, id)
@staticmethod @staticmethod
def get_node_from_global_id(info, global_id, only_type=None): def get_node_from_global_id(info, global_id, only_type=None):
type, id = global_id.split(':') type, id = global_id.split(":")
if only_type: if only_type:
# We assure that the node type that we want to retrieve # We assure that the node type that we want to retrieve
# is the same that was indicated in the field type # is the same that was indicated in the field type
assert type == only_type._meta.name, 'Received not compatible node.' assert type == only_type._meta.name, "Received not compatible node."
if type == 'User': if type == "User":
return get_user(id) return get_user(id)
elif type == 'Photo': elif type == "Photo":
return get_photo(id) return get_photo(id)
@ -94,7 +88,7 @@ Example usage:
.. code:: python .. code:: python
class Query(graphene.ObjectType): class Query(ObjectType):
# Should be CustomNode.Field() if we want to use our custom Node # Should be CustomNode.Field() if we want to use our custom Node
node = relay.Node.Field() node = relay.Node.Field()

View File

@ -40,14 +40,11 @@ To use the test client, instantiate ``graphene.test.Client`` and retrieve GraphQ
from graphene.test import Client from graphene.test import Client
def test_hey(): def test_hey():
client = Client(my_schema) client = Client(my_schema)
executed = client.execute('''{ hey }''') executed = client.execute("""{ hey }""")
assert executed == { assert executed == {"data": {"hey": "hello!"}}
'data': {
'hey': 'hello!'
}
}
Execute parameters Execute parameters
@ -61,14 +58,11 @@ You can also add extra keyword arguments to the ``execute`` method, such as
from graphene.test import Client from graphene.test import Client
def test_hey(): def test_hey():
client = Client(my_schema) client = Client(my_schema)
executed = client.execute('''{ hey }''', context={'user': 'Peter'}) executed = client.execute("""{ hey }""", context={"user": "Peter"})
assert executed == { assert executed == {"data": {"hey": "hello Peter!"}}
'data': {
'hey': 'hello Peter!'
}
}
Snapshot testing Snapshot testing
@ -95,7 +89,7 @@ Here is a simple example on how our tests will look if we use ``pytest``:
# This will create a snapshot dir and a snapshot file # This will create a snapshot dir and a snapshot file
# the first time the test is executed, with the response # the first time the test is executed, with the response
# of the execution. # of the execution.
snapshot.assert_match(client.execute('''{ hey }''')) snapshot.assert_match(client.execute("""{ hey }"""))
If we are using ``unittest``: If we are using ``unittest``:
@ -104,8 +98,9 @@ If we are using ``unittest``:
from snapshottest import TestCase from snapshottest import TestCase
class APITestCase(TestCase): class APITestCase(TestCase):
def test_api_me(self): def test_api_me(self):
"""Testing the API for /me""" """Testing the API for /me"""
client = Client(my_schema) client = Client(my_schema)
self.assertMatchSnapshot(client.execute('''{ hey }''')) self.assertMatchSnapshot(client.execute("""{ hey }"""))

View File

@ -20,17 +20,19 @@ plus the ones defined in ``UserFields``.
.. code:: python .. code:: python
import graphene from graphene import AbstractType, ObjectType, InputObjectType, String
class UserFields(graphene.AbstractType):
name = graphene.String()
class User(graphene.ObjectType, UserFields): class UserFields(AbstractType):
name = String()
class User(ObjectType, UserFields):
pass pass
class UserInput(graphene.InputObjectType, UserFields):
pass
class UserInput(InputObjectType, UserFields):
pass
.. code:: .. code::

View File

@ -11,9 +11,10 @@ You can create an ``Enum`` using classes:
.. code:: python .. code:: python
import graphene from graphene import Enum
class Episode(graphene.Enum):
class Episode(Enum):
NEWHOPE = 4 NEWHOPE = 4
EMPIRE = 5 EMPIRE = 5
JEDI = 6 JEDI = 6
@ -22,7 +23,7 @@ But also using instances of Enum:
.. code:: python .. code:: python
Episode = graphene.Enum('Episode', [('NEWHOPE', 4), ('EMPIRE', 5), ('JEDI', 6)]) Episode = Enum("Episode", [("NEWHOPE", 4), ("EMPIRE", 5), ("JEDI", 6)])
Value descriptions Value descriptions
------------------ ------------------
@ -32,7 +33,7 @@ needs to have the ``description`` property on it.
.. code:: python .. code:: python
class Episode(graphene.Enum): class Episode(Enum):
NEWHOPE = 4 NEWHOPE = 4
EMPIRE = 5 EMPIRE = 5
JEDI = 6 JEDI = 6
@ -40,9 +41,8 @@ needs to have the ``description`` property on it.
@property @property
def description(self): def description(self):
if self == Episode.NEWHOPE: if self == Episode.NEWHOPE:
return 'New Hope Episode' return "New Hope Episode"
return 'Other episode' return "Other episode"
Usage with Python Enums Usage with Python Enums
----------------------- -----------------------
@ -52,16 +52,16 @@ the ``Enum.from_enum`` function.
.. code:: python .. code:: python
graphene.Enum.from_enum(AlreadyExistingPyEnum) Enum.from_enum(AlreadyExistingPyEnum)
``Enum.from_enum`` supports a ``description`` and ``deprecation_reason`` lambdas as input so ``Enum.from_enum`` supports a ``description`` and ``deprecation_reason`` lambdas as input so
you can add description etc. to your enum without changing the original: you can add description etc. to your enum without changing the original:
.. code:: python .. code:: python
graphene.Enum.from_enum( Enum.from_enum(
AlreadyExistingPyEnum, AlreadyExistingPyEnum,
description=lambda v: return 'foo' if v == AlreadyExistingPyEnum.Foo else 'bar') description=lambda v: return "foo" if v == AlreadyExistingPyEnum.Foo else "bar")
Notes Notes
@ -76,19 +76,23 @@ In the Python ``Enum`` implementation you can access a member by initing the Enu
.. code:: python .. code:: python
from enum import Enum from enum import Enum
class Color(Enum): class Color(Enum):
RED = 1 RED = 1
GREEN = 2 GREEN = 2
BLUE = 3 BLUE = 3
assert Color(1) == Color.RED
assert Color(1) == Color.RED
However, in Graphene ``Enum`` you need to call get to have the same effect: However, in Graphene ``Enum`` you need to call get to have the same effect:
.. code:: python .. code:: python
from graphene import Enum from graphene import Enum
class Color(Enum): class Color(Enum):
RED = 1 RED = 1
GREEN = 2 GREEN = 2

View File

@ -9,12 +9,13 @@ character in the Star Wars trilogy:
.. code:: python .. code:: python
import graphene from graphene import ID, Interface, String, List
class Character(graphene.Interface):
id = graphene.ID(required=True) class Character(Interface):
name = graphene.String(required=True) id = ID(required=True)
friends = graphene.List(lambda: Character) name = String(required=True)
friends = List(lambda: Character)
Any ObjectType that implements ``Character`` will have these exact fields, with Any ObjectType that implements ``Character`` will have these exact fields, with
@ -24,19 +25,13 @@ For example, here are some types that might implement ``Character``:
.. code:: python .. code:: python
class Human(graphene.ObjectType): class Human(ObjectType, interfaces=(Character,)):
class Meta: starships = List(Starship)
interfaces = (Character, ) home_planet = String()
starships = graphene.List(Starship)
home_planet = graphene.String()
class Droid(graphene.ObjectType):
class Meta:
interfaces = (Character, )
primary_function = graphene.String()
class Droid(ObjectType, interfaces=(Character,)):
primary_function = String()
Both of these types have all of the fields from the ``Character`` interface, Both of these types have all of the fields from the ``Character`` interface,
but also bring in extra fields, ``home_planet``, ``starships`` and but also bring in extra fields, ``home_planet``, ``starships`` and
@ -75,20 +70,17 @@ For example, you can define a field ``hero`` that resolves to any
.. code:: python .. code:: python
class Query(graphene.ObjectType): class Query(ObjectType):
hero = graphene.Field( hero = Field(Character, required=True, episode=Int(required=True))
Character,
required=True,
episode=graphene.Int(required=True)
)
def resolve_hero(_, info, episode): def resolve_hero(root, info, episode):
# Luke is the hero of Episode V # Luke is the hero of Episode V
if episode == 5: if episode == 5:
return get_human(name='Luke Skywalker') return get_human(name="Luke Skywalker")
return get_droid(name='R2-D2') return get_droid(name="R2-D2")
schema = graphene.Schema(query=Query, types=[Human, Droid])
schema = Schema(query=Query, types=[Human, Droid])
This allows you to directly query for fields that exist on the Character interface This allows you to directly query for fields that exist on the Character interface
as well as selecting specific fields on any type that implements the interface as well as selecting specific fields on any type that implements the interface
@ -159,12 +151,12 @@ maps a data object to a Graphene type:
.. code:: python .. code:: python
class Character(graphene.Interface): class Character(Interface):
id = graphene.ID(required=True) id = ID(required=True)
name = graphene.String(required=True) name = String(required=True)
@classmethod @classmethod
def resolve_type(cls, instance, info): def resolve_type(cls, instance, info):
if instance.type == 'DROID': if instance.type == "DROID":
return Droid return Droid
return Human return Human

View File

@ -11,11 +11,11 @@ NonNull
.. code:: python .. code:: python
import graphene from graphene import ObjectType, NonNull, String
class Character(graphene.ObjectType):
name = graphene.NonNull(graphene.String)
class Character(ObjectType):
name = NonNull(String)
Here, we're using a ``String`` type and marking it as Non-Null by wrapping Here, we're using a ``String`` type and marking it as Non-Null by wrapping
it using the ``NonNull`` class. This means that our server always expects it using the ``NonNull`` class. This means that our server always expects
@ -28,21 +28,22 @@ The previous ``NonNull`` code snippet is also equivalent to:
.. code:: python .. code:: python
import graphene from graphene import ObjectType, String
class Character(graphene.ObjectType):
name = graphene.String(required=True)
class Character(ObjectType):
name = String(required=True)
List List
---- ----
.. code:: python .. code:: python
import graphene from graphene import ObjectType, List, String
class Character(graphene.ObjectType):
appears_in = graphene.List(graphene.String) class Character(ObjectType):
appears_in = List(String)
Lists work in a similar way: We can use a type modifier to mark a type as a Lists work in a similar way: We can use a type modifier to mark a type as a
``List``, which indicates that this field will return a list of that type. ``List``, which indicates that this field will return a list of that type.
@ -57,10 +58,11 @@ any nullable items the type needs to be marked as ``NonNull``. For example:
.. code:: python .. code:: python
import graphene from graphene import ObjectType, List, NonNull, String
class Character(graphene.ObjectType):
appears_in = graphene.List(graphene.NonNull(graphene.String)) class Character(ObjectType):
appears_in = List(NonNull(String))
The above results in the type definition: The above results in the type definition:

View File

@ -10,14 +10,15 @@ This example defines a Mutation:
.. code:: python .. code:: python
import graphene from graphene import Mutation, String, Boolean, Field
class CreatePerson(graphene.Mutation):
class CreatePerson(Mutation):
class Arguments: class Arguments:
name = graphene.String() name = String()
ok = graphene.Boolean() ok = Boolean()
person = graphene.Field(lambda: Person) person = Field(lambda: Person)
def mutate(self, info, name): def mutate(self, info, name):
person = Person(name=name) person = Person(name=name)
@ -38,20 +39,37 @@ So, we can finish our schema like this:
.. code:: python .. code:: python
# ... the Mutation Class from graphene import ObjectType, Mutation, String, Boolean, Field, Int, Schema
class Person(graphene.ObjectType):
name = graphene.String()
age = graphene.Int()
class MyMutations(graphene.ObjectType): class Person(ObjectType):
name = String()
age = Int()
class CreatePerson(Mutation):
class Arguments:
name = String()
ok = Boolean()
person = Field(lambda: Person)
def mutate(self, info, name):
person = Person(name=name)
ok = True
return CreatePerson(person=person, ok=ok)
class MyMutations(ObjectType):
create_person = CreatePerson.Field() create_person = CreatePerson.Field()
# We must define a query for our schema
class Query(graphene.ObjectType):
person = graphene.Field(Person)
schema = graphene.Schema(query=Query, mutation=MyMutations) # We must define a query for our schema
class Query(ObjectType):
person = Field(Person)
schema = Schema(query=Query, mutation=MyMutations)
Executing the Mutation Executing the Mutation
---------------------- ----------------------
@ -91,27 +109,25 @@ To use an InputField you define an InputObjectType that specifies the structure
.. code:: python .. code:: python
import graphene from graphene import InputObjectType, Mutation, String, Field, Int
class PersonInput(graphene.InputObjectType):
name = graphene.String(required=True)
age = graphene.Int(required=True)
class CreatePerson(graphene.Mutation): class PersonInput(InputObjectType):
name = String(required=True)
age = Int(required=True)
class CreatePerson(Mutation):
class Arguments: class Arguments:
person_data = PersonInput(required=True) person_data = PersonInput(required=True)
person = graphene.Field(Person) person = Field(Person)
@staticmethod @staticmethod
def mutate(root, info, person_data=None): def mutate(root, info, person_data=None):
person = Person( person = Person(name=person_data.name, age=person_data.age)
name=person_data.name,
age=person_data.age
)
return CreatePerson(person=person) return CreatePerson(person=person)
Note that **name** and **age** are part of **person_data** now Note that **name** and **age** are part of **person_data** now
Using the above mutation your new query would look like this: Using the above mutation your new query would look like this:
@ -132,16 +148,18 @@ as complex of input data as you need
.. code:: python .. code:: python
import graphene from graphene import InputObjectType, InputField, Float, String
class LatLngInput(graphene.InputObjectType):
lat = graphene.Float()
lng = graphene.Float()
#A location has a latlng associated to it class LatLngInput(InputObjectType):
class LocationInput(graphene.InputObjectType): lat = Float()
name = graphene.String() lng = Float()
latlng = graphene.InputField(LatLngInput)
# A location has a latlng associated to it
class LocationInput(InputObjectType):
name = String()
latlng = InputField(LatLngInput)
Output type example Output type example
------------------- -------------------
@ -149,11 +167,12 @@ To return an existing ObjectType instead of a mutation-specific type, set the **
.. code:: python .. code:: python
import graphene from graphene import Mutation, String
class CreatePerson(graphene.Mutation):
class CreatePerson(Mutation):
class Arguments: class Arguments:
name = graphene.String() name = String()
Output = Person Output = Person

View File

@ -18,15 +18,16 @@ This example model defines a Person, with a first and a last name:
.. code:: python .. code:: python
import graphene from graphene import ObjectType, String
class Person(graphene.ObjectType):
first_name = graphene.String() class Person(ObjectType):
last_name = graphene.String() first_name = String()
full_name = graphene.String() last_name = String()
full_name = String()
def resolve_full_name(root, info): def resolve_full_name(root, info):
return '{} {}'.format(root.first_name, root.last_name) return "{} {}".format(root.first_name, root.last_name)
**first\_name** and **last\_name** are fields of the ObjectType. Each **first\_name** and **last\_name** are fields of the ObjectType. Each
field is specified as a class attribute, and each attribute maps to a field is specified as a class attribute, and each attribute maps to a
@ -62,25 +63,24 @@ passed to the ``ObjectType``.
.. code:: python .. code:: python
import graphene from graphene import ObjectType, Field, String
class Person(graphene.ObjectType):
first_name = graphene.String()
last_name = graphene.String()
class Query(graphene.ObjectType): class Person(ObjectType):
me = graphene.Field(Person) first_name = String()
best_friend = graphene.Field(Person) last_name = String()
class Query(ObjectType):
me = Field(Person)
best_friend = Field(Person)
def resolve_me(_, info): def resolve_me(_, info):
# returns an object that represents a Person # returns an object that represents a Person
return get_human(name='Luke Skywalker') return get_human(name="Luke Skywalker")
def resolve_best_friend(_, info): def resolve_best_friend(root, info):
return { return {"first_name": "R2", "last_name": "D2"}
"first_name": "R2",
"last_name": "D2",
}
Resolvers with arguments Resolvers with arguments
@ -91,10 +91,11 @@ kwargs. For example:
.. code:: python .. code:: python
import graphene from graphene import ObjectType, Field, String
class Query(graphene.ObjectType):
human_by_name = graphene.Field(Human, name=graphene.String(required=True)) class Query(ObjectType):
human_by_name = Field(Human, name=String(required=True))
def resolve_human_by_name(_, info, name): def resolve_human_by_name(_, info, name):
return get_human(name=name) return get_human(name=name)
@ -119,10 +120,11 @@ For example, given this schema:
.. code:: python .. code:: python
import graphene from graphene import ObjectType, String
class Query(graphene.ObjectType):
hello = graphene.String(required=True, name=graphene.String()) class Query(ObjectType):
hello = String(required=True, name=String())
def resolve_hello(_, info, name): def resolve_hello(_, info, name):
return name if name else 'World' return name if name else 'World'
@ -146,8 +148,8 @@ into a dict:
.. code:: python .. code:: python
class Query(graphene.ObjectType): class Query(ObjectType):
hello = graphene.String(required=True, name=graphene.String()) hello = String(required=True, name=String())
def resolve_hello(_, info, **args): def resolve_hello(_, info, **args):
return args.get('name', 'World') return args.get('name', 'World')
@ -156,8 +158,8 @@ Or by setting a default value for the keyword argument:
.. code:: python .. code:: python
class Query(graphene.ObjectType): class Query(ObjectType):
hello = graphene.String(required=True, name=graphene.String()) hello = String(required=True, name=String())
def resolve_hello(_, info, name='World'): def resolve_hello(_, info, name='World'):
return name return name
@ -170,15 +172,15 @@ A field can use a custom resolver from outside the class:
.. code:: python .. code:: python
import graphene from graphene import ObjectType, String
def resolve_full_name(person, info): def resolve_full_name(person, info):
return '{} {}'.format(person.first_name, person.last_name) return '{} {}'.format(person.first_name, person.last_name)
class Person(graphene.ObjectType): class Person(ObjectType):
first_name = graphene.String() first_name = String()
last_name = graphene.String() last_name = String()
full_name = graphene.String(resolver=resolve_full_name) full_name = String(resolver=resolve_full_name)
Instances as data containers Instances as data containers
@ -203,8 +205,7 @@ property on the ``Meta`` class:
.. code:: python .. code:: python
class MyGraphQlSong(graphene.ObjectType): class MyGraphQlSong(ObjectType, name="Song"):
class Meta: pass
name = 'Song'
.. _Interface: /docs/interfaces/ .. _Interface: /docs/interfaces/

View File

@ -91,8 +91,9 @@ The following is an example for creating a DateTime scalar:
from graphene.types import Scalar from graphene.types import Scalar
from graphql.language import ast from graphql.language import ast
class DateTime(Scalar): class DateTime(Scalar):
'''DateTime Scalar Description''' """DateTime Scalar Description"""
@staticmethod @staticmethod
def serialize(dt): def serialize(dt):
@ -101,8 +102,7 @@ The following is an example for creating a DateTime scalar:
@staticmethod @staticmethod
def parse_literal(node): def parse_literal(node):
if isinstance(node, ast.StringValue): if isinstance(node, ast.StringValue):
return datetime.datetime.strptime( return datetime.datetime.strptime(node.value, "%Y-%m-%dT%H:%M:%S.%f")
node.value, "%Y-%m-%dT%H:%M:%S.%f")
@staticmethod @staticmethod
def parse_value(value): def parse_value(value):
@ -116,13 +116,15 @@ Scalars mounted in a ``ObjectType``, ``Interface`` or ``Mutation`` act as
.. code:: python .. code:: python
class Person(graphene.ObjectType): from graphene import ObjectType, Field, String
name = graphene.String()
class Person(ObjectType):
name = String()
# Is equivalent to: # Is equivalent to:
class Person(graphene.ObjectType): class Person(ObjectType):
name = graphene.Field(graphene.String) name = Field(String)
**Note:** when using the ``Field`` constructor directly, pass the type and **Note:** when using the ``Field`` constructor directly, pass the type and
not an instance. not an instance.
@ -132,7 +134,7 @@ Types mounted in a ``Field`` act as ``Argument``\ s.
.. code:: python .. code:: python
graphene.Field(graphene.String, to=graphene.String()) Field(String, to=String())
# Is equivalent to: # Is equivalent to:
graphene.Field(graphene.String, to=graphene.Argument(graphene.String)) Field(String, to=Argument(String))

View File

@ -37,7 +37,7 @@ To query a schema, call the ``execute`` method on it.
.. code:: python .. code:: python
my_schema.execute('{ lastName }') my_schema.execute("{ lastName }")
Auto CamelCase field names Auto CamelCase field names
@ -51,9 +51,9 @@ For example with the ObjectType
.. code:: python .. code:: python
class Person(graphene.ObjectType): class Person(ObjectType):
last_name = graphene.String() last_name = String()
other_name = graphene.String(name='_other_Name') other_name = String(name="_other_Name")
the ``last_name`` field name is converted to ``lastName``. the ``last_name`` field name is converted to ``lastName``.

View File

@ -17,23 +17,26 @@ This example model defines several ObjectTypes with their own fields.
.. code:: python .. code:: python
import graphene from graphene import ObjectType, String, Int, Union
class Human(graphene.ObjectType):
name = graphene.String()
born_in = graphene.String()
class Droid(graphene.ObjectType): class Human(ObjectType):
name = graphene.String() name = String()
primary_function = graphene.String() born_in = String()
class Starship(graphene.ObjectType):
name = graphene.String()
length = graphene.Int()
class SearchResult(graphene.Union): class Droid(ObjectType):
class Meta: name = String()
types = (Human, Droid, Starship) primary_function = String()
class Starship(ObjectType):
name = String()
length = Int()
class SearchResult(Union, types=(Human, Droid, Starship)):
pass
Wherever we return a SearchResult type in our schema, we might get a Human, a Droid, or a Starship. Wherever we return a SearchResult type in our schema, we might get a Human, a Droid, or a Starship.

View File

@ -1,21 +1,24 @@
from graphene import InputObjectType, Float, ObjectType, String, Field, Schema
# Naming confusion/conflict with class Mutation and explicit import of graphene.mutation.
import graphene import graphene
class GeoInput(graphene.InputObjectType): class GeoInput(InputObjectType):
lat = graphene.Float(required=True) lat = Float(required=True)
lng = graphene.Float(required=True) lng = Float(required=True)
@property @property
def latlng(self): def latlng(self):
return "({},{})".format(self.lat, self.lng) return "({},{})".format(self.lat, self.lng)
class Address(graphene.ObjectType): class Address(ObjectType):
latlng = graphene.String() latlng = String()
class Query(graphene.ObjectType): class Query(ObjectType):
address = graphene.Field(Address, geo=GeoInput(required=True)) address = Field(Address, geo=GeoInput(required=True))
def resolve_address(self, info, geo): def resolve_address(self, info, geo):
return Address(latlng=geo.latlng) return Address(latlng=geo.latlng)
@ -31,11 +34,11 @@ class CreateAddress(graphene.Mutation):
return Address(latlng=geo.latlng) return Address(latlng=geo.latlng)
class Mutation(graphene.ObjectType): class Mutation(ObjectType):
create_address = CreateAddress.Field() create_address = CreateAddress.Field()
schema = graphene.Schema(query=Query, mutation=Mutation) schema = Schema(query=Query, mutation=Mutation)
query = """ query = """
query something{ query something{
address(geo: {lat:32.2, lng:12}) { address(geo: {lat:32.2, lng:12}) {

View File

@ -1,19 +1,19 @@
import graphene from graphene import ObjectType, ID, String, Field, Schema
class User(graphene.ObjectType): class User(ObjectType):
id = graphene.ID() id = ID()
name = graphene.String() name = String()
class Query(graphene.ObjectType): class Query(ObjectType):
me = graphene.Field(User) me = Field(User)
def resolve_me(self, info): def resolve_me(self, info):
return info.context["user"] return info.context["user"]
schema = graphene.Schema(query=Query) schema = Schema(query=Query)
query = """ query = """
query something{ query something{
me { me {

View File

@ -1,21 +1,21 @@
import graphene from graphene import ObjectType, ID, String, Int, Field, Schema
class Patron(graphene.ObjectType): class Patron(ObjectType):
id = graphene.ID() id = ID()
name = graphene.String() name = String()
age = graphene.Int() age = Int()
class Query(graphene.ObjectType): class Query(ObjectType):
patron = graphene.Field(Patron) patron = Field(Patron)
def resolve_patron(self, info): def resolve_patron(self, info):
return Patron(id=1, name="Syrus", age=27) return Patron(id=1, name="Syrus", age=27)
schema = graphene.Schema(query=Query) schema = Schema(query=Query)
query = """ query = """
query something{ query something{
patron { patron {

View File

@ -1,43 +1,37 @@
import graphene from graphene import Enum, Interface, ID, List, ObjectType, String, Field, Schema
from .data import get_character, get_droid, get_hero, get_human from .data import get_character, get_droid, get_hero, get_human
class Episode(graphene.Enum): class Episode(Enum):
NEWHOPE = 4 NEWHOPE = 4
EMPIRE = 5 EMPIRE = 5
JEDI = 6 JEDI = 6
class Character(graphene.Interface): class Character(Interface):
id = graphene.ID() id = ID()
name = graphene.String() name = String()
friends = graphene.List(lambda: Character) friends = List(lambda: Character)
appears_in = graphene.List(Episode) appears_in = List(Episode)
def resolve_friends(self, info): def resolve_friends(self, info):
# The character friends is a list of strings # The character friends is a list of strings
return [get_character(f) for f in self.friends] return [get_character(f) for f in self.friends]
class Human(graphene.ObjectType): class Human(ObjectType, interfaces=(Character,)):
class Meta: home_planet = String()
interfaces = (Character,)
home_planet = graphene.String()
class Droid(graphene.ObjectType): class Droid(ObjectType, interfaces=(Character,)):
class Meta: primary_function = String()
interfaces = (Character,)
primary_function = graphene.String()
class Query(graphene.ObjectType): class Query(ObjectType):
hero = graphene.Field(Character, episode=Episode()) hero = Field(Character, episode=Episode())
human = graphene.Field(Human, id=graphene.String()) human = Field(Human, id=String())
droid = graphene.Field(Droid, id=graphene.String()) droid = Field(Droid, id=String())
def resolve_hero(self, info, episode=None): def resolve_hero(self, info, episode=None):
return get_hero(episode) return get_hero(episode)
@ -49,4 +43,4 @@ class Query(graphene.ObjectType):
return get_droid(id) return get_droid(id)
schema = graphene.Schema(query=Query) schema = Schema(query=Query)

View File

@ -1,34 +1,27 @@
import graphene from graphene import ObjectType, Schema, Field, String
from graphene import relay from graphene import relay
from .data import create_ship, get_empire, get_faction, get_rebels, get_ship from .data import create_ship, get_empire, get_faction, get_rebels, get_ship
class Ship(graphene.ObjectType): class Ship(ObjectType, interfaces=(relay.Node,)):
"""A ship in the Star Wars saga""" """A ship in the Star Wars saga."""
class Meta: name = String(description="The name of the ship.")
interfaces = (relay.Node,)
name = graphene.String(description="The name of the ship.")
@classmethod @classmethod
def get_node(cls, info, id): def get_node(cls, info, id):
return get_ship(id) return get_ship(id)
class ShipConnection(relay.Connection): class ShipConnection(relay.Connection, node=Ship):
class Meta: pass
node = Ship
class Faction(graphene.ObjectType): class Faction(ObjectType, interfaces=(relay.Node,)):
"""A faction in the Star Wars saga""" """A faction in the Star Wars saga."""
class Meta: name = String(description="The name of the faction.")
interfaces = (relay.Node,)
name = graphene.String(description="The name of the faction.")
ships = relay.ConnectionField( ships = relay.ConnectionField(
ShipConnection, description="The ships used by the faction." ShipConnection, description="The ships used by the faction."
) )
@ -44,11 +37,11 @@ class Faction(graphene.ObjectType):
class IntroduceShip(relay.ClientIDMutation): class IntroduceShip(relay.ClientIDMutation):
class Input: class Input:
ship_name = graphene.String(required=True) ship_name = String(required=True)
faction_id = graphene.String(required=True) faction_id = String(required=True)
ship = graphene.Field(Ship) ship = Field(Ship)
faction = graphene.Field(Faction) faction = Field(Faction)
@classmethod @classmethod
def mutate_and_get_payload( def mutate_and_get_payload(
@ -59,9 +52,9 @@ class IntroduceShip(relay.ClientIDMutation):
return IntroduceShip(ship=ship, faction=faction) return IntroduceShip(ship=ship, faction=faction)
class Query(graphene.ObjectType): class Query(ObjectType):
rebels = graphene.Field(Faction) rebels = Field(Faction)
empire = graphene.Field(Faction) empire = Field(Faction)
node = relay.Node.Field() node = relay.Node.Field()
def resolve_rebels(self, info): def resolve_rebels(self, info):
@ -71,8 +64,8 @@ class Query(graphene.ObjectType):
return get_empire() return get_empire()
class Mutation(graphene.ObjectType): class Mutation(ObjectType):
introduce_ship = IntroduceShip.Field() introduce_ship = IntroduceShip.Field()
schema = graphene.Schema(query=Query, mutation=Mutation) schema = Schema(query=Query, mutation=Mutation)

View File

@ -808,14 +808,14 @@ class Signature(object):
def bind(self, *args, **kwargs): def bind(self, *args, **kwargs):
"""Get a BoundArguments object, that maps the passed `args` """Get a BoundArguments object, that maps the passed `args`
and `kwargs` to the function's signature. Raises `TypeError` and `kwargs` to the function's signature. Raises `TypeError`
if the passed arguments can not be bound. if the passed arguments cannot be bound.
""" """
return self._bind(args, kwargs) return self._bind(args, kwargs)
def bind_partial(self, *args, **kwargs): def bind_partial(self, *args, **kwargs):
"""Get a BoundArguments object, that partially maps the """Get a BoundArguments object, that partially maps the
passed `args` and `kwargs` to the function's signature. passed `args` and `kwargs` to the function's signature.
Raises `TypeError` if the passed arguments can not be bound. Raises `TypeError` if the passed arguments cannot be bound.
""" """
return self._bind(args, kwargs, partial=True) return self._bind(args, kwargs, partial=True)

View File

@ -41,7 +41,7 @@ class Field(MountedType):
source and resolver source and resolver
), "A Field cannot have a source and a resolver in at the same time." ), "A Field cannot have a source and a resolver in at the same time."
assert not callable(default_value), ( assert not callable(default_value), (
'The default value can not be a function but received "{}".' 'The default value cannot be a function but received "{}".'
).format(base_type(default_value)) ).format(base_type(default_value))
if required: if required:

View File

@ -14,7 +14,7 @@ class Structure(UnmountedType):
cls_name = type(self).__name__ cls_name = type(self).__name__
of_type_name = type(of_type).__name__ of_type_name = type(of_type).__name__
raise Exception( raise Exception(
"{} could not have a mounted {}() as inner type. Try with {}({}).".format( "{} cannot have a mounted {}() as inner type. Try {}({}).".format(
cls_name, of_type_name, cls_name, of_type_name cls_name, of_type_name, cls_name, of_type_name
) )
) )

View File

@ -57,7 +57,7 @@ def test_field_default_value_not_callable():
Field(MyType, default_value=lambda: True) Field(MyType, default_value=lambda: True)
except AssertionError as e: except AssertionError as e:
# substring comparison for py 2/3 compatibility # substring comparison for py 2/3 compatibility
assert "The default value can not be a function but received" in str(e) assert "The default value cannot be a function but received" in str(e)
def test_field_source(): def test_field_source():

View File

@ -19,7 +19,7 @@ def test_list_with_unmounted_type():
assert ( assert (
str(exc_info.value) str(exc_info.value)
== "List could not have a mounted String() as inner type. Try with List(String)." == "List cannot have a mounted String() as inner type. Try List(String)."
) )
@ -97,7 +97,7 @@ def test_nonnull_with_unmounted_type():
assert ( assert (
str(exc_info.value) str(exc_info.value)
== "NonNull could not have a mounted String() as inner type. Try with NonNull(String)." == "NonNull cannot have a mounted String() as inner type. Try NonNull(String)."
) )