CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-graphql-core

GraphQL-core is a Python port of GraphQL.js, the JavaScript reference implementation for GraphQL.

Pending
Overview
Eval results
Files

utilities.mddocs/

Schema Utilities and Introspection

Build schemas from SDL, perform introspection, compare schemas, and manipulate GraphQL type information for tooling and development. Provides comprehensive utilities for schema analysis, transformation, and development workflows.

Capabilities

Schema Construction

Build GraphQL schemas from various sources including Schema Definition Language (SDL) and introspection results.

def build_schema(
    source: Union[str, Source],
    assume_valid: bool = False,
    assume_valid_sdl: bool = False,
    no_location: bool = False,
    allow_legacy_fragment_variables: bool = False,
) -> GraphQLSchema
def build_ast_schema(document_ast: DocumentNode, assume_valid: bool = False, assume_valid_sdl: bool = False) -> GraphQLSchema
def build_client_schema(introspection: Dict[str, Any], assume_valid: bool = False) -> GraphQLSchema
def extend_schema(schema: GraphQLSchema, document_ast: DocumentNode, assume_valid: bool = False, assume_valid_sdl: bool = False) -> GraphQLSchema

Parameters:

  • source: SDL string or Source object
  • document_ast: Parsed SDL document
  • introspection: Introspection query result
  • assume_valid: Skip validation for performance
  • assume_valid_sdl: Skip SDL validation
  • no_location: Don't include location information in AST
  • allow_legacy_fragment_variables: Allow legacy fragment variable syntax

Returns: GraphQLSchema instance

Usage Examples

from graphql import build_schema, build_ast_schema, parse, build_client_schema

# Build from SDL string
schema = build_schema('''
    type Query {
        user(id: ID!): User
        users: [User]
    }
    
    type User {
        id: ID!
        name: String!
        email: String
        posts: [Post]
    }
    
    type Post {
        id: ID!
        title: String!
        content: String
        author: User
    }
''')

# Build from parsed AST
sdl_document = parse('''
    type Query {
        hello: String
    }
''')
schema_from_ast = build_ast_schema(sdl_document)

# Build from introspection result
introspection_result = {
    'data': {
        '__schema': {
            'queryType': {'name': 'Query'},
            'types': [
                {
                    'name': 'Query',
                    'kind': 'OBJECT',
                    'fields': [
                        {
                            'name': 'hello',
                            'type': {'name': 'String', 'kind': 'SCALAR'},
                            'args': []
                        }
                    ]
                }
            ]
        }
    }
}
client_schema = build_client_schema(introspection_result['data'])

Schema Extension

Extend existing schemas with additional type definitions and modifications.

def extend_schema(
    schema: GraphQLSchema, 
    document_ast: DocumentNode, 
    assume_valid: bool = False, 
    assume_valid_sdl: bool = False
) -> GraphQLSchema

Usage Example

from graphql import build_schema, extend_schema, parse

base_schema = build_schema('''
    type Query {
        user(id: ID!): User
    }
    
    type User {
        id: ID!
        name: String!
    }
''')

extension = parse('''
    extend type User {
        email: String
        posts: [Post]
    }
    
    type Post {
        id: ID!
        title: String!
        author: User
    }
    
    extend type Query {
        posts: [Post]
    }
''')

extended_schema = extend_schema(base_schema, extension)

Schema Introspection

Generate and process GraphQL introspection queries for schema discovery and tooling.

def get_introspection_query(
    description: bool = True,
    specified_by_url: bool = False,
    directive_is_repeatable: bool = False,
    schema_description: bool = False,
    input_value_deprecation: bool = False,
) -> str

def introspection_from_schema(
    schema: GraphQLSchema, 
    options: Optional[IntrospectionOptions] = None
) -> Dict[str, Any]

class IntrospectionOptions:
    description: bool = True
    specified_by_url: bool = False
    directive_is_repeatable: bool = False
    schema_description: bool = False
    input_value_deprecation: bool = False

IntrospectionQuery = Dict[str, Any]

Usage Example

from graphql import get_introspection_query, introspection_from_schema, graphql_sync

# Get introspection query
introspection_query = get_introspection_query(
    description=True,
    specified_by_url=True
)

# Execute introspection against schema
result = graphql_sync(schema, introspection_query)
schema_info = result.data

