fix: review

This commit is contained in:
Laurent Riviere 2022-10-26 08:03:56 +00:00
parent 84237060f4
commit 97dd7e5ac1
5 changed files with 408 additions and 160 deletions

View File

@ -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: The prefix will be added to the name of:
* Query / Mutation / Subscription * Query / Mutation / Subscription
* Scalar
* ObjectType * ObjectType
* InputType * InputType
* Enum
* Interface * Interface
* Union * Union
* Enum
While fields and arguments name will be left untouched. While fields and arguments name will be left untouched.
@ -157,6 +158,8 @@ More specifically, the following schema:
myEnum: MyEnum myEnum: MyEnum
} }
scalar MyScalar
enum MyEnum { enum MyEnum {
FOO FOO
BAR BAR
@ -209,6 +212,8 @@ Will be transformed to:
myEnum: MyPrefixMyEnum myEnum: MyPrefixMyEnum
} }
scalar MyPrefixMyScalar
enum MyPrefixMyEnum { enum MyPrefixMyEnum {
FOO FOO
BAR BAR
@ -225,3 +230,15 @@ Will be transformed to:
type Subscription { type Subscription {
myPrefixCountToTen: Int 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.

View File

@ -36,13 +36,14 @@ class BaseType(SubclassWithMeta):
@classmethod @classmethod
def __init_subclass_with_meta__( 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" assert "_meta" not in cls.__dict__, "Can't assign meta directly"
if not _meta: if not _meta:
return return
_meta.name = name or cls.__name__ _meta.name = name or cls.__name__
_meta.description = description or trim_docstring(cls.__doc__) _meta.description = description or trim_docstring(cls.__doc__)
_meta.type_name_prefix = type_name_prefix
_meta.freeze() _meta.freeze()
cls._meta = _meta cls._meta = _meta
super(BaseType, cls).__init_subclass_with_meta__() super(BaseType, cls).__init_subclass_with_meta__()

View File

@ -166,7 +166,7 @@ class TypeMap(dict):
return GrapheneScalarType( return GrapheneScalarType(
graphene_type=graphene_type, 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, description=graphene_type._meta.description,
serialize=getattr(graphene_type, "serialize", None), serialize=getattr(graphene_type, "serialize", None),
parse_value=getattr(graphene_type, "parse_value", None), parse_value=getattr(graphene_type, "parse_value", None),
@ -201,7 +201,7 @@ class TypeMap(dict):
return GrapheneEnumType( return GrapheneEnumType(
graphene_type=graphene_type, graphene_type=graphene_type,
values=values, values=values,
name=self.add_prefix_to_type_name(graphene_type._meta.name), name=self.get_type_name(graphene_type),
description=type_description, description=type_description,
) )
@ -226,7 +226,7 @@ class TypeMap(dict):
if graphene_type._meta.name in self.root_type_names: if graphene_type._meta.name in self.root_type_names:
name = graphene_type._meta.name name = graphene_type._meta.name
else: else:
name = self.add_prefix_to_type_name(graphene_type._meta.name) name = self.get_type_name(graphene_type)
return GrapheneObjectType( return GrapheneObjectType(
graphene_type=graphene_type, graphene_type=graphene_type,
@ -256,7 +256,7 @@ class TypeMap(dict):
return GrapheneInterfaceType( return GrapheneInterfaceType(
graphene_type=graphene_type, 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, description=graphene_type._meta.description,
fields=partial(self.create_fields_for_type, graphene_type), fields=partial(self.create_fields_for_type, graphene_type),
interfaces=interfaces, interfaces=interfaces,
@ -266,7 +266,7 @@ class TypeMap(dict):
def create_inputobjecttype(self, graphene_type): def create_inputobjecttype(self, graphene_type):
return GrapheneInputObjectType( return GrapheneInputObjectType(
graphene_type=graphene_type, 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, description=graphene_type._meta.description,
out_type=graphene_type._meta.container, out_type=graphene_type._meta.container,
fields=partial( fields=partial(
@ -295,7 +295,7 @@ class TypeMap(dict):
return GrapheneUnionType( return GrapheneUnionType(
graphene_type=graphene_type, 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, description=graphene_type._meta.description,
types=types, types=types,
resolve_type=resolve_type, resolve_type=resolve_type,
@ -373,10 +373,7 @@ class TypeMap(dict):
if field.name: if field.name:
field_name = field.name field_name = field.name
else: else:
if graphene_type._meta.name in self.root_type_names: field_name = self.get_field_name(graphene_type, name)
field_name = self.add_prefix_to_field_name(name)
else:
field_name = self.get_name(name)
fields[field_name] = _field fields[field_name] = _field
return fields return fields
@ -410,21 +407,35 @@ class TypeMap(dict):
return_type = self[type_name] return_type = self[type_name]
return default_type_resolver(root, info, return_type) return default_type_resolver(root, info, return_type)
def add_prefix_to_type_name(self, name): def get_type_name(self, graphene_type):
if self.type_name_prefix: type_name_prefix = (
return self.type_name_prefix[0].upper() + self.type_name_prefix[1:] + name graphene_type._meta.type_name_prefix
return name if graphene_type._meta.type_name_prefix is not None
else self.type_name_prefix
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) if type_name_prefix:
return (
type_name_prefix[0].upper()
+ type_name_prefix[1:]
+ graphene_type._meta.name
)
return graphene_type._meta.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) return self.get_name(name)

View File

@ -167,137 +167,3 @@ def test_schema_requires_query_type():
assert len(result.errors) == 1 assert len(result.errors) == 1
error = result.errors[0] error = result.errors[0]
assert error.message == "Query root type must be provided." 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()
)

View File

@ -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()
)