def test_graphql_options(): class Book(GraphQLModel): class GraphQL: gql_type = "Book" class User_2(GraphQLModel): class GraphQL: gql_type = "User" include = ["username"] exclude = ["profile"] class User_3(GraphQLModel): class GraphQL: gql_type = "User" include = ["unknow"] bindable = PydanticBindable({"User_2": User_2, "Book": Book}) with pytest.raises(PydanticBindError): make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, bindable, ) bindable = PydanticBindable({"User_3": User_3, "Book": Book}) with pytest.raises(PydanticBindError): make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, bindable, )
def test_executable_schema_creation_errors_if_type_defs_is_graphql_query(): type_defs = """ query { test } """ with pytest.raises(TypeError): make_executable_schema(type_defs)
def test_non_null(): schema = gql( """ scalar Date scalar DateTime scalar JSON directive @policy on FIELD_DEFINITION type Query { _: Boolean } type Mutation { _: Boolean } type GraphQLTypes { nonNull: Int! @policy } """ ) from turbulette.apps.auth.directives import PolicyDirective with pytest.raises(SchemaError): make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, directives={"policy": PolicyDirective}, )
def test_validator(): class Book(GraphQLModel): class GraphQL: gql_type = "Book" class User(GraphQLModel): class GraphQL: gql_type = "User" @validator("username") def check_username(value): if len(value) <= 3: raise ValueError("Username length must be greater than 3") return value bindable = PydanticBindable({"User": User, "Book": Book}) make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, bindable, ) User(username="******") with pytest.raises(ValidationError): User(username="******")
def test_register_type(): class Foo(GraphQLModel): class GraphQL: gql_type = "Foo" bindable = PydanticBindable({"Foo": Foo}) # Remove JSON type bindable._type_map.pop("JSON") with pytest.raises(PydanticBindError): make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, bindable, ) # Bring it back through `register` method bindable.register_scalar("JSON", dict) make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, bindable, )
def test_executable_schema_creation_errors_if_type_defs_is_invalid_schema(): type_defs = """ type Mutation { test: Boolean! } """ with pytest.raises(TypeError): make_executable_schema(type_defs)
def test_directive_raises_type_error_if_required_argument_is_not_given(): type_defs = """ directive @test(arg: String!) on FIELD_DEFINITION type Query { hello: String @test } """ with pytest.raises(TypeError): make_executable_schema(type_defs, directives={"test": ReturnValueDirective})
def test_graphql_types(): """Test pydantic bindings.""" class GraphQLTypes(GraphQLModel): class GraphQL: gql_type = "GraphQLTypes" bindable = PydanticBindable({"GraphQLTypes": GraphQLTypes}) make_executable_schema( schema, base_scalars_resolvers, snake_case_fallback_resolvers, bindable, ) book_schema = GraphQLTypes.schema() book_schema.pop("description") assert book_schema == { "properties": { "id": { "title": "Id", "anyOf": [{ "type": "integer" }, { "type": "string" }], }, "string": { "title": "String", "type": "string" }, "int": { "title": "Int", "type": "integer" }, "float": { "title": "Float", "type": "number" }, "bool": { "title": "Bool", "type": "boolean" }, }, "required": ["int"], "title": "GraphQLTypes", "type": "object", } GraphQLTypes(int=1) with pytest.raises(ValueError): GraphQLTypes()
def test_visitor_missing_method_raises_error(): type_defs = """ directive @objectFieldDirective on FIELD_DEFINITION type Query { people: [String] @objectFieldDirective } """ class Visitor(SchemaDirectiveVisitor): def visit_object(self, object_: GraphQLObjectType): return object_ with pytest.raises(ValueError): make_executable_schema(type_defs, directives={"objectFieldDirective": Visitor})
def schema(): type_defs = """ interface Other { name: String! } type Query { constant: Int! simple(value: Int!): Int! complex(valueA: Int, valueB: Int): Int! nested(value: NestedInput!): Int! child(value: Int!): [Child!]! } input NestedInput{ num: Int! } type Child { name: String! online: Boolean! } """ return make_executable_schema(type_defs)
def test_int_enum_input_nested_default_python_value_is_set(): input_schema = """ type Query { complex(i: BetterTest = { test: { role: EMPIRE }}): Boolean } input Test { ignore: String role: Episode = EMPIRE } input BetterTest { newIgnore: String test: Test = { role: NEWHOPE } } """ query = QueryType() def resolve_test_enum(*_, i): return i["test"]["role"] == PyIntEnum.EMPIRE query.set_field("complex", resolve_test_enum) schema = make_executable_schema([enum_definition, input_schema], [query, int_enum]) result = graphql_sync(schema, "{ complex(i: {test: {} }) }") assert result.errors is None assert result.data["complex"]
def test_query_custom_type_custom_resolver(): type_defs = """ schema { query: Query } type Query { test: Custom } type Custom { node: String } """ resolvers = { "Query": { "test": lambda *_: { "node": "custom" } }, "Custom": { "node": lambda *_: "deep" }, } schema = make_executable_schema(type_defs, resolvers) result = graphql(schema, "{ test { node } }") assert result.errors is None assert result.data == {"test": {"node": "deep"}}
def test_query_custom_scalar(): type_defs = """ schema { query: Query } scalar Date type Query { test: Date } """ resolvers = { "Query": { "test": lambda *_: date.today() }, "Date": lambda date: date.strftime("%Y-%m-%d"), } schema = make_executable_schema(type_defs, resolvers) result = graphql(schema, "{ test }") assert result.errors is None assert result.data == {"test": date.today().strftime("%Y-%m-%d")}
def test_mapping_resolver_to_object_attribute(): type_defs = """ type Query { user: User } type User { firstName: String } """ resolvers = { "Query": { "user": lambda *_: Mock(first_name="Joe") }, "User": { "firstName": resolve_to("first_name") }, } schema = make_executable_schema(type_defs, resolvers) result = graphql(schema, "{ user { firstName } }") assert result.errors is None assert result.data == {"user": {"firstName": "Joe"}}
def test_query_custom_type_merged_custom_default_resolvers(): type_defs = """ type Query { test: Custom } type Custom { node: String default: String } """ resolvers = { "Query": { "test": lambda *_: { "node": "custom", "default": "ok" } }, "Custom": { "node": lambda *_: "deep" }, } schema = make_executable_schema(type_defs, resolvers) result = graphql(schema, "{ test { node default } }") assert result.errors is None assert result.data == {"test": {"node": "deep", "default": "ok"}}
def test_mutation_input(): type_defs = """ type Query { _: String } input StaffInput { name: String } type Staff { name: String } type Mutation { addStaff(data: StaffInput): Staff } """ def resolve_add_staff(*_, data): assert data == {"name": "Bob"} return data resolvers = {"Mutation": {"addStaff": resolve_add_staff}} schema = make_executable_schema(type_defs, resolvers) result = graphql(schema, 'mutation { addStaff(data: { name: "Bob" }) { name } }') assert result.errors is None assert result.data == {"addStaff": {"name": "Bob"}}
def test_enum_input_value_resolution(mocker): class ClownTypes(Enum): SAD = "Sad Clown" HAPPY = "Happy Clown" class ClownEmotionResolver(InputMixin, Resolver): def retrieve(self, *args, **kwargs): """Get sad, return happy""" assert self.get_input_data().get("type") == "Sad Clown" return ClownTypes.HAPPY class ClownEmotionResolverOff(InputMixin, Resolver): convert_enums = False def retrieve(self, *args, **kwargs): """Get sad enum, return happy enum""" assert self.get_input_data().get("type") == ClownTypes.SAD return ClownTypes.HAPPY type_defs = """ enum ClownTypes { "Sad Clown" SAD "Happy Clown" HAPPY } input ClownInput { type: ClownTypes } type Query { clownEmotion(input: ClownInput!): ClownTypes clownEmotionOff(input: ClownInput!): ClownTypes } """ query = QueryType() clown_types = EnumType("ClownTypes", ClownTypes) query.set_field("clownEmotion", ClownEmotionResolver.as_resolver()) query.set_field("clownEmotionOff", ClownEmotionResolverOff.as_resolver()) resolvers = [query, clown_types] schema = make_executable_schema(type_defs, resolvers) result = graphql_sync( schema, """ query { on: clownEmotion(input: {type: SAD}) off: clownEmotionOff(input: {type: SAD}) } """, ) assert result.errors is None assert glom(result.data, "on") == "HAPPY" assert glom(result.data, "off") == "HAPPY"
def test_field_definition_directive_replaces_field_resolver_with_custom_one(): type_defs = """ directive @upper on FIELD_DEFINITION directive @reverse on FIELD_DEFINITION type Query { test: Custom } type Custom { node: String @upper name: String @reverse } """ query = QueryType() query.set_field("test", lambda *_: {"node": "custom", "name": "uppercase"}) schema = make_executable_schema( type_defs, [query], directives={"upper": UpperDirective, "reverse": ReverseDirective}, ) result = graphql_sync(schema, "{ test { node name }}") assert result.errors is None assert result.data == {"test": {"node": "CUSTOM", "name": "esacreppu"}}
def test_succesfull_enum_typed_field(): query = QueryType() query.set_field("testEnum", lambda *_: TEST_VALUE) schema = make_executable_schema([enum_definition, enum_field], query) result = graphql_sync(schema, "{ testEnum }") assert result.errors is None
def create_server( type_defs, resolvers, directives=None, extensions=None, error_formatter=None ): schema = make_executable_schema( type_defs, *resolvers, snake_case_fallback_resolvers, directives=directives, ) app = Flask(__name__) @app.route("/graphql", methods=["GET"]) def graphql_playgroud(): return PLAYGROUND_HTML, 200 @app.route("/graphql", methods=["POST"]) def graphql_server(): data = request.get_json() success, result = graphql_sync( schema, data, debug=app.debug, context_value=None, error_formatter=error_formatter, extensions=extensions, ) status_code = 200 if success else 400 return jsonify(result), status_code return app
def test_can_implement_remove_enum_values_directive(): type_defs = """ directive @remove(if: Boolean) on ENUM_VALUE type Query { age(unit: AgeUnit): Int } enum AgeUnit { DOG_YEARS TURTLE_YEARS @remove(if: true) PERSON_YEARS @remove(if: false) } """ class RemoveEnumDirective(SchemaDirectiveVisitor): def visit_enum_value(self, value: GraphQLEnumValue, enum_type: GraphQLEnumType): if self.args["if"]: return False return None schema = make_executable_schema( type_defs, directives={"remove": RemoveEnumDirective} ) enum_type: GraphQLEnumType = schema.get_type("AgeUnit") assert list(enum_type.values.keys()) == ["DOG_YEARS", "PERSON_YEARS"]
def test_directive_can_add_new_type_to_schema(): type_defs = """ directive @key on OBJECT type Query { people: [String] } type User @key { id: Int } type Admin @key { id: Int } """ class Visitor(SchemaDirectiveVisitor): def visit_object(self, object_: GraphQLObjectType): try: types = self.schema.type_map["_Entity"].types except KeyError: u = self.schema.type_map["_Entity"] = GraphQLUnionType("_Entity", []) types = u.types types.append(object_) schema = make_executable_schema(type_defs, directives={"key": Visitor}) assert {t.name for t in schema.get_type("_Entity").types} == {"User", "Admin"}
def test_executing_mutation_takes_scalar_arg_and_returns_type(): type_defs = """ type Query { _: String } type Staff { name: String } type Mutation { addStaff(name: String): Staff } """ mutation = MutationType() @mutation.field("addStaff") def resolve_add_staff(*_, name): # pylint: disable=unused-variable assert name == "Bob" return {"name": name} schema = make_executable_schema(type_defs, mutation) result = graphql_sync(schema, 'mutation { addStaff(name: "Bob") { name } }') assert result.errors is None assert result.data == {"addStaff": {"name": "Bob"}}
def test_result_is_thread_title_if_union_resolves_type_to_thread( query_with_thread_item, ): union = UnionType("FeedItem", type_resolver=resolve_result_type) schema = make_executable_schema(type_defs, [query_with_thread_item, union]) result = graphql_sync(schema, test_query) assert result.data == {"item": {"__typename": "Thread", "title": Thread.title}}
def test_executing_mutation_using_input_type(): type_defs = """ type Query { _: String } input StaffInput { name: String } type Staff { name: String } type Mutation { addStaff(data: StaffInput): Staff } """ mutation = MutationType() @mutation.field("addStaff") def resolve_add_staff(*_, data): # pylint: disable=unused-variable assert data == {"name": "Bob"} return data schema = make_executable_schema(type_defs, mutation) result = graphql_sync( schema, 'mutation { addStaff(data: { name: "Bob" }) { name } }') assert result.errors is None assert result.data == {"addStaff": {"name": "Bob"}}
def test_result_is_none_if_union_didnt_resolve_the_type( query_with_invalid_item): union = UnionType("FeedItem", type_resolver=resolve_result_type) schema = make_executable_schema(type_defs, [query_with_invalid_item, union]) result = graphql_sync(schema, test_query) assert result.data == {"item": None}
def test_graphql(): type_defs = load_schema_from_path('schema.graphql') query = QueryType() building = ObjectType('Building') resident = ObjectType('Resident') # test dataset rec = building_with_id(None, None, "1") assert rec == {'id': '1', 'buildYear': 2009} residents = resolve_residents_in_building(rec, None) assert len(residents) > 0 # field holders query.set_field('building_with_id', building_with_id) building.set_field('residents', resolve_residents_in_building) schema = make_executable_schema(type_defs, [building, resident, query]) q = """{ building_with_id(_id:"1"){ id residents { id name } } } """ result = graphql_sync(schema, q) pprint(result.data) assert result.data['building_with_id']['id'] == '1'
def test_mutation_return_type(): type_defs = """ type Query { _: String } type Staff { name: String } type Mutation { addStaff(name: String): Staff } """ def resolve_add_staff(*_, name): assert name == "Bob" return {"name": name} resolvers = {"Mutation": {"addStaff": resolve_add_staff}} schema = make_executable_schema(type_defs, resolvers) result = graphql(schema, 'mutation { addStaff(name: "Bob") { name } }') assert result.errors is None assert result.data == {"addStaff": {"name": "Bob"}}
def test_unsuccesfull_invalid_enum_value_evaluation(): query = QueryType() query.set_field("testEnum", lambda *_: INVALID_VALUE) schema = make_executable_schema([enum_definition, enum_field], query) result = graphql_sync(schema, "{ testEnum }") assert result.errors is not None
def test_unsuccessful_invalid_enum_value_passed_as_argument(): query = QueryType() query.set_field("testEnum", lambda *_, value: True) schema = make_executable_schema([enum_definition, enum_param], query) result = graphql_sync(schema, "{ testEnum(value: %s) }" % INVALID_VALUE) assert result.errors is not None
import os from ariadne import QueryType, load_schema_from_path, make_executable_schema from .analytics import analytics from .status import status from .versioncheck import version_check FILE_PATH = os.path.dirname(os.path.abspath(__file__)) SCHEMA_PATH = os.path.join(FILE_PATH, "schema.graphql") type_defs = load_schema_from_path(SCHEMA_PATH) schema = make_executable_schema(type_defs, [analytics, status, version_check])