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

Reply via email to