fromtypingimportCollection,List,Optional,Typefrom..errorimportGraphQLErrorfrom..languageimportDocumentNode,ParallelVisitor,visitfrom..pyutilsimportinspect,is_collectionfrom..typeimportGraphQLSchema,assert_valid_schemafrom..utilitiesimportTypeInfo,TypeInfoVisitorfrom.rulesimportASTValidationRulefrom.specified_rulesimportspecified_rules,specified_sdl_rulesfrom.validation_contextimportSDLValidationContext,ValidationContext__all__=["assert_valid_sdl","assert_valid_sdl_extension","validate","validate_sdl"]classValidationAbortedError(RuntimeError):"""Error when a validation has been aborted (error limit reached)."""
[docs]defvalidate(schema:GraphQLSchema,document_ast:DocumentNode,rules:Optional[Collection[Type[ASTValidationRule]]]=None,max_errors:Optional[int]=None,type_info:Optional[TypeInfo]=None,)->List[GraphQLError]:"""Implements the "Validation" section of the spec. Validation runs synchronously, returning a list of encountered errors, or an empty list if no errors were encountered and the document is valid. A list of specific validation rules may be provided. If not provided, the default list of rules defined by the GraphQL specification will be used. Each validation rule is a ValidationRule object which is a visitor object that holds a ValidationContext (see the language/visitor API). Visitor methods are expected to return GraphQLErrors, or lists of GraphQLErrors when invalid. Validate will stop validation after a ``max_errors`` limit has been reached. Attackers can send pathologically invalid queries to induce a DoS attack, so by default ``max_errors`` set to 100 errors. Providing a custom TypeInfo instance is deprecated and will be removed in v3.3. """ifnotdocument_astornotisinstance(document_ast,DocumentNode):raiseTypeError("Must provide document.")# If the schema used for validation is invalid, throw an error.assert_valid_schema(schema)ifmax_errorsisNone:max_errors=100elifnotisinstance(max_errors,int):raiseTypeError("The maximum number of errors must be passed as an int.")iftype_infoisNone:type_info=TypeInfo(schema)elifnotisinstance(type_info,TypeInfo):raiseTypeError(f"Not a TypeInfo object: {inspect(type_info)}.")ifrulesisNone:rules=specified_ruleselifnotis_collection(rules)ornotall(isinstance(rule,type)andissubclass(rule,ASTValidationRule)forruleinrules):raiseTypeError("Rules must be specified as a collection of ASTValidationRule subclasses.")errors:List[GraphQLError]=[]defon_error(error:GraphQLError)->None:iflen(errors)>=max_errors:errors.append(GraphQLError("Too many validation errors, error limit reached."" Validation aborted."))raiseValidationAbortedErrorerrors.append(error)context=ValidationContext(schema,document_ast,type_info,on_error)# This uses a specialized visitor which runs multiple visitors in parallel,# while maintaining the visitor skip and break API.visitors=[rule(context)forruleinrules]# Visit the whole document with each instance of all provided rules.try:visit(document_ast,TypeInfoVisitor(type_info,ParallelVisitor(visitors)))exceptValidationAbortedError:passreturnerrors
defvalidate_sdl(document_ast:DocumentNode,schema_to_extend:Optional[GraphQLSchema]=None,rules:Optional[Collection[Type[ASTValidationRule]]]=None,)->List[GraphQLError]:"""Validate an SDL document. For internal use only. """errors:List[GraphQLError]=[]context=SDLValidationContext(document_ast,schema_to_extend,errors.append)ifrulesisNone:rules=specified_sdl_rulesvisitors=[rule(context)forruleinrules]visit(document_ast,ParallelVisitor(visitors))returnerrorsdefassert_valid_sdl(document_ast:DocumentNode)->None:"""Assert document is valid SDL. Utility function which asserts a SDL document is valid by throwing an error if it is invalid. """errors=validate_sdl(document_ast)iferrors:raiseTypeError("\n\n".join(error.messageforerrorinerrors))defassert_valid_sdl_extension(document_ast:DocumentNode,schema:GraphQLSchema)->None:"""Assert document is a valid SDL extension. Utility function which asserts a SDL document is valid by throwing an error if it is invalid. """errors=validate_sdl(document_ast,schema)iferrors:raiseTypeError("\n\n".join(error.messageforerrorinerrors))