@@ -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