def produces_helpful_error_messages(): bad_ast = {"random": "Data"} with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_ast(bad_ast) msg = str(exc_info.value) assert msg == "Not an AST Node: {'random': 'Data'}"
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 produces_helpful_error_messages(): bad_ast = {"random": "Data"} with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_ast(bad_ast) # type: ignore assert str(exc_info.value) == "Not an AST Node: {'random': 'Data'}." corrupt_ast = FieldNode(name="random data") with raises(TypeError) as exc_info: print_ast(corrupt_ast) assert str(exc_info.value) == "Invalid AST Node: 'random data'."
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 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 survives_circular_dependencies(): ast = parse(""" query One { ...A } fragment A on T { ...B } fragment B on T { ...A } query Two { ...B } """) separated_asts = separate_operations(ast) assert list(separated_asts) == ['One', 'Two'] assert print_ast(separated_asts['One']) == dedent(""" query One { ...A } fragment A on T { ...B } fragment B on T { ...A } """) assert print_ast(separated_asts['Two']) == dedent(""" fragment A on T { ...B } fragment B on T { ...A } query Two { ...B } """)
def schema_extension_ast_are_available_from_schema_object(): schema = extend_test_schema(""" extend schema { mutation: Mutation } type Mutation extend schema { subscription: Subscription } type Subscription """) ast = parse(""" extend schema @foo """) schema = extend_schema(schema, ast) nodes = schema.extension_ast_nodes or FrozenList() assert "".join(print_ast(node) + "\n" for node in nodes) == dedent(""" extend schema { mutation: Mutation } extend schema { subscription: Subscription } extend schema @foo """)
def concats_two_acts_together(): source_a = Source(""" { a, b, ... Frag } """) source_b = Source(""" fragment Frag on T { c } """) ast_a = parse(source_a) ast_b = parse(source_b) ast_c = concat_ast([ast_a, ast_b]) assert print_ast(ast_c) == dedent(""" { a b ...Frag } fragment Frag on T { c } """)
def schema_extension_ast_are_available_from_schema_object(): schema = extend_test_schema(""" extend schema { mutation: Mutation } extend schema { subscription: Subscription } type Mutation { doSomething: String } type Subscription { hearSomething: String } """) ast = parse(""" extend schema @foo """) schema = extend_schema(schema, ast) nodes = schema.extension_ast_nodes assert ''.join( print_ast(node) + '\n' for node in nodes) == dedent(""" extend schema { mutation: Mutation } extend schema { subscription: Subscription } extend schema @foo """)
def correctly_prints_single_line_block_strings_with_leading_space(): ast_with_artifacts = parse('{ field(arg: """ space-led value""") }') assert print_ast(ast_with_artifacts) == dedent(''' { field(arg: """ space-led value""") } ''')
def experimental_correctly_prints_fragment_defined_variables(): source = """ fragment Foo($a: ComplexType, $b: Boolean = false) on TestType { id } """ fragment_with_variable = parse(source, experimental_fragment_variables=True) assert print_ast(fragment_with_variable) == dedent(source)
def extends_scalars_by_adding_new_directives(): extended_schema = extend_test_schema(""" extend scalar SomeScalar @foo """) some_scalar = extended_schema.get_type("SomeScalar") assert len(some_scalar.extension_ast_nodes) == 1 assert print_ast(some_scalar.extension_ast_nodes[0]) == ( "extend scalar SomeScalar @foo")
def correctly_prints_single_line_with_leading_space_and_quotation(): source = ''' { field(arg: """ space-led value "quoted string" """) } ''' ast_with_artifacts = parse(source) assert print_ast(ast_with_artifacts) == dedent(source)
def prints_kitchen_sink(kitchen_sink): # noqa: F811 ast = parse(kitchen_sink) printed = print_ast(ast) assert printed == dedent(r''' query queryName($foo: ComplexType, $site: Site = MOBILE) { whoever123is: node(id: [123, 456]) { id ... on User @defer { field2 { id alias: field1(first: 10, after: $foo) @include(if: $foo) { id ...frag } } } ... @skip(unless: $foo) { id } ... { id } } } mutation likeStory { like(story: 123) @defer { story { id } } } subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { storyLikeSubscribe(input: $input) { story { likers { count } likeSentence { text } } } } fragment frag on Friend { foo(size: $size, bar: $b, obj: {key: "value", block: """ block string uses \""" """}) } { unnamed(truthy: true, falsey: false, nullish: null) query } ''') # noqa
def correctly_prints_query_operation_with_artifacts(): query_ast_with_artifacts = parse( "query ($foo: TestType) @testDirective { id, name }") assert print_ast(query_ast_with_artifacts) == dedent(""" query ($foo: TestType) @testDirective { id name } """)
def correctly_prints_mutation_operation_with_artifacts(): mutation_ast_with_artifacts = parse( "mutation ($foo: TestType) @testDirective { id, name }") assert print_ast(mutation_ast_with_artifacts) == dedent(""" mutation ($foo: TestType) @testDirective { id name } """)
def prints_query_with_variable_directives(): query_ast_with_variable_directive = parse( "query ($foo: TestType = {a: 123}" " @testDirective(if: true) @test) { id }") assert print_ast(query_ast_with_variable_directive) == dedent(""" query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { id } """)
def experimental_prints_fragment_with_variable_directives(): query_ast_with_variable_directive = parse( "fragment Foo($foo: TestType @test) on TestType @testDirective { id }", experimental_fragment_variables=True, ) assert print_ast(query_ast_with_variable_directive) == dedent(""" fragment Foo($foo: TestType @test) on TestType @testDirective { id } """)
def experimental_prints_query_with_variable_directives(): query_ast_with_variable_directive = parse( 'query ($foo: TestType = {a: 123}' ' @testDirective(if: true) @test) { id }', experimental_variable_definition_directives=True) assert print_ast(query_ast_with_variable_directive) == dedent(""" query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { id } """)
def keeps_arguments_on_one_line_if_line_has_80_chars_or_less(): printed = print_ast( parse("{trip(wheelchair:false arriveBy:false){dateTime}}")) assert printed == dedent(""" { trip(wheelchair: false, arriveBy: false) { dateTime } } """)
def correctly_prints_string_with_a_first_line_indentation(): source = ''' { field(arg: """ first line indentation """) } ''' ast_with_artifacts = parse(source) assert print_ast(ast_with_artifacts) == dedent(source)
def puts_arguments_on_multiple_lines_if_line_has_more_than_80_chars(): printed = print_ast( parse( "{trip(wheelchair:false arriveBy:false includePlannedCancellations:true" " transitDistanceReluctance:2000){dateTime}}")) assert printed == dedent(""" { trip( wheelchair: false arriveBy: false includePlannedCancellations: true transitDistanceReluctance: 2000 ) { dateTime } } """)
def correctly_prints_mutation_operation_without_name(): mutation_ast = parse("mutation { id, name }") assert print_ast(mutation_ast) == "mutation {\n id\n name\n}\n"
def correctly_prints_query_operation_without_name(): query_ast_shorthanded = parse("query { id, name }") assert print_ast(query_ast_shorthanded) == "{\n id\n name\n}\n"
def print_ast_node(obj: TypeWithAstNode) -> str: assert obj is not None and obj.ast_node is not None return print_ast(obj.ast_node)
def prints_minimal_ast(): ast = FieldNode(name=NameNode(value="foo")) assert print_ast(ast) == "foo"
def does_not_alter_ast(kitchen_sink): # noqa: F811 ast = parse(kitchen_sink) ast_before = deepcopy(ast) print_ast(ast) assert ast == ast_before
def prints_minimal_ast(): node = ScalarTypeDefinitionNode(name=NameNode(value="foo")) assert print_ast(node) == "scalar foo"
def prints_kitchen_sink(kitchen_sink_sdl): # noqa: F811 ast = parse(kitchen_sink_sdl) printed = print_ast(ast) assert printed == dedent(''' schema { query: QueryType mutation: MutationType } """ This is a description of the `Foo` type. """ type Foo implements Bar & Baz { "Description of the `one` field." one: Type """This is a description of the `two` field.""" two( """This is a description of the `argument` argument.""" argument: InputType! ): Type """This is a description of the `three` field.""" three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type seven(argument: Int = null): Type } type AnnotatedObject @onObject(arg: "value") { annotatedField(arg: Type = "default" @onArgumentDefinition): Type @onField } type UndefinedType extend type Foo { seven(argument: [String]): Type } extend type Foo @onType interface Bar { one: Type four(argument: String = "string"): String } interface AnnotatedInterface @onInterface { annotatedField(arg: Type @onArgumentDefinition): Type @onField } interface UndefinedInterface extend interface Bar { two(argument: InputType!): Type } extend interface Bar @onInterface union Feed = Story | Article | Advert union AnnotatedUnion @onUnion = A | B union AnnotatedUnionTwo @onUnion = A | B union UndefinedUnion extend union Feed = Photo | Video extend union Feed @onUnion scalar CustomScalar scalar AnnotatedScalar @onScalar extend scalar CustomScalar @onScalar enum Site { """This is a description of the `DESKTOP` value""" DESKTOP """This is a description of the `MOBILE` value""" MOBILE "This is a description of the `WEB` value" WEB } enum AnnotatedEnum @onEnum { ANNOTATED_VALUE @onEnumValue OTHER_VALUE } enum UndefinedEnum extend enum Site { VR } extend enum Site @onEnum input InputType { key: String! answer: Int = 42 } input AnnotatedInput @onInputObject { annotatedField: Type @onInputFieldDefinition } input UndefinedInput extend input InputType { other: Float = 1.23e4 @onInputFieldDefinition } extend input InputType @onInputObject """This is a description of the `@skip` directive""" directive @skip(if: Boolean! @onArgumentDefinition) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include2(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @myRepeatableDir(name: String!) repeatable on OBJECT | INTERFACE extend schema @onSchema extend schema @onSchema { subscription: SubscriptionType } ''' # noqa: E501 )
def does_not_alter_ast(kitchen_sink_sdl): # noqa: F811 ast = parse(kitchen_sink_sdl) ast_copy = deepcopy(ast) print_ast(ast) assert ast == ast_copy