def extends_without_altering_original_schema(): extended_schema = extend_test_schema(""" extend type Query { newField: String } """) assert extend_schema != test_schema assert "newField" in print_schema(extended_schema) assert "newField" not in print_schema(test_schema)
def test_get_schema_with_macros_original_schema_unchanged(self) -> None: empty_macro_registry = get_empty_test_macro_registry() original_printed_schema = print_schema( self.macro_registry.schema_without_macros) printed_schema_with_0_macros = print_schema( get_schema_with_macros(empty_macro_registry)) printed_schema_afterwards = print_schema( self.macro_registry.schema_without_macros) self.assertEqual(original_printed_schema, printed_schema_afterwards) self.assertEqual(original_printed_schema, printed_schema_with_0_macros)
def expect_schema_changes(schema: GraphQLSchema, extended_schema: GraphQLSchema, expected: str) -> None: schema_definitions = { print_ast(node) for node in parse(print_schema(schema)).definitions } assert ("\n\n".join(schema_def for schema_def in ( print_ast(node) for node in parse(print_schema(extended_schema)).definitions) if schema_def not in schema_definitions) == expected)
def legacy_support_for_interfaces_with_null_as_interfaces_field(): introspection = introspection_from_schema(dummy_schema) some_interface_introspection = next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "SomeInterface") assert some_interface_introspection["interfaces"] == [] some_interface_introspection["interfaces"] = None client_schema = build_client_schema(introspection) assert print_schema(client_schema) == print_schema(dummy_schema)
def print_schema_changes(schema: GraphQLSchema, extended_schema: GraphQLSchema) -> str: schema_definitions = [ print_ast(definition) for definition in parse(print_schema(schema)).definitions ] ast = parse(print_schema(extended_schema)) return print_ast( DocumentNode(definitions=FrozenList( node for node in ast.definitions if print_ast(node) not in schema_definitions)))
def may_extend_mutations_and_subscriptions(): mutation_schema = build_schema( """ type Query { queryField: String } type Mutation { mutationField: String } type Subscription { subscriptionField: String } """ ) ast = parse( """ extend type Query { newQueryField: Int } extend type Mutation { newMutationField: Int } extend type Subscription { newSubscriptionField: Int } """ ) original_print = print_schema(mutation_schema) extended_schema = extend_schema(mutation_schema, ast) assert extended_schema != mutation_schema assert print_schema(mutation_schema) == original_print assert print_schema(extended_schema) == dedent( """ type Query { queryField: String newQueryField: Int } type Mutation { mutationField: String newMutationField: Int } type Subscription { subscriptionField: String newSubscriptionField: Int } """ )
def may_extend_mutations_and_subscriptions(): mutationSchema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields=lambda: {"queryField": GraphQLField(GraphQLString)} ), mutation=GraphQLObjectType( name="Mutation", fields=lambda: {"mutationField": GraphQLField(GraphQLString)}, ), subscription=GraphQLObjectType( name="Subscription", fields=lambda: {"subscriptionField": GraphQLField(GraphQLString)}, ), ) ast = parse( """ extend type Query { newQueryField: Int } extend type Mutation { newMutationField: Int } extend type Subscription { newSubscriptionField: Int } """ ) original_print = print_schema(mutationSchema) extended_schema = extend_schema(mutationSchema, ast) assert extended_schema != mutationSchema assert print_schema(mutationSchema) == original_print assert print_schema(extended_schema) == dedent( """ type Mutation { mutationField: String newMutationField: Int } type Query { queryField: String newQueryField: Int } type Subscription { subscriptionField: String newSubscriptionField: Int } """ )
def test_default_conversion_type_name(): assert ( print_schema(graphql_schema(query=[b])) == """\ type Query { b: B! } type B { a: Int! } """ ) assert serialization_schema(B, all_refs=True) == { "$ref": "#/$defs/B", "$defs": { "B": {"$ref": "#/$defs/A"}, "A": { "type": "object", "properties": {"a": {"type": "integer"}}, "required": ["a"], "additionalProperties": False, }, }, "$schema": "http://json-schema.org/draft/2019-09/schema#", } assert serialization_schema(B) == { "type": "object", "properties": {"a": {"type": "integer"}}, "required": ["a"], "additionalProperties": False, "$schema": "http://json-schema.org/draft/2019-09/schema#", }
def print_test_schema_changes(extended_schema): ast = parse(print_schema(extended_schema)) ast.definitions = [ node for node in ast.definitions if print_ast(node) not in test_schema_definitions ] return print_ast(ast)
def _get_directives_in_string_form(directives): """Return a set of directives in their string form, from the native directive type.""" fake_query_type = GraphQLObjectType( "Query", fields={"foo": GraphQLField(GraphQLString)} ) fake_schema = GraphQLSchema(fake_query_type, directives=directives) # Split schema on double line breaks where the following character is not a space. # It is not possible to simply split on double line breaks because print_schema puts a # double line break between GraphQLArguments. The not space character is retained and # reattached to the rest of the line. split_schema_lines = [ line.strip() for line in re.split("\n\n([^ ])", print_schema(fake_schema)) ] # Reattach the delimiter's character to the rest of the line. The first line does # not have a separated character from regular expression splitting. schema_lines = [split_schema_lines[0]] + [ delimiter_character + line for delimiter_character, line in zip( split_schema_lines[1::2], split_schema_lines[2::2] ) ] return {line for line in schema_lines if line.startswith("directive")}
def can_deep_copy_a_schema(): source = """ schema { query: Farm mutation: Work } type Cow { id: ID! name: String moos: Boolean } type Pig { id: ID! name: String oink: Boolean } union Animal = Cow | Pig enum Food { CORN FRUIT } input Feed { amount: Float type: Food } type Farm { animals: [Animal!]! } type Work { feed(feed: Feed): Boolean } """ schema = build_schema(source) schema_copy = deepcopy(schema) for name in ("Cow", "Pig", "Animal", "Food", "Feed", "Farm", "Work"): assert schema.get_type(name) is not schema_copy.get_type(name) assert print_schema(lexicographic_sort_schema(schema)) == print_schema( lexicographic_sort_schema(schema_copy))
def dump_schema(connection, schema, out_file): """Dump the GraphQL Schema to stdout or file""" from nebulo.gql.sqla_to_gql import sqla_models_to_graphql_schema from nebulo.sql.reflection.manager import reflect_sqla_models engine = create_engine(connection) sqla_models, sql_functions = reflect_sqla_models(engine, schema=schema) schema = sqla_models_to_graphql_schema(sqla_models, sql_functions) schema_str = print_schema(schema) click.echo(schema_str, file=out_file)
def cycle_sdl(sdl: str) -> str: """Full cycle test. This function does a full cycle of going from a string with the contents of the SDL, parsed in a schema AST, materializing that schema AST into an in-memory GraphQLSchema, and then finally printing that GraphQL into the SDÖ. """ ast = parse(sdl) schema = build_ast_schema(ast) return print_schema(schema)
async def test_subscription(alias, conversion, error_handler, resolver): if alias is not None: sub_name = alias elif resolver is not None: sub_name = resolver.__name__ else: sub_name = events.__name__ if (alias, conversion, error_handler, resolver) == (None, None, Undefined, None): sub_op = events else: sub_op = Subscription(events, alias, conversion, None, error_handler, resolver=resolver) schema = graphql_schema(query=[hello], subscription=[sub_op], types=[Event]) sub_field = sub_name if resolver is not None: sub_field += "(dummy: Boolean)" sub_field += f": {'String' if conversion else 'Event'}" if error_handler is Undefined: sub_field += "!" schema_str = """\ type Event { name: String! } type Query { hello: String! } type Subscription { %s } """ assert print_schema(schema) == schema_str % sub_field sub_query = sub_name if conversion is None: sub_query += "{name}" subscription = await graphql.subscribe( schema, graphql.parse("subscription {%s}" % sub_query)) result = EVENTS if resolver: result = [s.capitalize() for s in result] if not conversion: result = [{"name": s} for s in result] assert [ev.data async for ev in subscription] == [{ sub_name: r } for r in result]
def test_annotated_schema(): assert (deserialization_schema(A) == serialization_schema(A) == { "$schema": "http://json-schema.org/draft/2019-09/schema#", "type": "object", "properties": { "a": { "type": "integer", "maximum": 10, "minimum": 0, "description": "field description", } }, "required": ["a"], "additionalProperties": False, }) assert (deserialization_schema(A, all_refs=True) == serialization_schema( A, all_refs=True) == { "$schema": "http://json-schema.org/draft/2019-09/schema#", "$ref": "#/$defs/A", "$defs": { "A": { "additionalProperties": False, "properties": { "a": { "$ref": "#/$defs/someInt", "description": "field description", "minimum": 0, } }, "required": ["a"], "type": "object", }, "someInt": { "description": "type description", "maximum": 10, "type": "integer", }, }, }) assert (print_schema(graphql_schema(query=[a])) == '''\ type Query { a: A! } type A { """field description""" a: someInt! } """type description""" scalar someInt ''')
def builds_a_schema_without_the_query_type(): sdl = dedent(""" type Query { foo: String } """) schema = build_schema(sdl) introspection = introspection_from_schema(schema) del introspection["__schema"]["queryType"] client_schema = build_client_schema(introspection) assert client_schema.query_type is None assert print_schema(client_schema) == sdl
def cycle_introspection(sdl_string): """Test that the client side introspection gives the same result. This function does a full cycle of going from a string with the contents of the SDL, build in-memory GraphQLSchema from it, produce a client-side representation of the schema by using "build_client_schema" and then finally printing that that schema into the SDL. """ server_schema = build_schema(sdl_string) initial_introspection = introspection_from_schema(server_schema) client_schema = build_client_schema(initial_introspection) # If the client then runs the introspection query against the client-side schema, # it should get a result identical to what was returned by the server second_introspection = introspection_from_schema(client_schema) assert initial_introspection == second_introspection return print_schema(client_schema)
def builds_a_schema_without_directives(): sdl = dedent(""" type Query { foo: String } """) schema = build_schema(sdl) introspection = introspection_from_schema(schema) del introspection["__schema"]["directives"] client_schema = build_client_schema(introspection) assert schema.directives assert client_schema.directives == [] assert print_schema(client_schema) == sdl
def test_meta_fields_from_constant(self) -> None: fields = schema.EXTENDED_META_FIELD_DEFINITIONS.copy() fields.update( OrderedDict(( ("foo", GraphQLField(GraphQLString)), ("bar", GraphQLField(GraphQLInt)), ))) graphql_type = GraphQLObjectType("MyType", fields) custom_schema = GraphQLSchema(graphql_type, directives=schema.DIRECTIVES) # Ensure that stringifying and parsing this schema works just fine. printed_schema = print_schema(custom_schema) expected_type_definition = """\ type MyType { _x_count: Int foo: String bar: Int }""".replace(" ", " ") # 2 space indentation instead of 4 spaces self.assertIn(expected_type_definition, printed_schema)
def cycle_introspection(sdl_string): """Test that the client side introspection gives the same result. This function does a full cycle of going from a string with the contents of the SDL, build in-memory GraphQLSchema from it, produce a client-side representation of the schema by using "build_client_schema" and then return that schema printed as SDL. """ options = dict(specified_by_url=True, directive_is_repeatable=True) server_schema = build_schema(sdl_string) initial_introspection = introspection_from_schema(server_schema, **options) client_schema = build_client_schema(initial_introspection) # If the client then runs the introspection query against the client-side schema, # it should get a result identical to what was returned by the server second_introspection = introspection_from_schema(client_schema, **options) # If the client then runs the introspection query against the client-side # schema, it should get a result identical to what was returned by the server. assert initial_introspection == second_introspection return print_schema(client_schema)
def test_resolver_default_parameter_not_serializable(tp, default): def resolver(arg=default) -> bool: return arg is default resolver.__annotations__["arg"] = tp # wraps in order to trigger the bug of get_type_hints with None default value resolver2 = wraps(resolver)(lambda arg=default: resolver(arg)) schema = graphql_schema(query=[resolver2]) assert ( print_schema(schema) == """\ type Query { resolver(arg: Int): Boolean! } """ ) assert ( graphql_sync(schema, "{resolver}").data == graphql_sync(schema, "{resolver(arg: null)}").data == {"resolver": True} )
def test_resolver_position(): assert serialization_schema(B) == { "type": "object", "properties": { "a": { "type": "integer" }, "b": { "type": "integer" }, "c": { "type": "integer" }, "d": { "type": "integer" }, "e": { "type": "integer" }, }, "required": ["a", "b", "c", "d", "e"], "additionalProperties": False, "$schema": "http://json-schema.org/draft/2019-09/schema#", } assert (print_schema(graphql_schema(query=[query])) == """\ type Query { query: B! } type B { a: Int! b: Int! c: Int! d: Int! e: Int! } """)
def define_sample_schema(): BlogImage = GraphQLObjectType( "Image", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) BlogAuthor = GraphQLObjectType( "Author", lambda: { "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), "pic": GraphQLField( BlogImage, args={ "width": GraphQLArgument(GraphQLInt), "height": GraphQLArgument(GraphQLInt), }, ), "recentArticle": GraphQLField(BlogArticle), }, ) BlogArticle = GraphQLObjectType( "Article", lambda: { "id": GraphQLField(GraphQLString), "isPublished": GraphQLField(GraphQLBoolean), "author": GraphQLField(BlogAuthor), "title": GraphQLField(GraphQLString), "body": GraphQLField(GraphQLString), }, ) BlogQuery = GraphQLObjectType( "Query", { "article": GraphQLField(BlogArticle, args={"id": GraphQLArgument(GraphQLString)}), "feed": GraphQLField(GraphQLList(BlogArticle)), }, ) BlogMutation = GraphQLObjectType( "Mutation", {"writeArticle": GraphQLField(BlogArticle)}) BlogSubscription = GraphQLObjectType( "Subscription", { "articleSubscribe": GraphQLField(args={"id": GraphQLArgument(GraphQLString)}, type_=BlogArticle) }, ) schema = GraphQLSchema(BlogQuery, BlogMutation, BlogSubscription) assert print_schema(schema) == dedent(""" type Article { id: String isPublished: Boolean author: Author title: String body: String } type Author { id: String name: String pic(width: Int, height: Int): Image recentArticle: Article } type Image { url: String width: Int height: Int } type Mutation { writeArticle: Article } type Query { article(id: String): Article feed: [Article] } type Subscription { articleSubscribe(id: String): Article } """)
def define_sample_schema(): BlogImage = GraphQLObjectType( "Image", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) BlogArticle: GraphQLObjectType BlogAuthor = GraphQLObjectType( "Author", lambda: { "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), "pic": GraphQLField( BlogImage, args={ "width": GraphQLArgument(GraphQLInt), "height": GraphQLArgument(GraphQLInt), }, ), "recentArticle": GraphQLField(BlogArticle), }, ) BlogArticle = GraphQLObjectType( "Article", lambda: { "id": GraphQLField(GraphQLString), "isPublished": GraphQLField(GraphQLBoolean), "author": GraphQLField(BlogAuthor), "title": GraphQLField(GraphQLString), "body": GraphQLField(GraphQLString), }, ) BlogQuery = GraphQLObjectType( "Query", { "article": GraphQLField(BlogArticle, args={"id": GraphQLArgument(GraphQLString)}), "feed": GraphQLField(GraphQLList(BlogArticle)), }, ) BlogMutation = GraphQLObjectType( "Mutation", {"writeArticle": GraphQLField(BlogArticle)}) BlogSubscription = GraphQLObjectType( "Subscription", { "articleSubscribe": GraphQLField(args={"id": GraphQLArgument(GraphQLString)}, type_=BlogArticle) }, ) schema = GraphQLSchema(BlogQuery, BlogMutation, BlogSubscription) kwargs = schema.to_kwargs() types = kwargs.pop("types") assert types == list(schema.type_map.values()) assert kwargs == { "query": BlogQuery, "mutation": BlogMutation, "subscription": BlogSubscription, "directives": None, "ast_node": None, "extensions": None, "extension_ast_nodes": None, "assume_valid": False, } assert print_schema(schema) == dedent(""" type Article { id: String isPublished: Boolean author: Author title: String body: String } type Author { id: String name: String pic(width: Int, height: Int): Image recentArticle: Article } type Image { url: String width: Int height: Int } type Mutation { writeArticle: Article } type Query { article(id: String): Article feed: [Article] } type Subscription { articleSubscribe(id: String): Article } """)
def extend_test_schema(sdl, **options) -> GraphQLSchema: original_print = print_schema(test_schema) ast = parse(sdl) extended_schema = extend_schema(test_schema, ast, **options) assert print_schema(test_schema) == original_print return extended_schema
def correctly_assigns_ast_nodes_to_new_and_extended_types(): extended_schema = extend_test_schema(""" extend type Query { newField(testArg: TestInput): TestEnum } extend scalar SomeScalar @foo extend enum SomeEnum { NEW_VALUE } extend union SomeUnion = Bar extend input SomeInput { newField: String } extend interface SomeInterface { newField: String } enum TestEnum { TEST_VALUE } input TestInput { testInputField: TestEnum } """) ast = parse(""" extend type Query { oneMoreNewField: TestUnion } extend scalar SomeScalar @test extend enum SomeEnum { ONE_MORE_NEW_VALUE } extend union SomeUnion = TestType extend input SomeInput { oneMoreNewField: String } extend interface SomeInterface { oneMoreNewField: String } union TestUnion = TestType interface TestInterface { interfaceField: String } type TestType implements TestInterface { interfaceField: String } directive @test(arg: Int) repeatable on FIELD | SCALAR """) extended_twice_schema = extend_schema(extended_schema, ast) query = assert_object_type(extended_twice_schema.get_type("Query")) some_enum = assert_enum_type( extended_twice_schema.get_type("SomeEnum")) some_union = assert_union_type( extended_twice_schema.get_type("SomeUnion")) some_scalar = assert_scalar_type( extended_twice_schema.get_type("SomeScalar")) some_input = assert_input_object_type( extended_twice_schema.get_type("SomeInput")) some_interface = assert_interface_type( extended_twice_schema.get_type("SomeInterface")) test_input = assert_input_object_type( extended_twice_schema.get_type("TestInput")) test_enum = assert_enum_type( extended_twice_schema.get_type("TestEnum")) test_union = assert_union_type( extended_twice_schema.get_type("TestUnion")) test_type = assert_object_type( extended_twice_schema.get_type("TestType")) test_interface = assert_interface_type( extended_twice_schema.get_type("TestInterface")) test_directive = assert_directive( extended_twice_schema.get_directive("test")) assert test_type.extension_ast_nodes is None assert test_enum.extension_ast_nodes is None assert test_union.extension_ast_nodes is None assert test_input.extension_ast_nodes is None assert test_interface.extension_ast_nodes is None assert query.extension_ast_nodes assert len(query.extension_ast_nodes) == 2 assert some_scalar.extension_ast_nodes assert len(some_scalar.extension_ast_nodes) == 2 assert some_enum.extension_ast_nodes assert len(some_enum.extension_ast_nodes) == 2 assert some_union.extension_ast_nodes assert len(some_union.extension_ast_nodes) == 2 assert some_input.extension_ast_nodes assert len(some_input.extension_ast_nodes) == 2 assert some_interface.extension_ast_nodes assert len(some_interface.extension_ast_nodes) == 2 definitions: List[Optional[TypeSystemDefinitionNode]] = [ test_input.ast_node, test_enum.ast_node, test_union.ast_node, test_interface.ast_node, test_type.ast_node, test_directive.ast_node, ] extensions: List[Optional[FrozenList[TypeSystemDefinitionNode]]] = [ query.extension_ast_nodes, some_scalar.extension_ast_nodes, some_enum.extension_ast_nodes, some_union.extension_ast_nodes, some_input.extension_ast_nodes, some_interface.extension_ast_nodes, ] for extension_ast_nodes in extensions: if extension_ast_nodes: definitions.extend(extension_ast_nodes) restored_extension_ast = DocumentNode(definitions=definitions) assert print_schema(extend_schema( test_schema, restored_extension_ast)) == print_schema(extended_twice_schema) new_field = query.fields["newField"] assert print_ast_node( new_field) == "newField(testArg: TestInput): TestEnum" assert print_ast_node( new_field.args["testArg"]) == "testArg: TestInput" assert (print_ast_node( query.fields["oneMoreNewField"]) == "oneMoreNewField: TestUnion") new_value = some_enum.values["NEW_VALUE"] assert some_enum assert print_ast_node(new_value) == "NEW_VALUE" one_more_new_value = some_enum.values["ONE_MORE_NEW_VALUE"] assert one_more_new_value assert print_ast_node(one_more_new_value) == "ONE_MORE_NEW_VALUE" assert print_ast_node( some_input.fields["newField"]) == "newField: String" assert (print_ast_node( some_input.fields["oneMoreNewField"]) == "oneMoreNewField: String") assert print_ast_node( some_interface.fields["newField"]) == "newField: String" assert (print_ast_node(some_interface.fields["oneMoreNewField"]) == "oneMoreNewField: String") assert (print_ast_node( test_input.fields["testInputField"]) == "testInputField: TestEnum") test_value = test_enum.values["TEST_VALUE"] assert test_value assert print_ast_node(test_value) == "TEST_VALUE" assert (print_ast_node(test_interface.fields["interfaceField"]) == "interfaceField: String") assert (print_ast_node( test_type.fields["interfaceField"]) == "interfaceField: String") assert print_ast_node(test_directive.args["arg"]) == "arg: Int"
someEnum: SomeEnum someInterface(id: ID!): SomeInterface someInput(input: SomeInput): String } """) def extend_test_schema(sdl, **options) -> GraphQLSchema: original_print = print_schema(test_schema) ast = parse(sdl) extended_schema = extend_schema(test_schema, ast, **options) assert print_schema(test_schema) == original_print return extended_schema test_schema_ast = parse(print_schema(test_schema)) test_schema_definitions = [ print_ast(node) for node in test_schema_ast.definitions ] def print_test_schema_changes(extended_schema): ast = parse(print_schema(extended_schema)) ast.definitions = FrozenList( node for node in ast.definitions if print_ast(node) not in test_schema_definitions) return print_ast(ast) TypeWithAstNode = Union[GraphQLArgument, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLNamedType, GraphQLSchema, ]
} type Bar { field: String! } input FooInput { bar: BarInput baz: Int } input BarInput { field: String! } """ assert print_schema(schema) == schema_str query_str = """ { query(foo: {bar: {field: "value"}}) { bar { field } baz } } """ assert graphql_sync(schema, query_str).data == { "query": {"bar": {"field": "value"}, "baz": None} }
def print_for_test(schema: GraphQLSchema) -> str: schema_text = print_schema(schema) # keep print_schema and build_schema in sync assert print_schema(build_schema(schema_text)) == schema_text return schema_text
def expect_printed_schema(schema: GraphQLSchema) -> str: schema_text = print_schema(schema) # keep print_schema and build_schema in sync assert print_schema(build_schema(schema_text)) == schema_text return schema_text