mirror of
https://github.com/graphql-python/graphene.git
synced 2025-07-18 12:02:19 +03:00
Merge branch 'graphql-python:master' into fix/inputobjecttype_undefined
This commit is contained in:
commit
a8cb8ca4c2
|
@ -1,12 +1,6 @@
|
|||
Graphene
|
||||
========
|
||||
|
||||
------------
|
||||
|
||||
The documentation below is for the ``dev`` (prerelease) version of Graphene. To view the documentation for the latest stable Graphene version go to the `v2 docs <https://docs.graphene-python.org/en/stable/>`_.
|
||||
|
||||
------------
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -271,7 +271,7 @@ The following is an example for creating a DateTime scalar:
|
|||
|
||||
@staticmethod
|
||||
def parse_literal(node, _variables=None):
|
||||
if isinstance(node, ast.StringValue):
|
||||
if isinstance(node, ast.StringValueNode):
|
||||
return datetime.datetime.strptime(
|
||||
node.value, "%Y-%m-%dT%H:%M:%S.%f")
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ from .types import (
|
|||
from .utils.module_loading import lazy_import
|
||||
from .utils.resolve_only_args import resolve_only_args
|
||||
|
||||
VERSION = (3, 1, 1, "final", 0)
|
||||
VERSION = (3, 2, 1, "final", 0)
|
||||
|
||||
|
||||
__version__ = get_version(VERSION)
|
||||
|
|
|
@ -31,18 +31,22 @@ class Argument(MountedType):
|
|||
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
|
||||
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.
|
||||
name (str): the name of the GraphQL argument. Defaults to parameter name.
|
||||
description (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
|
||||
name (optional, str): the name of the GraphQL argument. Defaults to parameter name.
|
||||
description (optional, str): the description of the GraphQL argument in the schema.
|
||||
default_value (optional, Any): The value to be provided if the user does not set this argument in
|
||||
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__(
|
||||
self,
|
||||
type_,
|
||||
default_value=Undefined,
|
||||
deprecation_reason=None,
|
||||
description=None,
|
||||
name=None,
|
||||
required=False,
|
||||
|
@ -51,12 +55,16 @@ class Argument(MountedType):
|
|||
super(Argument, self).__init__(_creation_counter=_creation_counter)
|
||||
|
||||
if required:
|
||||
assert (
|
||||
deprecation_reason is None
|
||||
), f"Argument {name} is required, cannot deprecate it."
|
||||
type_ = NonNull(type_)
|
||||
|
||||
self.name = name
|
||||
self._type = type_
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
self.deprecation_reason = deprecation_reason
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
|
@ -68,6 +76,7 @@ class Argument(MountedType):
|
|||
and self.type == other.type
|
||||
and self.default_value == other.default_value
|
||||
and self.description == other.description
|
||||
and self.deprecation_reason == other.deprecation_reason
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -55,11 +55,14 @@ class InputField(MountedType):
|
|||
description=None,
|
||||
required=False,
|
||||
_creation_counter=None,
|
||||
**extra_args
|
||||
**extra_args,
|
||||
):
|
||||
super(InputField, self).__init__(_creation_counter=_creation_counter)
|
||||
self.name = name
|
||||
if required:
|
||||
assert (
|
||||
deprecation_reason is None
|
||||
), f"InputField {name} is required, cannot deprecate it."
|
||||
type_ = NonNull(type_)
|
||||
self._type = type_
|
||||
self.deprecation_reason = deprecation_reason
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from enum import Enum as PyEnum
|
||||
import inspect
|
||||
from functools import partial
|
||||
|
||||
|
@ -169,10 +170,16 @@ class TypeMap(dict):
|
|||
values = {}
|
||||
for name, value in graphene_type._meta.enum.__members__.items():
|
||||
description = getattr(value, "description", None)
|
||||
deprecation_reason = getattr(value, "deprecation_reason", None)
|
||||
# if the "description" attribute is an Enum, it is likely an enum member
|
||||
# called description, not a description property
|
||||
if isinstance(description, PyEnum):
|
||||
description = None
|
||||
if not description and callable(graphene_type._meta.description):
|
||||
description = graphene_type._meta.description(value)
|
||||
|
||||
deprecation_reason = getattr(value, "deprecation_reason", None)
|
||||
if isinstance(deprecation_reason, PyEnum):
|
||||
deprecation_reason = None
|
||||
if not deprecation_reason and callable(
|
||||
graphene_type._meta.deprecation_reason
|
||||
):
|
||||
|
@ -309,6 +316,7 @@ class TypeMap(dict):
|
|||
default_value=field.default_value,
|
||||
out_name=name,
|
||||
description=field.description,
|
||||
deprecation_reason=field.deprecation_reason,
|
||||
)
|
||||
else:
|
||||
args = {}
|
||||
|
@ -320,6 +328,7 @@ class TypeMap(dict):
|
|||
out_name=arg_name,
|
||||
description=arg.description,
|
||||
default_value=arg.default_value,
|
||||
deprecation_reason=arg.deprecation_reason,
|
||||
)
|
||||
subscribe = field.wrap_subscribe(
|
||||
self.get_function_for_type(
|
||||
|
|
|
@ -18,8 +18,20 @@ def test_argument():
|
|||
|
||||
|
||||
def test_argument_comparasion():
|
||||
arg1 = Argument(String, name="Hey", description="Desc", default_value="default")
|
||||
arg2 = Argument(String, name="Hey", description="Desc", default_value="default")
|
||||
arg1 = Argument(
|
||||
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 != 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():
|
||||
args = {"arg_string": Field(String)}
|
||||
|
||||
|
|
|
@ -565,3 +565,36 @@ def test_iterable_instance_creation_enum():
|
|||
for c in TestEnum:
|
||||
result.append(c.name)
|
||||
assert result == expected_values
|
||||
|
||||
|
||||
# https://github.com/graphql-python/graphene/issues/1321
|
||||
def test_enum_description_member_not_interpreted_as_property():
|
||||
class RGB(Enum):
|
||||
"""Description"""
|
||||
|
||||
red = "red"
|
||||
green = "green"
|
||||
blue = "blue"
|
||||
description = "description"
|
||||
deprecation_reason = "deprecation_reason"
|
||||
|
||||
class Query(ObjectType):
|
||||
color = RGB()
|
||||
|
||||
def resolve_color(_, info):
|
||||
return RGB.description
|
||||
|
||||
values = RGB._meta.enum.__members__.values()
|
||||
assert sorted(v.name for v in values) == [
|
||||
"blue",
|
||||
"deprecation_reason",
|
||||
"description",
|
||||
"green",
|
||||
"red",
|
||||
]
|
||||
|
||||
schema = Schema(query=Query)
|
||||
|
||||
results = schema.execute("query { color }")
|
||||
assert not results.errors
|
||||
assert results.data["color"] == RGB.description.name
|
||||
|
|
|
@ -128,13 +128,20 @@ def test_field_name_as_argument():
|
|||
|
||||
def test_field_source_argument_as_kw():
|
||||
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 isinstance(field.args["b"], Argument)
|
||||
assert isinstance(field.args["b"].type, NonNull)
|
||||
assert field.args["b"].type.of_type is True
|
||||
assert isinstance(field.args["c"], Argument)
|
||||
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"].type, NonNull)
|
||||
assert field.args["a"].type.of_type is False
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from functools import partial
|
||||
|
||||
from pytest import raises
|
||||
|
||||
from ..inputfield import InputField
|
||||
from ..structures import NonNull
|
||||
from .utils import MyLazyType
|
||||
|
@ -12,6 +14,22 @@ def test_inputfield_required():
|
|||
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():
|
||||
MyType = object()
|
||||
field = InputField(lambda: MyType)
|
||||
|
|
Loading…
Reference in New Issue
Block a user