Source code for graphene.types.objecttype

from collections import OrderedDict

from .base import BaseOptions, BaseType
from .field import Field
from .interface import Interface
from .utils import yank_fields_from_attrs

# For static type checking with Mypy
MYPY = False
if MYPY:
    from typing import Dict, Iterable, Type  # NOQA


class ObjectTypeOptions(BaseOptions):
    fields = None  # type: Dict[str, Field]
    interfaces = ()  # type: Iterable[Type[Interface]]


[docs]class ObjectType(BaseType): """ Object Type Definition Almost all of the GraphQL types you define will be object types. Object types have a name, but most importantly describe their fields. The name of the type defined by an _ObjectType_ defaults to the class name. The type description defaults to the class docstring. This can be overriden by adding attributes to a Meta inner class. The class attributes of an _ObjectType_ are mounted as instances of ``graphene.Field``. Methods starting with ``resolve_<field_name>`` are bound as resolvers of the matching Field name. If no resolver is provided, the default resolver is used. Ambiguous types with Interface and Union can be determined through``is_type_of`` method and ``Meta.possible_types`` attribute. .. code:: python from graphene import ObjectType, String, Field class Person(ObjectType): class Meta: description = 'A human' # implicitly mounted as Field first_name = String() # explicitly mounted as Field last_name = Field(String) def resolve_last_name(parent, info): return last_name ObjectType must be mounted using ``graphene.Field``. .. code:: python from graphene import ObjectType, Field class Query(ObjectType): person = Field(Person, description="My favorite person") Meta class options (optional): name (str): Name of the GraphQL type (must be unique in schema). Defaults to class name. description (str): Description of the GraphQL type in the schema. Defaults to class docstring. interfaces (Iterable[graphene.Interface]): GraphQL interfaces to extend with this object. all fields from interface will be included in this object's schema. possible_types (Iterable[class]): Used to test parent value object via isintance to see if this type can be used to resolve an ambigous type (interface, union). default_resolver (any Callable resolver): Override the default resolver for this type. Defaults to graphene default resolver which returns an attribute or dictionary key with the same name as the field. fields (Dict[str, graphene.Field]): Dictionary of field name to Field. Not recommended to use (prefer class attributes). An _ObjectType_ can be used as a simple value object by creating an instance of the class. .. code:: python p = Person(first_name='Bob', last_name='Roberts') assert p.first_name == 'Bob' Args: *args (List[Any]): Positional values to use for Field values of value object **kwargs (Dict[str: Any]): Keyword arguments to use for Field values of value object """ @classmethod def __init_subclass_with_meta__( cls, interfaces=(), possible_types=(), default_resolver=None, _meta=None, **options ): if not _meta: _meta = ObjectTypeOptions(cls) fields = OrderedDict() for interface in interfaces: assert issubclass(interface, Interface), ( 'All interfaces of {} must be a subclass of Interface. Received "{}".' ).format(cls.__name__, interface) fields.update(interface._meta.fields) for base in reversed(cls.__mro__): fields.update(yank_fields_from_attrs(base.__dict__, _as=Field)) assert not (possible_types and cls.is_type_of), ( "{name}.Meta.possible_types will cause type collision with {name}.is_type_of. " "Please use one or other." ).format(name=cls.__name__) if _meta.fields: _meta.fields.update(fields) else: _meta.fields = fields _meta.interfaces = interfaces _meta.possible_types = possible_types _meta.default_resolver = default_resolver super(ObjectType, cls).__init_subclass_with_meta__(_meta=_meta, **options) is_type_of = None def __init__(self, *args, **kwargs): # ObjectType acting as container args_len = len(args) fields = self._meta.fields.items() if args_len > len(fields): # Daft, but matches old exception sans the err msg. raise IndexError("Number of args exceeds number of fields") fields_iter = iter(fields) if not kwargs: for val, (name, field) in zip(args, fields_iter): setattr(self, name, val) else: for val, (name, field) in zip(args, fields_iter): setattr(self, name, val) kwargs.pop(name, None) for name, field in fields_iter: try: val = kwargs.pop( name, field.default_value if isinstance(field, Field) else None ) setattr(self, name, val) except KeyError: pass if kwargs: for prop in list(kwargs): try: if isinstance( getattr(self.__class__, prop), property ) or prop.startswith("_"): setattr(self, prop, kwargs.pop(prop)) except AttributeError: pass if kwargs: raise TypeError( "'{}' is an invalid keyword argument for {}".format( list(kwargs)[0], self.__class__.__name__ ) )