CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-graphene

GraphQL Framework for Python providing declarative schema construction and query execution

Pending
Overview
Eval results
Files

type-system.mddocs/

Type System

Graphene provides a comprehensive GraphQL type system through Python classes that mirror the GraphQL specification. This includes object types for data structures, scalar types for primitive values, composite types for complex relationships, input types for mutations and queries, and field definitions for connecting data.

Capabilities

Object Types

Define GraphQL object types that represent data structures with typed fields and resolvers.

class ObjectType(BaseType):
    """
    Primary GraphQL object type for defining data structures.
    
    Features:
    - Automatic dataclass integration for field access
    - Field collection via metaclass
    - Interface implementation support
    - Custom resolver binding
    
    Meta Options:
        interfaces: List of interfaces this type implements
        possible_types: For interface resolution
        default_resolver: Default field resolver function
        fields: Custom field definitions
    
    Usage:
        class Person(graphene.ObjectType):
            name = graphene.String(required=True)
            age = graphene.Int()
            
            def resolve_age(self, info):
                return self.calculate_age()
    """

Field Definitions

Define individual fields on GraphQL types with arguments, resolvers, and metadata.

class Field(MountedType):
    """
    Defines individual fields on GraphQL types.
    
    Parameters:
        type_: The GraphQL type for this field
        args: Dictionary of field arguments
        resolver: Custom resolver function
        source: Source field name for automatic resolution
        deprecation_reason: Deprecation message
        name: Field name (defaults to Python attribute name)
        description: Field description
        required: Whether field is NonNull (alternative to NonNull wrapper)
        default_value: Default value for the field
    
    Methods:
        wrap_resolve(parent_resolver): Wraps resolver for field resolution
        wrap_subscribe(parent_subscribe): Wraps subscription resolver
    """

def Field(type_, **kwargs):
    """
    Create a field with the specified type and options.
    
    Args:
        type_: GraphQL type (String, Int, ObjectType, etc.)
        resolver: Custom resolver function
        args: Field arguments
        required: Make field non-null
        description: Field documentation
        deprecation_reason: Mark field as deprecated
        
    Returns:
        Field instance
    """

Scalar Types

Built-in GraphQL scalar types for primitive values with automatic serialization and parsing.

Basic Scalars

class String(Scalar):
    """
    UTF-8 text representation with automatic type coercion.
    
    Features:
    - Coerces various Python types to string
    - UTF-8 encoding/decoding
    - Null value handling
    """

class Int(Scalar):
    """
    32-bit signed integers with range validation.
    
    Range: -2^31 to 2^31-1
    Features:
    - Automatic range checking
    - Float to int conversion with validation
    - Null value handling
    """

class BigInt(Scalar):
    """
    Unlimited precision integers.
    
    Features:
    - No range limitations
    - Handles Python's arbitrary precision integers
    - String/numeric parsing
    """

class Float(Scalar):
    """
    IEEE 754 double-precision floating point numbers.
    
    Features:
    - Standard floating point operations
    - Automatic type coercion from int/string
    - NaN and infinity handling
    """

class Boolean(Scalar):
    """
    True/false values with Python truthiness conversion.
    
    Features:
    - Uses Python's bool() function for coercion
    - Handles various truthy/falsy values
    """

class ID(Scalar):
    """
    Unique identifier that accepts string or int, serializes to string.
    
    Features:
    - Accepts both string and integer input
    - Always serializes to string format
    - Used for object identification
    """

Extended Scalars

class UUID(Scalar):
    """
    Native UUID type using Python's uuid.UUID.
    
    Features:
    - Automatic UUID validation
    - String to UUID conversion
    - Standard UUID format support
    """

class DateTime(Scalar):
    """
    ISO 8601 datetime representation with timezone support.
    
    Features:
    - Uses dateutil.parser.isoparse for flexible parsing
    - Timezone-aware datetime support
    - ISO 8601 string serialization
    """

class Date(Scalar):
    """
    ISO 8601 date representation (YYYY-MM-DD).
    
    Features:
    - Handles datetime.date objects
    - ISO date string parsing
    - Date-only operations
    """

class Time(Scalar):
    """
    ISO 8601 time representation (HH:MM:SS).
    
    Features:
    - Handles datetime.time objects
    - Time-only operations
    - Optional microsecond precision
    """

class Decimal(Scalar):
    """
    Python Decimal type for precise numeric values.
    
    Features:
    - Maintains decimal precision
    - String/numeric parsing
    - Financial calculations support
    """

