Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-graphene for openSUSE:Factory 
checked in at 2023-01-06 17:06:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-graphene (Old)
 and      /work/SRC/openSUSE:Factory/.python-graphene.new.1563 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-graphene"

Fri Jan  6 17:06:05 2023 rev:8 rq:1056360 version:3.2.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-graphene/python-graphene.changes  
2022-10-12 18:27:33.842069267 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-graphene.new.1563/python-graphene.changes    
    2023-01-06 17:06:50.456614442 +0100
@@ -1,0 +2,8 @@
+Thu Jan  5 19:48:47 UTC 2023 - Yogalakshmi Arunachalam <[email protected]>
+
+- Update to version 3.2.1 
+  * What's Changed
+  Non-required InputFields and Arguments can now be marked as deprecated by 
passing the deprecation_reason keyword argument to the constructor.
+  Complete deprecated fields and arguments support by @vhutov in #1472
+
+-------------------------------------------------------------------

Old:
----
  graphene-3.1.1.tar.gz

New:
----
  graphene-3.2.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-graphene.spec ++++++
--- /var/tmp/diff_new_pack.YKEYE2/_old  2023-01-06 17:06:50.856616689 +0100
+++ /var/tmp/diff_new_pack.YKEYE2/_new  2023-01-06 17:06:50.860616711 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-graphene
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-graphene
-Version:        3.1.1
+Version:        3.2.1
 Release:        0
 Summary:        GraphQL Framework for Python
 License:        MIT

