fix: reviews comments

This commit is contained in:
Laurent Riviere 2022-10-24 16:24:13 +00:00
parent 0633b629f5
commit 8cb9791342
7 changed files with 324 additions and 84 deletions

View File

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

View File

@ -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
}

View File

@ -91,7 +91,7 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class TypeMap(dict):
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 @@ class Schema:
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 @@ class Schema:
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,

View File

@ -220,7 +220,7 @@ def test_mutation_as_subclass():
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 @@ def test_object_type_name_prefix():
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 @@ def test_object_type_name_prefix():
)
assert not result.errors
assert result.data == {
"prefixCreateUserWithPlanet": {"name": "Peter", "planet": "earth"}
"myPrefixCreateUserWithPlanet": {"name": "Peter", "planet": "earth"}
}

View File

@ -499,7 +499,7 @@ def test_default_as_kwarg_to_NonNull():
assert result.data == expected
def test_object_type_name_prefix():
def test_type_name_prefix():
class Cat(ObjectType):
name = String()
@ -516,9 +516,9 @@ def test_object_type_name_prefix():
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

View File

@ -5,23 +5,53 @@ from pytest import raises
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 MyInputObjectType(InputObjectType):
field = String()
class MyEnum(Enum):
FOO = "foo"
BAR = "bar"
class MyInterface(Interface):
field = String()
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()
class MyOtherType(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,16 +108,39 @@ def test_schema_str():
== dedent(
"""
type Query {
inner: MyOtherType
}
type MyOtherType {
field: String
myType: MyType
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
}
"""
).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 PrefixQuery {
prefixInner: PrefixMyOtherType
}
type PrefixMyOtherType {
type MyPrefixMyType {
field: String
myType: PrefixMyType
myUnion: MyPrefixMyUnion
myBarType: MyPrefixMyBarType
myFooType: MyPrefixMyFooType
}
type PrefixMyType {
union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType
type MyPrefixMyBarType {
field(input: MyPrefixMyInputObjectType): String
myInterface: MyPrefixMyInterface
}
input MyPrefixMyInputObjectType {
field: String
}
type PrefixMutation {
prefixCreateUser(name: String): PrefixCreateUser
interface MyPrefixMyInterface {
field: String
}
type PrefixCreateUser {
type MyPrefixMyFooType {
field: String
myEnum: MyPrefixMyEnum
}
enum MyPrefixMyEnum {
FOO
BAR
}
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 PrefixQuery {
prefix_inner: PrefixMyOtherType
}
type PrefixMyOtherType {
type MyPrefixMyType {
field: String
my_type: PrefixMyType
my_union: MyPrefixMyUnion
my_bar_type: MyPrefixMyBarType
my_foo_type: MyPrefixMyFooType
}
type PrefixMyType {
union MyPrefixMyUnion = MyPrefixMyBarType | MyPrefixMyFooType
type MyPrefixMyBarType {
field(input: MyPrefixMyInputObjectType): String
my_interface: MyPrefixMyInterface
}
input MyPrefixMyInputObjectType {
field: String
}
type PrefixMutation {
prefix_create_user(name: String): PrefixCreateUser
interface MyPrefixMyInterface {
field: String
}
type PrefixCreateUser {
type MyPrefixMyFooType {
field: String
my_enum: MyPrefixMyEnum
}
enum MyPrefixMyEnum {
FOO
BAR
}
type Mutation {
MyPrefixcreate_user(name: String): MyPrefixCreateUser
}
type MyPrefixCreateUser {
name: String
}
type PrefixSubscription {
prefix_count_to_ten: Int
type Subscription {
MyPrefixcount_to_ten: Int
}
"""
).strip()

View File

@ -54,7 +54,7 @@ tests_require = [
"coveralls>=3.3,<4",
"promise>=2.3,<3",
"mock>=4,<5",
"pytz==2022.1",
"pytz==2022.5",
"iso8601>=1,<2",
]