Example #1
0
def check_macro_edge_for_definition_conflicts(macro_registry,
                                              macro_edge_descriptor):
    """Ensure that the macro edge on the specified class does not cause any definition conflicts."""
    # There are two kinds of conflicts that we check for:
    # - defining this macro edge would not conflict with any macro edges that already exist
    #   at the same type or at a superclass of the base class of the macro; and
    # - defining this macro edge would not cause any subclass of the base class of the macro
    #   to have a conflicting definition for any of its fields originating from prior
    #   macro edge definitions.
    # We check for both of them simultaneously, by ensuring that none of the subclasses of the
    # base class name have a macro edge by the specified name.
    macro_edge_name = macro_edge_descriptor.macro_edge_name
    base_class_name = macro_edge_descriptor.base_class_name
    target_class_name = macro_edge_descriptor.target_class_name

    existing_descriptor = _find_any_macro_edge_name_at_subclass(
        macro_registry, base_class_name, macro_edge_name)
    if existing_descriptor is not None:
        conflict_on_class_name = existing_descriptor.base_class_name
        extra_error_text = _get_type_relationship_error_description_text(
            macro_registry.subclass_sets, base_class_name,
            conflict_on_class_name)
        raise GraphQLInvalidMacroError(
            "A macro edge with name {edge_name} cannot be defined on type {current_type} due "
            "to a conflict with another macro edge with the same name defined "
            "on type {original_type}{extra_error_text}."
            "Cannot define this conflicting macro, please verify "
            "if the existing macro edge does what you want, or rename your macro "
            "edge to avoid the conflict. Existing macro definition and args: "
            "{macro_graphql} {macro_args}".format(
                edge_name=macro_edge_name,
                current_type=base_class_name,
                original_type=conflict_on_class_name,
                extra_error_text=extra_error_text,
                macro_graphql=print_ast(existing_descriptor.expansion_ast),
                macro_args=existing_descriptor.macro_args,
            ))

    existing_descriptor = _find_any_macro_edge_name_to_subclass(
        macro_registry, target_class_name, macro_edge_name)
    if existing_descriptor is not None:
        conflict_on_class_name = existing_descriptor.target_class_name
        extra_error_text = _get_type_relationship_error_description_text(
            macro_registry.subclass_sets, target_class_name,
            conflict_on_class_name)
        raise GraphQLInvalidMacroError(
            "A macro edge with name {edge_name} cannot be defined to point to {target_type} due "
            "to a conflict with another macro edge with the same name that points to "
            "type {original_type}{extra_error_text}."
            "Cannot define this conflicting macro, please verify "
            "if the existing macro edge does what you want, or rename your macro "
            "edge to avoid the conflict. Existing macro definition and args: "
            "{macro_graphql} {macro_args}".format(
                edge_name=macro_edge_name,
                target_type=target_class_name,
                original_type=conflict_on_class_name,
                extra_error_text=extra_error_text,
                macro_graphql=print_ast(existing_descriptor.expansion_ast),
                macro_args=existing_descriptor.macro_args,
            ))
Example #2
0
def _process_directive_definition(directive, existing_directives,
                                  merged_schema_ast):
    """Compare new directive against existing directives, update records and schema.

    Args:
        directive: DirectiveDefinition, an AST node representing the definition of a directive
        existing_directives: Dict[str, DirectiveDefinition], mapping the name of each existing
                             directive to the AST node defining it. It is modified by this
                             function
        merged_schema_ast: Document, AST representing a schema. It is modified by this function
    """
    directive_name = directive.name.value
    if directive_name in existing_directives:
        if directive == existing_directives[directive_name]:
            return
        else:
            raise SchemaNameConflictError(
                u'Directive "{}" with definition "{}" has already been defined with '
                u'definition "{}".'.format(
                    directive_name,
                    print_ast(directive),
                    print_ast(existing_directives[directive_name]),
                ))
    # new directive
    merged_schema_ast.definitions.append(directive)
    existing_directives[directive_name] = directive