++++++ graphene-3.1.1.tar.gz -> graphene-3.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/.github/workflows/tests.yml 
new/graphene-3.2.1/.github/workflows/tests.yml
--- old/graphene-3.1.1/.github/workflows/tests.yml      2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/.github/workflows/tests.yml      2022-12-11 
21:05:25.000000000 +0100
@@ -30,7 +30,7 @@
           - {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
           - {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
           - {name: '3.7', python: '3.7', os: ubuntu-latest, tox: py37}
-          - {name: '3.6', python: '3.6', os: ubuntu-latest, tox: py36}
+          - {name: '3.6', python: '3.6', os: ubuntu-20.04, tox: py36}
     steps:
       - uses: actions/checkout@v3
       - uses: actions/setup-python@v4
@@ -58,7 +58,7 @@
         if: ${{ matrix.python == '3.10' }}
         uses: actions/upload-artifact@v3
         with:
-          name: graphene-sqlalchemy-coverage
+          name: graphene-coverage
           path: coverage.xml
           if-no-files-found: error
       - name: Upload coverage.xml to codecov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/Makefile new/graphene-3.2.1/Makefile
--- old/graphene-3.1.1/Makefile 2022-09-08 10:55:05.000000000 +0200
+++ new/graphene-3.2.1/Makefile 2022-12-11 21:05:25.000000000 +0100
@@ -7,6 +7,7 @@
 install-dev:
        pip install -e ".[dev]"
 
+.PHONY: test ## Run tests
 test:
        py.test graphene examples
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/docs/execution/middleware.rst 
new/graphene-3.2.1/docs/execution/middleware.rst
--- old/graphene-3.1.1/docs/execution/middleware.rst    2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/docs/execution/middleware.rst    2022-12-11 
21:05:25.000000000 +0100
@@ -41,6 +41,8 @@
 
     result = schema.execute('THE QUERY', 
middleware=[AuthorizationMiddleware()])
 
+If the ``middleware`` argument includes multiple middlewares,
+these middlewares will be executed bottom-up, i.e. from last to first.
 
 Functional example
 ------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/docs/quickstart.rst 
new/graphene-3.2.1/docs/quickstart.rst
--- old/graphene-3.1.1/docs/quickstart.rst      2022-09-08 10:55:05.000000000 
+0200
+++ new/graphene-3.2.1/docs/quickstart.rst      2022-12-11 21:05:25.000000000 
+0100
@@ -37,12 +37,12 @@
 
 Let’s build a basic GraphQL schema to say "hello" and "goodbye" in Graphene.
 
-When we send a **Query** requesting only one **Field**, ``hello``, and specify 
a value for the ``name`` **Argument**...
+When we send a **Query** requesting only one **Field**, ``hello``, and specify 
a value for the ``firstName`` **Argument**...
 
 .. code::
 
     {
-      hello(name: "friend")
+      hello(firstName: "friend")
     }
 
 ...we would expect the following Response containing only the data requested 
(the ``goodbye`` field is not resolved).
@@ -79,14 +79,15 @@
     from graphene import ObjectType, String, Schema
 
     class Query(ObjectType):
-        # this defines a Field `hello` in our Schema with a single Argument 
`name`
-        hello = String(name=String(default_value="stranger"))
+        # this defines a Field `hello` in our Schema with a single Argument 
`first_name`
+        # By default, the argument name will automatically be camel-based into 
firstName in the generated schema
+        hello = String(first_name=String(default_value="stranger"))
         goodbye = String()
 
         # our Resolver method takes the GraphQL context (root, info) as well as
-        # Argument (name) for the Field and returns data for the query Response
-        def resolve_hello(root, info, name):
-            return f'Hello {name}!'
+        # Argument (first_name) for the Field and returns data for the query 
Response
+        def resolve_hello(root, info, first_name):
+            return f'Hello {first_name}!'
 
         def resolve_goodbye(root, info):
             return 'See ya!'
@@ -110,7 +111,7 @@
 .. code::
 
     type Query {
-      hello(name: String = "stranger"): String
+      hello(firstName: String = "stranger"): String
       goodbye: String
     }
 
@@ -130,7 +131,7 @@
     # "Hello stranger!"
 
     # or passing the argument in the query
-    query_with_argument = '{ hello(name: "GraphQL") }'
+    query_with_argument = '{ hello(firstName: "GraphQL") }'
     result = schema.execute(query_with_argument)
     print(result.data['hello'])
     # "Hello GraphQL!"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/__init__.py 
new/graphene-3.2.1/graphene/__init__.py
--- old/graphene-3.1.1/graphene/__init__.py     2022-09-08 10:55:05.000000000 
+0200
+++ new/graphene-3.2.1/graphene/__init__.py     2022-12-11 21:05:25.000000000 
+0100
@@ -1,11 +1,15 @@
 from .pyutils.version import get_version
 from .relay import (
+    BaseGlobalIDType,
     ClientIDMutation,
     Connection,
     ConnectionField,
+    DefaultGlobalIDType,
     GlobalID,
     Node,
     PageInfo,
+    SimpleGlobalIDType,
+    UUIDGlobalIDType,
     is_node,
 )
 from .types import (
@@ -42,7 +46,7 @@
 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)
@@ -52,6 +56,7 @@
     "Argument",
     "Base64",
     "BigInt",
+    "BaseGlobalIDType",
     "Boolean",
     "ClientIDMutation",
     "Connection",
@@ -60,6 +65,7 @@
     "Date",
     "DateTime",
     "Decimal",
+    "DefaultGlobalIDType",
     "Dynamic",
     "Enum",
     "Field",
@@ -80,10 +86,12 @@
     "ResolveInfo",
     "Scalar",
     "Schema",
+    "SimpleGlobalIDType",
     "String",
     "Time",
-    "UUID",
     "Union",
+    "UUID",
+    "UUIDGlobalIDType",
     "is_node",
     "lazy_import",
     "resolve_only_args",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/relay/__init__.py 
new/graphene-3.2.1/graphene/relay/__init__.py
--- old/graphene-3.1.1/graphene/relay/__init__.py       2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/relay/__init__.py       2022-12-11 
21:05:25.000000000 +0100
@@ -1,13 +1,23 @@
 from .node import Node, is_node, GlobalID
 from .mutation import ClientIDMutation
 from .connection import Connection, ConnectionField, PageInfo
+from .id_type import (
+    BaseGlobalIDType,
+    DefaultGlobalIDType,
+    SimpleGlobalIDType,
+    UUIDGlobalIDType,
+)
 
 __all__ = [
-    "Node",
-    "is_node",
-    "GlobalID",
+    "BaseGlobalIDType",
     "ClientIDMutation",
     "Connection",
     "ConnectionField",
+    "DefaultGlobalIDType",
+    "GlobalID",
+    "Node",
     "PageInfo",
+    "SimpleGlobalIDType",
+    "UUIDGlobalIDType",
+    "is_node",
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/relay/id_type.py 
new/graphene-3.2.1/graphene/relay/id_type.py
--- old/graphene-3.1.1/graphene/relay/id_type.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/graphene-3.2.1/graphene/relay/id_type.py        2022-12-11 
21:05:25.000000000 +0100
@@ -0,0 +1,87 @@
+from graphql_relay import from_global_id, to_global_id
+
+from ..types import ID, UUID
+from ..types.base import BaseType
+
+from typing import Type
+
+
+class BaseGlobalIDType:
+    """
+    Base class that define the required attributes/method for a type.
+    """
+
+    graphene_type = ID  # type: Type[BaseType]
+
+    @classmethod
+    def resolve_global_id(cls, info, global_id):
+        # return _type, _id
+        raise NotImplementedError
+
+    @classmethod
+    def to_global_id(cls, _type, _id):
+        # return _id
+        raise NotImplementedError
+
+
+class DefaultGlobalIDType(BaseGlobalIDType):
+    """
+    Default global ID type: base64 encoded version of "<node type name>: <node 
id>".
+    """
+
+    graphene_type = ID
+
+    @classmethod
+    def resolve_global_id(cls, info, global_id):
+        try:
+            _type, _id = from_global_id(global_id)
+            if not _type:
+                raise ValueError("Invalid Global ID")
+            return _type, _id
+        except Exception as e:
+            raise Exception(
+                f'Unable to parse global ID "{global_id}". '
+                'Make sure it is a base64 encoded string in the format: 
"TypeName:id". '
+                f"Exception message: {e}"
+            )
+
+    @classmethod
+    def to_global_id(cls, _type, _id):
+        return to_global_id(_type, _id)
+
+
+class SimpleGlobalIDType(BaseGlobalIDType):
+    """
+    Simple global ID type: simply the id of the object.
+    To be used carefully as the user is responsible for ensuring that the IDs 
are indeed global
+    (otherwise it could cause request caching issues).
+    """
+
+    graphene_type = ID
+
+    @classmethod
+    def resolve_global_id(cls, info, global_id):
+        _type = info.return_type.graphene_type._meta.name
+        return _type, global_id
+
+    @classmethod
+    def to_global_id(cls, _type, _id):
+        return _id
+
+
+class UUIDGlobalIDType(BaseGlobalIDType):
+    """
+    UUID global ID type.
+    By definition UUID are global so they are used as they are.
+    """
+
+    graphene_type = UUID
+
+    @classmethod
+    def resolve_global_id(cls, info, global_id):
+        _type = info.return_type.graphene_type._meta.name
+        return _type, global_id
+
+    @classmethod
+    def to_global_id(cls, _type, _id):
+        return _id
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/relay/node.py 
new/graphene-3.2.1/graphene/relay/node.py
--- old/graphene-3.1.1/graphene/relay/node.py   2022-09-08 10:55:05.000000000 
+0200
+++ new/graphene-3.2.1/graphene/relay/node.py   2022-12-11 21:05:25.000000000 
+0100
@@ -1,11 +1,10 @@
 from functools import partial
 from inspect import isclass
 
-from graphql_relay import from_global_id, to_global_id
-
-from ..types import ID, Field, Interface, ObjectType
+from ..types import Field, Interface, ObjectType
 from ..types.interface import InterfaceOptions
 from ..types.utils import get_type
+from .id_type import BaseGlobalIDType, DefaultGlobalIDType
 
 
 def is_node(objecttype):
@@ -22,8 +21,18 @@
 
 
 class GlobalID(Field):
-    def __init__(self, node=None, parent_type=None, required=True, *args, 
**kwargs):
-        super(GlobalID, self).__init__(ID, required=required, *args, **kwargs)
+    def __init__(
+        self,
+        node=None,
+        parent_type=None,
+        required=True,
+        global_id_type=DefaultGlobalIDType,
+        *args,
+        **kwargs,
+    ):
+        super(GlobalID, self).__init__(
+            global_id_type.graphene_type, required=required, *args, **kwargs
+        )
         self.node = node or Node
         self.parent_type_name = parent_type._meta.name if parent_type else None
 
@@ -47,12 +56,14 @@
         assert issubclass(node, Node), "NodeField can only operate in Nodes"
         self.node_type = node
         self.field_type = type_
+        global_id_type = node._meta.global_id_type
 
         super(NodeField, self).__init__(
-            # If we don's specify a type, the field type will be the node
-            # interface
+            # If we don't specify a type, the field type will be the node 
interface
             type_ or node,
-            id=ID(required=True, description="The ID of the object"),
+            id=global_id_type.graphene_type(
+                required=True, description="The ID of the object"
+            ),
             **kwargs,
         )
 
@@ -65,11 +76,23 @@
         abstract = True
 
     @classmethod
-    def __init_subclass_with_meta__(cls, **options):
+    def __init_subclass_with_meta__(cls, global_id_type=DefaultGlobalIDType, 
**options):
+        assert issubclass(
+            global_id_type, BaseGlobalIDType
+        ), "Custom ID type need to be implemented as a subclass of 
BaseGlobalIDType."
         _meta = InterfaceOptions(cls)
-        _meta.fields = {"id": GlobalID(cls, description="The ID of the 
object")}
+        _meta.global_id_type = global_id_type
+        _meta.fields = {
+            "id": GlobalID(
+                cls, global_id_type=global_id_type, description="The ID of the 
object"
+            )
+        }
         super(AbstractNode, cls).__init_subclass_with_meta__(_meta=_meta, 
**options)
 
+    @classmethod
+    def resolve_global_id(cls, info, global_id):
+        return cls._meta.global_id_type.resolve_global_id(info, global_id)
+
 
 class Node(AbstractNode):
     """An object with an ID"""
@@ -84,16 +107,7 @@
 
     @classmethod
     def get_node_from_global_id(cls, info, global_id, only_type=None):
-        try:
-            _type, _id = cls.from_global_id(global_id)
-            if not _type:
-                raise ValueError("Invalid Global ID")
-        except Exception as e:
-            raise Exception(
-                f'Unable to parse global ID "{global_id}". '
-                'Make sure it is a base64 encoded string in the format: 
"TypeName:id". '
-                f"Exception message: {e}"
-            )
+        _type, _id = cls.resolve_global_id(info, global_id)
 
         graphene_type = info.schema.get_type(_type)
         if graphene_type is None:
@@ -117,9 +131,5 @@
             return get_node(info, _id)
 
     @classmethod
-    def from_global_id(cls, global_id):
-        return from_global_id(global_id)
-
-    @classmethod
     def to_global_id(cls, type_, id):
-        return to_global_id(type_, id)
+        return cls._meta.global_id_type.to_global_id(type_, id)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/graphene-3.1.1/graphene/relay/tests/test_custom_global_id.py 
new/graphene-3.2.1/graphene/relay/tests/test_custom_global_id.py
--- old/graphene-3.1.1/graphene/relay/tests/test_custom_global_id.py    
1970-01-01 01:00:00.000000000 +0100
+++ new/graphene-3.2.1/graphene/relay/tests/test_custom_global_id.py    
2022-12-11 21:05:25.000000000 +0100
@@ -0,0 +1,325 @@
+import re
+from uuid import uuid4
+
+from graphql import graphql_sync
+
+from ..id_type import BaseGlobalIDType, SimpleGlobalIDType, UUIDGlobalIDType
+from ..node import Node
+from ...types import Int, ObjectType, Schema, String
+
+
+class TestUUIDGlobalID:
+    def setup(self):
+        self.user_list = [
+            {"id": uuid4(), "name": "First"},
+            {"id": uuid4(), "name": "Second"},
+            {"id": uuid4(), "name": "Third"},
+            {"id": uuid4(), "name": "Fourth"},
+        ]
+        self.users = {user["id"]: user for user in self.user_list}
+
+        class CustomNode(Node):
+            class Meta:
+                global_id_type = UUIDGlobalIDType
+
+        class User(ObjectType):
+            class Meta:
+                interfaces = [CustomNode]
+
+            name = String()
+
+            @classmethod
+            def get_node(cls, _type, _id):
+                return self.users[_id]
+
+        class RootQuery(ObjectType):
+            user = CustomNode.Field(User)
+
+        self.schema = Schema(query=RootQuery, types=[User])
+        self.graphql_schema = self.schema.graphql_schema
+
+    def test_str_schema_correct(self):
+        """
+        Check that the schema has the expected and custom node interface and 
user type and that they both use UUIDs
+        """
+        parsed = re.findall(r"(.+) \{\n\s*([\w\W]*?)\n\}", str(self.schema))
+        types = [t for t, f in parsed]
+        fields = [f for t, f in parsed]
+        custom_node_interface = "interface CustomNode"
+        assert custom_node_interface in types
+        assert (
+            '"""The ID of the object"""\n  id: UUID!'
+            == fields[types.index(custom_node_interface)]
+        )
+        user_type = "type User implements CustomNode"
+        assert user_type in types
+        assert (
+            '"""The ID of the object"""\n  id: UUID!\n  name: String'
+            == fields[types.index(user_type)]
+        )
+
+    def test_get_by_id(self):
+        query = """query userById($id: UUID!) {
+            user(id: $id) {
+                id
+                name
+            }
+        }"""
+        # UUID need to be converted to string for serialization
+        result = graphql_sync(
+            self.graphql_schema,
+            query,
+            variable_values={"id": str(self.user_list[0]["id"])},
+        )
+        assert not result.errors
+        assert result.data["user"]["id"] == str(self.user_list[0]["id"])
+        assert result.data["user"]["name"] == self.user_list[0]["name"]
+
+
+class TestSimpleGlobalID:
+    def setup(self):
+        self.user_list = [
+            {"id": "my global primary key in clear 1", "name": "First"},
+            {"id": "my global primary key in clear 2", "name": "Second"},
+            {"id": "my global primary key in clear 3", "name": "Third"},
+            {"id": "my global primary key in clear 4", "name": "Fourth"},
+        ]
+        self.users = {user["id"]: user for user in self.user_list}
+
+        class CustomNode(Node):
+            class Meta:
+                global_id_type = SimpleGlobalIDType
+
+        class User(ObjectType):
+            class Meta:
+                interfaces = [CustomNode]
+
+            name = String()
+
+            @classmethod
+            def get_node(cls, _type, _id):
+                return self.users[_id]
+
+        class RootQuery(ObjectType):
+            user = CustomNode.Field(User)
+
+        self.schema = Schema(query=RootQuery, types=[User])
+        self.graphql_schema = self.schema.graphql_schema
+
+    def test_str_schema_correct(self):
+        """
+        Check that the schema has the expected and custom node interface and 
user type and that they both use UUIDs
+        """
+        parsed = re.findall(r"(.+) \{\n\s*([\w\W]*?)\n\}", str(self.schema))
+        types = [t for t, f in parsed]
+        fields = [f for t, f in parsed]
+        custom_node_interface = "interface CustomNode"
+        assert custom_node_interface in types
+        assert (
+            '"""The ID of the object"""\n  id: ID!'
+            == fields[types.index(custom_node_interface)]
+        )
+        user_type = "type User implements CustomNode"
+        assert user_type in types
+        assert (
+            '"""The ID of the object"""\n  id: ID!\n  name: String'
+            == fields[types.index(user_type)]
+        )
+
+    def test_get_by_id(self):
+        query = """query {
+            user(id: "my global primary key in clear 3") {
+                id
+                name
+            }
+        }"""
+        result = graphql_sync(self.graphql_schema, query)
+        assert not result.errors
+        assert result.data["user"]["id"] == self.user_list[2]["id"]
+        assert result.data["user"]["name"] == self.user_list[2]["name"]
+
+
+class TestCustomGlobalID:
+    def setup(self):
+        self.user_list = [
+            {"id": 1, "name": "First"},
+            {"id": 2, "name": "Second"},
+            {"id": 3, "name": "Third"},
+            {"id": 4, "name": "Fourth"},
+        ]
+        self.users = {user["id"]: user for user in self.user_list}
+
+        class CustomGlobalIDType(BaseGlobalIDType):
+            """
+            Global id that is simply and integer in clear.
+            """
+
+            graphene_type = Int
+
+            @classmethod
+            def resolve_global_id(cls, info, global_id):
+                _type = info.return_type.graphene_type._meta.name
+                return _type, global_id
+
+            @classmethod
+            def to_global_id(cls, _type, _id):
+                return _id
+
+        class CustomNode(Node):
+            class Meta:
+                global_id_type = CustomGlobalIDType
+
+        class User(ObjectType):
+            class Meta:
+                interfaces = [CustomNode]
+
+            name = String()
+
+            @classmethod
+            def get_node(cls, _type, _id):
+                return self.users[_id]
+
+        class RootQuery(ObjectType):
+            user = CustomNode.Field(User)
+
+        self.schema = Schema(query=RootQuery, types=[User])
+        self.graphql_schema = self.schema.graphql_schema
+
+    def test_str_schema_correct(self):
+        """
+        Check that the schema has the expected and custom node interface and 
user type and that they both use UUIDs
+        """
+        parsed = re.findall(r"(.+) \{\n\s*([\w\W]*?)\n\}", str(self.schema))
+        types = [t for t, f in parsed]
+        fields = [f for t, f in parsed]
+        custom_node_interface = "interface CustomNode"
+        assert custom_node_interface in types
+        assert (
+            '"""The ID of the object"""\n  id: Int!'
+            == fields[types.index(custom_node_interface)]
+        )
+        user_type = "type User implements CustomNode"
+        assert user_type in types
+        assert (
+            '"""The ID of the object"""\n  id: Int!\n  name: String'
+            == fields[types.index(user_type)]
+        )
+
+    def test_get_by_id(self):
+        query = """query {
+            user(id: 2) {
+                id
+                name
+            }
+        }"""
+        result = graphql_sync(self.graphql_schema, query)
+        assert not result.errors
+        assert result.data["user"]["id"] == self.user_list[1]["id"]
+        assert result.data["user"]["name"] == self.user_list[1]["name"]
+
+
+class TestIncompleteCustomGlobalID:
+    def setup(self):
+        self.user_list = [
+            {"id": 1, "name": "First"},
+            {"id": 2, "name": "Second"},
+            {"id": 3, "name": "Third"},
+            {"id": 4, "name": "Fourth"},
+        ]
+        self.users = {user["id"]: user for user in self.user_list}
+
+    def test_must_define_to_global_id(self):
+        """
+        Test that if the `to_global_id` method is not defined, we can query 
the object, but we can't request its ID.
+        """
+
+        class CustomGlobalIDType(BaseGlobalIDType):
+            graphene_type = Int
+
+            @classmethod
+            def resolve_global_id(cls, info, global_id):
+                _type = info.return_type.graphene_type._meta.name
+                return _type, global_id
+
+        class CustomNode(Node):
+            class Meta:
+                global_id_type = CustomGlobalIDType
+
+        class User(ObjectType):
+            class Meta:
+                interfaces = [CustomNode]
+
+            name = String()
+
+            @classmethod
+            def get_node(cls, _type, _id):
+                return self.users[_id]
+
+        class RootQuery(ObjectType):
+            user = CustomNode.Field(User)
+
+        self.schema = Schema(query=RootQuery, types=[User])
+        self.graphql_schema = self.schema.graphql_schema
+
+        query = """query {
+            user(id: 2) {
+                name
+            }
+        }"""
+        result = graphql_sync(self.graphql_schema, query)
+        assert not result.errors
+        assert result.data["user"]["name"] == self.user_list[1]["name"]
+
+        query = """query {
+            user(id: 2) {
+                id
+                name
+            }
+        }"""
+        result = graphql_sync(self.graphql_schema, query)
+        assert result.errors is not None
+        assert len(result.errors) == 1
+        assert result.errors[0].path == ["user", "id"]
+
+    def test_must_define_resolve_global_id(self):
+        """
+        Test that if the `resolve_global_id` method is not defined, we can't 
query the object by ID.
+        """
+
+        class CustomGlobalIDType(BaseGlobalIDType):
+            graphene_type = Int
+
+            @classmethod
+            def to_global_id(cls, _type, _id):
+                return _id
+
+        class CustomNode(Node):
+            class Meta:
+                global_id_type = CustomGlobalIDType
+
+        class User(ObjectType):
+            class Meta:
+                interfaces = [CustomNode]
+
+            name = String()
+
+            @classmethod
+            def get_node(cls, _type, _id):
+                return self.users[_id]
+
+        class RootQuery(ObjectType):
+            user = CustomNode.Field(User)
+
+        self.schema = Schema(query=RootQuery, types=[User])
+        self.graphql_schema = self.schema.graphql_schema
+
+        query = """query {
+            user(id: 2) {
+                id
+                name
+            }
+        }"""
+        result = graphql_sync(self.graphql_schema, query)
+        assert result.errors is not None
+        assert len(result.errors) == 1
+        assert result.errors[0].path == ["user"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/graphene-3.1.1/graphene/relay/tests/test_mutation_async.py 
new/graphene-3.2.1/graphene/relay/tests/test_mutation_async.py
--- old/graphene-3.1.1/graphene/relay/tests/test_mutation_async.py      
2022-09-08 10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/relay/tests/test_mutation_async.py      
2022-12-11 21:05:25.000000000 +0100
@@ -3,6 +3,7 @@
 from graphene.types import ID, Field, ObjectType, Schema
 from graphene.types.scalars import String
 from graphene.relay.mutation import ClientIDMutation
+from graphene.test import Client
 
 
 class SharedFields(object):
@@ -61,24 +62,27 @@
 
 
 schema = Schema(query=RootQuery, mutation=Mutation)
+client = Client(schema)
 
 
 @mark.asyncio
 async def test_node_query_promise():
-    executed = await schema.execute_async(
+    executed = await client.execute_async(
         'mutation a { sayPromise(input: {what:"hello", clientMutationId:"1"}) 
{ phrase } }'
     )
-    assert not executed.errors
-    assert executed.data == {"sayPromise": {"phrase": "hello"}}
+    assert isinstance(executed, dict)
+    assert "errors" not in executed
+    assert executed["data"] == {"sayPromise": {"phrase": "hello"}}
 
 
 @mark.asyncio
 async def test_edge_query():
-    executed = await schema.execute_async(
+    executed = await client.execute_async(
         'mutation a { other(input: {clientMutationId:"1"}) { clientMutationId, 
myNodeEdge { cursor node { name }} } }'
     )
-    assert not executed.errors
-    assert dict(executed.data) == {
+    assert isinstance(executed, dict)
+    assert "errors" not in executed
+    assert executed["data"] == {
         "other": {
             "clientMutationId": "1",
             "myNodeEdge": {"cursor": "1", "node": {"name": "name"}},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/relay/tests/test_node.py 
new/graphene-3.2.1/graphene/relay/tests/test_node.py
--- old/graphene-3.1.1/graphene/relay/tests/test_node.py        2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/relay/tests/test_node.py        2022-12-11 
21:05:25.000000000 +0100
@@ -55,6 +55,7 @@
     assert "id" in MyNode._meta.fields
     assert is_node(MyNode)
     assert not is_node(object)
+    assert not is_node("node")
 
 
 def test_node_query():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/test/__init__.py 
new/graphene-3.2.1/graphene/test/__init__.py
--- old/graphene-3.1.1/graphene/test/__init__.py        2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/test/__init__.py        2022-12-11 
21:05:25.000000000 +0100
@@ -1,4 +1,3 @@
-from promise import Promise, is_thenable
 from graphql.error import GraphQLError
 
 from graphene.types.schema import Schema
@@ -31,7 +30,10 @@
 
     def execute(self, *args, **kwargs):
         executed = self.schema.execute(*args, **dict(self.execute_options, 
**kwargs))
-        if is_thenable(executed):
-            return Promise.resolve(executed).then(self.format_result)
+        return self.format_result(executed)
 
+    async def execute_async(self, *args, **kwargs):
+        executed = await self.schema.execute_async(
+            *args, **dict(self.execute_options, **kwargs)
+        )
         return self.format_result(executed)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/argument.py 
new/graphene-3.2.1/graphene/types/argument.py
--- old/graphene-3.1.1/graphene/types/argument.py       2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/argument.py       2022-12-11 
21:05:25.000000000 +0100
@@ -31,18 +31,22 @@
         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 @@
         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 @@
             and self.type == other.type
             and self.default_value == other.default_value
             and self.description == other.description
+            and self.deprecation_reason == other.deprecation_reason
         )
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/definitions.py 
new/graphene-3.2.1/graphene/types/definitions.py
--- old/graphene-3.1.1/graphene/types/definitions.py    2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/definitions.py    2022-12-11 
21:05:25.000000000 +0100
@@ -20,6 +20,11 @@
         self.graphene_type = kwargs.pop("graphene_type")
         super(GrapheneGraphQLType, self).__init__(*args, **kwargs)
 
+    def __copy__(self):
+        result = GrapheneGraphQLType(graphene_type=self.graphene_type)
+        result.__dict__.update(self.__dict__)
+        return result
+
 
 class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType):
     pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/enum.py 
new/graphene-3.2.1/graphene/types/enum.py
--- old/graphene-3.1.1/graphene/types/enum.py   2022-09-08 10:55:05.000000000 
+0200
+++ new/graphene-3.2.1/graphene/types/enum.py   2022-12-11 21:05:25.000000000 
+0100
@@ -12,6 +12,10 @@
     return self.value is other
 
 
+def hash_enum(self):
+    return hash(self.name)
+
+
 EnumType = type(PyEnum)
 
 
@@ -22,7 +26,7 @@
 
 class EnumMeta(SubclassWithMeta_Meta):
     def __new__(cls, name_, bases, classdict, **options):
-        enum_members = dict(classdict, __eq__=eq_enum)
+        enum_members = dict(classdict, __eq__=eq_enum, __hash__=hash_enum)
         # We remove the Meta attribute from the class to not collide
         # with the enum values.
         enum_members.pop("Meta", None)
@@ -52,6 +56,9 @@
         return super(EnumMeta, cls).__call__(*args, **kwargs)
         # return cls._meta.enum(*args, **kwargs)
 
+    def __iter__(cls):
+        return cls._meta.enum.__iter__()
+
     def from_enum(
         cls, enum, name=None, description=None, deprecation_reason=None
     ):  # noqa: N805
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/inputfield.py 
new/graphene-3.2.1/graphene/types/inputfield.py
--- old/graphene-3.1.1/graphene/types/inputfield.py     2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/inputfield.py     2022-12-11 
21:05:25.000000000 +0100
@@ -55,11 +55,14 @@
         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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/inputobjecttype.py 
new/graphene-3.2.1/graphene/types/inputobjecttype.py
--- old/graphene-3.1.1/graphene/types/inputobjecttype.py        2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/inputobjecttype.py        2022-12-11 
21:05:25.000000000 +0100
@@ -14,7 +14,7 @@
     container = None  # type: InputObjectTypeContainer
 
 
-class InputObjectTypeContainer(dict, BaseType):
+class InputObjectTypeContainer(dict, BaseType):  # type: ignore
     class Meta:
         abstract = True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/schema.py 
new/graphene-3.2.1/graphene/types/schema.py
--- old/graphene-3.1.1/graphene/types/schema.py 2022-09-08 10:55:05.000000000 
+0200
+++ new/graphene-3.2.1/graphene/types/schema.py 2022-12-11 21:05:25.000000000 
+0100
@@ -1,3 +1,4 @@
+from enum import Enum as PyEnum
 import inspect
 from functools import partial
 
@@ -169,10 +170,16 @@
         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 @@
                     default_value=field.default_value,
                     out_name=name,
                     description=field.description,
+                    deprecation_reason=field.deprecation_reason,
                 )
             else:
                 args = {}
@@ -320,6 +328,7 @@
                         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(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/tests/test_argument.py 
new/graphene-3.2.1/graphene/types/tests/test_argument.py
--- old/graphene-3.1.1/graphene/types/tests/test_argument.py    2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/tests/test_argument.py    2022-12-11 
21:05:25.000000000 +0100
@@ -18,8 +18,20 @@
 
 
 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_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)}
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/graphene-3.1.1/graphene/types/tests/test_definition.py 
new/graphene-3.2.1/graphene/types/tests/test_definition.py
--- old/graphene-3.1.1/graphene/types/tests/test_definition.py  2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/tests/test_definition.py  2022-12-11 
21:05:25.000000000 +0100
@@ -1,4 +1,7 @@
+import copy
+
 from ..argument import Argument
+from ..definitions import GrapheneGraphQLType
 from ..enum import Enum
 from ..field import Field
 from ..inputfield import InputField
@@ -312,3 +315,16 @@
         pass
 
     assert TestInputObject1._meta.fields == TestInputObject2._meta.fields
+
+
+def test_graphene_graphql_type_can_be_copied():
+    class Query(ObjectType):
+        field = String()
+
+        def resolve_field(self, info):
+            return ""
+
+    schema = Schema(query=Query)
+    query_type_copy = copy.copy(schema.graphql_schema.query_type)
+    assert query_type_copy.__dict__ == 
schema.graphql_schema.query_type.__dict__
+    assert isinstance(schema.graphql_schema.query_type, GrapheneGraphQLType)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/tests/test_enum.py 
new/graphene-3.2.1/graphene/types/tests/test_enum.py
--- old/graphene-3.1.1/graphene/types/tests/test_enum.py        2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/tests/test_enum.py        2022-12-11 
21:05:25.000000000 +0100
@@ -518,3 +518,83 @@
     assert result.data == {"createPaint": {"color": "RED"}}
 
     assert color_input_value == RGB.RED
+
+
+def test_hashable_enum():
+    class RGB(Enum):
+        """Available colors"""
+
+        RED = 1
+        GREEN = 2
+        BLUE = 3
+
+    color_map = {RGB.RED: "a", RGB.BLUE: "b", 1: "c"}
+
+    assert color_map[RGB.RED] == "a"
+    assert color_map[RGB.BLUE] == "b"
+    assert color_map[1] == "c"
+
+
+def test_hashable_instance_creation_enum():
+    Episode = Enum("Episode", [("NEWHOPE", 4), ("EMPIRE", 5), ("JEDI", 6)])
+
+    trilogy_map = {Episode.NEWHOPE: "better", Episode.EMPIRE: "best", 5: "foo"}
+
+    assert trilogy_map[Episode.NEWHOPE] == "better"
+    assert trilogy_map[Episode.EMPIRE] == "best"
+    assert trilogy_map[5] == "foo"
+
+
+def test_enum_iteration():
+    class TestEnum(Enum):
+        FIRST = 1
+        SECOND = 2
+
+    result = []
+    expected_values = ["FIRST", "SECOND"]
+    for c in TestEnum:
+        result.append(c.name)
+    assert result == expected_values
+
+
+def test_iterable_instance_creation_enum():
+    TestEnum = Enum("TestEnum", [("FIRST", 1), ("SECOND", 2)])
+
+    result = []
+    expected_values = ["FIRST", "SECOND"]
+    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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/types/tests/test_field.py 
new/graphene-3.2.1/graphene/types/tests/test_field.py
--- old/graphene-3.1.1/graphene/types/tests/test_field.py       2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/tests/test_field.py       2022-12-11 
21:05:25.000000000 +0100
@@ -128,13 +128,20 @@
 
 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/graphene-3.1.1/graphene/types/tests/test_inputfield.py 
new/graphene-3.2.1/graphene/types/tests/test_inputfield.py
--- old/graphene-3.1.1/graphene/types/tests/test_inputfield.py  2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/types/tests/test_inputfield.py  2022-12-11 
21:05:25.000000000 +0100
@@ -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 @@
     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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/graphene/validation/depth_limit.py 
new/graphene-3.2.1/graphene/validation/depth_limit.py
--- old/graphene-3.1.1/graphene/validation/depth_limit.py       2022-09-08 
10:55:05.000000000 +0200
+++ new/graphene-3.2.1/graphene/validation/depth_limit.py       2022-12-11 
21:05:25.000000000 +0100
@@ -53,7 +53,7 @@
 def depth_limit_validator(
     max_depth: int,
     ignore: Optional[List[IgnoreType]] = None,
-    callback: Callable[[Dict[str, int]], None] = None,
+    callback: Optional[Callable[[Dict[str, int]], None]] = None,
 ):
     class DepthLimitValidator(ValidationRule):
         def __init__(self, validation_context: ValidationContext):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/graphene-3.1.1/setup.py new/graphene-3.2.1/setup.py
--- old/graphene-3.1.1/setup.py 2022-09-08 10:55:05.000000000 +0200
+++ new/graphene-3.2.1/setup.py 2022-12-11 21:05:25.000000000 +0100
@@ -52,7 +52,6 @@
     "pytest-asyncio>=0.16,<2",
     "snapshottest>=0.6,<1",
     "coveralls>=3.3,<4",
-    "promise>=2.3,<3",
     "mock>=4,<5",
     "pytz==2022.1",
     "iso8601>=1,<2",

Reply via email to