class JSONString(Scalar):
    """
    JSON-encoded strings (not recommended for schema design).
    
    Warning: Not recommended for new schemas
    Features:
    - Automatic JSON serialization/deserialization
    - Bypasses GraphQL type system
    """

class Base64(Scalar):
    """
    Base64-encoded binary data.
    
    Features:
    - Automatic base64 encoding/decoding
    - UTF-8 string handling
    - Binary data transport
    """

Composite Types

Complex GraphQL types for representing relationships and polymorphism.

class Interface(BaseType):
    """
    Defines shared fields across multiple object types.
    
    Features:
    - Field inheritance for implementing types
    - Type resolution at query time
    - Cannot be instantiated directly
    
    Meta Options:
        fields: Field definitions
        interfaces: Other interfaces this extends
    
    Methods:
        resolve_type(instance, info): Determines concrete type from instance
    
    Usage:
        class Node(graphene.Interface):
            id = graphene.ID(required=True)
            
            @classmethod
            def resolve_type(cls, instance, info):
                return type(instance).__name__
    """

class Union(UnmountedType, BaseType):
    """
    Represents one of several possible object types.
    
    Features:
    - Type resolution at query time
    - No shared fields between types
    - Useful for search results or heterogeneous collections
    
    Meta Options:
        types: Required list of ObjectTypes in the union
    
    Methods:
        resolve_type(instance, info): Type resolution for union members
    
    Usage:
        class SearchResult(graphene.Union):
            class Meta:
                types = (Person, Company, Product)
    """

class Enum(EnumMeta):
    """
    Defines static set of named values.
    
    Features:
    - Automatic Python Enum integration
    - Custom equality/hashing for enum values
    - Dynamic enum creation
    
    Meta Options:
        enum: Python Enum class to use
        description: Enum description
        deprecation_reason: Mark enum as deprecated
    
    Class Methods:
        from_enum(python_enum): Create GraphQL enum from Python enum
    
    Usage:
        class Color(graphene.Enum):
            RED = 1
            GREEN = 2
            BLUE = 3
            
        # Or from Python enum
        from enum import Enum as PyEnum
        class Status(PyEnum):
            ACTIVE = "active"
            INACTIVE = "inactive"
            
        GraphQLStatus = graphene.Enum.from_enum(Status)
    """

Input Types

Types for accepting structured input data in mutations and query arguments.

class InputObjectType(UnmountedType, BaseType):
    """
    Structured input data for mutations and queries.
    
    Features:
    - Automatic InputField mounting
    - Container class generation for value objects
    - Default value handling
    - Validation support
    
    Meta Options:
        container: Custom container class for input values
        fields: Custom field definitions
    
    Usage:
        class PersonInput(graphene.InputObjectType):
            name = graphene.String(required=True)
            age = graphene.Int()
            email = graphene.String()
    """

class InputField(MountedType):
    """
    Individual input fields on InputObjectType.
    
    Parameters:
        type_: Input field type (no Interface/Union types allowed)
        name: Field name
        default_value: Default value for optional fields
        deprecation_reason: Deprecation message
        description: Field description
        required: Whether field is NonNull
    
    Restrictions:
    - No arguments (unlike regular Field)
    - Cannot use Interface or Union types
    - Only input types allowed
    
    Usage:
        email = graphene.InputField(
            graphene.String, 
            description="User email address",
            required=True
        )
    """

class Argument(MountedType):
    """
    Field arguments for queries and mutations.
    
    Parameters:
        type_: Argument type
        default_value: Default value for optional arguments
        deprecation_reason: Deprecation message
        description: Argument description
        name: Argument name
        required: Whether argument is NonNull
    
    Features:
    - Automatic conversion from UnmountedTypes
    - Argument validation
    - Default value handling
    
    Usage:
        def resolve_users(self, info, limit=graphene.Argument(graphene.Int, default_value=10)):
            return User.objects.all()[:limit]
    """

Structure Modifiers

Wrappers for modifying type nullability and creating lists.

class List(Structure):
    """
    Array/list type wrapper for GraphQL lists.
    
    Features:
    - Type-safe list operations
    - Nested list support
    - Null item handling
    
    Usage:
        users = graphene.List(User)  # [User]
        matrix = graphene.List(graphene.List(graphene.Int))  # [[Int]]
    """

class NonNull(Structure):
    """
    Non-nullable type wrapper for required fields.
    
    Features:
    - Prevents null values
    - Validation at execution time
    - Cannot be nested (NonNull(NonNull(T)) is invalid)
    
    Usage:
        name = graphene.NonNull(graphene.String)  # String!
        # Or use required=True
        name = graphene.String(required=True)
    """

