async def call( self, document: GraphQLSchema, request: typing.Any = None, variables: typing.Dict[str, typing.Any] = None ) -> ExecutionResult: """Preform a query against the schema. This is meant to be called in an asyncio.loop, if you are using a web framework that is synchronous use the `call_sync` method. """ validation_errors = validate(self.schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) context = self.get_context(request) result = execute( schema=self.schema, document=document, context_value=context, variable_values=variables, middleware=self.middleware, ) if inspect.isawaitable(result): return await result return result
def execute(self, root=None, context=None, middleware=None, operation_name=None, variables=None, allowed_operations=None): if self.errors: return ExecutionResult(errors=self.errors, invalid=True) try: if allowed_operations is not None: operation_type = get_operation_from_operation_name( self.document_ast, operation_name) if operation_type and operation_type not in allowed_operations: raise GraphQLError("{} operations are not allowed.".format( operation_type)) return execute(self.schema, self.document_ast, root_value=root, middleware=middleware, context_value=context, variable_values=variables or {}, operation_name=operation_name, **self.execute_params) except Exception as e: return ExecutionResult(errors=[e])
def from_file( file: Union[IO[str], str], *, app: Any = None, base_url: Optional[str] = None, data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS, code_sample_style: str = CodeSampleStyle.default().name, location: Optional[str] = None, ) -> GraphQLSchema: """Load GraphQL schema from a file descriptor or a string. :param file: Could be a file descriptor, string or bytes. """ if isinstance(file, str): data = file else: data = file.read() document = graphql.build_schema(data) result = graphql.execute(document, INTROSPECTION_QUERY_AST) # TYPES: We don't pass `is_awaitable` above, therefore `result` is of the `ExecutionResult` type result = cast(ExecutionResult, result) # TYPES: # - `document` is a valid schema, because otherwise `build_schema` will rise an error; # - `INTROSPECTION_QUERY` is a valid query - it is known upfront; # Therefore the execution result is always valid at this point and `result.data` is not `None` raw_schema = cast(Dict[str, Any], result.data) return from_dict( raw_schema, app=app, base_url=base_url, data_generation_methods=data_generation_methods, code_sample_style=code_sample_style, location=location, )
def query(self, q): try: source = Source(q, name='GraphQL request') ast = parse(source) validation_errors = validate(self.schema, ast) if validation_errors: return ExecutionResult( errors=validation_errors, invalid=True, ) except Exception as e: return ExecutionResult(errors=[e], invalid=True) try: return execute(self.__schema, ast, root_value=None, variable_values={}, operation_name=None, context_value={ 'query': q, 'introspection': 'introspection' in q.lower() }, middleware=self.__middleware, executor=self.__executor) except Exception as e: return ExecutionResult(errors=[e], invalid=True)
def context_do_execute_handler(result): context, do_execute = result if not do_execute: return else: return execute(self.schema, parsed_query, root_value, context, variables, operation_name)
def _graphql( self, schema: GraphQLSchema, document: DocumentNode, root_value: Any = None, context_value: Any = None, variable_values: Dict[str, Any] = None, # type: ignore operation_name: str = None, # type: ignore field_resolver: GraphQLFieldResolver = None, # type: ignore type_resolver: GraphQLTypeResolver = None, # type: ignore middleware: Middleware = None, execution_context_class: Type[ExecutionContext] = ExecutionContext, ) -> AwaitableOrValue[ExecutionResult]: # Execute return execute( schema, document, root_value, context_value, variable_values, operation_name, field_resolver, type_resolver, middleware, execution_context_class, )
async def test_uuid_scalar_input_as_query_string_validates(self): query = """ query { uuid_input(uuid: "hello") } """ result = graphql.execute(schema, graphql.parse(query)) assert "invalid value" in str(result.errors)
async def test_datetime_scalar_input_as_query_string(self): query = """ query { datetime_input(dt: "2018-01-01T01:00:00-05:00") } """ result = graphql.execute(schema, graphql.parse(query)) assert result.data["datetime_input"] == 2018
def test_batches_correctly(executor): Business = GraphQLObjectType( 'Business', lambda: { 'id': GraphQLField(GraphQLID, resolver=lambda root, info, **args: root), }) Query = GraphQLObjectType( 'Query', lambda: { 'getBusiness': GraphQLField(Business, args={ 'id': GraphQLArgument(GraphQLNonNull(GraphQLID)), }, resolver=lambda root, info, **args: info.context. business_data_loader.load(args.get('id'))), }) schema = GraphQLSchema(query=Query) doc = ''' { business1: getBusiness(id: "1") { id } business2: getBusiness(id: "2") { id } } ''' doc_ast = parse(doc) load_calls = [] class BusinessDataLoader(DataLoader): def batch_load_fn(self, keys): load_calls.append(keys) return Promise.resolve(keys) class Context(object): business_data_loader = BusinessDataLoader() result = execute(schema, doc_ast, None, context_value=Context(), executor=executor) assert not result.errors assert result.data == { 'business1': { 'id': '1' }, 'business2': { 'id': '2' }, } assert load_calls == [['1', '2']]
def test_batches_correctly(executor): # type: (SyncExecutor) -> None Business = GraphQLObjectType( "Business", lambda: { "id": GraphQLField(GraphQLID, resolver=lambda root, info, **args: root) }, ) Query = GraphQLObjectType( "Query", lambda: { "getBusiness": GraphQLField( Business, args={"id": GraphQLArgument(GraphQLNonNull(GraphQLID))}, resolver=lambda root, info, **args: info.context. business_data_loader.load(args.get("id")), ) }, ) schema = GraphQLSchema(query=Query) doc = """ { business1: getBusiness(id: "1") { id } business2: getBusiness(id: "2") { id } } """ doc_ast = parse(doc) load_calls = [] class BusinessDataLoader(DataLoader): def batch_load_fn(self, keys): # type: (List[str]) -> Promise load_calls.append(keys) return Promise.resolve(keys) class Context(object): business_data_loader = BusinessDataLoader() result = execute(schema, doc_ast, None, context_value=Context(), executor=executor) assert not result.errors assert result.data == {"business1": {"id": "1"}, "business2": {"id": "2"}} assert load_calls == [["1", "2"]]
async def test_uuid_scalar_input_as_query_string(self): query = """ query { uuid_input(uuid: "8c9c95c5-30b8-467b-8acb-384c86dc3ab8") } """ result = graphql.execute(schema, graphql.parse(query)) assert result.data[ "uuid_input"] == "8c9c95c5-30b8-467b-8acb-384c86dc3ab8"
async def execute(self, *args, **kwargs): result = execute(self.schema, return_promise=self._enable_async, *args, **kwargs) if isinstance(result, Promise): return await result else: return result
async def test_json_scalar_input_as_variable(self): query = r""" query($j: JSON) { json_input(json: $j) } """ result = graphql.execute(schema, graphql.parse(query), variable_values=dict(j={"x": 1})) assert result.data["json_input"] == 1
def test_unicode_error_message(): ast = parse("query Example { unicode }") def resolver(context, *_): raise Exception(u"UNIÇODÉ!") Type = GraphQLObjectType("Type", {"unicode": GraphQLField(GraphQLString, resolver=resolver)}) result = execute(GraphQLSchema(Type), ast) assert isinstance(result.errors[0], GraphQLLocatedError)
async def test_uuid_scalar_input_as_variable_validates(self): query = """ query($uuid: UUID) { uuid_input(uuid: $uuid) } """ result = graphql.execute(schema, graphql.parse(query), variable_values=dict(uuid="hello")) assert "invalid value" in str(result.errors)
def test_page(session, schema, page, expected_count, result_length): document = parse(query_pagination) car2 = Car(name="Car 2") car3 = Car(name="Car 3") session.add(car2) session.add(car3) session.commit() result = execute(schema, document, context_value=session, variable_values=page) assert len(result.data["cars"]["result"]) == result_length assert result.data["cars"]["count"] == expected_count
def test_batches_correctly(executor): Business = GraphQLObjectType('Business', lambda: { 'id': GraphQLField(GraphQLID, resolver=lambda root, info, **args: root), }) Query = GraphQLObjectType('Query', lambda: { 'getBusiness': GraphQLField(Business, args={ 'id': GraphQLArgument(GraphQLNonNull(GraphQLID)), }, resolver=lambda root, info, **args: info.context.business_data_loader.load(args.get('id')) ), }) schema = GraphQLSchema(query=Query) doc = ''' { business1: getBusiness(id: "1") { id } business2: getBusiness(id: "2") { id } } ''' doc_ast = parse(doc) load_calls = [] class BusinessDataLoader(DataLoader): def batch_load_fn(self, keys): load_calls.append(keys) return Promise.resolve(keys) class Context(object): business_data_loader = BusinessDataLoader() result = execute(schema, doc_ast, None, context_value=Context(), executor=executor) assert not result.errors assert result.data == { 'business1': { 'id': '1' }, 'business2': { 'id': '2' }, } assert load_calls == [['1','2']]
async def test_json_scalar_input_as_query_string(self): """ Won't work unless the literal JSON string is parsed as JSON and passed to the resolver, so it can be indexed """ query = r""" query { json_input(json: "{\"x\": 1}") } """ result = graphql.execute(schema, graphql.parse(query)) assert result.data["json_input"] == 1
async def test_uuid_scalar_input_as_variable(self): query = """ query($uuid: UUID) { uuid_input(uuid: $uuid) } """ result = graphql.execute( schema, graphql.parse(query), variable_values=dict(uuid="8c9c95c5-30b8-467b-8acb-384c86dc3ab8"), ) assert result.data[ "uuid_input"] == "8c9c95c5-30b8-467b-8acb-384c86dc3ab8"
def test_unicode_error_message(): # type: () -> None ast = parse("query Example { unicode }") def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> NoReturn raise Exception(u"UNIÇODÉ!") Type = GraphQLObjectType( "Type", {"unicode": GraphQLField(GraphQLString, resolver=resolver)}) result = execute(GraphQLSchema(Type), ast) assert isinstance(result.errors[0], GraphQLLocatedError)
def execute(self, *args, **kwargs): operation_ast = get_operation_ast(args[0]) if operation_ast and operation_ast.operation == "subscription": result = subscribe(self.schema, *args, **kwargs) if isinstance(result, Observable): a = [] result.subscribe(lambda x: a.append(x)) if len(a) > 0: result = a[-1] return result return execute(self.schema, *args, **kwargs)
def test_unicode_error_message(): ast = parse('query Example { unicode }') def resolver(context, *_): raise Exception(u'UNIÇODÉ!') Type = GraphQLObjectType( 'Type', { 'unicode': GraphQLField(GraphQLString, resolver=resolver), }) result = execute(GraphQLSchema(Type), ast) assert isinstance(result.errors[0], GraphQLLocatedError)
async def test_datetime_scalar_input_as_variable(self): query = r""" query($dt: DateTime) { datetime_input(dt: $dt) } """ result = graphql.execute( schema, graphql.parse(query), variable_values=dict( dt=pendulum.datetime(2018, 1, 1, 1, tz="EST").isoformat()), ) assert result.data["datetime_input"] == 2018
def test_multiple_one_shot_middleware(): runs = [] class OneShotMiddleware: @run_only_once def resolve(self, next_, *args, **kwargs): runs.append("OneShotMiddleware") return next_(*args, **kwargs) class AnotherOneShotMiddleware: @run_only_once def resolve(self, next_, *args, **kwargs): runs.append("AnotherOneShotMiddleware") return next_(*args, **kwargs) middleware = (OneShotMiddleware(), AnotherOneShotMiddleware()) execute(schema=schema, document=parse(query), middleware=middleware, context_value={}) assert len(runs) == 2, "both middleware should have run" assert "OneShotMiddleware" in runs assert "AnotherOneShotMiddleware" in runs
async def _handle_query_over_ws( self, websocket, operation_id, subscriptions, document, context_value, variable_values, operation_name, ) -> List[GraphQLError]: result = execute( self.schema.graphql_schema, document, root_value=self.root_value, context_value=context_value, variable_values=variable_values, operation_name=operation_name, middleware=self.middleware, execution_context_class=self.execution_context_class, ) if isinstance(result, ExecutionResult) and result.errors: return result.errors if isawaitable(result): result = await cast(Awaitable[ExecutionResult], result) result = cast(ExecutionResult, result) payload: Dict[str, Any] = {} payload["data"] = result.data if result.errors: for error in result.errors: if error.original_error: self.logger.error( "An exception occurred in resolvers", exc_info=error.original_error, ) payload["errors"] = [ self.error_formatter(error) for error in result.errors ] await websocket.send_json({ "type": GQL_DATA, "id": operation_id, "payload": payload }) return []
def generate_schema_hash(schema: GraphQLSchema) -> str: """ Generates a stable hash of the current schema using an introspection query. """ ast = parse(introspection_query) result = cast(ExecutionResult, execute(schema, ast)) if result and not result.data: raise GraphQLError("Unable to generate server introspection document") schema = result.data["__schema"] # It's important that we perform a deterministic stringification here # since, depending on changes in the underlying `graphql-core` execution # layer, varying orders of the properties in the introspection stringified_schema = stringify(schema).encode("utf-8") return hashlib.sha512(stringified_schema).hexdigest()
def test_run_only_once(): class OneShotMiddleware: @run_only_once def resolve(self, next_, *args, **kwargs): runs.append("OneShotMiddleware") return next_(*args, **kwargs) runs = [] middleware = (OneShotMiddleware(), ) result = execute(schema=schema, document=parse(query), middleware=middleware, context_value={}) assert_no_errors(result) assert len(runs) == 1, "middleware should run only once"
async def test_custom_scalar_inline(): # https://github.com/PrefectHQ/cloud/issues/2414 query = r""" mutation($j: JSON!) { hello_mutation(input: {u: "51608cdf-c46c-4d02-a4e7-66ddd678243c", j: $j}) } """ result = graphql.execute(schema, graphql.parse(query), variable_values=dict(j={"x": 1})) assert result.data["hello_mutation"] == { "u": "51608cdf-c46c-4d02-a4e7-66ddd678243c", "j": { "x": 1 }, }
def test_middleware_with_wsgi_request_context_values(): runs = [] class OneShotMiddleware: @run_only_once def resolve(self, next_, *args, **kwargs): runs.append("OneShotMiddleware") return next_(*args, **kwargs) middleware = (OneShotMiddleware(), ) [ execute(schema=schema, document=parse(query), middleware=middleware, context_value=_get_fake_wsgi_request_obj()) for _ in (0, 1) ] assert len(runs) == 2, "middleware should run twice for 2 requests"
def execute_graphql(source, variables, operation_name=None): schema = build_schema(request.env) try: document_ast = parse(source) validation_errors = validate(schema, document_ast) if validation_errors: return ExecutionResult( errors=validation_errors, invalid=True, ) except Exception as e: return ExecutionResult(errors=[e], invalid=True) return execute( document_ast, variable_values=variables, operation_name=operation_name, context_value=request )
def execute_graphql_request( schema: GraphQLSchema, params: GraphQLParams, allow_only_query: bool = False, **kwargs, ): if not params.query: raise HttpQueryError(400, "Must provide query string.") try: document = parse(params.query) except GraphQLError as e: return ExecutionResult(data=None, errors=[e]) except Exception as e: e = GraphQLError(str(e), original_error=e) return ExecutionResult(data=None, errors=[e]) if allow_only_query: operation_ast = get_operation_ast(document, params.operation_name) if operation_ast: operation = operation_ast.operation.value if operation != "query": raise HttpQueryError( 405, f"Can only perform a {operation} operation from a POST request.", headers={"Allow": "POST"}, ) # Note: the schema is not validated here for performance reasons. # This should be done only once when starting the server. validation_errors = validate(schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) return execute( schema, document, variable_values=params.variables, operation_name=params.operation_name, **kwargs, )
async def _handle_query_via_ws( self, websocket, operation_id, subscriptions, document, context_value, variable_values, operation_name, ) -> List[GraphQLError]: result2 = execute( self.schema.graphql_schema, document, root_value=self.root_value, context_value=context_value, variable_values=variable_values, operation_name=operation_name, middleware=self.middleware, ) if isinstance(result2, ExecutionResult) and result2.errors: return result2.errors if isawaitable(result2): result2 = await cast(Awaitable[ExecutionResult], result2) result2 = cast(ExecutionResult, result2) payload: Dict[str, Any] = {} payload["data"] = result2.data if result2.errors: payload["errors"] = [ format_error(error) for error in result2.errors ] await websocket.send_json({ "type": GQL_DATA, "id": operation_id, "payload": payload }) return []
async def execute( self, document: DocumentNode, *args, **kwargs, ) -> ExecutionResult: """Execute the provided document AST for on a local GraphQL Schema.""" result_or_awaitable = execute(self.schema, document, *args, **kwargs) execution_result: ExecutionResult if isawaitable(result_or_awaitable): result_or_awaitable = cast(Awaitable[ExecutionResult], result_or_awaitable) execution_result = await result_or_awaitable else: result_or_awaitable = cast(ExecutionResult, result_or_awaitable) execution_result = result_or_awaitable return execution_result
def b(): return execute(schema, ast)
def execute(self, *args, **kwargs): return execute(self.schema, *args, **kwargs)