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-12-17 21:33:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-graphene (Old)
and /work/SRC/openSUSE:Factory/.python-graphene.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-graphene"
Sun Dec 17 21:33:10 2023 rev:11 rq:1133682 version:3.3.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-graphene/python-graphene.changes
2023-07-10 16:40:48.450867136 +0200
+++
/work/SRC/openSUSE:Factory/.python-graphene.new.25432/python-graphene.changes
2023-12-17 21:35:20.284153316 +0100
@@ -1,0 +2,19 @@
+Sun Dec 17 01:58:11 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 3.3.0:
+ * Default value for InputObjectTypes
+ * Default enum description to "An enumeration."
+ * Allow the user to change InputObjectType's default value on
+ non-specified inputs to a sentinel value
+ * 881: Corrected enum metaclass to fix pickle.dumps()
+ * chore: Use `typing.TYPE_CHECKING` instead of MYPY
+ * test: print schema with InputObjectType with DateTime field
+ with default_value (#1293)
+ * docs: add get_human function
+ * CI: drop python 3.6
+ * types: add option for strict connection types
+- update to 3.2.2:
+ * This release provides some internal refactoring to the relay
+ types to improve support for adding custom fields to them.
+
+-------------------------------------------------------------------
Old:
----
graphene-3.2.1.tar.gz
New:
----
graphene-3.3.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-graphene.spec ++++++
--- /var/tmp/diff_new_pack.05ARxi/_old 2023-12-17 21:35:20.708168723 +0100
+++ /var/tmp/diff_new_pack.05ARxi/_new 2023-12-17 21:35:20.708168723 +0100
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-graphene
-Version: 3.2.1
+Version: 3.3.0
Release: 0
Summary: GraphQL Framework for Python
License: MIT
++++++ graphene-3.2.1.tar.gz -> graphene-3.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/.github/workflows/tests.yml
new/graphene-3.3.0/.github/workflows/tests.yml
--- old/graphene-3.2.1/.github/workflows/tests.yml 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/.github/workflows/tests.yml 2023-07-26
08:26:30.000000000 +0200
@@ -25,12 +25,11 @@
fail-fast: false
matrix:
include:
- - {name: '3.11', python: '3.11-dev', os: ubuntu-latest, tox: py311}
+ - {name: '3.11', python: '3.11', os: ubuntu-latest, tox: py311}
- {name: '3.10', python: '3.10', os: ubuntu-latest, tox: py310}
- {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-20.04, tox: py36}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/README.md new/graphene-3.3.0/README.md
--- old/graphene-3.2.1/README.md 2022-12-11 21:05:25.000000000 +0100
+++ new/graphene-3.3.0/README.md 2023-07-26 08:26:30.000000000 +0200
@@ -1,6 +1,6 @@
-# 
[Graphene](http://graphene-python.org) [](https://travis-ci.org/graphql-python/graphene)
[](https://badge.fury.io/py/graphene)
[](https://coveralls.io/github/graphql-python/graphene?branch=master)
+# 
[Graphene](http://graphene-python.org) [](https://badge.fury.io/py/graphene)
[](https://coveralls.io/github/graphql-python/graphene?branch=master)
[](https://discord.gg/T6Gp6NFYHe)
-[ð¬ Join the community on
Slack](https://join.slack.com/t/graphenetools/shared_invite/enQtOTE2MDQ1NTg4MDM1LTA4Nzk0MGU0NGEwNzUxZGNjNDQ4ZjAwNDJjMjY0OGE1ZDgxZTg4YjM2ZTc4MjE2ZTAzZjE2ZThhZTQzZTkyMmM)
+[ð¬ Join the community on Discord](https://discord.gg/T6Gp6NFYHe)
**We are looking for contributors**! Please check the current issues to see
how you can help â¤ï¸
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/README.rst
new/graphene-3.3.0/README.rst
--- old/graphene-3.2.1/README.rst 2022-12-11 21:05:25.000000000 +0100
+++ new/graphene-3.3.0/README.rst 2023-07-26 08:26:30.000000000 +0200
@@ -36,9 +36,6 @@
| SQLAlchemy | `graphene-sqlalchemy <https://git |
| | hub.com/graphql-python/graphene-sqlalchemy/>`__ |
+-------------------+-------------------------------------------------+
-| Google App Engine | `graphene-gae <http |
-| | s://github.com/graphql-python/graphene-gae/>`__ |
-+-------------------+-------------------------------------------------+
Also, Graphene is fully compatible with the GraphQL spec, working
seamlessly with all GraphQL clients, such as
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/api/index.rst
new/graphene-3.3.0/docs/api/index.rst
--- old/graphene-3.2.1/docs/api/index.rst 2022-12-11 21:05:25.000000000
+0100
+++ new/graphene-3.3.0/docs/api/index.rst 2023-07-26 08:26:30.000000000
+0200
@@ -92,7 +92,7 @@
.. autoclass:: graphene.Context
-.. autoclass:: graphql.execution.base.ExecutionResult
+.. autoclass:: graphql.ExecutionResult
.. Relay
.. -----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/conf.py
new/graphene-3.3.0/docs/conf.py
--- old/graphene-3.2.1/docs/conf.py 2022-12-11 21:05:25.000000000 +0100
+++ new/graphene-3.3.0/docs/conf.py 2023-07-26 08:26:30.000000000 +0200
@@ -82,7 +82,7 @@
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
-language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
@@ -456,5 +456,4 @@
"http://docs.graphene-python.org/projects/sqlalchemy/en/latest/",
None,
),
- "graphene_gae":
("http://docs.graphene-python.org/projects/gae/en/latest/", None),
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/execution/dataloader.rst
new/graphene-3.3.0/docs/execution/dataloader.rst
--- old/graphene-3.2.1/docs/execution/dataloader.rst 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/docs/execution/dataloader.rst 2023-07-26
08:26:30.000000000 +0200
@@ -36,10 +36,10 @@
user_loader = UserLoader()
user1 = await user_loader.load(1)
- user1_best_friend = await user_loader.load(user1.best_friend_id))
+ user1_best_friend = await user_loader.load(user1.best_friend_id)
user2 = await user_loader.load(2)
- user2_best_friend = await user_loader.load(user2.best_friend_id))
+ user2_best_friend = await user_loader.load(user2.best_friend_id)
A naive application may have issued *four* round-trips to a backend for the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/execution/queryvalidation.rst
new/graphene-3.3.0/docs/execution/queryvalidation.rst
--- old/graphene-3.2.1/docs/execution/queryvalidation.rst 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/docs/execution/queryvalidation.rst 2023-07-26
08:26:30.000000000 +0200
@@ -1,5 +1,5 @@
Query Validation
-==========
+================
GraphQL uses query validators to check if Query AST is valid and can be
executed. Every GraphQL server implements
standard query validators. For example, there is an validator that tests if
queried field exists on queried type, that
makes query fail with "Cannot query field on type" error if it doesn't.
@@ -8,7 +8,7 @@
Depth limit Validator
------------------
+---------------------
The depth limit validator helps to prevent execution of malicious
queries. It takes in the following arguments.
@@ -17,7 +17,7 @@
- ``callback`` Called each time validation runs. Receives an Object which is a
map of the depths for each operation.
Usage
--------
+-----
Here is how you would implement depth-limiting on your schema.
@@ -54,7 +54,7 @@
This is a useful security measure in production environments.
Usage
--------
+-----
Here is how you would disable introspection for your schema.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/index.rst
new/graphene-3.3.0/docs/index.rst
--- old/graphene-3.2.1/docs/index.rst 2022-12-11 21:05:25.000000000 +0100
+++ new/graphene-3.3.0/docs/index.rst 2023-07-26 08:26:30.000000000 +0200
@@ -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::
@@ -27,7 +21,6 @@
* `Graphene-Django
<http://docs.graphene-python.org/projects/django/en/latest/>`_ (`source
<https://github.com/graphql-python/graphene-django/>`_)
* Flask-Graphql (`source <https://github.com/graphql-python/flask-graphql>`_)
* `Graphene-SQLAlchemy
<http://docs.graphene-python.org/projects/sqlalchemy/en/latest/>`_ (`source
<https://github.com/graphql-python/graphene-sqlalchemy/>`_)
-* `Graphene-GAE <http://docs.graphene-python.org/projects/gae/en/latest/>`_
(`source <https://github.com/graphql-python/graphene-gae/>`_)
* `Graphene-Mongo <http://graphene-mongo.readthedocs.io/en/latest/>`_ (`source
<https://github.com/graphql-python/graphene-mongo>`_)
* `Starlette <https://www.starlette.io/graphql/>`_ (`source
<https://github.com/encode/starlette>`_)
* `FastAPI <https://fastapi.tiangolo.com/advanced/graphql/>`_ (`source
<https://github.com/tiangolo/fastapi>`_)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/requirements.txt
new/graphene-3.3.0/docs/requirements.txt
--- old/graphene-3.2.1/docs/requirements.txt 2022-12-11 21:05:25.000000000
+0100
+++ new/graphene-3.3.0/docs/requirements.txt 2023-07-26 08:26:30.000000000
+0200
@@ -1,5 +1,5 @@
# Required library
-Sphinx==1.5.3
-sphinx-autobuild==0.7.1
+Sphinx==6.1.3
+sphinx-autobuild==2021.3.14
# Docs template
http://graphene-python.org/sphinx_graphene_theme.zip
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/types/objecttypes.rst
new/graphene-3.3.0/docs/types/objecttypes.rst
--- old/graphene-3.2.1/docs/types/objecttypes.rst 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/docs/types/objecttypes.rst 2023-07-26
08:26:30.000000000 +0200
@@ -80,6 +80,10 @@
from graphene import ObjectType, String, Field
+ def get_human(name):
+ first_name, last_name = name.split()
+ return Person(first_name, last_name)
+
class Person(ObjectType):
full_name = String()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/docs/types/scalars.rst
new/graphene-3.3.0/docs/types/scalars.rst
--- old/graphene-3.2.1/docs/types/scalars.rst 2022-12-11 21:05:25.000000000
+0100
+++ new/graphene-3.3.0/docs/types/scalars.rst 2023-07-26 08:26:30.000000000
+0200
@@ -271,7 +271,7 @@
@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")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/__init__.py
new/graphene-3.3.0/graphene/__init__.py
--- old/graphene-3.2.1/graphene/__init__.py 2022-12-11 21:05:25.000000000
+0100
+++ new/graphene-3.3.0/graphene/__init__.py 2023-07-26 08:26:30.000000000
+0200
@@ -46,7 +46,7 @@
from .utils.module_loading import lazy_import
from .utils.resolve_only_args import resolve_only_args
-VERSION = (3, 2, 1, "final", 0)
+VERSION = (3, 3, 0, "final", 0)
__version__ = get_version(VERSION)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/relay/connection.py
new/graphene-3.3.0/graphene/relay/connection.py
--- old/graphene-3.2.1/graphene/relay/connection.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/relay/connection.py 2023-07-26
08:26:30.000000000 +0200
@@ -1,6 +1,7 @@
import re
from collections.abc import Iterable
from functools import partial
+from typing import Type
from graphql_relay import connection_from_array
@@ -8,7 +9,34 @@
from ..types.field import Field
from ..types.objecttype import ObjectType, ObjectTypeOptions
from ..utils.thenables import maybe_thenable
-from .node import is_node
+from .node import is_node, AbstractNode
+
+
+def get_edge_class(
+ connection_class: Type["Connection"],
+ _node: Type[AbstractNode],
+ base_name: str,
+ strict_types: bool = False,
+):
+ edge_class = getattr(connection_class, "Edge", None)
+
+ class EdgeBase:
+ node = Field(
+ NonNull(_node) if strict_types else _node,
+ description="The item at the end of the edge",
+ )
+ cursor = String(required=True, description="A cursor for use in
pagination")
+
+ class EdgeMeta:
+ description = f"A Relay edge containing a `{base_name}` and its
cursor."
+
+ edge_name = f"{base_name}Edge"
+
+ edge_bases = [edge_class, EdgeBase] if edge_class else [EdgeBase]
+ if not isinstance(edge_class, ObjectType):
+ edge_bases = [*edge_bases, ObjectType]
+
+ return type(edge_name, tuple(edge_bases), {"Meta": EdgeMeta})
class PageInfo(ObjectType):
@@ -61,8 +89,11 @@
abstract = True
@classmethod
- def __init_subclass_with_meta__(cls, node=None, name=None, **options):
- _meta = ConnectionOptions(cls)
+ def __init_subclass_with_meta__(
+ cls, node=None, name=None, strict_types=False, _meta=None, **options
+ ):
+ if not _meta:
+ _meta = ConnectionOptions(cls)
assert node, f"You have to provide a node in {cls.__name__}.Meta"
assert isinstance(node, NonNull) or issubclass(
node, (Scalar, Enum, ObjectType, Interface, Union, NonNull)
@@ -72,39 +103,29 @@
if not name:
name = f"{base_name}Connection"
- edge_class = getattr(cls, "Edge", None)
- _node = node
+ options["name"] = name
- class EdgeBase:
- node = Field(_node, description="The item at the end of the edge")
- cursor = String(required=True, description="A cursor for use in
pagination")
-
- class EdgeMeta:
- description = f"A Relay edge containing a `{base_name}` and its
cursor."
-
- edge_name = f"{base_name}Edge"
- if edge_class:
- edge_bases = (edge_class, EdgeBase, ObjectType)
- else:
- edge_bases = (EdgeBase, ObjectType)
+ _meta.node = node
- edge = type(edge_name, edge_bases, {"Meta": EdgeMeta})
- cls.Edge = edge
+ if not _meta.fields:
+ _meta.fields = {}
- options["name"] = name
- _meta.node = node
- _meta.fields = {
- "page_info": Field(
+ if "page_info" not in _meta.fields:
+ _meta.fields["page_info"] = Field(
PageInfo,
name="pageInfo",
required=True,
description="Pagination data for this connection.",
- ),
- "edges": Field(
- NonNull(List(edge)),
+ )
+
+ if "edges" not in _meta.fields:
+ edge_class = get_edge_class(cls, node, base_name, strict_types) #
type: ignore
+ cls.Edge = edge_class
+ _meta.fields["edges"] = Field(
+ NonNull(List(NonNull(edge_class) if strict_types else
edge_class)),
description="Contains the nodes in this connection.",
- ),
- }
+ )
+
return super(Connection, cls).__init_subclass_with_meta__(
_meta=_meta, **options
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/graphene-3.2.1/graphene/relay/tests/test_connection.py
new/graphene-3.3.0/graphene/relay/tests/test_connection.py
--- old/graphene-3.2.1/graphene/relay/tests/test_connection.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/relay/tests/test_connection.py 2023-07-26
08:26:30.000000000 +0200
@@ -1,7 +1,15 @@
+import re
+
from pytest import raises
from ...types import Argument, Field, Int, List, NonNull, ObjectType, Schema,
String
-from ..connection import Connection, ConnectionField, PageInfo
+from ..connection import (
+ Connection,
+ ConnectionField,
+ PageInfo,
+ ConnectionOptions,
+ get_edge_class,
+)
from ..node import Node
@@ -51,6 +59,111 @@
assert list(fields) == ["page_info", "edges", "extra"]
+def test_connection_extra_abstract_fields():
+ class ConnectionWithNodes(Connection):
+ class Meta:
+ abstract = True
+
+ @classmethod
+ def __init_subclass_with_meta__(cls, node=None, name=None, **options):
+ _meta = ConnectionOptions(cls)
+
+ _meta.fields = {
+ "nodes": Field(
+ NonNull(List(node)),
+ description="Contains all the nodes in this connection.",
+ ),
+ }
+
+ return super(ConnectionWithNodes, cls).__init_subclass_with_meta__(
+ node=node, name=name, _meta=_meta, **options
+ )
+
+ class MyObjectConnection(ConnectionWithNodes):
+ class Meta:
+ node = MyObject
+
+ class Edge:
+ other = String()
+
+ assert MyObjectConnection._meta.name == "MyObjectConnection"
+ fields = MyObjectConnection._meta.fields
+ assert list(fields) == ["nodes", "page_info", "edges"]
+ edge_field = fields["edges"]
+ pageinfo_field = fields["page_info"]
+ nodes_field = fields["nodes"]
+
+ assert isinstance(edge_field, Field)
+ assert isinstance(edge_field.type, NonNull)
+ assert isinstance(edge_field.type.of_type, List)
+ assert edge_field.type.of_type.of_type == MyObjectConnection.Edge
+
+ assert isinstance(pageinfo_field, Field)
+ assert isinstance(pageinfo_field.type, NonNull)
+ assert pageinfo_field.type.of_type == PageInfo
+
+ assert isinstance(nodes_field, Field)
+ assert isinstance(nodes_field.type, NonNull)
+ assert isinstance(nodes_field.type.of_type, List)
+ assert nodes_field.type.of_type.of_type == MyObject
+
+
+def test_connection_override_fields():
+ class ConnectionWithNodes(Connection):
+ class Meta:
+ abstract = True
+
+ @classmethod
+ def __init_subclass_with_meta__(cls, node=None, name=None, **options):
+ _meta = ConnectionOptions(cls)
+ base_name = (
+ re.sub("Connection$", "", name or cls.__name__) or
node._meta.name
+ )
+
+ edge_class = get_edge_class(cls, node, base_name)
+
+ _meta.fields = {
+ "page_info": Field(
+ NonNull(
+ PageInfo,
+ name="pageInfo",
+ required=True,
+ description="Pagination data for this connection.",
+ )
+ ),
+ "edges": Field(
+ NonNull(List(NonNull(edge_class))),
+ description="Contains the nodes in this connection.",
+ ),
+ }
+
+ return super(ConnectionWithNodes, cls).__init_subclass_with_meta__(
+ node=node, name=name, _meta=_meta, **options
+ )
+
+ class MyObjectConnection(ConnectionWithNodes):
+ class Meta:
+ node = MyObject
+
+ assert MyObjectConnection._meta.name == "MyObjectConnection"
+ fields = MyObjectConnection._meta.fields
+ assert list(fields) == ["page_info", "edges"]
+ edge_field = fields["edges"]
+ pageinfo_field = fields["page_info"]
+
+ assert isinstance(edge_field, Field)
+ assert isinstance(edge_field.type, NonNull)
+ assert isinstance(edge_field.type.of_type, List)
+ assert isinstance(edge_field.type.of_type.of_type, NonNull)
+
+ assert edge_field.type.of_type.of_type.of_type.__name__ == "MyObjectEdge"
+
+ # This page info is NonNull
+ assert isinstance(pageinfo_field, Field)
+ assert isinstance(edge_field.type, NonNull)
+ assert pageinfo_field.type.of_type == PageInfo
+
+
def test_connection_name():
custom_name = "MyObjectCustomNameConnection"
@@ -186,3 +299,20 @@
executed = schema.execute("{ testConnection { edges { cursor } } }")
assert not executed.errors
assert executed.data == {"testConnection": {"edges": []}}
+
+
+def test_connectionfield_strict_types():
+ class MyObjectConnection(Connection):
+ class Meta:
+ node = MyObject
+ strict_types = True
+
+ connection_field = ConnectionField(MyObjectConnection)
+ edges_field_type = connection_field.type._meta.fields["edges"].type
+ assert isinstance(edges_field_type, NonNull)
+
+ edges_list_element_type = edges_field_type.of_type.of_type
+ assert isinstance(edges_list_element_type, NonNull)
+
+ node_field = edges_list_element_type.of_type._meta.fields["node"]
+ assert isinstance(node_field.type, NonNull)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/tests/issues/test_1293.py
new/graphene-3.3.0/graphene/tests/issues/test_1293.py
--- old/graphene-3.2.1/graphene/tests/issues/test_1293.py 1970-01-01
01:00:00.000000000 +0100
+++ new/graphene-3.3.0/graphene/tests/issues/test_1293.py 2023-07-26
08:26:30.000000000 +0200
@@ -0,0 +1,41 @@
+# https://github.com/graphql-python/graphene/issues/1293
+
+import datetime
+
+import graphene
+from graphql.utilities import print_schema
+
+
+class Filters(graphene.InputObjectType):
+ datetime_after = graphene.DateTime(
+ required=False,
+ default_value=datetime.datetime.utcfromtimestamp(1434549820776 / 1000),
+ )
+ datetime_before = graphene.DateTime(
+ required=False,
+ default_value=datetime.datetime.utcfromtimestamp(1444549820776 / 1000),
+ )
+
+
+class SetDatetime(graphene.Mutation):
+ class Arguments:
+ filters = Filters(required=True)
+
+ ok = graphene.Boolean()
+
+ def mutate(root, info, filters):
+ return SetDatetime(ok=True)
+
+
+class Query(graphene.ObjectType):
+ goodbye = graphene.String()
+
+
+class Mutations(graphene.ObjectType):
+ set_datetime = SetDatetime.Field()
+
+
+def test_schema_printable_with_default_datetime_value():
+ schema = graphene.Schema(query=Query, mutation=Mutations)
+ schema_str = print_schema(schema.graphql_schema)
+ assert schema_str, "empty schema printed"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/tests/issues/test_881.py
new/graphene-3.3.0/graphene/tests/issues/test_881.py
--- old/graphene-3.2.1/graphene/tests/issues/test_881.py 1970-01-01
01:00:00.000000000 +0100
+++ new/graphene-3.3.0/graphene/tests/issues/test_881.py 2023-07-26
08:26:30.000000000 +0200
@@ -0,0 +1,27 @@
+import pickle
+
+from ...types.enum import Enum
+
+
+class PickleEnum(Enum):
+ # is defined outside of test because pickle unable to dump class inside ot
pytest function
+ A = "a"
+ B = 1
+
+
+def test_enums_pickling():
+ a = PickleEnum.A
+ pickled = pickle.dumps(a)
+ restored = pickle.loads(pickled)
+ assert type(a) is type(restored)
+ assert a == restored
+ assert a.value == restored.value
+ assert a.name == restored.name
+
+ b = PickleEnum.B
+ pickled = pickle.dumps(b)
+ restored = pickle.loads(pickled)
+ assert type(a) is type(restored)
+ assert b == restored
+ assert b.value == restored.value
+ assert b.name == restored.name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/enum.py
new/graphene-3.3.0/graphene/types/enum.py
--- old/graphene-3.2.1/graphene/types/enum.py 2022-12-11 21:05:25.000000000
+0100
+++ new/graphene-3.3.0/graphene/types/enum.py 2023-07-26 08:26:30.000000000
+0200
@@ -31,9 +31,11 @@
# with the enum values.
enum_members.pop("Meta", None)
enum = PyEnum(cls.__name__, enum_members)
- return SubclassWithMeta_Meta.__new__(
+ obj = SubclassWithMeta_Meta.__new__(
cls, name_, bases, dict(classdict, __enum__=enum), **options
)
+ globals()[name_] = obj.__enum__
+ return obj
def get(cls, value):
return cls._meta.enum(value)
@@ -63,7 +65,7 @@
cls, enum, name=None, description=None, deprecation_reason=None
): # noqa: N805
name = name or enum.__name__
- description = description or enum.__doc__
+ description = description or enum.__doc__ or "An enumeration."
meta_dict = {
"enum": enum,
"description": description,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/inputobjecttype.py
new/graphene-3.3.0/graphene/types/inputobjecttype.py
--- old/graphene-3.2.1/graphene/types/inputobjecttype.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/inputobjecttype.py 2023-07-26
08:26:30.000000000 +0200
@@ -1,11 +1,12 @@
+from typing import TYPE_CHECKING
+
from .base import BaseOptions, BaseType
from .inputfield import InputField
from .unmountedtype import UnmountedType
from .utils import yank_fields_from_attrs
-# For static type checking with Mypy
-MYPY = False
-if MYPY:
+# For static type checking with type checker
+if TYPE_CHECKING:
from typing import Dict, Callable # NOQA
@@ -14,6 +15,31 @@
container = None # type: InputObjectTypeContainer
+# Currently in Graphene, we get a `None` whenever we access an (optional)
field that was not set in an InputObjectType
+# using the InputObjectType.<attribute> dot access syntax. This is ambiguous,
because in this current (Graphene
+# historical) arrangement, we cannot distinguish between a field not being set
and a field being set to None.
+# At the same time, we shouldn't break existing code that expects a `None`
when accessing a field that was not set.
+_INPUT_OBJECT_TYPE_DEFAULT_VALUE = None
+
+# To mitigate this, we provide the function
`set_input_object_type_default_value` to allow users to change the default
+# value returned in non-specified fields in InputObjectType to another
meaningful sentinel value (e.g. Undefined)
+# if they want to. This way, we can keep code that expects a `None` working
while we figure out a better solution (or
+# a well-documented breaking change) for this issue.
+
+
+def set_input_object_type_default_value(default_value):
+ """
+ Change the sentinel value returned by non-specified fields in an
InputObjectType
+ Useful to differentiate between a field not being set and a field being
set to None by using a sentinel value
+ (e.g. Undefined is a good sentinel value for this purpose)
+
+ This function should be called at the beginning of the app or in some
other place where it is guaranteed to
+ be called before any InputObjectType is defined.
+ """
+ global _INPUT_OBJECT_TYPE_DEFAULT_VALUE
+ _INPUT_OBJECT_TYPE_DEFAULT_VALUE = default_value
+
+
class InputObjectTypeContainer(dict, BaseType): # type: ignore
class Meta:
abstract = True
@@ -21,7 +47,7 @@
def __init__(self, *args, **kwargs):
dict.__init__(self, *args, **kwargs)
for key in self._meta.fields:
- setattr(self, key, self.get(key, None))
+ setattr(self, key, self.get(key, _INPUT_OBJECT_TYPE_DEFAULT_VALUE))
def __init_subclass__(cls, *args, **kwargs):
pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/interface.py
new/graphene-3.3.0/graphene/types/interface.py
--- old/graphene-3.2.1/graphene/types/interface.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/interface.py 2023-07-26
08:26:30.000000000 +0200
@@ -1,10 +1,11 @@
+from typing import TYPE_CHECKING
+
from .base import BaseOptions, BaseType
from .field import Field
from .utils import yank_fields_from_attrs
-# For static type checking with Mypy
-MYPY = False
-if MYPY:
+# For static type checking with type checker
+if TYPE_CHECKING:
from typing import Dict, Iterable, Type # NOQA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/mutation.py
new/graphene-3.3.0/graphene/types/mutation.py
--- old/graphene-3.2.1/graphene/types/mutation.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/mutation.py 2023-07-26
08:26:30.000000000 +0200
@@ -1,3 +1,5 @@
+from typing import TYPE_CHECKING
+
from ..utils.deprecated import warn_deprecation
from ..utils.get_unbound_function import get_unbound_function
from ..utils.props import props
@@ -6,9 +8,8 @@
from .utils import yank_fields_from_attrs
from .interface import Interface
-# For static type checking with Mypy
-MYPY = False
-if MYPY:
+# For static type checking with type checker
+if TYPE_CHECKING:
from .argument import Argument # NOQA
from typing import Dict, Type, Callable, Iterable # NOQA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/objecttype.py
new/graphene-3.3.0/graphene/types/objecttype.py
--- old/graphene-3.2.1/graphene/types/objecttype.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/objecttype.py 2023-07-26
08:26:30.000000000 +0200
@@ -1,3 +1,5 @@
+from typing import TYPE_CHECKING
+
from .base import BaseOptions, BaseType, BaseTypeMeta
from .field import Field
from .interface import Interface
@@ -7,9 +9,8 @@
from dataclasses import make_dataclass, field
except ImportError:
from ..pyutils.dataclasses import make_dataclass, field # type: ignore
-# For static type checking with Mypy
-MYPY = False
-if MYPY:
+# For static type checking with type checker
+if TYPE_CHECKING:
from typing import Dict, Iterable, Type # NOQA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/tests/conftest.py
new/graphene-3.3.0/graphene/types/tests/conftest.py
--- old/graphene-3.2.1/graphene/types/tests/conftest.py 1970-01-01
01:00:00.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/tests/conftest.py 2023-07-26
08:26:30.000000000 +0200
@@ -0,0 +1,12 @@
+import pytest
+from graphql import Undefined
+
+from graphene.types.inputobjecttype import set_input_object_type_default_value
+
+
[email protected]()
+def set_default_input_object_type_to_undefined():
+ """This fixture is used to change the default value of optional inputs in
InputObjectTypes for specific tests"""
+ set_input_object_type_default_value(Undefined)
+ yield
+ set_input_object_type_default_value(None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/tests/test_enum.py
new/graphene-3.3.0/graphene/types/tests/test_enum.py
--- old/graphene-3.2.1/graphene/types/tests/test_enum.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/tests/test_enum.py 2023-07-26
08:26:30.000000000 +0200
@@ -65,6 +65,21 @@
assert RGB.BLUE
+def test_enum_custom_description_in_constructor():
+ description = "An enumeration, but with a custom description"
+ RGB = Enum(
+ "RGB",
+ "RED,GREEN,BLUE",
+ description=description,
+ )
+ assert RGB._meta.description == description
+
+
+def test_enum_from_python3_enum_uses_default_builtin_doc():
+ RGB = Enum("RGB", "RED,GREEN,BLUE")
+ assert RGB._meta.description == "An enumeration."
+
+
def test_enum_from_builtin_enum_accepts_lambda_description():
def custom_description(value):
if not value:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/graphene-3.2.1/graphene/types/tests/test_inputobjecttype.py
new/graphene-3.3.0/graphene/types/tests/test_inputobjecttype.py
--- old/graphene-3.2.1/graphene/types/tests/test_inputobjecttype.py
2022-12-11 21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/tests/test_inputobjecttype.py
2023-07-26 08:26:30.000000000 +0200
@@ -1,3 +1,5 @@
+from graphql import Undefined
+
from ..argument import Argument
from ..field import Field
from ..inputfield import InputField
@@ -6,6 +8,7 @@
from ..scalars import Boolean, String
from ..schema import Schema
from ..unmountedtype import UnmountedType
+from ... import NonNull
class MyType:
@@ -136,3 +139,31 @@
assert not result.errors
assert result.data == {"isChild": True}
+
+
+def test_inputobjecttype_default_input_as_undefined(
+ set_default_input_object_type_to_undefined,
+):
+ class TestUndefinedInput(InputObjectType):
+ required_field = String(required=True)
+ optional_field = String()
+
+ class Query(ObjectType):
+ undefined_optionals_work = Field(NonNull(Boolean),
input=TestUndefinedInput())
+
+ def resolve_undefined_optionals_work(self, info, input:
TestUndefinedInput):
+ # Confirm that optional_field comes as Undefined
+ return (
+ input.required_field == "required" and input.optional_field is
Undefined
+ )
+
+ schema = Schema(query=Query)
+ result = schema.execute(
+ """query basequery {
+ undefinedOptionalsWork(input: {requiredField: "required"})
+ }
+ """
+ )
+
+ assert not result.errors
+ assert result.data == {"undefinedOptionalsWork": True}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/tests/test_type_map.py
new/graphene-3.3.0/graphene/types/tests/test_type_map.py
--- old/graphene-3.2.1/graphene/types/tests/test_type_map.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/types/tests/test_type_map.py 2023-07-26
08:26:30.000000000 +0200
@@ -20,8 +20,8 @@
from ..interface import Interface
from ..objecttype import ObjectType
from ..scalars import Int, String
-from ..structures import List, NonNull
from ..schema import Schema
+from ..structures import List, NonNull
def create_type_map(types, auto_camelcase=True):
@@ -227,6 +227,18 @@
assert foo_field.description == "Field description"
+def test_inputobject_undefined(set_default_input_object_type_to_undefined):
+ class OtherObjectType(InputObjectType):
+ optional_field = String()
+
+ type_map = create_type_map([OtherObjectType])
+ assert "OtherObjectType" in type_map
+ graphql_type = type_map["OtherObjectType"]
+
+ container = graphql_type.out_type({})
+ assert container.optional_field is Undefined
+
+
def test_objecttype_camelcase():
class MyObjectType(ObjectType):
"""Description"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/types/union.py
new/graphene-3.3.0/graphene/types/union.py
--- old/graphene-3.2.1/graphene/types/union.py 2022-12-11 21:05:25.000000000
+0100
+++ new/graphene-3.3.0/graphene/types/union.py 2023-07-26 08:26:30.000000000
+0200
@@ -1,9 +1,10 @@
+from typing import TYPE_CHECKING
+
from .base import BaseOptions, BaseType
from .unmountedtype import UnmountedType
-# For static type checking with Mypy
-MYPY = False
-if MYPY:
+# For static type checking with type checker
+if TYPE_CHECKING:
from .objecttype import ObjectType # NOQA
from typing import Iterable, Type # NOQA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/graphene/validation/depth_limit.py
new/graphene-3.3.0/graphene/validation/depth_limit.py
--- old/graphene-3.2.1/graphene/validation/depth_limit.py 2022-12-11
21:05:25.000000000 +0100
+++ new/graphene-3.3.0/graphene/validation/depth_limit.py 2023-07-26
08:26:30.000000000 +0200
@@ -30,7 +30,7 @@
except ImportError:
# backwards compatibility for v3.6
from typing import Pattern
-from typing import Callable, Dict, List, Optional, Union
+from typing import Callable, Dict, List, Optional, Union, Tuple
from graphql import GraphQLError
from graphql.validation import ValidationContext, ValidationRule
@@ -82,7 +82,7 @@
def get_fragments(
- definitions: List[DefinitionNode],
+ definitions: Tuple[DefinitionNode, ...],
) -> Dict[str, FragmentDefinitionNode]:
fragments = {}
for definition in definitions:
@@ -94,7 +94,7 @@
# This will actually get both queries and mutations.
# We can basically treat those the same
def get_queries_and_mutations(
- definitions: List[DefinitionNode],
+ definitions: Tuple[DefinitionNode, ...],
) -> Dict[str, OperationDefinitionNode]:
operations = {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/graphene-3.2.1/tox.ini new/graphene-3.3.0/tox.ini
--- old/graphene-3.2.1/tox.ini 2022-12-11 21:05:25.000000000 +0100
+++ new/graphene-3.3.0/tox.ini 2023-07-26 08:26:30.000000000 +0200
@@ -1,5 +1,5 @@
[tox]
-envlist = py3{6,7,8,9,10}, mypy, pre-commit
+envlist = py3{7,8,9,10,11}, mypy, pre-commit
skipsdist = true
[testenv]
@@ -8,7 +8,7 @@
setenv =
PYTHONPATH = .:{envdir}
commands =
- py{36,37,38,39,310}: pytest --cov=graphene graphene --cov-report=term
--cov-report=xml examples {posargs}
+ py{37,38,39,310,311}: pytest --cov=graphene graphene --cov-report=term
--cov-report=xml examples {posargs}
[testenv:pre-commit]
basepython = python3.10