@@ -391,3 +391,137 @@ def resolve_type(self, resolve_type_func, type_name, root, info, _type):
391
391
return graphql_type
392
392
393
393
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