Skip to content

Commit ea4e6d6

Browse files
authored
Update schema.py
1 parent 18cd345 commit ea4e6d6

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

graphene/types/schema.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,137 @@ def resolve_type(self, resolve_type_func, type_name, root, info, _type):
391391
return graphql_type
392392

393393
return type_
394+
395+
396+
class Schema:
397+
"""Schema Definition.
398+
A Graphene Schema can execute operations (query, mutation, subscription) against the defined
399+
types. For advanced purposes, the schema can be used to lookup type definitions and answer
400+
questions about the types through introspection.
401+
Args:
402+
query (Type[ObjectType]): Root query *ObjectType*. Describes entry point for fields to *read*
403+
data in your Schema.
404+
mutation (Optional[Type[ObjectType]]): Root mutation *ObjectType*. Describes entry point for
405+
fields to *create, update or delete* data in your API.
406+
subscription (Optional[Type[ObjectType]]): Root subscription *ObjectType*. Describes entry point
407+
for fields to receive continuous updates.
408+
types (Optional[List[Type[ObjectType]]]): List of any types to include in schema that
409+
may not be introspected through root types.
410+
directives (List[GraphQLDirective], optional): List of custom directives to include in the
411+
GraphQL schema. Defaults to only include directives defined by GraphQL spec (@include
412+
and @skip) [GraphQLIncludeDirective, GraphQLSkipDirective].
413+
auto_camelcase (bool): Fieldnames will be transformed in Schema's TypeMap from snake_case
414+
to camelCase (preferred by GraphQL standard). Default True.
415+
"""
416+
417+
def __init__(
418+
self,
419+
query=None,
420+
mutation=None,
421+
subscription=None,
422+
types=None,
423+
directives=None,
424+
auto_camelcase=True,
425+
):
426+
self.query = query
427+
self.mutation = mutation
428+
self.subscription = subscription
429+
type_map = TypeMap(
430+
query, mutation, subscription, types, auto_camelcase=auto_camelcase
431+
)
432+
self.graphql_schema = GraphQLSchema(
433+
type_map.query,
434+
type_map.mutation,
435+
type_map.subscription,
436+
type_map.types,
437+
directives,
438+
)
439+
440+
def __str__(self):
441+
return print_schema(self.graphql_schema)
442+
443+
def __getattr__(self, type_name):
444+
"""
445+
This function let the developer select a type in a given schema
446+
by accessing its attrs.
447+
Example: using schema.Query for accessing the "Query" type in the Schema
448+
"""
449+
_type = self.graphql_schema.get_type(type_name)
450+
if _type is None:
451+
raise AttributeError(f'Type "{type_name}" not found in the Schema')
452+
if isinstance(_type, GrapheneGraphQLType):
453+
return _type.graphene_type
454+
return _type
455+
456+
def lazy(self, _type):
457+
return lambda: self.get_type(_type)
458+
459+
def execute(self, *args, **kwargs):
460+
"""Execute a GraphQL query on the schema.
461+
Use the `graphql_sync` function from `graphql-core` to provide the result
462+
for a query string. Most of the time this method will be called by one of the Graphene
463+
:ref:`Integrations` via a web request.
464+
Args:
465+
request_string (str or Document): GraphQL request (query, mutation or subscription)
466+
as string or parsed AST form from `graphql-core`.
467+
root_value (Any, optional): Value to use as the parent value object when resolving
468+
root types.
469+
context_value (Any, optional): Value to be made available to all resolvers via
470+
`info.context`. Can be used to share authorization, dataloaders or other
471+
information needed to resolve an operation.
472+
variable_values (dict, optional): If variables are used in the request string, they can
473+
be provided in dictionary form mapping the variable name to the variable value.
474+
operation_name (str, optional): If multiple operations are provided in the
475+
request_string, an operation name must be provided for the result to be provided.
476+
middleware (List[SupportsGraphQLMiddleware]): Supply request level middleware as
477+
defined in `graphql-core`.
478+
execution_context_class (ExecutionContext, optional): The execution context class
479+
to use when resolving queries and mutations.
480+
Returns:
481+
:obj:`ExecutionResult` containing any data and errors for the operation.
482+
"""
483+
kwargs = normalize_execute_kwargs(kwargs)
484+
return graphql_sync(self.graphql_schema, *args, **kwargs)
485+
486+
async def execute_async(self, *args, **kwargs):
487+
"""Execute a GraphQL query on the schema asynchronously.
488+
Same as `execute`, but uses `graphql` instead of `graphql_sync`.
489+
"""
490+
kwargs = normalize_execute_kwargs(kwargs)
491+
return await graphql(self.graphql_schema, *args, **kwargs)
492+
493+
async def subscribe(self, query, *args, **kwargs):
494+
"""Execute a GraphQL subscription on the schema asynchronously."""
495+
# Do parsing
496+
try:
497+
document = parse(query)
498+
except GraphQLError as error:
499+
return ExecutionResult(data=None, errors=[error])
500+
501+
# Do validation
502+
validation_errors = validate(self.graphql_schema, document)
503+
if validation_errors:
504+
return ExecutionResult(data=None, errors=validation_errors)
505+
506+
# Execute the query
507+
kwargs = normalize_execute_kwargs(kwargs)
508+
return await subscribe(self.graphql_schema, document, *args, **kwargs)
509+
510+
def introspect(self):
511+
introspection = self.execute(introspection_query)
512+
if introspection.errors:
513+
raise introspection.errors[0]
514+
return introspection.data
515+
516+
517+
def normalize_execute_kwargs(kwargs):
518+
"""Replace alias names in keyword arguments for graphql()"""
519+
if "root" in kwargs and "root_value" not in kwargs:
520+
kwargs["root_value"] = kwargs.pop("root")
521+
if "context" in kwargs and "context_value" not in kwargs:
522+
kwargs["context_value"] = kwargs.pop("context")
523+
if "variables" in kwargs and "variable_values" not in kwargs:
524+
kwargs["variable_values"] = kwargs.pop("variables")
525+
if "operation" in kwargs and "operation_name" not in kwargs:
526+
kwargs["operation_name"] = kwargs.pop("operation")
527+
return kwargs

0 commit comments

Comments
 (0)