Special Types

Advanced types for complex scenarios and runtime behavior.

class Dynamic(MountedType):
    """
    Runtime type resolution for lazy fields and circular references.
    
    Parameters:
        type_: Function that returns the actual type
        with_schema: Whether to pass schema to type function
    
    Methods:
        get_type(schema=None): Resolves type at schema build time
    
    Usage:
        # Resolve circular reference
        def get_user_type():
            return User
            
        friends = graphene.Dynamic(get_user_type)
        
        # With schema access
        def get_type_with_schema(schema):
            return schema.get_type('User')
            
        user = graphene.Dynamic(get_type_with_schema, with_schema=True)
    """

class Scalar(GraphQLScalar):
    """
    Base class for custom scalar types.
    
    Abstract Methods:
        serialize(value): Convert internal value to transport format
        parse_value(value): Parse transport value to internal format
        parse_literal(ast_node): Parse AST literal to internal format
    
    Usage:
        class EmailScalar(graphene.Scalar):
            @staticmethod
            def serialize(email):
                return str(email)
                
            @staticmethod
            def parse_value(value):
                if not re.match(r'^[^@]+@[^@]+\.[^@]+$', value):
                    raise ValueError('Invalid email format')
                return value
                
            @staticmethod
            def parse_literal(node):
                if isinstance(node, StringValueNode):
                    return EmailScalar.parse_value(node.value)
                raise ValueError('Expected string value')
    """

Usage Examples

Creating Custom Object Types

import graphene

class Address(graphene.ObjectType):
    street = graphene.String(required=True)
    city = graphene.String(required=True)
    country = graphene.String(required=True)
    postal_code = graphene.String()

class Person(graphene.ObjectType):
    # Basic fields
    name = graphene.String(required=True, description="Full name")
    age = graphene.Int(description="Age in years")
    email = graphene.String()
    
    # Complex fields
    address = graphene.Field(Address)
    friends = graphene.List(lambda: Person)  # Self-reference
    
    # Field with arguments
    posts = graphene.List(
        'Post',  # String reference to avoid circular import
        limit=graphene.Argument(graphene.Int, default_value=10)
    )
    
    # Custom resolver
    def resolve_posts(self, info, limit=10):
        return get_posts_for_user(self.id, limit)
    
    # Computed field
    display_name = graphene.String()
    
    def resolve_display_name(self, info):
        return f"{self.name} ({self.age})"

Working with Input Types

class CreatePersonInput(graphene.InputObjectType):
    name = graphene.String(required=True)
    age = graphene.Int()
    email = graphene.String()
    address = graphene.Field('AddressInput')

class AddressInput(graphene.InputObjectType):
    street = graphene.String(required=True)
    city = graphene.String(required=True)
    country = graphene.String(required=True)
    postal_code = graphene.String()

class CreatePerson(graphene.Mutation):
    class Arguments:
        input = CreatePersonInput(required=True)
    
    person = graphene.Field(Person)
    success = graphene.Boolean()
    
    def mutate(self, info, input):
        # Access input fields
        person_data = {
            'name': input.name,
            'age': input.age,
            'email': input.email
        }
        
        if input.address:
            person_data['address'] = {
                'street': input.address.street,
                'city': input.address.city,
                'country': input.address.country,
                'postal_code': input.address.postal_code
            }
        
        # Create person
        person = create_person(person_data)
        return CreatePerson(person=person, success=True)

Custom Scalar Example

import graphene
import re
from datetime import datetime
from graphql.language.ast import StringValueNode

class EmailType(graphene.Scalar):
    """Email address scalar with validation."""
    
    @staticmethod
    def serialize(email):
        """Serialize email to string."""
        return str(email)
    
    @staticmethod
    def parse_value(value):
        """Parse email from input value."""
        if not isinstance(value, str):
            raise ValueError(f"Expected string, got {type(value).__name__}")
        
        email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(email_pattern, value):
            raise ValueError(f"Invalid email format: {value}")
        
        return value
    
    @staticmethod
    def parse_literal(node):
        """Parse email from AST literal."""
        if isinstance(node, StringValueNode):
            return EmailType.parse_value(node.value)
        raise ValueError("Expected string literal for email")

# Usage in schema
class User(graphene.ObjectType):
    name = graphene.String()
    email = EmailType()  # Custom scalar
    verified_at = graphene.DateTime()

Install with Tessl CLI

npx tessl i tessl/pypi-graphene

docs

index.md

relay.md

schema-execution.md

type-system.md

tile.json