mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 12:44:15 +03:00
fix: Input fields and Arguments can now be deprecated (#1472)
Non-required InputFields and arguments now support deprecation via setting the `deprecation_reason` argument upon creation.
This commit is contained in:
parent
d5dadb7b1b
commit
19ea63b9c5
|
@ -31,18 +31,22 @@ class Argument(MountedType):
|
||||||
type (class for a graphene.UnmountedType): must be a class (not an instance) of an
|
type (class for a graphene.UnmountedType): must be a class (not an instance) of an
|
||||||
unmounted graphene type (ex. scalar or object) which is used for the type of this
|
unmounted graphene type (ex. scalar or object) which is used for the type of this
|
||||||
argument in the GraphQL schema.
|
argument in the GraphQL schema.
|
||||||
required (bool): indicates this argument as not null in the graphql schema. Same behavior
|
required (optional, bool): indicates this argument as not null in the graphql schema. Same behavior
|
||||||
as graphene.NonNull. Default False.
|
as graphene.NonNull. Default False.
|
||||||
name (str): the name of the GraphQL argument. Defaults to parameter name.
|
name (optional, str): the name of the GraphQL argument. Defaults to parameter name.
|
||||||
description (str): the description of the GraphQL argument in the schema.
|
description (optional, str): the description of the GraphQL argument in the schema.
|
||||||
default_value (Any): The value to be provided if the user does not set this argument in
|
default_value (optional, Any): The value to be provided if the user does not set this argument in
|
||||||
the operation.
|
the operation.
|
||||||
|
deprecation_reason (optional, str): Setting this value indicates that the argument is
|
||||||
|
depreciated and may provide instruction or reason on how for clients to proceed. Cannot be
|
||||||
|
set if the argument is required (see spec).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
type_,
|
type_,
|
||||||
default_value=Undefined,
|
default_value=Undefined,
|
||||||
|
deprecation_reason=None,
|
||||||
description=None,
|
description=None,
|
||||||
name=None,
|
name=None,
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -51,12 +55,16 @@ class Argument(MountedType):
|
||||||
super(Argument, self).__init__(_creation_counter=_creation_counter)
|
super(Argument, self).__init__(_creation_counter=_creation_counter)
|
||||||
|
|
||||||
if required:
|
if required:
|
||||||
|
assert (
|
||||||
|
deprecation_reason is None
|
||||||
|
), f"Argument {name} is required, cannot deprecate it."
|
||||||
type_ = NonNull(type_)
|
type_ = NonNull(type_)
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self._type = type_
|
self._type = type_
|
||||||
self.default_value = default_value
|
self.default_value = default_value
|
||||||
self.description = description
|
self.description = description
|
||||||
|
self.deprecation_reason = deprecation_reason
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
|
@ -68,6 +76,7 @@ class Argument(MountedType):
|
||||||
and self.type == other.type
|
and self.type == other.type
|
||||||
and self.default_value == other.default_value
|
and self.default_value == other.default_value
|
||||||
and self.description == other.description
|
and self.description == other.description
|
||||||
|
and self.deprecation_reason == other.deprecation_reason
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,11 +55,14 @@ class InputField(MountedType):
|
||||||
description=None,
|
description=None,
|
||||||
required=False,
|
required=False,
|
||||||
_creation_counter=None,
|
_creation_counter=None,
|
||||||
**extra_args
|
**extra_args,
|
||||||
):
|
):
|
||||||
super(InputField, self).__init__(_creation_counter=_creation_counter)
|
super(InputField, self).__init__(_creation_counter=_creation_counter)
|
||||||
self.name = name
|
self.name = name
|
||||||
if required:
|
if required:
|
||||||
|
assert (
|
||||||
|
deprecation_reason is None
|
||||||
|
), f"InputField {name} is required, cannot deprecate it."
|
||||||
type_ = NonNull(type_)
|
type_ = NonNull(type_)
|
||||||
self._type = type_
|
self._type = type_
|
||||||
self.deprecation_reason = deprecation_reason
|
self.deprecation_reason = deprecation_reason
|
||||||
|
|
|
@ -316,6 +316,7 @@ class TypeMap(dict):
|
||||||
default_value=field.default_value,
|
default_value=field.default_value,
|
||||||
out_name=name,
|
out_name=name,
|
||||||
description=field.description,
|
description=field.description,
|
||||||
|
deprecation_reason=field.deprecation_reason,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
args = {}
|
args = {}
|
||||||
|
@ -327,6 +328,7 @@ class TypeMap(dict):
|
||||||
out_name=arg_name,
|
out_name=arg_name,
|
||||||
description=arg.description,
|
description=arg.description,
|
||||||
default_value=arg.default_value,
|
default_value=arg.default_value,
|
||||||
|
deprecation_reason=arg.deprecation_reason,
|
||||||
)
|
)
|
||||||
subscribe = field.wrap_subscribe(
|
subscribe = field.wrap_subscribe(
|
||||||
self.get_function_for_type(
|
self.get_function_for_type(
|
||||||
|
|
|
@ -18,8 +18,20 @@ def test_argument():
|
||||||
|
|
||||||
|
|
||||||
def test_argument_comparasion():
|
def test_argument_comparasion():
|
||||||
arg1 = Argument(String, name="Hey", description="Desc", default_value="default")
|
arg1 = Argument(
|
||||||
arg2 = Argument(String, name="Hey", description="Desc", default_value="default")
|
String,
|
||||||
|
name="Hey",
|
||||||
|
description="Desc",
|
||||||
|
default_value="default",
|
||||||
|
deprecation_reason="deprecated",
|
||||||
|
)
|
||||||
|
arg2 = Argument(
|
||||||
|
String,
|
||||||
|
name="Hey",
|
||||||
|
description="Desc",
|
||||||
|
default_value="default",
|
||||||
|
deprecation_reason="deprecated",
|
||||||
|
)
|
||||||
|
|
||||||
assert arg1 == arg2
|
assert arg1 == arg2
|
||||||
assert arg1 != String()
|
assert arg1 != String()
|
||||||
|
@ -40,6 +52,30 @@ def test_to_arguments():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_to_arguments_deprecated():
|
||||||
|
args = {"unmounted_arg": String(required=False, deprecation_reason="deprecated")}
|
||||||
|
|
||||||
|
my_args = to_arguments(args)
|
||||||
|
assert my_args == {
|
||||||
|
"unmounted_arg": Argument(
|
||||||
|
String, required=False, deprecation_reason="deprecated"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_to_arguments_required_deprecated():
|
||||||
|
args = {
|
||||||
|
"unmounted_arg": String(
|
||||||
|
required=True, name="arg", deprecation_reason="deprecated"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
with raises(AssertionError) as exc_info:
|
||||||
|
to_arguments(args)
|
||||||
|
|
||||||
|
assert str(exc_info.value) == "Argument arg is required, cannot deprecate it."
|
||||||
|
|
||||||
|
|
||||||
def test_to_arguments_raises_if_field():
|
def test_to_arguments_raises_if_field():
|
||||||
args = {"arg_string": Field(String)}
|
args = {"arg_string": Field(String)}
|
||||||
|
|
||||||
|
|
|
@ -128,13 +128,20 @@ def test_field_name_as_argument():
|
||||||
|
|
||||||
def test_field_source_argument_as_kw():
|
def test_field_source_argument_as_kw():
|
||||||
MyType = object()
|
MyType = object()
|
||||||
field = Field(MyType, b=NonNull(True), c=Argument(None), a=NonNull(False))
|
deprecation_reason = "deprecated"
|
||||||
|
field = Field(
|
||||||
|
MyType,
|
||||||
|
b=NonNull(True),
|
||||||
|
c=Argument(None, deprecation_reason=deprecation_reason),
|
||||||
|
a=NonNull(False),
|
||||||
|
)
|
||||||
assert list(field.args) == ["b", "c", "a"]
|
assert list(field.args) == ["b", "c", "a"]
|
||||||
assert isinstance(field.args["b"], Argument)
|
assert isinstance(field.args["b"], Argument)
|
||||||
assert isinstance(field.args["b"].type, NonNull)
|
assert isinstance(field.args["b"].type, NonNull)
|
||||||
assert field.args["b"].type.of_type is True
|
assert field.args["b"].type.of_type is True
|
||||||
assert isinstance(field.args["c"], Argument)
|
assert isinstance(field.args["c"], Argument)
|
||||||
assert field.args["c"].type is None
|
assert field.args["c"].type is None
|
||||||
|
assert field.args["c"].deprecation_reason == deprecation_reason
|
||||||
assert isinstance(field.args["a"], Argument)
|
assert isinstance(field.args["a"], Argument)
|
||||||
assert isinstance(field.args["a"].type, NonNull)
|
assert isinstance(field.args["a"].type, NonNull)
|
||||||
assert field.args["a"].type.of_type is False
|
assert field.args["a"].type.of_type is False
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
|
from pytest import raises
|
||||||
|
|
||||||
from ..inputfield import InputField
|
from ..inputfield import InputField
|
||||||
from ..structures import NonNull
|
from ..structures import NonNull
|
||||||
from .utils import MyLazyType
|
from .utils import MyLazyType
|
||||||
|
@ -12,6 +14,22 @@ def test_inputfield_required():
|
||||||
assert field.type.of_type == MyType
|
assert field.type.of_type == MyType
|
||||||
|
|
||||||
|
|
||||||
|
def test_inputfield_deprecated():
|
||||||
|
MyType = object()
|
||||||
|
deprecation_reason = "deprecated"
|
||||||
|
field = InputField(MyType, required=False, deprecation_reason=deprecation_reason)
|
||||||
|
assert isinstance(field.type, type(MyType))
|
||||||
|
assert field.deprecation_reason == deprecation_reason
|
||||||
|
|
||||||
|
|
||||||
|
def test_inputfield_required_deprecated():
|
||||||
|
MyType = object()
|
||||||
|
with raises(AssertionError) as exc_info:
|
||||||
|
InputField(MyType, name="input", required=True, deprecation_reason="deprecated")
|
||||||
|
|
||||||
|
assert str(exc_info.value) == "InputField input is required, cannot deprecate it."
|
||||||
|
|
||||||
|
|
||||||
def test_inputfield_with_lazy_type():
|
def test_inputfield_with_lazy_type():
|
||||||
MyType = object()
|
MyType = object()
|
||||||
field = InputField(lambda: MyType)
|
field = InputField(lambda: MyType)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user