Example #3
0
def test_print_produces_helpful_error_messages():
    # type: () -> None
    bad_ast = {"random": "Data"}
    with raises(AssertionError) as excinfo:
        print_ast(bad_ast)

    assert "Invalid AST Node: {'random': 'Data'}" in str(excinfo.value)
Example #4
0
 def test_rename_field_one_to_many(self):
     query_string = dedent("""\
         {
           Human {
             new_name @output(out_name: "name")
           }
         }
     """)
     alternative_query_string = dedent("""\
         {
           Human {
             name @output(out_name: "name")
           }
         }
     """)
     renamed_schema = rename_schema(
         parse(ISS.multiple_fields_schema), {},
         {"Human": {
             "name": {"name", "new_name"}
         }})
     renamed_query = rename_query(parse(query_string), renamed_schema)
     renamed_alternative_query = rename_query(
         parse(alternative_query_string), renamed_schema)
     renamed_query_string = dedent("""\
         {
           Human {
             name @output(out_name: "name")
           }
         }
     """)
     self.assertEqual(renamed_query_string, print_ast(renamed_query))
     self.assertEqual(renamed_query_string,
                      print_ast(renamed_alternative_query))
Example #5
0
def construct_stitched_query(info):
    if len(info.operation.variable_definitions) > 0:
        variable_defs = '(' + ','.join(
                print_ast(info.operation.variable_definitions)) + ')'
    else:
        variable_defs = ''
    query = print_ast(info.field_asts[0].selection_set)
    fragments = [print_ast(x) for x in info.fragments.values()]
    return '\n'.join([
        f'''query {info.operation.name.value}{variable_defs} {query}''']
        + fragments)
def _parse_long_literal(value_node: ValueNode, _variables=None) -> int:
    if not isinstance(value_node, IntValueNode):
        raise GraphQLError(
            'Long cannot represent non-integer value: ' +
            print_ast(value_node), value_node)
    num = int(value_node.value)
    if not MIN_LONG <= num <= MAX_LONG:
        raise GraphQLError(
            'Long cannot represent non 53-biy signed integer value: ' +
            print_ast(value_node), value_node)
    return num
Example #7
0
def perform_macro_expansion(macro_registry, graphql_with_macro, graphql_args):
    """Return a new GraphQL query string and args, after expanding any encountered macros.

    Args:
        macro_registry: MacroRegistry, the registry of macro descriptors used for expansion
        graphql_with_macro: string, GraphQL query that potentially requires macro expansion
        graphql_args: dict mapping strings to any type, containing the arguments for the query

    Returns:
        tuple (new_graphql_string, new_graphql_args) containing the rewritten GraphQL query and
        its new args, after macro expansion. If the input GraphQL query contained no macros,
        the returned values are guaranteed to be identical to the input query and args.
    """
    query_ast = safe_parse_graphql(graphql_with_macro)
    schema_with_macros = get_schema_with_macros(macro_registry)
    validation_errors = validate_schema_and_query_ast(schema_with_macros,
                                                      query_ast)
    if validation_errors:
        raise GraphQLValidationError(
            u'The provided GraphQL input does not validate: {} {}'.format(
                graphql_with_macro, validation_errors))

    new_query_ast, new_args = expand_macros_in_query_ast(
        macro_registry, query_ast, graphql_args)
    new_graphql_string = print_ast(new_query_ast)

    return new_graphql_string, new_args
