mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-22 17:46:57 +03:00
Update schema.py
This commit is contained in:
parent
7d890bf915
commit
946c2a3807
|
@ -391,239 +391,3 @@ class TypeMap(dict):
|
|||
return graphql_type
|
||||
|
||||
return type_
|
||||
|
||||
|
||||
class UnforgivingExecutionContext(ExecutionContext):
|
||||
"""An execution context which doesn't swallow exceptions.
|
||||
|
||||
The only difference between this execution context and the one it inherits from is
|
||||
that ``except Exception`` is commented out within ``resolve_field_value_or_error``.
|
||||
By removing that exception handling, only ``GraphQLError``'s are caught.
|
||||
"""
|
||||
|
||||
def resolve_field_value_or_error(
|
||||
self, field_def, field_nodes, resolve_fn, source, info
|
||||
):
|
||||
"""Resolve field to a value or an error.
|
||||
|
||||
Isolates the "ReturnOrAbrupt" behavior to not de-opt the resolve_field()
|
||||
method. Returns the result of resolveFn or the abrupt-return Error object.
|
||||
|
||||
For internal use only.
|
||||
"""
|
||||
try:
|
||||
# Build a dictionary of arguments from the field.arguments AST, using the
|
||||
# variables scope to fulfill any variable references.
|
||||
args = get_argument_values(field_def, field_nodes[0], self.variable_values)
|
||||
|
||||
# Note that contrary to the JavaScript implementation, we pass the context
|
||||
# value as part of the resolve info.
|
||||
result = resolve_fn(source, info, **args)
|
||||
if self.is_awaitable(result):
|
||||
# noinspection PyShadowingNames
|
||||
async def await_result():
|
||||
try:
|
||||
return await result
|
||||
except GraphQLError as error:
|
||||
return error
|
||||
# except Exception as error:
|
||||
# return GraphQLError(str(error), original_error=error)
|
||||
|
||||
# Yes, this is commented out code. It's been intentionally
|
||||
# _not_ removed to show what has changed from the original
|
||||
# implementation.
|
||||
|
||||
return await_result()
|
||||
return result
|
||||
except GraphQLError as error:
|
||||
return error
|
||||
# except Exception as error:
|
||||
# return GraphQLError(str(error), original_error=error)
|
||||
|
||||
# Yes, this is commented out code. It's been intentionally _not_
|
||||
# removed to show what has changed from the original implementation.
|
||||
|
||||
def complete_value_catching_error(
|
||||
self, return_type, field_nodes, info, path, result
|
||||
):
|
||||
"""Complete a value while catching an error.
|
||||
|
||||
This is a small wrapper around completeValue which detects and logs errors in
|
||||
the execution context.
|
||||
"""
|
||||
try:
|
||||
if self.is_awaitable(result):
|
||||
|
||||
async def await_result():
|
||||
value = self.complete_value(
|
||||
return_type, field_nodes, info, path, await result
|
||||
)
|
||||
if self.is_awaitable(value):
|
||||
return await value
|
||||
return value
|
||||
|
||||
completed = await_result()
|
||||
else:
|
||||
completed = self.complete_value(
|
||||
return_type, field_nodes, info, path, result
|
||||
)
|
||||
if self.is_awaitable(completed):
|
||||
# noinspection PyShadowingNames
|
||||
async def await_completed():
|
||||
try:
|
||||
return await completed
|
||||
|
||||
# CHANGE WAS MADE HERE
|
||||
# ``GraphQLError`` was swapped in for ``except Exception``
|
||||
except GraphQLError as error:
|
||||
self.handle_field_error(error, field_nodes, path, return_type)
|
||||
|
||||
return await_completed()
|
||||
return completed
|
||||
|
||||
# CHANGE WAS MADE HERE
|
||||
# ``GraphQLError`` was swapped in for ``except Exception``
|
||||
except GraphQLError as error:
|
||||
self.handle_field_error(error, field_nodes, path, return_type)
|
||||
return None
|
||||
|
||||
|
||||
class Schema:
|
||||
"""Schema Definition.
|
||||
|
||||
A Graphene Schema can execute operations (query, mutation, subscription) against the defined
|
||||
types. For advanced purposes, the schema can be used to lookup type definitions and answer
|
||||
questions about the types through introspection.
|
||||
|
||||
Args:
|
||||
query (Type[ObjectType]): Root query *ObjectType*. Describes entry point for fields to *read*
|
||||
data in your Schema.
|
||||
mutation (Optional[Type[ObjectType]]): Root mutation *ObjectType*. Describes entry point for
|
||||
fields to *create, update or delete* data in your API.
|
||||
subscription (Optional[Type[ObjectType]]): Root subscription *ObjectType*. Describes entry point
|
||||
for fields to receive continuous updates.
|
||||
types (Optional[List[Type[ObjectType]]]): List of any types to include in schema that
|
||||
may not be introspected through root types.
|
||||
directives (List[GraphQLDirective], optional): List of custom directives to include in the
|
||||
GraphQL schema. Defaults to only include directives defined by GraphQL spec (@include
|
||||
and @skip) [GraphQLIncludeDirective, GraphQLSkipDirective].
|
||||
auto_camelcase (bool): Fieldnames will be transformed in Schema's TypeMap from snake_case
|
||||
to camelCase (preferred by GraphQL standard). Default True.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
query=None,
|
||||
mutation=None,
|
||||
subscription=None,
|
||||
types=None,
|
||||
directives=None,
|
||||
auto_camelcase=True,
|
||||
):
|
||||
self.query = query
|
||||
self.mutation = mutation
|
||||
self.subscription = subscription
|
||||
type_map = TypeMap(
|
||||
query, mutation, subscription, types, auto_camelcase=auto_camelcase
|
||||
)
|
||||
self.graphql_schema = GraphQLSchema(
|
||||
type_map.query,
|
||||
type_map.mutation,
|
||||
type_map.subscription,
|
||||
type_map.types,
|
||||
directives,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return print_schema(self.graphql_schema)
|
||||
|
||||
def __getattr__(self, type_name):
|
||||
"""
|
||||
This function let the developer select a type in a given schema
|
||||
by accessing its attrs.
|
||||
|
||||
Example: using schema.Query for accessing the "Query" type in the Schema
|
||||
"""
|
||||
_type = self.graphql_schema.get_type(type_name)
|
||||
if _type is None:
|
||||
raise AttributeError(f'Type "{type_name}" not found in the Schema')
|
||||
if isinstance(_type, GrapheneGraphQLType):
|
||||
return _type.graphene_type
|
||||
return _type
|
||||
|
||||
def lazy(self, _type):
|
||||
return lambda: self.get_type(_type)
|
||||
|
||||
def execute(self, *args, **kwargs):
|
||||
"""Execute a GraphQL query on the schema.
|
||||
|
||||
Use the `graphql_sync` function from `graphql-core` to provide the result
|
||||
for a query string. Most of the time this method will be called by one of the Graphene
|
||||
:ref:`Integrations` via a web request.
|
||||
|
||||
Args:
|
||||
request_string (str or Document): GraphQL request (query, mutation or subscription)
|
||||
as string or parsed AST form from `graphql-core`.
|
||||
root_value (Any, optional): Value to use as the parent value object when resolving
|
||||
root types.
|
||||
context_value (Any, optional): Value to be made available to all resolvers via
|
||||
`info.context`. Can be used to share authorization, dataloaders or other
|
||||
information needed to resolve an operation.
|
||||
variable_values (dict, optional): If variables are used in the request string, they can
|
||||
be provided in dictionary form mapping the variable name to the variable value.
|
||||
operation_name (str, optional): If multiple operations are provided in the
|
||||
request_string, an operation name must be provided for the result to be provided.
|
||||
middleware (List[SupportsGraphQLMiddleware]): Supply request level middleware as
|
||||
defined in `graphql-core`.
|
||||
execution_context_class (ExecutionContext, optional): The execution context class
|
||||
to use when resolving queries and mutations.
|
||||
|
||||
Returns:
|
||||
:obj:`ExecutionResult` containing any data and errors for the operation.
|
||||
"""
|
||||
kwargs = normalize_execute_kwargs(kwargs)
|
||||
return graphql_sync(self.graphql_schema, *args, **kwargs)
|
||||
|
||||
async def execute_async(self, *args, **kwargs):
|
||||
"""Execute a GraphQL query on the schema asynchronously.
|
||||
|
||||
Same as `execute`, but uses `graphql` instead of `graphql_sync`.
|
||||
"""
|
||||
kwargs = normalize_execute_kwargs(kwargs)
|
||||
return await graphql(self.graphql_schema, *args, **kwargs)
|
||||
|
||||
async def subscribe(self, query, *args, **kwargs):
|
||||
"""Execute a GraphQL subscription on the schema asynchronously."""
|
||||
# Do parsing
|
||||
try:
|
||||
document = parse(query)
|
||||
except GraphQLError as error:
|
||||
return ExecutionResult(data=None, errors=[error])
|
||||
|
||||
# Do validation
|
||||
validation_errors = validate(self.graphql_schema, document)
|
||||
if validation_errors:
|
||||
return ExecutionResult(data=None, errors=validation_errors)
|
||||
|
||||
# Execute the query
|
||||
kwargs = normalize_execute_kwargs(kwargs)
|
||||
return await subscribe(self.graphql_schema, document, *args, **kwargs)
|
||||
|
||||
def introspect(self):
|
||||
introspection = self.execute(introspection_query)
|
||||
if introspection.errors:
|
||||
raise introspection.errors[0]
|
||||
return introspection.data
|
||||
|
||||
|
||||
def normalize_execute_kwargs(kwargs):
|
||||
"""Replace alias names in keyword arguments for graphql()"""
|
||||
if "root" in kwargs and "root_value" not in kwargs:
|
||||
kwargs["root_value"] = kwargs.pop("root")
|
||||
if "context" in kwargs and "context_value" not in kwargs:
|
||||
kwargs["context_value"] = kwargs.pop("context")
|
||||
if "variables" in kwargs and "variable_values" not in kwargs:
|
||||
kwargs["variable_values"] = kwargs.pop("variables")
|
||||
if "operation" in kwargs and "operation_name" not in kwargs:
|
||||
kwargs["operation_name"] = kwargs.pop("operation")
|
||||
return kwargs
|
||||
|
|
Loading…
Reference in New Issue
Block a user