# Or get introspection directly from schema
introspection_result = introspection_from_schema(schema)
print(introspection_result['__schema']['queryType']['name'])

Schema Printing

Convert GraphQL schemas and types back to SDL representation.

def print_schema(schema: GraphQLSchema, options: Optional[SchemaPrintOptions] = None) -> str
def print_type(type_: GraphQLNamedType, options: Optional[SchemaPrintOptions] = None) -> str
def print_introspection_schema(schema: GraphQLSchema) -> str

class SchemaPrintOptions:
    comment_descriptions: bool = False
    include_directives: Optional[Callable[[GraphQLDirective], bool]] = None

Usage Example

from graphql import print_schema, print_type, print_introspection_schema

# Print entire schema as SDL
sdl = print_schema(schema)
print(sdl)

# Print specific type
user_type = schema.type_map['User']
user_sdl = print_type(user_type)
print(user_sdl)

# Print introspection schema
introspection_sdl = print_introspection_schema(schema)
print(introspection_sdl)

Schema Sorting

Sort schema types and fields lexicographically for consistent output.

def lexicographic_sort_schema(schema: GraphQLSchema) -> GraphQLSchema

Usage Example

from graphql import lexicographic_sort_schema, print_schema

# Sort schema for consistent output
sorted_schema = lexicographic_sort_schema(schema)
sorted_sdl = print_schema(sorted_schema)

Operation Processing

Extract and analyze operations from GraphQL documents.

def get_operation_ast(document: DocumentNode, operation_name: Optional[str] = None) -> Optional[OperationDefinitionNode]
def get_operation_root_type(schema: GraphQLSchema, operation: OperationDefinitionNode) -> GraphQLObjectType

Usage Example

from graphql import get_operation_ast, get_operation_root_type, parse

document = parse('''
    query GetUser($id: ID!) {
        user(id: $id) { name }
    }
    
    mutation CreateUser($input: UserInput!) {
        createUser(input: $input) { id }
    }
''')

# Get specific operation
query_op = get_operation_ast(document, 'GetUser')
mutation_op = get_operation_ast(document, 'CreateUser')

# Get root type for operation
query_root = get_operation_root_type(schema, query_op)  # Returns Query type
mutation_root = get_operation_root_type(schema, mutation_op)  # Returns Mutation type

AST Processing and Manipulation

Convert between AST representations and Python objects, manipulate documents.

def ast_to_dict(node: Node) -> Dict[str, Any]
def value_from_ast(value_node: Optional[ValueNode], type_: GraphQLInputType, variables: Optional[Dict[str, Any]] = None) -> Any
def value_from_ast_untyped(value_node: ValueNode, variables: Optional[Dict[str, Any]] = None) -> Any
def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]
def type_from_ast(schema: GraphQLSchema, type_node: TypeNode) -> Optional[GraphQLType]
def coerce_input_value(input_value: Any, type_: GraphQLInputType, on_error: Optional[Callable[[List[str], Any, GraphQLError], None]] = None) -> CoercionResult

Usage Example

from graphql import ast_to_dict, value_from_ast, ast_from_value, parse_value, GraphQLString

# Convert AST to dictionary
value_ast = parse_value('"hello world"')
value_dict = ast_to_dict(value_ast)
print(value_dict)  # {'kind': 'StringValue', 'value': 'hello world'}

# Extract value from AST with type
string_value = value_from_ast(value_ast, GraphQLString)
print(string_value)  # 'hello world'

# Create AST from value
new_ast = ast_from_value('hello', GraphQLString)
print(new_ast.value)  # 'hello'

Document Manipulation

Manipulate and transform GraphQL documents.

def concat_ast(*documents: DocumentNode) -> DocumentNode
def separate_operations(document: DocumentNode) -> Dict[str, DocumentNode]
def strip_ignored_characters(source: str) -> str

Usage Example

from graphql import concat_ast, separate_operations, strip_ignored_characters, parse

# Concatenate documents
doc1 = parse('query A { user { name } }')
doc2 = parse('query B { posts { title } }')
combined = concat_ast(doc1, doc2)

# Separate operations
multi_op_doc = parse('''
    query GetUser { user { name } }
    query GetPosts { posts { title } }
''')
separated = separate_operations(multi_op_doc)
print(separated.keys())  # ['GetUser', 'GetPosts']

# Strip ignored characters (comments, extra whitespace)
minified = strip_ignored_characters('''
    # This is a comment
    query {
        user {
            name
        }
    }
''')
print(minified)  # 'query{user{name}}'

Type Information and Analysis

Get detailed type information for AST traversal and analysis.

class TypeInfo:
    def __init__(self, schema: GraphQLSchema, initial_type: Optional[GraphQLType] = None, get_field_def_fn: Optional[Callable] = None)
    
    def get_type(self) -> Optional[GraphQLType]
    def get_parent_type(self) -> Optional[GraphQLCompositeType]
    def get_input_type(self) -> Optional[GraphQLInputType]
    def get_parent_input_type(self) -> Optional[GraphQLInputType]
    def get_field_def(self) -> Optional[GraphQLField]
    def get_default_value(self) -> Optional[Any]
    def get_directive(self) -> Optional[GraphQLDirective]
    def get_argument(self) -> Optional[GraphQLArgument]
    def get_enum_value(self) -> Optional[GraphQLEnumValue]
    
    def enter(self, node: Node) -> None
    def leave(self, node: Node) -> None

class TypeInfoVisitor:
    def __init__(self, type_info: TypeInfo, visitor: Visitor)

Usage Example

from graphql import TypeInfo, visit, Visitor

class FieldCollector(Visitor):
    def __init__(self, type_info):
        self.type_info = type_info
        self.fields = []
    
    def enter_field(self, node, key, parent, path, ancestors):
        field_def = self.type_info.get_field_def()
        parent_type = self.type_info.get_parent_type()
        if field_def and parent_type:
            self.fields.append(f"{parent_type.name}.{field_def.name}")

type_info = TypeInfo(schema)
collector = FieldCollector(type_info)
visitor = TypeInfoVisitor(type_info, collector)

document = parse('{ user { name email } posts { title } }')
visit(document, visitor)
print(collector.fields)  # ['Query.user', 'User.name', 'User.email', 'Query.posts', 'Post.title']

Type Comparisons

Compare and analyze relationships between GraphQL types.

def is_equal_type(type_a: GraphQLType, type_b: GraphQLType) -> bool
def is_type_sub_type_of(schema: GraphQLSchema, maybe_sub_type: GraphQLType, super_type: GraphQLType) -> bool
def do_types_overlap(schema: GraphQLSchema, type_a: GraphQLCompositeType, type_b: GraphQLCompositeType) -> bool

Usage Example

from graphql import is_equal_type, is_type_sub_type_of, do_types_overlap, GraphQLNonNull, GraphQLString

# Compare types
print(is_equal_type(GraphQLString, GraphQLString))  # True
print(is_equal_type(GraphQLString, GraphQLNonNull(GraphQLString)))  # False

# Check subtype relationships
print(is_type_sub_type_of(schema, GraphQLNonNull(GraphQLString), GraphQLString))  # True
print(is_type_sub_type_of(schema, GraphQLString, GraphQLNonNull(GraphQLString)))  # False

# Check type overlap (for unions/interfaces)
user_type = schema.type_map['User']
admin_type = schema.type_map.get('Admin')
if admin_type:
    print(do_types_overlap(schema, user_type, admin_type))

Schema Comparison

Find breaking and dangerous changes between schema versions.

def find_breaking_changes(old_schema: GraphQLSchema, new_schema: GraphQLSchema) -> List[BreakingChange]
def find_dangerous_changes(old_schema: GraphQLSchema, new_schema: GraphQLSchema) -> List[DangerousChange]

class BreakingChange:
    type: BreakingChangeType
    description: str

class DangerousChange:
    type: DangerousChangeType
    description: str