Example #8
0
    def test_query_type_field_argument(self):
        schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type SchemaQuery {
              Human(id: String!): Human
            }

            type Human {
              name: String
            }
        ''')
        renamed_schema = rename_schema(parse(schema_string), {
            'Human': 'NewHuman',
            'id': 'Id'
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type SchemaQuery {
              NewHuman(id: String!): NewHuman
            }

            type NewHuman {
              name: String
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({'NewHuman': 'Human'},
                         renamed_schema.reverse_name_map)
Example #9
0
    def test_union_rename(self):
        renamed_schema = rename_schema(parse(ISS.union_schema), {
            'HumanOrDroid': 'NewHumanOrDroid',
            'Droid': 'NewDroid'
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type Human {
              id: String
            }

            type NewDroid {
              id: String
            }

            union NewHumanOrDroid = Human | NewDroid

            type SchemaQuery {
              Human: Human
              NewDroid: NewDroid
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual(
            {
                'NewDroid': 'Droid',
                'NewHumanOrDroid': 'HumanOrDroid'
            }, renamed_schema.reverse_name_map)
Example #10
0
    def test_directive_rename(self):
        renamed_schema = rename_schema(parse(ISS.directive_schema), {
            'Human': 'NewHuman',
            'Droid': 'NewDroid',
            'stitch': 'NewStitch',
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type NewHuman {
              id: String
            }

            type NewDroid {
              id: String
              friend: NewHuman @stitch(source_field: "id", sink_field: "id")
            }

            directive @stitch(source_field: String!, sink_field: String!) on FIELD_DEFINITION

            type SchemaQuery {
              NewHuman: NewHuman
              NewDroid: NewDroid
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            'NewHuman': 'Human',
            'NewDroid': 'Droid'
        }, renamed_schema.reverse_name_map)
Example #11
0
    def test_scalar_rename(self):
        renamed_schema = rename_schema(parse(ISS.scalar_schema), {
            'Human': 'NewHuman',
            'Date': 'NewDate',
            'String': 'NewString'
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type NewHuman {
              id: String
              birthday: Date
            }

            scalar Date

            type SchemaQuery {
              NewHuman: NewHuman
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({'NewHuman': 'Human'},
                         renamed_schema.reverse_name_map)
Example #12
0
    def test_interface_rename(self):
        renamed_schema = rename_schema(parse(ISS.interface_schema), {
            'Kid': 'NewKid',
            'Character': 'NewCharacter'
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            interface NewCharacter {
              id: String
            }

            type NewKid implements NewCharacter {
              id: String
            }

            type SchemaQuery {
              NewCharacter: NewCharacter
              NewKid: NewKid
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            'NewKid': 'Kid',
            'NewCharacter': 'Character'
        }, renamed_schema.reverse_name_map)
Example #13
0
    def test_enum_rename(self):
        renamed_schema = rename_schema(parse(ISS.enum_schema), {
            'Droid': 'NewDroid',
            'Height': 'NewHeight'
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type NewDroid {
              height: NewHeight
            }

            type SchemaQuery {
              NewDroid: NewDroid
            }

            enum NewHeight {
              TALL
              SHORT
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            'NewDroid': 'Droid',
            'NewHeight': 'Height'
        }, renamed_schema.reverse_name_map)
Example #14
0
    def test_swap_rename(self):
        renamed_schema = rename_schema(parse(ISS.multiple_objects_schema), {
            'Human': 'Droid',
            'Droid': 'Human'
        })
        renamed_schema_string = dedent('''\
            schema {
              query: SchemaQuery
            }

            type Droid {
              name: String
            }

            type Human {
              id: String
            }

            type Dog {
              nickname: String
            }

            type SchemaQuery {
              Droid: Droid
              Human: Human
              Dog: Dog
            }
        ''')
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            'Human': 'Droid',
            'Droid': 'Human'
        }, renamed_schema.reverse_name_map)
Example #15
0
    def test_swap_rename(self):
        renamed_schema = rename_schema(parse(ISS.multiple_objects_schema), {
            "Human": "Droid",
            "Droid": "Human"
        })
        renamed_schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            type Droid {
              name: String
            }

            type Human {
              id: String
            }

            type Dog {
              nickname: String
            }

            type SchemaQuery {
              Droid: Droid
              Human: Human
              Dog: Dog
            }
        """)
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            "Human": "Droid",
            "Droid": "Human"
        }, renamed_schema.reverse_name_map)
Example #16
0
    def test_scalar_rename(self):
        renamed_schema = rename_schema(
            parse(ISS.scalar_schema),
            {
                "Human": "NewHuman",
                "Date": "NewDate",
                "String": "NewString"
            },
        )
        renamed_schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            type NewHuman {
              id: String
              birthday: Date
            }

            scalar Date

            type SchemaQuery {
              NewHuman: NewHuman
            }
        """)
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({"NewHuman": "Human"},
                         renamed_schema.reverse_name_map)
Example #17
0
def _raise_macro_reversal_conflict_error(new_macro_descriptor,
                                         existing_descriptor,
                                         specific_resolution_advice):
    """Raise a macro validation error related to the inability to reverse the given macro edge."""
    if not specific_resolution_advice:
        raise AssertionError(
            "No specific error resolution advice given, this should never happen: {} {} {}"
            .format(new_macro_descriptor, existing_descriptor,
                    specific_resolution_advice))

    raise GraphQLInvalidMacroError(
        "The given macro edge with name {edge_name} defined on type {base_class_name} and "
        "pointing to type {target_class_name} is invalid due to a reversibility conflict. "
        "Macro edges are required to be reversible, but the corresponding reversed macro "
        "edge {reverse_edge_name} from {target_class_name} to {base_class_name} would be "
        "impossible to define because of a conflict with an existing macro edge: "
        "{reverse_edge_name} from {conflicting_base} to {conflicting_target}. To resolve "
        "the issue, either choose a new name for your macro edge, or "
        "{specific_advice}."
        "Conflicting macro edge definition: {macro_graphql} with args {macro_args}"
        .format(
            edge_name=new_macro_descriptor.macro_edge_name,
            base_class_name=new_macro_descriptor.base_class_name,
            target_class_name=new_macro_descriptor.target_class_name,
            reverse_edge_name=existing_descriptor.macro_edge_name,
            conflicting_base=existing_descriptor.base_class_name,
            conflicting_target=existing_descriptor.target_class_name,
            specific_advice=specific_resolution_advice,
            macro_graphql=print_ast(existing_descriptor.expansion_ast),
            macro_args=existing_descriptor.macro_args,
        ))
 def test_rename_nested_query(self):
     query_string = dedent('''\
         {
           NewAnimal {
             name @output(out_name: "name")
             out_Animal_ParentOf {
               name @output(out_name: "parent_name")
               description @output(out_name: "parent_description")
               out_Animal_LivesIn {
                 description @output(out_name: "parent_location")
               }
             }
           }
         }
     ''')
     renamed_query = rename_query(parse(query_string), basic_renamed_schema)
     renamed_query_string = dedent('''\
         {
           Animal {
             name @output(out_name: "name")
             out_Animal_ParentOf {
               name @output(out_name: "parent_name")
               description @output(out_name: "parent_description")
               out_Animal_LivesIn {
                 description @output(out_name: "parent_location")
               }
             }
           }
         }
     ''')
     self.assertEqual(renamed_query_string, print_ast(renamed_query))
Example #19
0
    def test_interface_rename(self):
        renamed_schema = rename_schema(parse(ISS.interface_schema), {
            "Kid": "NewKid",
            "Character": "NewCharacter"
        })
        renamed_schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            interface NewCharacter {
              id: String
            }

            type NewKid implements NewCharacter {
              id: String
            }

            type SchemaQuery {
              NewCharacter: NewCharacter
              NewKid: NewKid
            }
        """)
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            "NewKid": "Kid",
            "NewCharacter": "Character"
        }, renamed_schema.reverse_name_map)
Example #20
0
    def test_enum_rename(self):
        renamed_schema = rename_schema(parse(ISS.enum_schema), {
            "Droid": "NewDroid",
            "Height": "NewHeight"
        })
        renamed_schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            type NewDroid {
              height: NewHeight
            }

            type SchemaQuery {
              NewDroid: NewDroid
            }

            enum NewHeight {
              TALL
              SHORT
            }
        """)
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({
            "NewDroid": "Droid",
            "NewHeight": "Height"
        }, renamed_schema.reverse_name_map)
 def test_nested_inline_fragment(self):
     query_string = dedent('''\
         {
           NewEntity {
             out_Entity_Related {
               ... on NewAnimal {
                 out_Animal_ImportantEvent {
                   ... on NewBirthEvent {
                     event_date @output(out_name: "date")
                   }
                 }
               }
             }
           }
         }
     ''')
     renamed_query = rename_query(parse(query_string), basic_renamed_schema)
     renamed_query_string = dedent('''\
         {
           Entity {
             out_Entity_Related {
               ... on Animal {
                 out_Animal_ImportantEvent {
                   ... on BirthEvent {
                     event_date @output(out_name: "date")
                   }
                 }
               }
             }
           }
         }
     ''')
     self.assertEqual(renamed_query_string, print_ast(renamed_query))
Example #22
0
    def execute(
        self,
        document: DocumentNode,
        variable_values: Dict[str, Any] = {}  # noqa: B006
    ) -> ExtendedExecutionResult:
        query_str = print_ast(document)
        payload = {"query": query_str, "variables": variable_values}

        response = self.session.post(
            self.url,
            data=json.dumps(payload, default=encode_variable).encode("utf-8"),
            headers=self.headers,
        )

        result = response.json()

        extensions = {}
        if "x-correlation-id" in response.headers:
            extensions["trace_id"] = response.headers["x-correlation-id"]

        assert ("errors" in result or "data" in result
                ), 'Received non-compatible response "{}"'.format(result)

        return ExtendedExecutionResult(
            response=response.text,
            errors=result.get("errors"),
            data=result.get("data"),
            extensions=extensions,
        )
 def test_inline_fragment(self):
     query_string = dedent('''\
         {
           NewEntity {
             out_Entity_Related {
               ... on NewAnimal {
                 color @output(out_name: "color")
               }
             }
           }
         }
     ''')
     renamed_query = rename_query(parse(query_string), basic_renamed_schema)
     renamed_query_string = dedent('''\
         {
           Entity {
             out_Entity_Related {
               ... on Animal {
                 color @output(out_name: "color")
               }
             }
           }
         }
     ''')
     self.assertEqual(renamed_query_string, print_ast(renamed_query))
Example #24
0
    def execute(self,
                document,
                variable_values=None,
                timeout=None,
                return_json=True):
        query_str = print_ast(document)
        payload = {"query": query_str, "variables": variable_values or {}}

        request = self.session.post(
            self.url,
            data=json.dumps(payload, default=encode_variable).encode("utf-8"),
            headers=self.headers,
        )
        request.raise_for_status()

        result = request.json()

        extensions = {}
        if "x-correlation-id" in request.headers:
            extensions["err_id"] = request.headers["x-correlation-id"]

        assert ("errors" in result or "data" in result
                ), 'Received non-compatible response "{}"'.format(result)

        data = result.get("data") if return_json else request.text
        return ExtendedExecutionResult(errors=result.get("errors"),
                                       data=data,
                                       extensions=extensions)
Example #25
0
def parse_definitions(identifiers, definitions):
    ret = ''
    fragments = set()

    for identifier in identifiers.split(','):
        identifier = identifier.strip()

        if identifier not in definitions:
            msg = 'Cannot import definition `{}`'.format(identifier)
            raise DocumentImportError(msg)

        definition = definitions[identifier]
        ret += print_ast(definition)
        fragments.update(fragments_generator(definition, definitions))

    return ''.join(print_ast(fragment) for fragment in fragments) + ret
Example #26
0
 def from_ast_with_parameters(
         cls: Type[QueryStringWithParametersT],
         ast_with_params: "ASTWithParameters"
 ) -> QueryStringWithParametersT:
     """Convert an ASTWithParameters into its equivalent QueryStringWithParameters form."""
     query_string = print_ast(ast_with_params.query_ast)
     return cls(query_string, ast_with_params.parameters)
Example #27
0
    def execute(self,
                document,
                variable_values=None,
                timeout=None,
                token=None):
        payload = {
            "query": print_ast(document),
            "variables": variable_values or {}
        }

        # TODO: check for file objects: hasattr(fp, 'read')

        self.inject_token(token)

        post_args = {
            "headers": self.headers,
            "timeout": timeout or self.default_timeout,
            "json": payload,
        }

        request = requests.post(self.url, **post_args)
        request.raise_for_status()

        result = request.json()
        assert ("errors" in result or "data" in result
                ), 'Received non-compatible response "{}"'.format(result)
        return ExecutionResult(errors=result.get("errors"),
                               data=result.get("data"))
 def test_directive(self):
     query_string = dedent('''\
         {
           NewEntity {
             out_Entity_Related {
               ... on NewAnimal {
                 color @output(out_name: "color")
                 out_Animal_ParentOf @optional {
                   name @filter(op_name: "=", value: ["$species_name"])
                 }
               }
             }
           }
         }
     ''')
     renamed_query = rename_query(parse(query_string), basic_renamed_schema)
     renamed_query_string = dedent('''\
         {
           Entity {
             out_Entity_Related {
               ... on Animal {
                 color @output(out_name: "color")
                 out_Animal_ParentOf @optional {
                   name @filter(op_name: "=", value: ["$species_name"])
                 }
               }
             }
           }
         }
     ''')
     self.assertEqual(renamed_query_string, print_ast(renamed_query))
Example #29
0
    def test_query_type_field_argument(self):
        schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            type SchemaQuery {
              Human(id: String!): Human
            }

            type Human {
              name: String
            }
        """)
        renamed_schema = rename_schema(parse(schema_string), {
            "Human": "NewHuman",
            "id": "Id"
        })
        renamed_schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            type SchemaQuery {
              NewHuman(id: String!): NewHuman
            }

            type NewHuman {
              name: String
            }
        """)
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual({"NewHuman": "Human"},
                         renamed_schema.reverse_name_map)
Example #30
0
    def test_union_rename(self):
        renamed_schema = rename_schema(parse(ISS.union_schema), {
            "HumanOrDroid": "NewHumanOrDroid",
            "Droid": "NewDroid"
        })
        renamed_schema_string = dedent("""\
            schema {
              query: SchemaQuery
            }

            type Human {
              id: String
            }

            type NewDroid {
              id: String
            }

            union NewHumanOrDroid = Human | NewDroid

            type SchemaQuery {
              Human: Human
              NewDroid: NewDroid
            }
        """)
        self.assertEqual(renamed_schema_string,
                         print_ast(renamed_schema.schema_ast))
        self.assertEqual(
            {
                "NewDroid": "Droid",
                "NewHumanOrDroid": "HumanOrDroid"
            },
            renamed_schema.reverse_name_map,
        )
def test_it_concatenates_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) == '''{
def test_prints_kitchen_sink():
    ast = parse(SCHEMA_KITCHEN_SINK)
    printed = print_ast(ast)

    expected = '''schema {
  query: QueryType
  mutation: MutationType
}

type Foo implements Bar {
  one: Type
  two(argument: InputType!): Type
  three(argument: InputType, other: String): Int
  four(argument: String = "string"): String
  five(argument: [String] = ["string", "string"]): String
  six(argument: InputType = {key: "value"}): Type
}

interface Bar {
  one: Type
  four(argument: String = "string"): String
}

union Feed = Story | Article | Advert

scalar CustomScalar

enum Site {
  DESKTOP
  MOBILE
}

input InputType {
  key: String!
  answer: Int = 42
}

extend type Foo {
  seven(argument: [String]): Type
}

directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
'''

    assert printed == expected
Example #33
0
    def execute(self, document, variable_values=None, timeout=None):
        query_str = print_ast(document)
        payload = {
            'query': query_str,
            'variables': variable_values or {}
        }

        data_key = 'json' if self.use_json else 'data'
        post_args = {
            'headers': self.headers,
            'auth': self.auth,
            'cookies': self.cookies,
            'timeout': timeout or self.default_timeout,
            data_key: payload
        }
        request = requests.post(self.url, **post_args)
        request.raise_for_status()

        result = request.json()
        assert 'errors' in result or 'data' in result, 'Received non-compatible response "{}"'.format(result)
        return ExecutionResult(
            errors=result.get('errors'),
            data=result.get('data')
        )
def test_prints_minimal_ast():
    ast = Field(name=Name(loc=None, value='foo'))
    assert print_ast(ast) == 'foo'
def test_prints_kitchen_sink():
    ast = parse(KITCHEN_SINK)
    printed = print_ast(ast)
    assert printed == '''query queryName($foo: ComplexType, $site: Site = MOBILE) {
def test_prints_kitchen_sink():
    ast = parse(SCHEMA_KITCHEN_SINK)
    printed = print_ast(ast)

    expected = '''schema {
  query: QueryType
  mutation: MutationType
}

type Foo implements Bar {
  one: Type
  two(argument: InputType!): Type
  three(argument: InputType, other: String): Int
  four(argument: String = "string"): String
  five(argument: [String] = ["string", "string"]): String
  six(argument: InputType = {key: "value"}): Type
}

type AnnotatedObject @onObject(arg: "value") {
  annotatedField(arg: Type = "default" @onArg): Type @onField
}

interface Bar {
  one: Type
  four(argument: String = "string"): String
}

interface AnnotatedInterface @onInterface {
  annotatedField(arg: Type @onArg): Type @onField
}

union Feed = Story | Article | Advert

union AnnotatedUnion @onUnion = A | B

scalar CustomScalar

scalar AnnotatedScalar @onScalar

enum Site {
  DESKTOP
  MOBILE
}

enum AnnotatedEnum @onEnum {
  ANNOTATED_VALUE @onEnumValue
  OTHER_VALUE
}

input InputType {
  key: String!
  answer: Int = 42
}

input AnnotatedInput @onInputObjectType {
  annotatedField: Type @onField
}

extend type Foo {
  seven(argument: [String]): Type
}

extend type Foo @onType {}

type NoFields {}

directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
'''

    assert printed == expected
Example #37
0
 def __str__(self):
     return print_ast(self.ast_field)
def test_print_produces_helpful_error_messages():
    bad_ast = {'random': 'Data'}
    with raises(AssertionError) as excinfo:
        print_ast(bad_ast)

    assert "Invalid AST Node: {'random': 'Data'}" in str(excinfo.value)
def test_visits_with_typeinfo_maintains_type_info_during_edit():
    visited = []
    ast = parse('{ human(id: 4) { name, pets }, alien }')

    type_info = TypeInfo(test_schema)

    class TestVisitor(Visitor):

        def enter(self, node, key, parent, *args):
            parent_type = type_info.get_parent_type()
            _type = type_info.get_type()
            input_type = type_info.get_input_type()
            visited.append([
                'enter',
                type(node).__name__,
                node.value if type(node).__name__ == "Name" else None,
                str(parent_type) if parent_type else None,
                str(_type) if _type else None,
                str(input_type) if input_type else None
            ])

            # Make a query valid by adding missing selection sets.
            if type(node).__name__ == "Field" and not node.selection_set and is_composite_type(get_named_type(_type)):
                return Field(
                    alias=node.alias,
                    name=node.name,
                    arguments=node.arguments,
                    directives=node.directives,
                    selection_set=SelectionSet(
                        [Field(name=Name(value='__typename'))]
                    )
                )

        def leave(self, node, key, parent, *args):
            parent_type = type_info.get_parent_type()
            _type = type_info.get_type()
            input_type = type_info.get_input_type()
            visited.append([
                'leave',
                type(node).__name__,
                node.value if type(node).__name__ == "Name" else None,
                str(parent_type) if parent_type else None,
                str(_type) if _type else None,
                str(input_type) if input_type else None
            ])

    edited_ast = visit(ast, TypeInfoVisitor(type_info, TestVisitor()))

    # assert print_ast(ast) == print_ast(parse(
    #     '{ human(id: 4) { name, pets }, alien }'
    # ))
    assert print_ast(edited_ast) == print_ast(parse(
        '{ human(id: 4) { name, pets { __typename } }, alien { __typename } }'
    ))
    assert visited == [
        ['enter', 'Document', None, None, None, None],
        ['enter', 'OperationDefinition', None, None, 'QueryRoot', None],
        ['enter', 'SelectionSet', None, 'QueryRoot', 'QueryRoot', None],
        ['enter', 'Field', None, 'QueryRoot', 'Human', None],
        ['enter', 'Name', 'human', 'QueryRoot', 'Human', None],
        ['leave', 'Name', 'human', 'QueryRoot', 'Human', None],
        ['enter', 'Argument', None, 'QueryRoot', 'Human', 'ID'],
        ['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],
        ['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],
        ['enter', 'IntValue', None, 'QueryRoot', 'Human', 'ID'],
        ['leave', 'IntValue', None, 'QueryRoot', 'Human', 'ID'],
        ['leave', 'Argument', None, 'QueryRoot', 'Human', 'ID'],
        ['enter', 'SelectionSet', None, 'Human', 'Human', None],
        ['enter', 'Field', None, 'Human', 'String', None],
        ['enter', 'Name', 'name', 'Human', 'String', None],
        ['leave', 'Name', 'name', 'Human', 'String', None],
        ['leave', 'Field', None, 'Human', 'String', None],
        ['enter', 'Field', None, 'Human', '[Pet]', None],
        ['enter', 'Name', 'pets', 'Human', '[Pet]', None],
        ['leave', 'Name', 'pets', 'Human', '[Pet]', None],
        ['enter', 'SelectionSet', None, 'Pet', '[Pet]', None],
        ['enter', 'Field', None, 'Pet', 'String!', None],
        ['enter', 'Name', '__typename', 'Pet', 'String!', None],
        ['leave', 'Name', '__typename', 'Pet', 'String!', None],
        ['leave', 'Field', None, 'Pet', 'String!', None],
        ['leave', 'SelectionSet', None, 'Pet', '[Pet]', None],
        ['leave', 'Field', None, 'Human', '[Pet]', None],
        ['leave', 'SelectionSet', None, 'Human', 'Human', None],
        ['leave', 'Field', None, 'QueryRoot', 'Human', None],
        ['enter', 'Field', None, 'QueryRoot', 'Alien', None],
        ['enter', 'Name', 'alien', 'QueryRoot', 'Alien', None],
        ['leave', 'Name', 'alien', 'QueryRoot', 'Alien', None],
        ['enter', 'SelectionSet', None, 'Alien', 'Alien', None],
        ['enter', 'Field', None, 'Alien', 'String!', None],
        ['enter', 'Name', '__typename', 'Alien', 'String!', None],
        ['leave', 'Name', '__typename', 'Alien', 'String!', None],
        ['leave', 'Field', None, 'Alien', 'String!', None],
        ['leave', 'SelectionSet', None, 'Alien', 'Alien', None],
        ['leave', 'Field', None, 'QueryRoot', 'Alien', None],
        ['leave', 'SelectionSet', None, 'QueryRoot', 'QueryRoot', None],
        ['leave', 'OperationDefinition', None, None, 'QueryRoot', None],
        ['leave', 'Document', None, None, None, None]
    ]
def test_prints_minimal_ast():
    node = ast.ScalarTypeDefinition(
        name=ast.Name('foo')
    )

    assert print_ast(node) == 'scalar foo'
def test_produces_helpful_error_messages():
    bad_ast = {'random': 'Data'}
    with raises(Exception) as excinfo:
        print_ast(bad_ast)
    assert 'Invalid AST Node' in str(excinfo.value)
def test_does_not_alter_ast():
    ast = parse(SCHEMA_KITCHEN_SINK)
    ast_copy = deepcopy(ast)
    print_ast(ast)
    assert ast == ast_copy
def test_correctly_prints_mutation_operation_without_name():
    mutation_ast = parse('mutation { id, name }')
    assert print_ast(mutation_ast) == '''mutation {
def test_correctly_prints_query_operation_without_name():
    query_ast_shorthanded = parse('query { id, name }')
    assert print_ast(query_ast_shorthanded) == '''{
def test_correctly_prints_mutation_with_artifacts():
    query_ast_shorthanded = parse(
        'mutation ($foo: TestType) @testDirective { id, name }'
    )
    assert print_ast(query_ast_shorthanded) == '''mutation ($foo: TestType) @testDirective {