Skip to content

Pydantic

Turbulette has an Ariadne bindable that can automatically add fields and annotations to a pydantic model from a given GraphQL type.

For this to work, Pydantic models must subclass GraphQLModel and define a __type__ class attribute that indicates the corresponding GraphQL type:

type User {
    username: String!
    email: String!
    age: Int
}
from turbulette.validation import GraphQLModel

class User(GraphQLModel):
    __type__ = "User"

During schema binding, attributes username, email and age will be added to the User model with proper Python annotations.

All GraphQL scalars will be converted to their Python equivalent :

GraphQL Scalar Python annotation
Int int
Float float
String str
Boolean bool
ID Union[str, int]

The same goes for wrapping types :

GraphQL Wrapping type Python annotation
List List
Non-Null Every nullable fields have None as default value, non-nullable ones are required

For non scalar fields (i.e: other GraphQL types), the bindable will look for an existing GraphQLModel that describes it. If it can't found it, a PydanticBindError will be raised.

Provide the tooling to generate pydantic models from the GraphQL schema.

GraphQLModel pydantic-model

Base pydantic model for GraphQL type binding.

The GraphQL type must be assigned to GraphQL.gql_type when subclassing. __initialized__ is used at binding time, to avoid the model to be processed multiple times. (ex : when the GraphQL type is referenced by fields of other GraphQL types)

Config

Needed to allow referencing custom GraphQL types in models.

validator(*fields, *, pre=False, each_item=False, always=False, check_fields=False, whole=None, allow_reuse=False)

Shortcut to Pydantic @validator decorator with check_fields=False.

When check_fields is True validators are checked on class creation to confirm that the fields they specify actually exist on the model. Because models subclassing GraphQLModel won't declare any fields at creation (as they'll be added dynamically later), but may declare validators, this behavior becomes an undesirable effect and it's necessary to disable it.

Source code in turbulette/validation/pyd_model.py
def validator(
    *fields: str,
    pre: bool = False,
    each_item: bool = False,
    always: bool = False,
    check_fields: bool = False,
    whole: bool = None,
    allow_reuse: bool = False,
) -> Callable[[AnyCallable], classmethod]:
    """Shortcut to Pydantic `@validator` decorator with `check_fields=False`.

    When `check_fields` is `True` validators are checked on class creation to
    confirm that the fields they specify actually exist on the model.
    Because models subclassing `GraphQLModel` won't declare any fields at creation
    (as they'll be added dynamically later), but may declare validators,
    this behavior becomes an undesirable effect and it's necessary to disable it.
    """
    return pyd_validator(
        *fields,
        pre=pre,
        each_item=each_item,
        always=always,
        check_fields=check_fields,
        whole=whole,
        allow_reuse=allow_reuse,
    )

Exceptions raised during pydantic binding.

PydanticBindError

Raised if Turbulette fails to bind GraphQL pydantic models.

Common causes are:

  • The pydantic model does not defines a __type__ attribute.
  • The GraphQL type defined by __type__ does not exists.
  • The GraphQL type exists, but one of its fields refers to a GraphQL type that does not exist.

Last update: 2021-02-18