class BreakingChangeType(Enum):
    TYPE_REMOVED = "TYPE_REMOVED"
    TYPE_CHANGED_KIND = "TYPE_CHANGED_KIND"
    TYPE_REMOVED_FROM_UNION = "TYPE_REMOVED_FROM_UNION"
    VALUE_REMOVED_FROM_ENUM = "VALUE_REMOVED_FROM_ENUM"
    REQUIRED_INPUT_FIELD_ADDED = "REQUIRED_INPUT_FIELD_ADDED"
    IMPLEMENTED_INTERFACE_REMOVED = "IMPLEMENTED_INTERFACE_REMOVED"
    FIELD_REMOVED = "FIELD_REMOVED"
    FIELD_CHANGED_KIND = "FIELD_CHANGED_KIND"
    REQUIRED_ARG_ADDED = "REQUIRED_ARG_ADDED"
    ARG_REMOVED = "ARG_REMOVED"
    ARG_CHANGED_KIND = "ARG_CHANGED_KIND"
    DIRECTIVE_REMOVED = "DIRECTIVE_REMOVED"
    DIRECTIVE_ARG_REMOVED = "DIRECTIVE_ARG_REMOVED"
    REQUIRED_DIRECTIVE_ARG_ADDED = "REQUIRED_DIRECTIVE_ARG_ADDED"
    DIRECTIVE_REPEATABLE_REMOVED = "DIRECTIVE_REPEATABLE_REMOVED"
    DIRECTIVE_LOCATION_REMOVED = "DIRECTIVE_LOCATION_REMOVED"

class DangerousChangeType(Enum):
    VALUE_ADDED_TO_ENUM = "VALUE_ADDED_TO_ENUM"
    TYPE_ADDED_TO_UNION = "TYPE_ADDED_TO_UNION"
    OPTIONAL_INPUT_FIELD_ADDED = "OPTIONAL_INPUT_FIELD_ADDED"
    OPTIONAL_ARG_ADDED = "OPTIONAL_ARG_ADDED"
    IMPLEMENTED_INTERFACE_ADDED = "IMPLEMENTED_INTERFACE_ADDED"
    ARG_DEFAULT_VALUE_CHANGE = "ARG_DEFAULT_VALUE_CHANGE"

Usage Example

from graphql import find_breaking_changes, find_dangerous_changes, build_schema

old_schema = build_schema('''
    type Query {
        user(id: ID!): User
    }
    
    type User {
        id: ID!
        name: String!
    }
''')

new_schema = build_schema('''
    type Query {
        user(id: ID!): User
        users: [User]
    }
    
    type User {
        id: ID!
        name: String!
        email: String
    }
''')

breaking_changes = find_breaking_changes(old_schema, new_schema)
dangerous_changes = find_dangerous_changes(old_schema, new_schema)

print(f"Breaking changes: {len(breaking_changes)}")
print(f"Dangerous changes: {len(dangerous_changes)}")

for change in dangerous_changes:
    print(f"{change.type.value}: {change.description}")

Name Validation

Validate GraphQL names according to specification rules.

def assert_valid_name(name: str) -> str
def is_valid_name_error(name: str) -> Optional[GraphQLError]

Usage Example

from graphql import assert_valid_name, is_valid_name_error

# Valid names
assert_valid_name('User')      # Returns 'User'
assert_valid_name('_internal') # Returns '_internal'

# Invalid names
try:
    assert_valid_name('123Invalid')  # Raises GraphQLError
except GraphQLError as e:
    print(e.message)

error = is_valid_name_error('invalid-name')
if error:
    print(error.message)  # Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "invalid-name" does not.

Types

# Import required types
from typing import Any, Dict, List, Optional, Union, Callable, TypedDict
from graphql.type import GraphQLSchema, GraphQLType, GraphQLNamedType, GraphQLInputType, GraphQLCompositeType, GraphQLObjectType, GraphQLDirective, GraphQLField, GraphQLEnumValue
from graphql.language import DocumentNode, Source, Node, ValueNode, TypeNode, OperationDefinitionNode
from graphql.error import GraphQLError

# Schema construction types
SchemaPrintOptions = class SchemaPrintOptions
IntrospectionOptions = class IntrospectionOptions
IntrospectionQuery = Dict[str, Any]

# Type analysis types
TypeInfo = class TypeInfo
TypeInfoVisitor = class TypeInfoVisitor

# Schema comparison types
BreakingChange = class BreakingChange
DangerousChange = class DangerousChange
BreakingChangeType = Enum
DangerousChangeType = Enum

# Value coercion types
class CoercionResult:
    value: Any
    errors: List[GraphQLError]

Install with Tessl CLI

npx tessl i tessl/pypi-graphql-core

docs

error-handling.md

execution-engine.md

execution.md

index.md

language.md

type-system.md

utilities.md

validation.md

tile.json