From 2dee4f2b375671af3d10475f8af39d6a626676a8 Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Fri, 14 Oct 2022 13:21:09 +0000 Subject: [PATCH 1/8] feat: added object_type_name_prefix --- graphene/types/schema.py | 38 +++++++- graphene/types/tests/test_mutation.py | 41 +++++++++ graphene/types/tests/test_query.py | 25 ++++++ graphene/types/tests/test_schema.py | 125 +++++++++++++++++++++++++- 4 files changed, 225 insertions(+), 4 deletions(-) diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 1a33a93d3..0915899d8 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -91,6 +91,7 @@ def __init__( subscription=None, types=None, auto_camelcase=True, + object_type_name_prefix=None, ): assert_valid_root_type(query) assert_valid_root_type(mutation) @@ -101,9 +102,18 @@ def __init__( assert is_graphene_type(type_) self.auto_camelcase = auto_camelcase + self.object_type_name_prefix = object_type_name_prefix create_graphql_type = self.add_type + self.root_names = [] + if query: + self.root_names.append(query._meta.name) + if mutation: + self.root_names.append(mutation._meta.name) + if subscription: + self.root_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 self.subscription = create_graphql_type(subscription) if subscription else None @@ -215,9 +225,15 @@ 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 + return GrapheneObjectType( graphene_type=graphene_type, - name=graphene_type._meta.name, + name=name, description=graphene_type._meta.description, fields=partial(self.create_fields_for_type, graphene_type), is_type_of=is_type_of, @@ -357,7 +373,17 @@ def create_fields_for_type(self, graphene_type, is_input_type=False): deprecation_reason=field.deprecation_reason, description=field.description, ) - field_name = field.name or self.get_name(name) + if field.name: + field_name = field.name + else: + if ( + self.object_type_name_prefix + and graphene_type._meta.name in self.root_names + ): + object_type_name_prefix = self.object_type_name_prefix + "_" + field_name = self.get_name(object_type_name_prefix + name) + else: + field_name = self.get_name(name) fields[field_name] = _field return fields @@ -421,12 +447,18 @@ def __init__( types=None, directives=None, auto_camelcase=True, + object_type_name_prefix=None, ): self.query = query self.mutation = mutation self.subscription = subscription type_map = TypeMap( - query, mutation, subscription, types, auto_camelcase=auto_camelcase + query, + mutation, + subscription, + types, + auto_camelcase=auto_camelcase, + object_type_name_prefix=object_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 4a7ad3c7c..09ec51029 100644 --- a/graphene/types/tests/test_mutation.py +++ b/graphene/types/tests/test_mutation.py @@ -218,3 +218,44 @@ class Query(ObjectType): ) assert not result.errors assert result.data == {"createUserWithPlanet": {"name": "Peter", "planet": "earth"}} + + +def test_object_type_name_prefix(): + class BaseCreateUser(Mutation): + class Arguments: + name = String() + + name = String() + + def mutate(self, info, **args): + return args + + class CreateUserWithPlanet(BaseCreateUser): + class Arguments(BaseCreateUser.Arguments): + planet = String() + + planet = String() + + def mutate(self, info, **args): + return CreateUserWithPlanet(**args) + + class MyMutation(ObjectType): + create_user_with_planet = CreateUserWithPlanet.Field() + + class Query(ObjectType): + a = String() + + schema = Schema(query=Query, mutation=MyMutation, object_type_name_prefix="prefix") + result = schema.execute( + """ mutation mymutation { + prefixCreateUserWithPlanet(name:"Peter", planet: "earth") { + name + planet + } + } + """ + ) + assert not result.errors + assert result.data == { + "prefixCreateUserWithPlanet": {"name": "Peter", "planet": "earth"} + } diff --git a/graphene/types/tests/test_query.py b/graphene/types/tests/test_query.py index e117754fe..3b9debebf 100644 --- a/graphene/types/tests/test_query.py +++ b/graphene/types/tests/test_query.py @@ -497,3 +497,28 @@ def resolve_user(self, *args, **kwargs): assert not result.errors assert result.data == expected + + +def test_object_type_name_prefix(): + class Cat(ObjectType): + name = String() + + class User(ObjectType): + name = String() + cat = Field(Cat) + + def resolve_cat(self, *args, **kwargs): + return Cat(name="bar") + + class Query(ObjectType): + user = Field(User) + + 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 } } }") + + 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 c03c81ba0..a8e25ee8d 100644 --- a/graphene/types/tests/test_schema.py +++ b/graphene/types/tests/test_schema.py @@ -5,19 +5,43 @@ from graphql.type import GraphQLObjectType, GraphQLSchema from ..field import Field +from ..mutation import Mutation from ..objecttype import ObjectType -from ..scalars import String +from ..scalars import Int, String from ..schema import Schema +class MyType(ObjectType): + field = String() + + class MyOtherType(ObjectType): field = String() + my_type = Field(MyType) class Query(ObjectType): inner = Field(MyOtherType) +class CreateUser(Mutation): + class Arguments: + name = String() + + name = String() + + def mutate(self, info, name): + return CreateUser(name=name) + + +class Mutation(ObjectType): + create_user = CreateUser.Field() + + +class Subscription(ObjectType): + count_to_ten = Field(Int) + + def test_schema(): schema = Schema(Query) graphql_schema = schema.graphql_schema @@ -54,6 +78,11 @@ def test_schema_str(): type MyOtherType { field: String + myType: MyType + } + + type MyType { + field: String } """ ).strip() @@ -72,3 +101,97 @@ def test_schema_requires_query_type(): assert len(result.errors) == 1 error = result.errors[0] assert error.message == "Query root type must be provided." + + +def test_schema_object_type_name_prefix_camelcase(): + schema = Schema( + Query, + Mutation, + Subscription, + auto_camelcase=True, + object_type_name_prefix="prefix", + ) + assert ( + str(schema).strip() + == dedent( + """ + schema { + query: PrefixQuery + mutation: PrefixMutation + subscription: PrefixSubscription + } + + type PrefixQuery { + prefixInner: PrefixMyOtherType + } + + type PrefixMyOtherType { + field: String + myType: PrefixMyType + } + + type PrefixMyType { + field: String + } + + type PrefixMutation { + prefixCreateUser(name: String): PrefixCreateUser + } + + type PrefixCreateUser { + name: String + } + + type PrefixSubscription { + prefixCountToTen: Int + } + """ + ).strip() + ) + + +def test_schema_object_type_name_prefix_camelcase_disabled(): + schema = Schema( + Query, + Mutation, + Subscription, + auto_camelcase=False, + object_type_name_prefix="prefix", + ) + assert ( + str(schema).strip() + == dedent( + """ + schema { + query: PrefixQuery + mutation: PrefixMutation + subscription: PrefixSubscription + } + + type PrefixQuery { + prefix_inner: PrefixMyOtherType + } + + type PrefixMyOtherType { + field: String + my_type: PrefixMyType + } + + type PrefixMyType { + field: String + } + + type PrefixMutation { + prefix_create_user(name: String): PrefixCreateUser + } + + type PrefixCreateUser { + name: String + } + + type PrefixSubscription { + prefix_count_to_ten: Int + } + """ + ).strip() + ) From 0633b629f59d642fd31c399e7b3f47792c0b0854 Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Sat, 15 Oct 2022 10:39:38 +0000 Subject: [PATCH 2/8] fix: style --- graphene/types/schema.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 0915899d8..7d885b271 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -380,8 +380,9 @@ def create_fields_for_type(self, graphene_type, is_input_type=False): self.object_type_name_prefix and graphene_type._meta.name in self.root_names ): - object_type_name_prefix = self.object_type_name_prefix + "_" - field_name = self.get_name(object_type_name_prefix + name) + field_name = self.get_name( + self.object_type_name_prefix + "_" + name + ) else: field_name = self.get_name(name) fields[field_name] = _field From 8cb979134200c1c84f1f1064c54a11aa5366a30f Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Mon, 24 Oct 2022 16:24:13 +0000 Subject: [PATCH 3/8] 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", ] From 84237060f436c3d92e5ca768360039130794b0e1 Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Tue, 25 Oct 2022 14:28:35 +0000 Subject: [PATCH 4/8] fix: added Scalar --- graphene/types/schema.py | 5 ++--- graphene/types/tests/test_schema.py | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 5db3a83e9..340eedc3e 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -151,8 +151,7 @@ def add_type(self, graphene_type): self[name] = graphql_type return graphql_type - @staticmethod - def create_scalar(graphene_type): + def create_scalar(self, graphene_type): # We have a mapping to the original GraphQL types # so there are no collisions. _scalars = { @@ -167,7 +166,7 @@ def create_scalar(graphene_type): return GrapheneScalarType( 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, serialize=getattr(graphene_type, "serialize", None), parse_value=getattr(graphene_type, "parse_value", None), diff --git a/graphene/types/tests/test_schema.py b/graphene/types/tests/test_schema.py index 75084976f..3ac0600b8 100644 --- a/graphene/types/tests/test_schema.py +++ b/graphene/types/tests/test_schema.py @@ -10,7 +10,7 @@ from ..interface import Interface from ..mutation import Mutation from ..objecttype import ObjectType -from ..scalars import Int, String +from ..scalars import Int, String, Scalar from ..schema import Schema from ..union import Union @@ -19,6 +19,10 @@ class MyInputObjectType(InputObjectType): field = String() +class MyScalar(Scalar): + ... + + class MyEnum(Enum): FOO = "foo" BAR = "bar" @@ -35,6 +39,7 @@ class MyBarType(ObjectType): class MyFooType(ObjectType): field = String() + my_scalar = MyScalar() my_enum = MyEnum() @@ -135,9 +140,12 @@ def test_schema_str(): type MyFooType { field: String + myScalar: MyScalar myEnum: MyEnum } + scalar MyScalar + enum MyEnum { FOO BAR @@ -201,9 +209,12 @@ def test_schema_type_name_prefix_camelcase(): type MyPrefixMyFooType { field: String + myScalar: MyPrefixMyScalar myEnum: MyPrefixMyEnum } + scalar MyPrefixMyScalar + enum MyPrefixMyEnum { FOO BAR @@ -265,9 +276,12 @@ def test_schema_type_name_prefix_camelcase_disabled(): type MyPrefixMyFooType { field: String + my_scalar: MyPrefixMyScalar my_enum: MyPrefixMyEnum } + scalar MyPrefixMyScalar + enum MyPrefixMyEnum { FOO BAR From 97dd7e5ac1800bf0fbf84530f8a209656d54eaf9 Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Wed, 26 Oct 2022 08:03:56 +0000 Subject: [PATCH 5/8] fix: review --- docs/types/schema.rst | 19 +- graphene/types/base.py | 3 +- graphene/types/schema.py | 59 +-- graphene/types/tests/test_schema.py | 134 ------- graphene/types/tests/test_type_name_prefix.py | 353 ++++++++++++++++++ 5 files changed, 408 insertions(+), 160 deletions(-) create mode 100644 graphene/types/tests/test_type_name_prefix.py diff --git a/docs/types/schema.rst b/docs/types/schema.rst index f491dd123..407dbe9b9 100644 --- a/docs/types/schema.rst +++ b/docs/types/schema.rst @@ -114,11 +114,12 @@ This is useful in a micro-services architecture to prepend the service name to a The prefix will be added to the name of: * Query / Mutation / Subscription +* Scalar * ObjectType * InputType +* Enum * Interface * Union -* Enum While fields and arguments name will be left untouched. @@ -157,6 +158,8 @@ More specifically, the following schema: myEnum: MyEnum } + scalar MyScalar + enum MyEnum { FOO BAR @@ -209,6 +212,8 @@ Will be transformed to: myEnum: MyPrefixMyEnum } + scalar MyPrefixMyScalar + enum MyPrefixMyEnum { FOO BAR @@ -225,3 +230,15 @@ Will be transformed to: type Subscription { myPrefixCountToTen: Int } + +You can override the prefix for a specific type by setting the ``type_name_prefix`` property on the ``Meta`` class: + +.. code:: python + + from graphene import ObjectType + + class MyGraphQlType(ObjectType): + class Meta: + type_name_prefix = 'MyOtherPrefix' + +This is useful when defining external types in a federated schema for example. diff --git a/graphene/types/base.py b/graphene/types/base.py index 84cb377a2..451851e0f 100644 --- a/graphene/types/base.py +++ b/graphene/types/base.py @@ -36,13 +36,14 @@ def create_type(cls, class_name, **options): @classmethod def __init_subclass_with_meta__( - cls, name=None, description=None, _meta=None, **_kwargs + cls, name=None, description=None, type_name_prefix=None, _meta=None, **_kwargs ): assert "_meta" not in cls.__dict__, "Can't assign meta directly" if not _meta: return _meta.name = name or cls.__name__ _meta.description = description or trim_docstring(cls.__doc__) + _meta.type_name_prefix = type_name_prefix _meta.freeze() cls._meta = _meta super(BaseType, cls).__init_subclass_with_meta__() diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 340eedc3e..e1ed9cebe 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -166,7 +166,7 @@ def create_scalar(self, graphene_type): return GrapheneScalarType( graphene_type=graphene_type, - name=self.add_prefix_to_type_name(graphene_type._meta.name), + name=self.get_type_name(graphene_type), description=graphene_type._meta.description, serialize=getattr(graphene_type, "serialize", None), parse_value=getattr(graphene_type, "parse_value", None), @@ -201,7 +201,7 @@ def create_enum(self, graphene_type): return GrapheneEnumType( graphene_type=graphene_type, values=values, - name=self.add_prefix_to_type_name(graphene_type._meta.name), + name=self.get_type_name(graphene_type), description=type_description, ) @@ -226,7 +226,7 @@ def interfaces(): 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) + name = self.get_type_name(graphene_type) return GrapheneObjectType( graphene_type=graphene_type, @@ -256,7 +256,7 @@ def interfaces(): return GrapheneInterfaceType( graphene_type=graphene_type, - name=self.add_prefix_to_type_name(graphene_type._meta.name), + name=self.get_type_name(graphene_type), description=graphene_type._meta.description, fields=partial(self.create_fields_for_type, graphene_type), interfaces=interfaces, @@ -266,7 +266,7 @@ def interfaces(): def create_inputobjecttype(self, graphene_type): return GrapheneInputObjectType( graphene_type=graphene_type, - name=self.add_prefix_to_type_name(graphene_type._meta.name), + name=self.get_type_name(graphene_type), description=graphene_type._meta.description, out_type=graphene_type._meta.container, fields=partial( @@ -295,7 +295,7 @@ def types(): return GrapheneUnionType( graphene_type=graphene_type, - name=self.add_prefix_to_type_name(graphene_type._meta.name), + name=self.get_type_name(graphene_type), description=graphene_type._meta.description, types=types, resolve_type=resolve_type, @@ -373,10 +373,7 @@ def create_fields_for_type(self, graphene_type, is_input_type=False): if field.name: field_name = field.name else: - 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) + field_name = self.get_field_name(graphene_type, name) fields[field_name] = _field return fields @@ -410,21 +407,35 @@ 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 get_type_name(self, graphene_type): + type_name_prefix = ( + graphene_type._meta.type_name_prefix + if graphene_type._meta.type_name_prefix is not None + else self.type_name_prefix + ) + if type_name_prefix: + return ( + type_name_prefix[0].upper() + + type_name_prefix[1:] + + graphene_type._meta.name + ) + return graphene_type._meta.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) + def get_field_name(self, graphene_type, name): + if graphene_type._meta.name in self.root_type_names: + # We only add the prefix to the root types and types defined prefixes take precedence + # over schema defined prefix. + type_name_prefix = ( + graphene_type._meta.type_name_prefix + if graphene_type._meta.type_name_prefix is not None + else self.type_name_prefix + ) + if type_name_prefix: + if self.auto_camelcase: + return to_camel_case( + type_name_prefix[0].lower() + type_name_prefix[1:] + "_" + name + ) + return type_name_prefix + name return self.get_name(name) diff --git a/graphene/types/tests/test_schema.py b/graphene/types/tests/test_schema.py index 3ac0600b8..22941970f 100644 --- a/graphene/types/tests/test_schema.py +++ b/graphene/types/tests/test_schema.py @@ -167,137 +167,3 @@ def test_schema_requires_query_type(): assert len(result.errors) == 1 error = result.errors[0] assert error.message == "Query root type must be provided." - - -def test_schema_type_name_prefix_camelcase(): - schema = Schema( - Query, - Mutation, - Subscription, - auto_camelcase=True, - type_name_prefix="MyPrefix", - ) - assert ( - str(schema).strip() - == dedent( - """ - 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 - myScalar: MyPrefixMyScalar - myEnum: MyPrefixMyEnum - } - - scalar MyPrefixMyScalar - - enum MyPrefixMyEnum { - FOO - BAR - } - - type Mutation { - myPrefixCreateUser(name: String): MyPrefixCreateUser - } - - type MyPrefixCreateUser { - name: String - } - - type Subscription { - myPrefixCountToTen: Int - } - """ - ).strip() - ) - - -def test_schema_type_name_prefix_camelcase_disabled(): - schema = Schema( - Query, - Mutation, - Subscription, - auto_camelcase=False, - type_name_prefix="MyPrefix", - ) - assert ( - str(schema).strip() - == dedent( - """ - type Query { - MyPrefixinner: MyPrefixMyType - } - - type MyPrefixMyType { - field: String - my_union: MyPrefixMyUnion - my_bar_type: MyPrefixMyBarType - my_foo_type: MyPrefixMyFooType - } - - union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType - - type MyPrefixMyBarType { - field(input: MyPrefixMyInputObjectType): String - my_interface: MyPrefixMyInterface - } - - input MyPrefixMyInputObjectType { - field: String - } - - interface MyPrefixMyInterface { - field: String - } - - type MyPrefixMyFooType { - field: String - my_scalar: MyPrefixMyScalar - my_enum: MyPrefixMyEnum - } - - scalar MyPrefixMyScalar - - enum MyPrefixMyEnum { - FOO - BAR - } - - type Mutation { - MyPrefixcreate_user(name: String): MyPrefixCreateUser - } - - type MyPrefixCreateUser { - name: String - } - - type Subscription { - MyPrefixcount_to_ten: Int - } - """ - ).strip() - ) diff --git a/graphene/types/tests/test_type_name_prefix.py b/graphene/types/tests/test_type_name_prefix.py new file mode 100644 index 000000000..add188aeb --- /dev/null +++ b/graphene/types/tests/test_type_name_prefix.py @@ -0,0 +1,353 @@ +from textwrap import dedent + + +from ..field import Field +from ..enum import Enum +from ..inputobjecttype import InputObjectType +from ..interface import Interface +from ..mutation import Mutation as Mutation_ +from ..objecttype import ObjectType +from ..scalars import Int, String, Scalar +from ..schema import Schema +from ..union import Union + + +def test_schema_type_name_prefix_override(): + class MyInputObjectType(InputObjectType): + class Meta: + type_name_prefix = "OverridePrefix" + + field = String() + + class MyScalar(Scalar): + class Meta: + type_name_prefix = "" + + class MyEnum(Enum): + class Meta: + type_name_prefix = "" + + FOO = "foo" + BAR = "bar" + + class MyInterface(Interface): + class Meta: + type_name_prefix = "" + + field = String() + + class MyBarType(ObjectType): + class Meta: + type_name_prefix = "" + + field = String(input=MyInputObjectType()) + my_interface = Field(MyInterface) + my_scalar = MyScalar() + my_enum = MyEnum() + + class MyFooType(ObjectType): + class Meta: + type_name_prefix = "" + + field = String() + + class MyUnion(Union): + class Meta: + type_name_prefix = "" + types = (MyBarType, MyFooType) + + class MyType(ObjectType): + class Meta: + type_name_prefix = "" + + field = String() + my_union = MyUnion() + my_bar_type = Field(MyBarType) + + class Query(ObjectType): + class Meta: + type_name_prefix = "OverridePrefix" + + inner = Field(MyType) + + class CreateUser(Mutation_): + class Meta: + type_name_prefix = "" + + class Arguments: + name = String() + + name = String() + + def mutate(self, info, name): + return CreateUser(name=name) + + class Mutation(ObjectType): + class Meta: + type_name_prefix = "" + + create_user = CreateUser.Field() + + class Subscription(ObjectType): + class Meta: + type_name_prefix = "" + + count_to_ten = Field(Int) + + schema = Schema( + Query, + Mutation, + Subscription, + auto_camelcase=True, + type_name_prefix="MyPrefix", + ) + assert ( + str(schema).strip() + == dedent( + """ + type Query { + overridePrefixInner: MyType + } + + type MyType { + field: String + myUnion: MyUnion + myBarType: MyBarType + } + + union MyUnion = MyBarType | MyFooType + + type MyBarType { + field(input: OverridePrefixMyInputObjectType): String + myInterface: MyInterface + myScalar: MyScalar + myEnum: MyEnum + } + + input OverridePrefixMyInputObjectType { + field: String + } + + interface MyInterface { + field: String + } + + scalar MyScalar + + enum MyEnum { + FOO + BAR + } + + type MyFooType { + field: String + } + + type Mutation { + createUser(name: String): CreateUser + } + + type CreateUser { + name: String + } + + type Subscription { + countToTen: Int + } + """ + ).strip() + ) + + +class MyInputObjectType(InputObjectType): + field = String() + + +class MyScalar(Scalar): + ... + + +class MyEnum(Enum): + FOO = "foo" + BAR = "bar" + + +class MyInterface(Interface): + field = String() + + +class MyBarType(ObjectType): + field = String(input=MyInputObjectType()) + my_interface = Field(MyInterface) + my_scalar = MyScalar() + my_enum = MyEnum() + + +class MyFooType(ObjectType): + field = String() + + +class MyUnion(Union): + class Meta: + types = (MyBarType, MyFooType) + + +class MyType(ObjectType): + field = String() + my_union = MyUnion() + my_bar_type = Field(MyBarType) + + +class Query(ObjectType): + inner = Field(MyType) + + +class CreateUser(Mutation_): + class Arguments: + name = String() + + name = String() + + def mutate(self, info, name): + return CreateUser(name=name) + + +class Mutation(ObjectType): + create_user = CreateUser.Field() + + +class Subscription(ObjectType): + count_to_ten = Field(Int) + + +def test_schema_type_name_prefix_camelcase(): + + schema = Schema( + Query, + Mutation, + Subscription, + auto_camelcase=True, + type_name_prefix="MyPrefix", + ) + assert ( + str(schema).strip() + == dedent( + """ + type Query { + myPrefixInner: MyPrefixMyType + } + + type MyPrefixMyType { + field: String + myUnion: MyPrefixMyUnion + myBarType: MyPrefixMyBarType + } + + union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType + + type MyPrefixMyBarType { + field(input: MyPrefixMyInputObjectType): String + myInterface: MyPrefixMyInterface + myScalar: MyPrefixMyScalar + myEnum: MyPrefixMyEnum + } + + input MyPrefixMyInputObjectType { + field: String + } + + interface MyPrefixMyInterface { + field: String + } + + scalar MyPrefixMyScalar + + enum MyPrefixMyEnum { + FOO + BAR + } + + type MyPrefixMyFooType { + field: String + } + + type Mutation { + myPrefixCreateUser(name: String): MyPrefixCreateUser + } + + type MyPrefixCreateUser { + name: String + } + + type Subscription { + myPrefixCountToTen: Int + } + """ + ).strip() + ) + + +def test_schema_type_name_prefix_camelcase_disabled(): + schema = Schema( + Query, + Mutation, + Subscription, + auto_camelcase=False, + type_name_prefix="MyPrefix", + ) + assert ( + str(schema).strip() + == dedent( + """ + type Query { + MyPrefixinner: MyPrefixMyType + } + + type MyPrefixMyType { + field: String + my_union: MyPrefixMyUnion + my_bar_type: MyPrefixMyBarType + } + + union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType + + type MyPrefixMyBarType { + field(input: MyPrefixMyInputObjectType): String + my_interface: MyPrefixMyInterface + my_scalar: MyPrefixMyScalar + my_enum: MyPrefixMyEnum + } + + input MyPrefixMyInputObjectType { + field: String + } + + interface MyPrefixMyInterface { + field: String + } + + scalar MyPrefixMyScalar + + enum MyPrefixMyEnum { + FOO + BAR + } + + type MyPrefixMyFooType { + field: String + } + + type Mutation { + MyPrefixcreate_user(name: String): MyPrefixCreateUser + } + + type MyPrefixCreateUser { + name: String + } + + type Subscription { + MyPrefixcount_to_ten: Int + } + """ + ).strip() + ) From b0e179fcf5dcb240509de8f97560ca13be80b37e Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Wed, 26 Oct 2022 08:11:36 +0000 Subject: [PATCH 6/8] fix: style --- graphene/types/tests/test_type_name_prefix.py | 295 +++++++++--------- 1 file changed, 147 insertions(+), 148 deletions(-) diff --git a/graphene/types/tests/test_type_name_prefix.py b/graphene/types/tests/test_type_name_prefix.py index add188aeb..49cb9b0a3 100644 --- a/graphene/types/tests/test_type_name_prefix.py +++ b/graphene/types/tests/test_type_name_prefix.py @@ -1,6 +1,5 @@ from textwrap import dedent - from ..field import Field from ..enum import Enum from ..inputobjecttype import InputObjectType @@ -12,153 +11,6 @@ from ..union import Union -def test_schema_type_name_prefix_override(): - class MyInputObjectType(InputObjectType): - class Meta: - type_name_prefix = "OverridePrefix" - - field = String() - - class MyScalar(Scalar): - class Meta: - type_name_prefix = "" - - class MyEnum(Enum): - class Meta: - type_name_prefix = "" - - FOO = "foo" - BAR = "bar" - - class MyInterface(Interface): - class Meta: - type_name_prefix = "" - - field = String() - - class MyBarType(ObjectType): - class Meta: - type_name_prefix = "" - - field = String(input=MyInputObjectType()) - my_interface = Field(MyInterface) - my_scalar = MyScalar() - my_enum = MyEnum() - - class MyFooType(ObjectType): - class Meta: - type_name_prefix = "" - - field = String() - - class MyUnion(Union): - class Meta: - type_name_prefix = "" - types = (MyBarType, MyFooType) - - class MyType(ObjectType): - class Meta: - type_name_prefix = "" - - field = String() - my_union = MyUnion() - my_bar_type = Field(MyBarType) - - class Query(ObjectType): - class Meta: - type_name_prefix = "OverridePrefix" - - inner = Field(MyType) - - class CreateUser(Mutation_): - class Meta: - type_name_prefix = "" - - class Arguments: - name = String() - - name = String() - - def mutate(self, info, name): - return CreateUser(name=name) - - class Mutation(ObjectType): - class Meta: - type_name_prefix = "" - - create_user = CreateUser.Field() - - class Subscription(ObjectType): - class Meta: - type_name_prefix = "" - - count_to_ten = Field(Int) - - schema = Schema( - Query, - Mutation, - Subscription, - auto_camelcase=True, - type_name_prefix="MyPrefix", - ) - assert ( - str(schema).strip() - == dedent( - """ - type Query { - overridePrefixInner: MyType - } - - type MyType { - field: String - myUnion: MyUnion - myBarType: MyBarType - } - - union MyUnion = MyBarType | MyFooType - - type MyBarType { - field(input: OverridePrefixMyInputObjectType): String - myInterface: MyInterface - myScalar: MyScalar - myEnum: MyEnum - } - - input OverridePrefixMyInputObjectType { - field: String - } - - interface MyInterface { - field: String - } - - scalar MyScalar - - enum MyEnum { - FOO - BAR - } - - type MyFooType { - field: String - } - - type Mutation { - createUser(name: String): CreateUser - } - - type CreateUser { - name: String - } - - type Subscription { - countToTen: Int - } - """ - ).strip() - ) - - class MyInputObjectType(InputObjectType): field = String() @@ -351,3 +203,150 @@ def test_schema_type_name_prefix_camelcase_disabled(): """ ).strip() ) + + +def test_schema_type_name_prefix_override(): + class MyInputObjectType(InputObjectType): + class Meta: + type_name_prefix = "OverridePrefix" + + field = String() + + class MyScalar(Scalar): + class Meta: + type_name_prefix = "" + + class MyEnum(Enum): + class Meta: + type_name_prefix = "" + + FOO = "foo" + BAR = "bar" + + class MyInterface(Interface): + class Meta: + type_name_prefix = "" + + field = String() + + class MyBarType(ObjectType): + class Meta: + type_name_prefix = "" + + field = String(input=MyInputObjectType()) + my_interface = Field(MyInterface) + my_scalar = MyScalar() + my_enum = MyEnum() + + class MyFooType(ObjectType): + class Meta: + type_name_prefix = "" + + field = String() + + class MyUnion(Union): + class Meta: + type_name_prefix = "" + types = (MyBarType, MyFooType) + + class MyType(ObjectType): + class Meta: + type_name_prefix = "" + + field = String() + my_union = MyUnion() + my_bar_type = Field(MyBarType) + + class Query(ObjectType): + class Meta: + type_name_prefix = "OverridePrefix" + + inner = Field(MyType) + + class CreateUser(Mutation_): + class Meta: + type_name_prefix = "" + + class Arguments: + name = String() + + name = String() + + def mutate(self, info, name): + return CreateUser(name=name) + + class Mutation(ObjectType): + class Meta: + type_name_prefix = "" + + create_user = CreateUser.Field() + + class Subscription(ObjectType): + class Meta: + type_name_prefix = "" + + count_to_ten = Field(Int) + + schema = Schema( + Query, + Mutation, + Subscription, + auto_camelcase=True, + type_name_prefix="MyPrefix", + ) + assert ( + str(schema).strip() + == dedent( + """ + type Query { + overridePrefixInner: MyType + } + + type MyType { + field: String + myUnion: MyUnion + myBarType: MyBarType + } + + union MyUnion = MyBarType | MyFooType + + type MyBarType { + field(input: OverridePrefixMyInputObjectType): String + myInterface: MyInterface + myScalar: MyScalar + myEnum: MyEnum + } + + input OverridePrefixMyInputObjectType { + field: String + } + + interface MyInterface { + field: String + } + + scalar MyScalar + + enum MyEnum { + FOO + BAR + } + + type MyFooType { + field: String + } + + type Mutation { + createUser(name: String): CreateUser + } + + type CreateUser { + name: String + } + + type Subscription { + countToTen: Int + } + """ + ).strip() + ) From 673a28288d7d82021abb1e3516ae2d5c87844ec7 Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Wed, 26 Oct 2022 08:12:00 +0000 Subject: [PATCH 7/8] fix: docs --- docs/types/schema.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/schema.rst b/docs/types/schema.rst index 407dbe9b9..e7d2c101e 100644 --- a/docs/types/schema.rst +++ b/docs/types/schema.rst @@ -239,6 +239,6 @@ You can override the prefix for a specific type by setting the ``type_name_prefi class MyGraphQlType(ObjectType): class Meta: - type_name_prefix = 'MyOtherPrefix' + type_name_prefix = '' This is useful when defining external types in a federated schema for example. From 0ea463671e989b5cead493004db30600e70f27a5 Mon Sep 17 00:00:00 2001 From: Laurent Riviere Date: Thu, 27 Oct 2022 13:06:48 +0000 Subject: [PATCH 8/8] fix: static method --- graphene/types/schema.py | 32 +++++++++++++------------------- graphene/types/utils.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/graphene/types/schema.py b/graphene/types/schema.py index e1ed9cebe..4819d76ab 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -49,7 +49,7 @@ from .scalars import ID, Boolean, Float, Int, Scalar, String from .structures import List, NonNull from .union import Union -from .utils import get_field_as +from .utils import get_field_as, get_type_name introspection_query = get_introspection_query() IntrospectionSchema = introspection_types["__Schema"] @@ -141,9 +141,9 @@ def add_type(self, graphene_type): elif issubclass(graphene_type, Interface): graphql_type = self.create_interface(graphene_type) elif issubclass(graphene_type, Scalar): - graphql_type = self.create_scalar(graphene_type) + graphql_type = self.create_scalar(graphene_type, self.type_name_prefix) elif issubclass(graphene_type, Enum): - graphql_type = self.create_enum(graphene_type) + graphql_type = self.create_enum(graphene_type, self.type_name_prefix) elif issubclass(graphene_type, Union): graphql_type = self.construct_union(graphene_type) else: @@ -151,7 +151,11 @@ def add_type(self, graphene_type): self[name] = graphql_type return graphql_type - def create_scalar(self, graphene_type): + @staticmethod + def create_scalar( + graphene_type, + type_name_prefix=None, + ): # We have a mapping to the original GraphQL types # so there are no collisions. _scalars = { @@ -166,14 +170,15 @@ def create_scalar(self, graphene_type): return GrapheneScalarType( graphene_type=graphene_type, - name=self.get_type_name(graphene_type), + name=get_type_name(graphene_type, type_name_prefix), description=graphene_type._meta.description, serialize=getattr(graphene_type, "serialize", None), parse_value=getattr(graphene_type, "parse_value", None), parse_literal=getattr(graphene_type, "parse_literal", None), ) - def create_enum(self, graphene_type): + @staticmethod + def create_enum(graphene_type, type_name_prefix=None): values = {} for name, value in graphene_type._meta.enum.__members__.items(): description = getattr(value, "description", None) @@ -201,7 +206,7 @@ def create_enum(self, graphene_type): return GrapheneEnumType( graphene_type=graphene_type, values=values, - name=self.get_type_name(graphene_type), + name=get_type_name(graphene_type, type_name_prefix), description=type_description, ) @@ -408,18 +413,7 @@ def resolve_type(self, resolve_type_func, type_name, root, info, _type): return default_type_resolver(root, info, return_type) def get_type_name(self, graphene_type): - type_name_prefix = ( - graphene_type._meta.type_name_prefix - if graphene_type._meta.type_name_prefix is not None - else self.type_name_prefix - ) - if type_name_prefix: - return ( - type_name_prefix[0].upper() - + type_name_prefix[1:] - + graphene_type._meta.name - ) - return graphene_type._meta.name + return get_type_name(graphene_type, self.type_name_prefix) def get_field_name(self, graphene_type, name): if graphene_type._meta.name in self.root_type_names: diff --git a/graphene/types/utils.py b/graphene/types/utils.py index 1976448aa..e609e6a28 100644 --- a/graphene/types/utils.py +++ b/graphene/types/utils.py @@ -48,3 +48,18 @@ def get_underlying_type(_type): while hasattr(_type, "of_type"): _type = _type.of_type return _type + + +def get_type_name(graphene_type, type_name_prefix): + type_name_prefix = ( + graphene_type._meta.type_name_prefix + if graphene_type._meta.type_name_prefix is not None + else type_name_prefix + ) + if type_name_prefix: + return ( + type_name_prefix[0].upper() + + type_name_prefix[1:] + + graphene_type._meta.name + ) + return graphene_type._meta.name