# -*- coding: utf-8 -*-
"""
This module implements all the exceptions exposed by this library.
"""
from typing import Any, Dict, List, Mapping, Optional, Sequence
from ._string_utils import (
ResponsePath,
highlight_location,
index_to_loc,
stringify_path,
)
from .lang import ast as _ast
[docs]class GraphQLError(Exception):
"""
Base GraphQL exception from which all other inherit.
You should prefer using one of its subclasses most of the time.
"""
def __init__(self, message: str = ""):
super().__init__(message)
self.message = message
def __str__(self) -> str:
return self.message
[docs]class GraphQLResponseError(GraphQLError):
"""
Errors suitable for use in responses and being exposed to end users.
See `the relevant part of the spec
<https://graphql.github.io/graphql-spec/June2018/#sec-Errors>`_ for more
information on response errors.
"""
[docs] def to_dict(self) -> Dict[str, Any]:
"""
Convert the exception to a dictionary.
The return value should be serializable to JSON for use in a GraphQL
response.
"""
raise NotImplementedError()
[docs]class GraphQLSyntaxError(GraphQLResponseError):
"""
Syntax error while parsing a GraphQL document (query or schema definition).
Args:
message: Explanatory message
position: 0-indexed position locating the syntax error
source: Source string from which the syntax error originated
Attributes:
message (str): Explanatory message
position (int): 0-indexed position locating the syntax error
source (str): Source string from which the syntax error originated
"""
def __init__(self, message: str, position: int, source: str):
super().__init__(message)
self.source = source
self.position = position
self._highlighted = None # type: Optional[str]
@property
def highlighted(self) -> str:
"""
Message followed by the detailed location location of the error.
"""
if self._highlighted is not None:
return self._highlighted
highlight = highlight_location(self.source, self.position)
self._highlighted = "%s %s" % (self.message, highlight)
return self._highlighted
def __str__(self) -> str:
return self.highlighted
[docs] def to_dict(self) -> Dict[str, Any]:
line, col = index_to_loc(self.source, self.position)
return {
"message": str(self),
"locations": [{"line": line, "columne": col}],
}
[docs]class InvalidCharacter(GraphQLSyntaxError):
pass
[docs]class UnexpectedCharacter(GraphQLSyntaxError):
pass
[docs]class UnexpectedEOF(GraphQLSyntaxError):
"""
Document terminated before parsing could finish.
Args:
position: 0-indexed position locating the syntax error
source: Source string from which the syntax error originated
"""
def __init__(self, position: int, source: str):
super().__init__("Unexpected <EOF>", position, source)
[docs]class NonTerminatedString(GraphQLSyntaxError):
pass
[docs]class InvalidEscapeSequence(GraphQLSyntaxError):
pass
[docs]class UnexpectedToken(GraphQLSyntaxError):
pass
[docs]class GraphQLLocatedError(GraphQLResponseError):
"""
Response error that can be traced back to specific position(s) and node(s).
Args:
message: Explanatory message
nodes: Nodes relevant to the exception
path: Location of the error during execution
Attributes:
message (str): Explanatory message
nodes (List[py_gql.lang.ast.Node]): Nodes relevant to the exception
path (Optional[Sequence[Union[int, str]]]):
Location of the error during execution
"""
def __init__(
self,
message: str,
nodes: Optional[Sequence[_ast.Node]] = None,
path: Optional[ResponsePath] = None,
):
super().__init__(message)
self.path = path
self.nodes = list(nodes[:]) if nodes else [] # type: List[_ast.Node]
def __str__(self) -> str:
return self.message
[docs] def to_dict(self) -> Dict[str, Any]:
kv = (
("message", str(self)),
(
"locations",
[
{"line": line, "column": col}
for line, col in (
index_to_loc(node.source, node.loc[0])
for node in self.nodes
if node.loc and node.source
)
],
),
("path", self.path if self.path is not None else None),
)
return {k: v for k, v in kv if v}
[docs]class InvalidValue(GraphQLLocatedError, ValueError):
pass
[docs]class UnknownEnumValue(InvalidValue):
pass
[docs]class UnknownVariable(InvalidValue):
pass
[docs]class ScalarSerializationError(GraphQLError, ValueError):
pass
[docs]class ScalarParsingError(InvalidValue):
pass
[docs]class SchemaError(GraphQLError):
pass
[docs]class SchemaValidationError(SchemaError):
def __init__(self, errors: Sequence[SchemaError]):
super().__init__("Invalid schema: %d errors" % len(errors))
self.errors = errors
def __str__(self) -> str:
if len(self.errors) == 1:
return str(self.errors[0])
return ",\n".join([str(err) for err in self.errors])
[docs]class UnknownType(SchemaError, KeyError):
pass
[docs]class ValidationError(GraphQLLocatedError):
pass
[docs]class ExecutionError(GraphQLResponseError):
"""
Error that prevented execution of a query.
Args:
message: Explanatory message
Attributes:
message (str): Explanatory message
"""
[docs] def to_dict(self) -> Dict[str, Any]:
return {"message": str(self)}
[docs]class InvalidOperationError(ExecutionError):
pass
[docs]class VariableCoercionError(GraphQLLocatedError):
pass
[docs]class VariablesCoercionError(GraphQLError):
"""
Collection of multiple :class:`VariableCoercionError`.
Args:
errors: Wrapped errors
Attributes:
errors (Sequence[VariableCoercionError]): Wrapped errors
"""
def __init__(self, errors: Sequence[VariableCoercionError]):
super().__init__("%d errors" % len(errors))
self.errors = errors
def __str__(self) -> str:
if len(self.errors) == 1:
return str(self.errors[0])
return ",\n".join([str(err) for err in self.errors])
[docs]class CoercionError(GraphQLLocatedError):
def __init__(self, message, node=None, path=None, value_path=None):
super().__init__(message, node, path)
self.value_path = value_path
def __str__(self):
if self.value_path:
return "%s at %s" % (self.message, stringify_path(self.value_path))
return self.message
[docs]class MultiCoercionError(CoercionError):
"""
Collection of multiple :class:`CoercionError`.
Args:
errors: Wrapped errors
Attributes:
errors (Sequence[CoercionError]): Wrapped errors
"""
def __init__(self, errors: Sequence[CoercionError]):
super().__init__("%d errors" % len(errors))
self.errors = errors
def __str__(self):
if len(self.errors) == 1:
return str(self.errors[0])
return ",\n".join([str(err) for err in self.errors])
[docs]class ResolverError(GraphQLLocatedError):
"""
Raised when an expected error happens during field resolution.
Subclass or raise this exception directly for use in your own
resolvers in order for them to report errors instead of crashing the
query execution.
If your exception exposes an ``extensions`` attribute it will be included
in the serialized version without the need to override :meth:`to_dict`.
Args:
message: Explanatory message
nodes: Node or nodes relevant to the exception
path: Location of the error during execution
extensions: Error extensions
Attributes:
message (str): Explanatory message
nodes (List[py_gql.lang.ast.Node]): Node or nodes relevant to the exception
path (Optional[Sequence[Union[int, str]]]):
Location of the error during execution
extensions (Optional[Mapping[str, Any]]): Error extensions
"""
def __init__(
self,
message: str,
nodes: Optional[Sequence[_ast.Node]] = None,
path: Optional[ResponsePath] = None,
extensions: Optional[Mapping[str, Any]] = None,
):
super().__init__(message, nodes, path)
self.extensions = extensions
[docs] def to_dict(self) -> Dict[str, Any]:
dict_ = super().to_dict()
if self.extensions:
dict_["extensions"] = dict(self.extensions)
return dict_
[docs]class SDLError(GraphQLLocatedError):
"""
Any error that occurred while interpreting a schema definition document.
"""
[docs]class ExtensionError(SDLError):
"""
Error that occurred when applying an extension node.
"""
[docs]class SchemaDirectiveError(SDLError):
"""
Error that occurred when applying schema directives.
"""