From 8cb979134200c1c84f1f1064c54a11aa5366a30f Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Mon, 24 Oct 2022 16:24:13 +0000 Subject: [PATCH] fix: reviews comments --- docs/requirements.txt | 1 + docs/types/schema.rst | 133 ++++++++++++++++++++ graphene/types/schema.py | 62 +++++---- graphene/types/tests/test_mutation.py | 12 +- graphene/types/tests/test_query.py | 8 +- graphene/types/tests/test_schema.py | 174 ++++++++++++++++++++------ setup.py | 2 +- 7 files changed, 316 insertions(+), 76 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index dcc403123..e94d216b7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,6 @@ # Required library Sphinx==1.5.3 +jinja2<3.1.0 sphinx-autobuild==0.7.1 # Docs template http://graphene-python.org/sphinx_graphene_theme.zip diff --git a/docs/types/schema.rst b/docs/types/schema.rst index a82addc9a..f491dd123 100644 --- a/docs/types/schema.rst +++ b/docs/types/schema.rst @@ -92,3 +92,136 @@ To disable this behavior, set the ``auto_camelcase`` to ``False`` upon schema in query=MyRootQuery, auto_camelcase=False, ) + +.. _SchemaTypeNamePrefix: + +Type name prefix +-------------------------- + +You can specify a prefix for all type names in the schema by setting the ``type_name_prefix`` argument upon schema instantiation: + +.. code:: python + + my_schema = Schema( + query=MyRootQuery, + mutation=MyRootMutation, + subscription=MyRootSubscription + type_name_prefix='MyPrefix', + ) + +This is useful in a micro-services architecture to prepend the service name to all types and avoid conflicts for example. + +The prefix will be added to the name of: + +* Query / Mutation / Subscription +* ObjectType +* InputType +* Interface +* Union +* Enum + +While fields and arguments name will be left untouched. + +More specifically, the following schema: + +.. code:: + + type Query { + inner: MyType + } + + type MyType { + field: String + myUnion: MyUnion + myBarType: MyBarType + myFooType: MyFooType + } + + union MyUnion = MyBarType | MyFooType + + type MyBarType { + field(input: MyInputObjectType): String + myInterface: MyInterface + } + + input MyInputObjectType { + field: String + } + + interface MyInterface { + field: String + } + + type MyFooType { + field: String + myEnum: MyEnum + } + + enum MyEnum { + FOO + BAR + } + + type Mutation { + createUser(name: String): CreateUser + } + + type CreateUser { + name: String + } + + type Subscription { + countToTen: Int + } + +Will be transformed to: + +.. code:: + + type Query { + myPrefixInner: MyPrefixMyType + } + + type MyPrefixMyType { + field: String + myUnion: MyPrefixMyUnion + myBarType: MyPrefixMyBarType + myFooType: MyPrefixMyFooType + } + + union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType + + type MyPrefixMyBarType { + field(input: MyPrefixMyInputObjectType): String + myInterface: MyPrefixMyInterface + } + + input MyPrefixMyInputObjectType { + field: String + } + + interface MyPrefixMyInterface { + field: String + } + + type MyPrefixMyFooType { + field: String + myEnum: MyPrefixMyEnum + } + + enum MyPrefixMyEnum { + FOO + BAR + } + + type Mutation { + myPrefixCreateUser(name: String): MyPrefixCreateUser + } + + type MyPrefixCreateUser { + name: String + } + + type Subscription { + myPrefixCountToTen: Int + } diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 7d885b271..5db3a83e9 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -91,7 +91,7 @@ def __init__( subscription=None, types=None, auto_camelcase=True, - object_type_name_prefix=None, + type_name_prefix=None, ): assert_valid_root_type(query) assert_valid_root_type(mutation) @@ -102,17 +102,17 @@ def __init__( assert is_graphene_type(type_) self.auto_camelcase = auto_camelcase - self.object_type_name_prefix = object_type_name_prefix + self.type_name_prefix = type_name_prefix create_graphql_type = self.add_type - self.root_names = [] + self.root_type_names = [] if query: - self.root_names.append(query._meta.name) + self.root_type_names.append(query._meta.name) if mutation: - self.root_names.append(mutation._meta.name) + self.root_type_names.append(mutation._meta.name) if subscription: - self.root_names.append(subscription._meta.name) + self.root_type_names.append(subscription._meta.name) self.query = create_graphql_type(query) if query else None self.mutation = create_graphql_type(mutation) if mutation else None @@ -174,8 +174,7 @@ def create_scalar(graphene_type): parse_literal=getattr(graphene_type, "parse_literal", None), ) - @staticmethod - def create_enum(graphene_type): + def create_enum(self, graphene_type): values = {} for name, value in graphene_type._meta.enum.__members__.items(): description = getattr(value, "description", None) @@ -203,7 +202,7 @@ def create_enum(graphene_type): return GrapheneEnumType( graphene_type=graphene_type, values=values, - name=graphene_type._meta.name, + name=self.add_prefix_to_type_name(graphene_type._meta.name), description=type_description, ) @@ -225,11 +224,10 @@ def interfaces(): else: is_type_of = graphene_type.is_type_of - name = ( - self.object_type_name_prefix.capitalize() - if self.object_type_name_prefix - else "" - ) + graphene_type._meta.name + if graphene_type._meta.name in self.root_type_names: + name = graphene_type._meta.name + else: + name = self.add_prefix_to_type_name(graphene_type._meta.name) return GrapheneObjectType( graphene_type=graphene_type, @@ -259,7 +257,7 @@ def interfaces(): return GrapheneInterfaceType( graphene_type=graphene_type, - name=graphene_type._meta.name, + name=self.add_prefix_to_type_name(graphene_type._meta.name), description=graphene_type._meta.description, fields=partial(self.create_fields_for_type, graphene_type), interfaces=interfaces, @@ -269,7 +267,7 @@ def interfaces(): def create_inputobjecttype(self, graphene_type): return GrapheneInputObjectType( graphene_type=graphene_type, - name=graphene_type._meta.name, + name=self.add_prefix_to_type_name(graphene_type._meta.name), description=graphene_type._meta.description, out_type=graphene_type._meta.container, fields=partial( @@ -298,7 +296,7 @@ def types(): return GrapheneUnionType( graphene_type=graphene_type, - name=graphene_type._meta.name, + name=self.add_prefix_to_type_name(graphene_type._meta.name), description=graphene_type._meta.description, types=types, resolve_type=resolve_type, @@ -376,13 +374,8 @@ def create_fields_for_type(self, graphene_type, is_input_type=False): if field.name: field_name = field.name else: - if ( - self.object_type_name_prefix - and graphene_type._meta.name in self.root_names - ): - field_name = self.get_name( - self.object_type_name_prefix + "_" + name - ) + if graphene_type._meta.name in self.root_type_names: + field_name = self.add_prefix_to_field_name(name) else: field_name = self.get_name(name) fields[field_name] = _field @@ -418,6 +411,23 @@ def resolve_type(self, resolve_type_func, type_name, root, info, _type): return_type = self[type_name] return default_type_resolver(root, info, return_type) + def add_prefix_to_type_name(self, name): + if self.type_name_prefix: + return self.type_name_prefix[0].upper() + self.type_name_prefix[1:] + name + return name + + def add_prefix_to_field_name(self, name): + if self.type_name_prefix: + if self.auto_camelcase: + return self.get_name( + self.type_name_prefix[0].lower() + + self.type_name_prefix[1:] + + "_" + + name + ) + return self.get_name(self.type_name_prefix + name) + return self.get_name(name) + class Schema: """Schema Definition. @@ -448,7 +458,7 @@ def __init__( types=None, directives=None, auto_camelcase=True, - object_type_name_prefix=None, + type_name_prefix=None, ): self.query = query self.mutation = mutation @@ -459,7 +469,7 @@ def __init__( subscription, types, auto_camelcase=auto_camelcase, - object_type_name_prefix=object_type_name_prefix, + type_name_prefix=type_name_prefix, ) self.graphql_schema = GraphQLSchema( type_map.query, diff --git a/graphene/types/tests/test_mutation.py b/graphene/types/tests/test_mutation.py index 09ec51029..1f13109c2 100644 --- a/graphene/types/tests/test_mutation.py +++ b/graphene/types/tests/test_mutation.py @@ -220,7 +220,7 @@ class Query(ObjectType): assert result.data == {"createUserWithPlanet": {"name": "Peter", "planet": "earth"}} -def test_object_type_name_prefix(): +def test_type_name_prefix(): class BaseCreateUser(Mutation): class Arguments: name = String() @@ -245,10 +245,14 @@ class MyMutation(ObjectType): class Query(ObjectType): a = String() - schema = Schema(query=Query, mutation=MyMutation, object_type_name_prefix="prefix") + schema = Schema( + query=Query, + mutation=MyMutation, + type_name_prefix="MyPrefix", + ) result = schema.execute( """ mutation mymutation { - prefixCreateUserWithPlanet(name:"Peter", planet: "earth") { + myPrefixCreateUserWithPlanet(name:"Peter", planet: "earth") { name planet } @@ -257,5 +261,5 @@ class Query(ObjectType): ) assert not result.errors assert result.data == { - "prefixCreateUserWithPlanet": {"name": "Peter", "planet": "earth"} + "myPrefixCreateUserWithPlanet": {"name": "Peter", "planet": "earth"} } diff --git a/graphene/types/tests/test_query.py b/graphene/types/tests/test_query.py index 3b9debebf..e808750b0 100644 --- a/graphene/types/tests/test_query.py +++ b/graphene/types/tests/test_query.py @@ -499,7 +499,7 @@ def resolve_user(self, *args, **kwargs): assert result.data == expected -def test_object_type_name_prefix(): +def test_type_name_prefix(): class Cat(ObjectType): name = String() @@ -516,9 +516,9 @@ class Query(ObjectType): def resolve_user(self, *args, **kwargs): return User(name="foo") - schema = Schema(query=Query, object_type_name_prefix="prefix") - expected = {"prefixUser": {"name": "foo", "cat": {"name": "bar"}}} - result = schema.execute("{ prefixUser { name cat { name } } }") + schema = Schema(query=Query, type_name_prefix="MyPrefix") + expected = {"myPrefixUser": {"name": "foo", "cat": {"name": "bar"}}} + result = schema.execute("{ myPrefixUser { name cat { name } } }") assert not result.errors assert result.data == expected diff --git a/graphene/types/tests/test_schema.py b/graphene/types/tests/test_schema.py index a8e25ee8d..75084976f 100644 --- a/graphene/types/tests/test_schema.py +++ b/graphene/types/tests/test_schema.py @@ -5,23 +5,53 @@ from graphql.type import GraphQLObjectType, GraphQLSchema from ..field import Field +from ..enum import Enum +from ..inputobjecttype import InputObjectType +from ..interface import Interface from ..mutation import Mutation from ..objecttype import ObjectType from ..scalars import Int, String from ..schema import Schema +from ..union import Union -class MyType(ObjectType): +class MyInputObjectType(InputObjectType): + field = String() + + +class MyEnum(Enum): + FOO = "foo" + BAR = "bar" + + +class MyInterface(Interface): field = String() -class MyOtherType(ObjectType): +class MyBarType(ObjectType): + field = String(input=MyInputObjectType()) + my_interface = Field(MyInterface) + + +class MyFooType(ObjectType): + field = String() + my_enum = MyEnum() + + +class MyUnion(Union): + class Meta: + types = (MyBarType, MyFooType) + + +class MyType(ObjectType): field = String() - my_type = Field(MyType) + my_union = MyUnion() + my_bar_type = Field(MyBarType) + my_foo_type = Field("graphene.types.tests.test_schema.MyFooType") class Query(ObjectType): - inner = Field(MyOtherType) + inner = Field(MyType) class CreateUser(Mutation): @@ -55,7 +85,12 @@ def test_schema(): def test_schema_get_type(): schema = Schema(Query) assert schema.Query == Query - assert schema.MyOtherType == MyOtherType + assert schema.MyType == MyType + assert schema.MyBarType == MyBarType + assert schema.MyFooType == MyFooType + assert schema.MyInputObjectType == MyInputObjectType + assert schema.MyInterface == MyInterface + assert schema.MyEnum == MyEnum def test_schema_get_type_error(): @@ -73,17 +108,40 @@ def test_schema_str(): == dedent( """ type Query { - inner: MyOtherType + inner: MyType } - type MyOtherType { + type MyType { field: String - myType: MyType + myUnion: MyUnion + myBarType: MyBarType + myFooType: MyFooType } - type MyType { + union MyUnion = MyBarType | MyFooType + + type MyBarType { + field(input: MyInputObjectType): String + myInterface: MyInterface + } + + input MyInputObjectType { + field: String + } + + interface MyInterface { field: String } + + type MyFooType { + field: String + myEnum: MyEnum + } + + enum MyEnum { + FOO + BAR + } """ ).strip() ) @@ -103,94 +161,128 @@ def test_schema_requires_query_type(): assert error.message == "Query root type must be provided." -def test_schema_object_type_name_prefix_camelcase(): +def test_schema_type_name_prefix_camelcase(): schema = Schema( Query, Mutation, Subscription, auto_camelcase=True, - object_type_name_prefix="prefix", + type_name_prefix="MyPrefix", ) assert ( str(schema).strip() == dedent( """ - schema { - query: PrefixQuery - mutation: PrefixMutation - subscription: PrefixSubscription + type Query { + myPrefixInner: MyPrefixMyType + } + + type MyPrefixMyType { + field: String + myUnion: MyPrefixMyUnion + myBarType: MyPrefixMyBarType + myFooType: MyPrefixMyFooType + } + + union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType + + type MyPrefixMyBarType { + field(input: MyPrefixMyInputObjectType): String + myInterface: MyPrefixMyInterface } - type PrefixQuery { - prefixInner: PrefixMyOtherType + input MyPrefixMyInputObjectType { + field: String } - type PrefixMyOtherType { + interface MyPrefixMyInterface { field: String - myType: PrefixMyType } - type PrefixMyType { + type MyPrefixMyFooType { field: String + myEnum: MyPrefixMyEnum } - type PrefixMutation { - prefixCreateUser(name: String): PrefixCreateUser + enum MyPrefixMyEnum { + FOO + BAR } - type PrefixCreateUser { + type Mutation { + myPrefixCreateUser(name: String): MyPrefixCreateUser + } + + type MyPrefixCreateUser { name: String } - type PrefixSubscription { - prefixCountToTen: Int + type Subscription { + myPrefixCountToTen: Int } """ ).strip() ) -def test_schema_object_type_name_prefix_camelcase_disabled(): +def test_schema_type_name_prefix_camelcase_disabled(): schema = Schema( Query, Mutation, Subscription, auto_camelcase=False, - object_type_name_prefix="prefix", + type_name_prefix="MyPrefix", ) assert ( str(schema).strip() == dedent( """ - schema { - query: PrefixQuery - mutation: PrefixMutation - subscription: PrefixSubscription + type Query { + MyPrefixinner: MyPrefixMyType + } + + type MyPrefixMyType { + field: String + my_union: MyPrefixMyUnion + my_bar_type: MyPrefixMyBarType + my_foo_type: MyPrefixMyFooType } - type PrefixQuery { - prefix_inner: PrefixMyOtherType + union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType + + type MyPrefixMyBarType { + field(input: MyPrefixMyInputObjectType): String + my_interface: MyPrefixMyInterface } - type PrefixMyOtherType { + input MyPrefixMyInputObjectType { field: String - my_type: PrefixMyType } - type PrefixMyType { + interface MyPrefixMyInterface { field: String } - type PrefixMutation { - prefix_create_user(name: String): PrefixCreateUser + type MyPrefixMyFooType { + field: String + my_enum: MyPrefixMyEnum + } + + enum MyPrefixMyEnum { + FOO + BAR + } + + type Mutation { + MyPrefixcreate_user(name: String): MyPrefixCreateUser } - type PrefixCreateUser { + type MyPrefixCreateUser { name: String } - type PrefixSubscription { - prefix_count_to_ten: Int + type Subscription { + MyPrefixcount_to_ten: Int } """ ).strip() diff --git a/setup.py b/setup.py index dce6aa6c0..243b6bae6 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def run_tests(self): "coveralls>=3.3,<4", "promise>=2.3,<3", "mock>=4,<5", - "pytz==2022.1", + "pytz==2022.5", "iso8601>=1,<2", ]