GraphQL-core is a Python port of GraphQL.js, the JavaScript reference implementation for GraphQL.
—
Parse GraphQL documents into Abstract Syntax Trees (AST), manipulate AST nodes, and work with GraphQL source code. This module provides lexical analysis, parsing capabilities, and visitor patterns for AST traversal and manipulation.
Parse GraphQL documents, values, and types from string sources into structured AST representations.
def parse(source: Union[str, Source]) -> DocumentNode
def parse_value(source: Union[str, Source]) -> ValueNode
def parse_const_value(source: Union[str, Source]) -> ConstValueNode
def parse_type(source: Union[str, Source]) -> TypeNodeParameters:
source: GraphQL source string or Source object to parseReturns: Corresponding AST node type
from graphql import parse, parse_value, parse_type
# Parse a complete GraphQL document
query = '''
query GetUser($id: ID!) {
user(id: $id) {
name
email
}
}
'''
document = parse(query)
print(document.kind) # 'document'
print(len(document.definitions)) # 1
# Parse individual values
value_ast = parse_value('"hello world"')
print(value_ast.kind) # 'string_value'
print(value_ast.value) # 'hello world'
# Parse type expressions
type_ast = parse_type('[String!]!')
print(type_ast.kind) # 'non_null_type'Manage GraphQL source code with location tracking for enhanced error reporting and tooling.
class Source:
def __init__(self, body: str, name: str = "GraphQL request", location_offset: SourceLocation = None)
body: str
name: str
location_offset: SourceLocation
def get_location(source: Source, position: int) -> SourceLocation
class SourceLocation:
line: int
column: intfrom graphql import Source, get_location, parse
source = Source('''
query {
user {
name
}
}
''', name="user-query.graphql")
# Parse with source tracking
document = parse(source)
# Get location information
location = get_location(source, 20)
print(f"Line {location.line}, Column {location.column}")Tokenize GraphQL source code for custom parsing or analysis tools.
class Lexer:
def __init__(self, source: Source)
def next_token(self) -> Token
def lookahead(self) -> Token
class Token:
kind: TokenKind
start: int
end: int
line: int
column: int
value: Optional[str]
prev: Optional[Token]
next: Optional[Token]
class TokenKind(Enum):
SOF = "StartOfFile"
EOF = "EndOfFile"
BANG = "!"
DOLLAR = "$"
AMP = "&"
PAREN_L = "("
PAREN_R = ")"
SPREAD = "..."
COLON = ":"
EQUALS = "="
AT = "@"
BRACKET_L = "["
BRACKET_R = "]"
BRACE_L = "{"
PIPE = "|"
BRACE_R = "}"
NAME = "Name"
INT = "Int"
FLOAT = "Float"
STRING = "String"
BLOCK_STRING = "BlockString"
COMMENT = "Comment"from graphql import Source, Lexer, TokenKind
source = Source('{ hello world }')
lexer = Lexer(source)
token = lexer.next_token()
while token.kind != TokenKind.EOF:
print(f"{token.kind.value}: {token.value}")
token = lexer.next_token()Convert AST nodes back to GraphQL string representation.
def print_ast(ast: Node) -> strfrom graphql import parse, print_ast
document = parse('{ user { name email } }')
printed = print_ast(document)
print(printed) # Formatted GraphQL stringVisit and transform AST nodes using the visitor pattern.
def visit(root: Node, visitor: Visitor, visitor_keys: Optional[VisitorKeyMap] = None) -> Any
class Visitor:
def enter(self, node: Node, key: Optional[str], parent: Optional[Node], path: List[Union[int, str]], ancestors: List[Node]) -> Optional[VisitorAction]
def leave(self, node: Node, key: Optional[str], parent: Optional[Node], path: List[Union[int, str]], ancestors: List[Node]) -> Optional[Union[VisitorAction, Node]]
class ParallelVisitor:
def __init__(self, visitors: Sequence[Visitor])
class VisitorAction(Enum):
BREAK = object()
SKIP = object()
REMOVE = object()
IDLE = object()
# Visitor action constants
BREAK: VisitorAction
SKIP: VisitorAction
REMOVE: VisitorAction
IDLE: VisitorActionfrom graphql import parse, visit, Visitor
class FieldNameCollector(Visitor):
def __init__(self):
self.field_names = []
def enter(self, node, key, parent, path, ancestors):
if node.kind == 'field':
self.field_names.append(node.name.value)
document = parse('{ user { name email posts { title } } }')
collector = FieldNameCollector()
visit(document, collector)
print(collector.field_names) # ['user', 'name', 'email', 'posts', 'title']Print formatted location information for debugging and error reporting.
def print_location(location: Location) -> str
def print_source_location(source: Source, location: SourceLocation) -> str
class Location:
start: int
end: int
start_token: Token
end_token: Token
source: Sourceclass Node:
kind: str
loc: Optional[Location]
class NameNode(Node):
kind: str = 'name'
value: str
class DocumentNode(Node):
kind: str = 'document'
definitions: List[DefinitionNode]class DefinitionNode(Node):
pass
class ExecutableDefinitionNode(DefinitionNode):
pass
class OperationDefinitionNode(ExecutableDefinitionNode):
kind: str = 'operation_definition'
operation: OperationType
name: Optional[NameNode]
variable_definitions: Optional[List[VariableDefinitionNode]]
directives: Optional[List[DirectiveNode]]
selection_set: SelectionSetNode
class OperationType(Enum):
QUERY = 'query'
MUTATION = 'mutation'
SUBSCRIPTION = 'subscription'
class FragmentDefinitionNode(ExecutableDefinitionNode):
kind: str = 'fragment_definition'
name: NameNode
variable_definitions: Optional[List[VariableDefinitionNode]]
type_condition: NamedTypeNode
directives: Optional[List[DirectiveNode]]
selection_set: SelectionSetNodeclass SelectionNode(Node):
pass
class FieldNode(SelectionNode):
kind: str = 'field'
alias: Optional[NameNode]
name: NameNode
arguments: Optional[List[ArgumentNode]]
directives: Optional[List[DirectiveNode]]
selection_set: Optional[SelectionSetNode]
class SelectionSetNode(Node):
kind: str = 'selection_set'
selections: List[SelectionNode]
class FragmentSpreadNode(SelectionNode):
kind: str = 'fragment_spread'
name: NameNode
directives: Optional[List[DirectiveNode]]
class InlineFragmentNode(SelectionNode):
kind: str = 'inline_fragment'
type_condition: Optional[NamedTypeNode]
directives: Optional[List[DirectiveNode]]
selection_set: SelectionSetNodeclass ValueNode(Node):
pass
class ConstValueNode(ValueNode):
pass
class VariableNode(ValueNode):
kind: str = 'variable'
name: NameNode
class IntValueNode(ConstValueNode):
kind: str = 'int_value'
value: str
class FloatValueNode(ConstValueNode):
kind: str = 'float_value'
value: str
class StringValueNode(ConstValueNode):
kind: str = 'string_value'
value: str
block: bool
class BooleanValueNode(ConstValueNode):
kind: str = 'boolean_value'
value: bool
class NullValueNode(ConstValueNode):
kind: str = 'null_value'
class EnumValueNode(ConstValueNode):
kind: str = 'enum_value'
value: str
class ListValueNode(ValueNode):
kind: str = 'list_value'
values: List[ValueNode]
class ObjectValueNode(ValueNode):
kind: str = 'object_value'
fields: List[ObjectFieldNode]
class ObjectFieldNode(Node):
kind: str = 'object_field'
name: NameNode
value: ValueNodeclass TypeNode(Node):
pass
class NamedTypeNode(TypeNode):
kind: str = 'named_type'
name: NameNode
class ListTypeNode(TypeNode):
kind: str = 'list_type'
type: TypeNode
class NonNullTypeNode(TypeNode):
kind: str = 'non_null_type'
type: Union[NamedTypeNode, ListTypeNode]def is_definition_node(node: Node) -> bool
def is_executable_definition_node(node: Node) -> bool
def is_selection_node(node: Node) -> bool
def is_value_node(node: Node) -> bool
def is_const_value_node(node: Node) -> bool
def is_type_node(node: Node) -> bool
def is_type_system_definition_node(node: Node) -> bool
def is_type_definition_node(node: Node) -> bool
def is_type_system_extension_node(node: Node) -> bool
def is_type_extension_node(node: Node) -> boolInstall with Tessl CLI
npx tessl i tessl/pypi-graphql-core