From f380a5d695ef728ce0bcfa5adaaf488de92db565 Mon Sep 17 00:00:00 2001 From: Jayden Windle Date: Fri, 7 Jun 2019 14:57:51 -0700 Subject: [PATCH] Add support for optional arguments when a default value is provided (#82) * added support for optional arguments when a default value is provided * fixed no default arguments case * Switched default argument detection to use inspect.signature, added tests for default arguments with custom types * added release info --- RELEASE.md | 18 +++++++++++++++++ strawberry/field.py | 6 +++++- tests/test_field.py | 49 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..fd39b323eb --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,18 @@ +Release type: minor + +Added support for optional fields with default arguments in the GraphQL schema when default arguments are passed to the resolver. + +Example: + ```python +@strawberry.type +class Query: + @strawberry.field + def hello(self, info, name: str = "world") -> str: + return name +``` + +```graphql +type Query { + hello(name: String = "world"): String +} +``` \ No newline at end of file diff --git a/strawberry/field.py b/strawberry/field.py index 94b0d813aa..5b5a01ef81 100644 --- a/strawberry/field.py +++ b/strawberry/field.py @@ -1,3 +1,4 @@ +import inspect import typing import dataclasses @@ -202,6 +203,7 @@ def _get_field( name = wrap.__name__ annotations = typing.get_type_hints(wrap, None, REGISTRY) + parameters = inspect.signature(wrap).parameters field_type = get_graphql_type_for_annotation(annotations["return"], name) arguments_annotations = { @@ -211,7 +213,9 @@ def _get_field( } arguments = { - to_camel_case(name): get_graphql_type_for_annotation(annotation, name) + to_camel_case(name): get_graphql_type_for_annotation( + annotation, name, parameters[name].default != inspect._empty + ) for name, annotation in arguments_annotations.items() } diff --git a/tests/test_field.py b/tests/test_field.py index 4a7dd5f170..7bc23c13f1 100644 --- a/tests/test_field.py +++ b/tests/test_field.py @@ -1,7 +1,12 @@ import pytest import strawberry -from graphql import GraphQLField, GraphQLNonNull +from graphql import ( + GraphQLField, + GraphQLInputObjectType, + GraphQLNonNull, + GraphQLScalarType, +) from strawberry.exceptions import ( MissingArgumentsAnnotationsError, MissingReturnAnnotationError, @@ -29,6 +34,48 @@ def hello(self, info, id: int) -> str: assert hello.field.args["id"].type.of_type.name == "Int" +def test_field_default_arguments_are_optional(): + @strawberry.field + def hello(self, info, test: int, id: int = 1, asdf: str = "hello") -> str: + return "I'm a resolver" + + assert hello.field + + assert type(hello.field) == GraphQLField + assert type(hello.field.type) == GraphQLNonNull + assert hello.field.type.of_type.name == "String" + + assert type(hello.field.args["id"].type) == GraphQLScalarType + assert hello.field.args["id"].type.name == "Int" + + assert type(hello.field.args["asdf"].type) == GraphQLScalarType + assert hello.field.args["asdf"].type.name == "String" + + +def test_field_default_optional_argument_custom_type(): + @strawberry.input + class CustomInputType: + field: str + + @strawberry.field + def hello( + self, info, required: CustomInputType, optional: CustomInputType = None + ) -> str: + return "I'm a resolver" + + assert hello.field + + assert type(hello.field) == GraphQLField + assert type(hello.field.type) == GraphQLNonNull + assert hello.field.type.of_type.name == "String" + + assert type(hello.field.args["required"].type) == GraphQLNonNull + assert hello.field.args["required"].type.of_type.name == "CustomInputType" + + assert type(hello.field.args["optional"].type) == GraphQLInputObjectType + assert hello.field.args["optional"].type.name == "CustomInputType" + + def test_raises_error_when_return_annotation_missing(): with pytest.raises(MissingReturnAnnotationError) as e: