Skip to content

Commit 6687245

Browse files
committed
backport: Add @OneOf support to introspection query (#241)
Also backport support for @OneOf directives in print_schema. Replicates graphql/graphql-js@7df786e and graphql/graphql-js@0b7590f
1 parent 18df18e commit 6687245

File tree

8 files changed

+54
-4
lines changed

8 files changed

+54
-4
lines changed

setup.cfg

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@ python-tag = py3
55
test = pytest
66

77
[tool:pytest]
8+
minversion = 7.4
89
# Only run benchmarks as tests.
910
# To actually run the benchmarks, use --benchmark-enable on the command line.
1011
# To run the slow tests (fuzzing), add --run-slow on the command line.
1112
addopts = --benchmark-disable
1213
# Deactivate default name pattern for test classes (we use pytest_describe).
1314
python_classes = PyTest*
1415
# Handle all async fixtures and tests automatically by asyncio
15-
asyncio_mode = auto
16+
asyncio_mode = strict
1617
# Default event loop scope used for asynchronous fixtures
1718
asyncio_default_fixture_loop_scope = function
1819
# Set a timeout in seconds for aborting tests that run too long.
1920
timeout = 100
2021
# Ignore config options not (yet) available in older Python versions.
2122
filterwarnings = ignore::pytest.PytestConfigWarning
23+
# All tests can be found in the tests directory.
24+
testpaths = tests

src/graphql/utilities/build_client_schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def build_input_object_def(
226226
fields=lambda: build_input_value_def_map(
227227
input_object_introspection["inputFields"]
228228
),
229+
is_one_of=input_object_introspection.get("isOneOf", False),
229230
)
230231

231232
type_builders: Dict[str, Callable[[IntrospectionType], GraphQLNamedType]] = {

src/graphql/utilities/get_introspection_query.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def get_introspection_query(
3434
directive_is_repeatable: bool = False,
3535
schema_description: bool = False,
3636
input_value_deprecation: bool = False,
37+
input_object_one_of: bool = False,
3738
) -> str:
3839
"""Get a query for introspection.
3940
@@ -45,6 +46,7 @@ def get_introspection_query(
4546
maybe_specified_by_url = "specifiedByURL" if specified_by_url else ""
4647
maybe_directive_is_repeatable = "isRepeatable" if directive_is_repeatable else ""
4748
maybe_schema_description = maybe_description if schema_description else ""
49+
maybe_input_object_one_of = "isOneOf" if input_object_one_of else ""
4850

4951
def input_deprecation(string: str) -> Optional[str]:
5052
return string if input_value_deprecation else ""
@@ -77,6 +79,7 @@ def input_deprecation(string: str) -> Optional[str]:
7779
name
7880
{maybe_description}
7981
{maybe_specified_by_url}
82+
{maybe_input_object_one_of}
8083
fields(includeDeprecated: true) {{
8184
name
8285
{maybe_description}
@@ -243,6 +246,7 @@ class IntrospectionEnumType(WithName):
243246
class IntrospectionInputObjectType(WithName):
244247
kind: Literal["input_object"]
245248
inputFields: List[IntrospectionInputValue]
249+
isOneOf: bool
246250

247251

248252
IntrospectionType = Union[
@@ -254,7 +258,6 @@ class IntrospectionInputObjectType(WithName):
254258
IntrospectionInputObjectType,
255259
]
256260

257-
258261
IntrospectionOutputType = Union[
259262
IntrospectionScalarType,
260263
IntrospectionObjectType,
@@ -263,7 +266,6 @@ class IntrospectionInputObjectType(WithName):
263266
IntrospectionEnumType,
264267
]
265268

266-
267269
IntrospectionInputType = Union[
268270
IntrospectionScalarType, IntrospectionEnumType, IntrospectionInputObjectType
269271
]

src/graphql/utilities/introspection_from_schema.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def introspection_from_schema(
1515
directive_is_repeatable: bool = True,
1616
schema_description: bool = True,
1717
input_value_deprecation: bool = True,
18+
input_object_one_of: bool = True,
1819
) -> IntrospectionQuery:
1920
"""Build an IntrospectionQuery from a GraphQLSchema
2021
@@ -31,6 +32,7 @@ def introspection_from_schema(
3132
directive_is_repeatable,
3233
schema_description,
3334
input_value_deprecation,
35+
input_object_one_of,
3436
)
3537
)
3638

src/graphql/utilities/print_schema.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,12 @@ def print_input_object(type_: GraphQLInputObjectType) -> str:
189189
print_description(field, " ", not i) + " " + print_input_value(name, field)
190190
for i, (name, field) in enumerate(type_.fields.items())
191191
]
192-
return print_description(type_) + f"input {type_.name}" + print_block(fields)
192+
return (
193+
print_description(type_)
194+
+ f"input {type_.name}"
195+
+ (" @oneOf" if type_.is_one_of else "")
196+
+ print_block(fields)
197+
)
193198

194199

195200
def print_fields(type_: Union[GraphQLObjectType, GraphQLInterfaceType]) -> str:

tests/utilities/test_build_client_schema.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,22 @@ def builds_a_schema_with_specified_by_url():
591591

592592
assert cycle_introspection(sdl) == sdl
593593

594+
def builds_a_schema_with_one_of_directive():
595+
sdl = dedent(
596+
"""
597+
type Query {
598+
someField(someArg: SomeInputObject): String
599+
}
600+
601+
input SomeInputObject @oneOf {
602+
someInputField1: String
603+
someInputField2: String
604+
}
605+
"""
606+
)
607+
608+
assert cycle_introspection(sdl) == sdl
609+
594610
def can_use_client_schema_for_limited_execution():
595611
schema = build_schema(
596612
"""

tests/utilities/test_get_introspection_query.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ def includes_deprecation_reason_field_on_input_values():
7979
"deprecationReason", 2
8080
)
8181

82+
def includes_input_object_one_of_field():
83+
ExcpectIntrospectionQuery().to_not_match("isOneOf")
84+
ExcpectIntrospectionQuery(input_object_one_of=True).to_match("isOneOf")
85+
ExcpectIntrospectionQuery(input_object_one_of=False).to_not_match("isOneOf")
86+
8287
def includes_deprecated_input_field_and_args():
8388
ExcpectIntrospectionQuery().to_match("includeDeprecated: true", 2)
8489
ExcpectIntrospectionQuery(input_value_deprecation=True).to_match(

tests/utilities/test_print_schema.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,22 @@ def prints_input_type():
511511
"""
512512
)
513513

514+
def prints_input_type_with_one_of_directive():
515+
input_type = GraphQLInputObjectType(
516+
name="InputType",
517+
fields={"int": GraphQLInputField(GraphQLInt)},
518+
is_one_of=True,
519+
)
520+
521+
schema = GraphQLSchema(types=[input_type])
522+
assert expect_printed_schema(schema) == dedent(
523+
"""
524+
input InputType @oneOf {
525+
int: Int
526+
}
527+
"""
528+
)
529+
514530
def prints_custom_scalar():
515531
odd_type = GraphQLScalarType(name="Odd")
516532

0 commit comments

Comments
 (0)