Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-zope.interface for
openSUSE:Factory checked in at 2026-06-25 10:49:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-zope.interface (Old)
and /work/SRC/openSUSE:Factory/.python-zope.interface.new.2088 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-zope.interface"
Thu Jun 25 10:49:34 2026 rev:46 rq:1360888 version:8.5
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-zope.interface/python-zope.interface.changes
2026-04-28 11:53:35.430583175 +0200
+++
/work/SRC/openSUSE:Factory/.python-zope.interface.new.2088/python-zope.interface.changes
2026-06-25 10:50:32.827542424 +0200
@@ -1,0 +2,16 @@
+Sun Jun 14 19:34:48 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 8.5:
+ * Build and upload free-threaded (cp314t, cp315t) wheels for
+ all platforms. Expand CI testing for free-threaded Python
+ 3.14t from Linux-only to all platforms (macOS, Windows), and
+ add 3.15t CI. See issue 374.
+ * Replace all remaining PyDict_GetItem() calls in the C
+ extension with exception-safe alternatives (PyDict_Contains,
+ PyDict_GetItemWithError). PyDict_GetItem silently swallows
+ exceptions from __hash__/__eq__, causing isOrExtends() to
+ return False instead of raising TypeError for unhashable
+ objects. Also use PyType_GetDict() on Python 3.13+ for free-
+ threading safety when accessing the type dict. See issue 357.
+
+-------------------------------------------------------------------
Old:
----
zope_interface-8.4.tar.gz
New:
----
zope_interface-8.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-zope.interface.spec ++++++
--- /var/tmp/diff_new_pack.ZlBjks/_old 2026-06-25 10:50:33.771575127 +0200
+++ /var/tmp/diff_new_pack.ZlBjks/_new 2026-06-25 10:50:33.775575267 +0200
@@ -27,7 +27,7 @@
%global modname zope.interface
%{?sle15_python_module_pythons}
Name: python-zope.interface%{psuffix}
-Version: 8.4
+Version: 8.5
Release: 0
Summary: Interfaces for Python
License: ZPL-2.1
++++++ zope_interface-8.4.tar.gz -> zope_interface-8.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/.manylinux-install.sh
new/zope_interface-8.5/.manylinux-install.sh
--- old/zope_interface-8.4/.manylinux-install.sh 2026-04-25
08:55:07.000000000 +0200
+++ new/zope_interface-8.5/.manylinux-install.sh 2026-05-26
08:12:56.000000000 +0200
@@ -32,7 +32,9 @@
*"cp311"*) echo 'py311';;
*"cp312"*) echo 'py312';;
*"cp313"*) echo 'py313';;
+ *"cp314t"*) echo 'py314t';;
*"cp314"*) echo 'py314';;
+ *"cp315t"*) echo 'py315t';;
*"cp315"*) echo 'py315';;
*) echo 'py';;
esac
@@ -46,8 +48,10 @@
[[ "${PYBIN}" == *"cp312/"* ]] || \
[[ "${PYBIN}" == *"cp313/"* ]] || \
[[ "${PYBIN}" == *"cp314/"* ]] || \
- [[ "${PYBIN}" == *"cp315/"* ]] ; then
- if [[ "${PYBIN}" == *"cp315/"* ]] ; then
+ [[ "${PYBIN}" == *"cp314t/"* ]] || \
+ [[ "${PYBIN}" == *"cp315/"* ]] || \
+ [[ "${PYBIN}" == *"cp315t/"* ]] ; then
+ if [[ "${PYBIN}" == *"cp315/"* ]] || [[ "${PYBIN}" == *"cp315t/"* ]] ;
then
"${PYBIN}/pip" install --pre -e /io/
"${PYBIN}/pip" wheel /io/ --pre -w wheelhouse/
else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/CHANGES.rst
new/zope_interface-8.5/CHANGES.rst
--- old/zope_interface-8.4/CHANGES.rst 2026-04-25 09:21:39.000000000 +0200
+++ new/zope_interface-8.5/CHANGES.rst 2026-05-26 08:12:56.000000000 +0200
@@ -1,6 +1,23 @@
Change log
==========
+8.5 (2026-05-26)
+----------------
+
+- Build and upload free-threaded (``cp314t``, ``cp315t``) wheels for all
+ platforms.
+ Expand CI testing for free-threaded Python 3.14t from Linux-only to all
+ platforms (macOS, Windows), and add 3.15t CI.
+ See `issue 374
<https://github.com/zopefoundation/zope.interface/issues/374>`_.
+
+- Replace all remaining ``PyDict_GetItem()`` calls in the C extension with
+ exception-safe alternatives (``PyDict_Contains``,
``PyDict_GetItemWithError``).
+ ``PyDict_GetItem`` silently swallows exceptions from ``__hash__``/``__eq__``,
+ causing ``isOrExtends()`` to return ``False`` instead of raising
``TypeError``
+ for unhashable objects. Also use ``PyType_GetDict()`` on Python 3.13+ for
+ free-threading safety when accessing the type dict.
+ See `issue 357
<https://github.com/zopefoundation/zope.interface/issues/357>`_.
+
8.4 (2026-04-25)
----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/PKG-INFO
new/zope_interface-8.5/PKG-INFO
--- old/zope_interface-8.4/PKG-INFO 2026-04-25 09:21:44.722239500 +0200
+++ new/zope_interface-8.5/PKG-INFO 2026-05-26 08:13:11.843406000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: zope.interface
-Version: 8.4
+Version: 8.5
Summary: Interfaces for Python
Author-email: Zope Foundation and contributors <[email protected]>
Maintainer-email: Plone Foundation and contributors <[email protected]>
@@ -75,6 +75,23 @@
Change log
==========
+8.5 (2026-05-26)
+----------------
+
+- Build and upload free-threaded (``cp314t``, ``cp315t``) wheels for all
+ platforms.
+ Expand CI testing for free-threaded Python 3.14t from Linux-only to all
+ platforms (macOS, Windows), and add 3.15t CI.
+ See `issue 374
<https://github.com/zopefoundation/zope.interface/issues/374>`_.
+
+- Replace all remaining ``PyDict_GetItem()`` calls in the C extension with
+ exception-safe alternatives (``PyDict_Contains``,
``PyDict_GetItemWithError``).
+ ``PyDict_GetItem`` silently swallows exceptions from ``__hash__``/``__eq__``,
+ causing ``isOrExtends()`` to return ``False`` instead of raising
``TypeError``
+ for unhashable objects. Also use ``PyType_GetDict()`` on Python 3.13+ for
+ free-threading safety when accessing the type dict.
+ See `issue 357
<https://github.com/zopefoundation/zope.interface/issues/357>`_.
+
8.4 (2026-04-25)
----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/docs/README.rst
new/zope_interface-8.5/docs/README.rst
--- old/zope_interface-8.4/docs/README.rst 2023-01-03 13:44:50.000000000
+0100
+++ new/zope_interface-8.5/docs/README.rst 2026-05-26 08:12:56.000000000
+0200
@@ -692,28 +692,29 @@
.. doctest::
- >>> from pprint import pprint
- >>> pprint(baz_implements.__sro__)
- (classImplements(Baz, IBaz),
- <InterfaceClass builtins.IBaz>,
- <InterfaceClass builtins.IFoo>,
- <InterfaceClass builtins.IBlat>,
- classImplements(object),
- <InterfaceClass zope.interface.Interface>)
+ >>> for item in baz_implements.__sro__:
+ ... print(repr(item))
+ classImplements(Baz, IBaz)
+ <InterfaceClass builtins.IBaz>
+ <InterfaceClass builtins.IFoo>
+ <InterfaceClass builtins.IBlat>
+ classImplements(object)
+ <InterfaceClass zope.interface.Interface>
>>> class IBiz(zope.interface.Interface):
... pass
>>> @zope.interface.implementer(IBiz)
... class Biz(Baz):
... pass
- >>> pprint(zope.interface.implementedBy(Biz).__sro__)
- (classImplements(Biz, IBiz),
- <InterfaceClass builtins.IBiz>,
- classImplements(Baz, IBaz),
- <InterfaceClass builtins.IBaz>,
- <InterfaceClass builtins.IFoo>,
- <InterfaceClass builtins.IBlat>,
- classImplements(object),
- <InterfaceClass zope.interface.Interface>)
+ >>> for item in zope.interface.implementedBy(Biz).__sro__:
+ ... print(repr(item))
+ classImplements(Biz, IBiz)
+ <InterfaceClass builtins.IBiz>
+ classImplements(Baz, IBaz)
+ <InterfaceClass builtins.IBaz>
+ <InterfaceClass builtins.IFoo>
+ <InterfaceClass builtins.IBlat>
+ classImplements(object)
+ <InterfaceClass zope.interface.Interface>
Tagged Values
=============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/pyproject.toml
new/zope_interface-8.5/pyproject.toml
--- old/zope_interface-8.4/pyproject.toml 2026-04-25 09:01:52.000000000
+0200
+++ new/zope_interface-8.5/pyproject.toml 2026-05-26 08:12:56.000000000
+0200
@@ -9,7 +9,7 @@
[project]
name = "zope.interface"
-version = "8.4"
+version = "8.5"
description = "Interfaces for Python"
keywords = ["interface", "components", "plugins"]
dynamic = ["readme"]
@@ -82,3 +82,8 @@
[tool.setuptools.dynamic]
readme = {file = ["README.rst", "CHANGES.rst"]}
+
+
+[tool.zest-releaser]
+create-wheel = false
+upload-pypi = false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/setup.cfg
new/zope_interface-8.5/setup.cfg
--- old/zope_interface-8.4/setup.cfg 2026-04-25 09:21:44.722628400 +0200
+++ new/zope_interface-8.5/setup.cfg 2026-05-26 08:13:11.844142000 +0200
@@ -1,6 +1,3 @@
-[zest.releaser]
-create-wheel = no
-
[flake8]
doctests = 1
ignore =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/zope_interface-8.4/src/zope/interface/_zope_interface_coptimizations.c
new/zope_interface-8.5/src/zope/interface/_zope_interface_coptimizations.c
--- old/zope_interface-8.4/src/zope/interface/_zope_interface_coptimizations.c
2026-04-15 13:21:28.000000000 +0200
+++ new/zope_interface-8.5/src/zope/interface/_zope_interface_coptimizations.c
2026-05-26 08:12:56.000000000 +0200
@@ -42,13 +42,13 @@
* 0 = not found (*result = NULL)
* -1 = error (*result = NULL, exception set)
*
- * On older Python (with GIL) this is equivalent to the existing
- * PyDict_GetItem() + Py_INCREF() pattern, with zero overhead.
+ * Uses PyDict_GetItemWithError() instead of PyDict_GetItem() to
+ * properly propagate exceptions from __hash__/__eq__.
*/
static inline int
_PyDict_GetItemRef(PyObject *p, PyObject *key, PyObject **result)
{
- PyObject *item = PyDict_GetItem(p, key);
+ PyObject *item = PyDict_GetItemWithError(p, key);
if (item != NULL) {
Py_INCREF(item);
*result = item;
@@ -326,13 +326,17 @@
SB_extends(SB* self, PyObject* other)
{
PyObject* implied;
+ int contains;
implied = self->_implied;
if (implied == NULL) {
return NULL;
}
- if (PyDict_GetItem(implied, other) != NULL)
+ contains = PyDict_Contains(implied, other);
+ if (contains < 0)
+ return NULL;
+ if (contains)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
@@ -792,8 +796,10 @@
return NULL;
}
- implements = PyDict_GetItem(implied, self) != NULL;
+ implements = PyDict_Contains(implied, self);
Py_DECREF(decl);
+ if (implements < 0)
+ return NULL;
} else {
/* decl is probably a security proxy. We have to go the long way
around.
@@ -863,6 +869,7 @@
IB__call__(PyObject* self, PyObject* args, PyObject* kwargs)
{
PyObject *conform, *obj, *alternate, *adapter;
+ int _has_custom;
static char* kwlist[] = { "obj", "alternate", NULL };
conform = obj = alternate = adapter = NULL;
@@ -900,10 +907,23 @@
will *never* be InterfaceBase, we're always subclassed by
InterfaceClass). Instead, we cooperate with InterfaceClass in Python to
set a flag in a new subclass when this is necessary. */
- /* Use pre-interned string + Py_TYPE() instead of PyDict_GetItemString
- * with a C literal (which creates a temporary Python string each call)
- * and direct ob_type access (incompatible with free-threaded Python). */
- if (PyDict_GetItem(Py_TYPE(self)->tp_dict, str_CALL_CUSTOM_ADAPT)) {
+ /* Check if the type has a _CALL_CUSTOM_ADAPT flag set by InterfaceClass.
+ * Use PyDict_Contains (error-safe) instead of PyDict_GetItem (which
+ * silently swallows exceptions). On 3.13+ use PyType_GetDict() for a
+ * strong reference to the type dict, needed for free-threaded Python. */
+ {
+#if PY_VERSION_HEX >= 0x030d0000
+ PyObject* _tp_dict = PyType_GetDict(Py_TYPE(self));
+ _has_custom = PyDict_Contains(_tp_dict, str_CALL_CUSTOM_ADAPT);
+ Py_DECREF(_tp_dict);
+#else
+ _has_custom = PyDict_Contains(
+ Py_TYPE(self)->tp_dict, str_CALL_CUSTOM_ADAPT);
+#endif
+ if (_has_custom < 0)
+ return NULL;
+ }
+ if (_has_custom) {
/* Doesn't matter what the value is. Simply being present is enough. */
adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL);
} else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/zope_interface-8.4/src/zope/interface/tests/test_interface.py
new/zope_interface-8.5/src/zope/interface/tests/test_interface.py
--- old/zope_interface-8.4/src/zope/interface/tests/test_interface.py
2026-04-15 13:21:28.000000000 +0200
+++ new/zope_interface-8.5/src/zope/interface/tests/test_interface.py
2026-05-26 08:12:56.000000000 +0200
@@ -218,6 +218,31 @@
with _Monkey(interface, implementedBy=_implementedBy):
self.assertFalse(sb.implementedBy(object()))
+ def test_isOrExtends_raises_TypeError_for_unhashable_iface(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class Unhashable:
+ __hash__ = None
+
+ with self.assertRaises(TypeError):
+ IFoo.isOrExtends(Unhashable())
+
+ def test_isOrExtends_propagates_MemoryError_from_hash_iface(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class BadHash:
+ def __hash__(self):
+ raise MemoryError("hash bomb")
+
+ with self.assertRaises(MemoryError):
+ IFoo.isOrExtends(BadHash())
+
class SpecificationBaseTests(
GenericSpecificationBaseTests,
@@ -256,6 +281,27 @@
sb._implied = {testing: {}} # not defined by SpecificationBasePy
self.assertTrue(sb(testing))
+ def test_isOrExtends_raises_TypeError_for_unhashable(self):
+ sb = self._makeOne()
+ sb._implied = {}
+
+ class Unhashable:
+ __hash__ = None
+
+ with self.assertRaises(TypeError):
+ sb.isOrExtends(Unhashable())
+
+ def test_isOrExtends_propagates_MemoryError_from_hash(self):
+ sb = self._makeOne()
+ sb._implied = {}
+
+ class BadHash:
+ def __hash__(self):
+ raise MemoryError("hash bomb")
+
+ with self.assertRaises(MemoryError):
+ sb.isOrExtends(BadHash())
+
def test_implementedBy_hit(self):
from zope.interface import interface
sb = self._makeOne()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/zope_interface-8.4/src/zope.interface.egg-info/PKG-INFO
new/zope_interface-8.5/src/zope.interface.egg-info/PKG-INFO
--- old/zope_interface-8.4/src/zope.interface.egg-info/PKG-INFO 2026-04-25
09:21:44.000000000 +0200
+++ new/zope_interface-8.5/src/zope.interface.egg-info/PKG-INFO 2026-05-26
08:13:11.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: zope.interface
-Version: 8.4
+Version: 8.5
Summary: Interfaces for Python
Author-email: Zope Foundation and contributors <[email protected]>
Maintainer-email: Plone Foundation and contributors <[email protected]>
@@ -75,6 +75,23 @@
Change log
==========
+8.5 (2026-05-26)
+----------------
+
+- Build and upload free-threaded (``cp314t``, ``cp315t``) wheels for all
+ platforms.
+ Expand CI testing for free-threaded Python 3.14t from Linux-only to all
+ platforms (macOS, Windows), and add 3.15t CI.
+ See `issue 374
<https://github.com/zopefoundation/zope.interface/issues/374>`_.
+
+- Replace all remaining ``PyDict_GetItem()`` calls in the C extension with
+ exception-safe alternatives (``PyDict_Contains``,
``PyDict_GetItemWithError``).
+ ``PyDict_GetItem`` silently swallows exceptions from ``__hash__``/``__eq__``,
+ causing ``isOrExtends()`` to return ``False`` instead of raising
``TypeError``
+ for unhashable objects. Also use ``PyType_GetDict()`` on Python 3.13+ for
+ free-threading safety when accessing the type dict.
+ See `issue 357
<https://github.com/zopefoundation/zope.interface/issues/357>`_.
+
8.4 (2026-04-25)
----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zope_interface-8.4/tox.ini
new/zope_interface-8.5/tox.ini
--- old/zope_interface-8.4/tox.ini 2026-04-25 08:55:07.000000000 +0200
+++ new/zope_interface-8.5/tox.ini 2026-05-26 08:12:56.000000000 +0200
@@ -12,15 +12,17 @@
py314,py314-pure
py315,py315-pure
py314t,py314t-pure
+ py315t,py315t-pure
pypy3
docs
coverage
- py314t,py314t-pure
[testenv]
-pip_pre = py315: true
+pip_pre =
+ py315: true
+ py315t: true
deps =
- setuptools >= 78.1.1,< 81
+ setuptools >= 78.1.1,< 82
Sphinx
setenv =
pure: PURE_PYTHON=1