Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-siphashc for openSUSE:Factory 
checked in at 2026-08-22 21:36:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-siphashc (Old)
 and      /work/SRC/openSUSE:Factory/.python-siphashc.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-siphashc"

Sat Aug 22 21:36:34 2026 rev:13 rq:1373066 version:2.8

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-siphashc/python-siphashc.changes  
2026-04-26 21:14:30.277244652 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-siphashc.new.1258/python-siphashc.changes    
    2026-08-22 21:38:41.183677437 +0200
@@ -1,0 +2,11 @@
+Sat Aug 22 13:35:07 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.8:
+  * Added support for Python 3.15, including free-threaded
+    builds.
+  * Fixed SipHash input decoding on platforms with different
+    alignment or byte order.
+  * Improved hashing performance and enabled concurrent hashing
+    of large inputs.
+
+-------------------------------------------------------------------

Old:
----
  siphashc-2.7.tar.gz

New:
----
  siphashc-2.8.tar.gz

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

Other differences:
------------------
++++++ python-siphashc.spec ++++++
--- /var/tmp/diff_new_pack.EFga3X/_old  2026-08-22 21:38:41.849701292 +0200
+++ /var/tmp/diff_new_pack.EFga3X/_new  2026-08-22 21:38:41.851701364 +0200
@@ -18,7 +18,7 @@
 
 
 Name:           python-siphashc
-Version:        2.7
+Version:        2.8
 Release:        0
 Summary:        Python C module to calculate SipHashes
 License:        ISC

++++++ siphashc-2.7.tar.gz -> siphashc-2.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/CHANGES.rst new/siphashc-2.8/CHANGES.rst
--- old/siphashc-2.7/CHANGES.rst        2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/CHANGES.rst        2026-08-08 13:02:34.000000000 +0200
@@ -1,6 +1,14 @@
 Changes
 =======
 
+2.8
+---
+
+* Added support for Python 3.15, including free-threaded builds.
+* Fixed SipHash input decoding on platforms with different alignment or byte
+  order.
+* Improved hashing performance and enabled concurrent hashing of large inputs.
+
 2.7
 ---
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/PKG-INFO new/siphashc-2.8/PKG-INFO
--- old/siphashc-2.7/PKG-INFO   2025-11-03 09:56:16.239639800 +0100
+++ new/siphashc-2.8/PKG-INFO   2026-08-08 13:02:37.114982600 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: siphashc
-Version: 2.7
+Version: 2.8
 Summary: Python module (in c) for siphash-2-4
 Author-email: Michal Čihař <[email protected]>
 License-Expression: ISC
@@ -20,6 +20,7 @@
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Requires-Python: >=3.10
 Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/pyproject.toml 
new/siphashc-2.8/pyproject.toml
--- old/siphashc-2.7/pyproject.toml     2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/pyproject.toml     2026-08-08 13:02:34.000000000 +0200
@@ -11,10 +11,10 @@
   {include-group = "pre-commit"}
 ]
 pre-commit = [
-  "pre-commit==4.3.0"
+  "prek==0.4.11"
 ]
 test = [
-  "pytest==8.4.2"
+  "pytest==9.1.1"
 ]
 
 [project]
@@ -29,6 +29,7 @@
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
   "Programming Language :: Python :: 3.14",
+  "Programming Language :: Python :: 3.15",
   "Topic :: Software Development :: Libraries :: Python Modules"
 ]
 description = "Python module (in c) for siphash-2-4"
@@ -37,7 +38,7 @@
 license-files = ["LICENSE.md"]
 name = "siphashc"
 requires-python = ">=3.10"
-version = "2.7"
+version = "2.8"
 
 [[project.authors]]
 email = "[email protected]"
@@ -80,6 +81,7 @@
 
 [tool.ruff.lint]
 ignore = [
+  "CPY001",  # TODO: update copyright info
   "S101",  # CONFIG: using pytest
   "D203",  # CONFIG: incompatible with D211
   "D212"  # CONFIG: incompatible with D213
@@ -96,6 +98,20 @@
 [tool.ruff.lint.per-file-ignores]
 "benchmark.py" = ["T201"]
 
+[tool.rumdl]
+disable = [
+  # We do not enforce heading
+  "first-line-heading",
+  # Avoid length limit checks
+  "line-length"
+]
+
+[tool.rumdl.per-file-ignores]
+"README.md" = [
+  # Allow HTML
+  "MD033"
+]
+
 [tool.setuptools]
 include-package-data = true
 zip-safe = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/setup.py new/siphashc-2.8/setup.py
--- old/siphashc-2.7/setup.py   2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/setup.py   2026-08-08 13:02:34.000000000 +0200
@@ -5,13 +5,14 @@
 
 from setuptools import Extension, setup
 
+free_threaded = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
 define_macros = [("Py_LIMITED_API", "0x030A0000")]
 bdist_options = {"py_limited_api": "cp310"}
 
-# Free-threaded Python is not compatible with ABI3, see
-# https://github.com/python/cpython/issues/111506
-if sysconfig.get_config_var("Py_GIL_DISABLED"):
-    define_macros = []
+# Build version-specific free-threaded wheels until setuptools supports ABI3T.
+# https://github.com/pypa/setuptools/issues/5205
+if free_threaded:
+    define_macros = [("Py_GIL_DISABLED", "1")]
     bdist_options = {}
 
 setup(
@@ -21,7 +22,7 @@
             sources=["siphashc.c", "siphash/siphash.c"],
             language="c",
             define_macros=define_macros,
-            py_limited_api=True,
+            py_limited_api=not free_threaded,
         ),
     ],
     options={"bdist_wheel": bdist_options},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/siphash/README.md 
new/siphashc-2.8/siphash/README.md
--- old/siphashc-2.7/siphash/README.md  2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/siphash/README.md  2026-08-08 13:02:34.000000000 +0200
@@ -1 +1 @@
-siphash from https://github.com/floodyberry/siphash
+siphash from <https://github.com/floodyberry/siphash>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/siphash/siphash.c 
new/siphashc-2.8/siphash/siphash.c
--- old/siphashc-2.7/siphash/siphash.c  2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/siphash/siphash.c  2026-08-08 13:02:34.000000000 +0200
@@ -4,7 +4,14 @@
 
 INLINE static uint64_t
 U8TO64_LE(const unsigned char *p) {
-    return *(const uint64_t *)p;
+    return ((uint64_t)p[0])
+        | ((uint64_t)p[1] << 8)
+        | ((uint64_t)p[2] << 16)
+        | ((uint64_t)p[3] << 24)
+        | ((uint64_t)p[4] << 32)
+        | ((uint64_t)p[5] << 40)
+        | ((uint64_t)p[6] << 48)
+        | ((uint64_t)p[7] << 56);
 }
 
 uint64_t
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/siphashc.c new/siphashc-2.8/siphashc.c
--- old/siphashc-2.7/siphashc.c 2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/siphashc.c 2026-08-08 13:02:34.000000000 +0200
@@ -24,21 +24,75 @@
 
 #define PY_SSIZE_T_CLEAN
 
+#include <Python.h>
 #include <stdlib.h>
 #include <string.h>
-#include <Python.h>
 #include "siphash/siphash.h"
 
-static PyObject *pysiphash(PyObject *self, PyObject *args) {
+#define SIPHASH_GIL_THRESHOLD 8192
+#if PY_VERSION_HEX < 0x030B0000
+#define SIPHASHC_PYC_FUNCTION_CAST(func) \
+    ((PyCFunction)(void (*)(void))(func))
+#else
+#define SIPHASHC_PYC_FUNCTION_CAST(func) _PyCFunction_CAST(func)
+#endif
+
+static int get_immutable_data(
+        PyObject *object,
+        const char *argument_name,
+        const char **data,
+        Py_ssize_t *size) {
+    if (PyBytes_Check(object)) {
+        char *bytes_data;
+
+        if (PyBytes_AsStringAndSize(object, &bytes_data, size) < 0) {
+            return 0;
+        }
+        *data = bytes_data;
+        return 1;
+    }
+
+    if (PyUnicode_Check(object)) {
+        *data = PyUnicode_AsUTF8AndSize(object, size);
+        return *data != NULL;
+    }
+
+    PyErr_Format(
+        PyExc_TypeError,
+        "%s must be str or bytes",
+        argument_name);
+    return 0;
+}
+
+static PyObject *pysiphash(
+        PyObject *self,
+        PyObject *const *args,
+        Py_ssize_t nargs) {
+    PyObject *key_object;
+    PyObject *plaintext_object;
     const char *key = NULL;
     Py_ssize_t key_sz;
     const char *plaintext = NULL;
     Py_ssize_t plain_sz;
     uint64_t hash;
 
-    if (!PyArg_ParseTuple(
-            args, "s#s#:siphash",
-            &key, &key_sz, &plaintext, &plain_sz)) {
+    if (nargs != 2) {
+        PyErr_Format(
+            PyExc_TypeError,
+            "siphash() takes exactly 2 arguments (%zd given)",
+            nargs);
+        return NULL;
+    }
+    key_object = args[0];
+    plaintext_object = args[1];
+
+    /* Both objects own immutable storage and remain alive for the call. */
+    if (!get_immutable_data(key_object, "key", &key, &key_sz) ||
+            !get_immutable_data(
+                plaintext_object,
+                "plaintext",
+                &plaintext,
+                &plain_sz)) {
         return NULL;
     }
 
@@ -49,10 +103,26 @@
         return NULL;
     }
 
+#ifdef Py_GIL_DISABLED
     hash = siphash(
-        (const unsigned char*)key,
-        (const unsigned char*)plaintext,
+        (const unsigned char *)key,
+        (const unsigned char *)plaintext,
         plain_sz);
+#else
+    if (plain_sz >= SIPHASH_GIL_THRESHOLD) {
+        Py_BEGIN_ALLOW_THREADS
+        hash = siphash(
+            (const unsigned char *)key,
+            (const unsigned char *)plaintext,
+            plain_sz);
+        Py_END_ALLOW_THREADS
+    } else {
+        hash = siphash(
+            (const unsigned char *)key,
+            (const unsigned char *)plaintext,
+            plain_sz);
+    }
+#endif
 
     return PyLong_FromUnsignedLongLong(hash);
 }
@@ -65,10 +135,31 @@
     "returns 64-bit output (python Long)\n";
 
 static PyMethodDef siphashc_methods[] = {
-    {"siphash", pysiphash, METH_VARARGS, siphash_docstring},
+    {"siphash", SIPHASHC_PYC_FUNCTION_CAST(pysiphash), METH_FASTCALL,
+     siphash_docstring},
     {NULL, NULL, 0, NULL} /* sentinel */
 };
 
+#ifdef Py_TARGET_ABI3T
+
+PyABIInfo_VAR(abi_info);
+
+static PySlot siphashc_slots[] = {
+    PySlot_STATIC_DATA(Py_mod_abi, &abi_info),
+    PySlot_STATIC_DATA(Py_mod_name, "siphashc"),
+    PySlot_STATIC_DATA(Py_mod_methods, siphashc_methods),
+    PySlot_STATIC_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
+    PySlot_END,
+};
+
+PyMODEXPORT_FUNC
+PyModExport_siphashc(void)
+{
+    return siphashc_slots;
+}
+
+#else
+
 static struct PyModuleDef moduledef = {
     PyModuleDef_HEAD_INIT,
     "siphashc",
@@ -84,5 +175,17 @@
 PyObject *
 PyInit_siphashc(void)
 {
-    return PyModule_Create(&moduledef);
+    PyObject *module = PyModule_Create(&moduledef);
+
+#ifdef Py_GIL_DISABLED
+    if (module != NULL &&
+            PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED) < 0) {
+        Py_DECREF(module);
+        return NULL;
+    }
+#endif
+
+    return module;
 }
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/siphashc.egg-info/PKG-INFO 
new/siphashc-2.8/siphashc.egg-info/PKG-INFO
--- old/siphashc-2.7/siphashc.egg-info/PKG-INFO 2025-11-03 09:56:16.000000000 
+0100
+++ new/siphashc-2.8/siphashc.egg-info/PKG-INFO 2026-08-08 13:02:37.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: siphashc
-Version: 2.7
+Version: 2.8
 Summary: Python module (in c) for siphash-2-4
 Author-email: Michal Čihař <[email protected]>
 License-Expression: ISC
@@ -20,6 +20,7 @@
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Requires-Python: >=3.10
 Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siphashc-2.7/test_siphashc.py 
new/siphashc-2.8/test_siphashc.py
--- old/siphashc-2.7/test_siphashc.py   2025-11-03 09:56:11.000000000 +0100
+++ new/siphashc-2.8/test_siphashc.py   2026-08-08 13:02:34.000000000 +0200
@@ -2,16 +2,41 @@
 
 from __future__ import annotations
 
+import sys
+import sysconfig
+import threading
+import time
 import unittest
 
 import pytest
 
 from siphashc import siphash
 
+GIL_THRESHOLD = 8192
+GIL_TEST_ITERATIONS = 10_000
+
+
+class BytesSubclass(bytes):
+    """Bytes subclass used to verify accepted immutable inputs."""
+
+
+class StringSubclass(str):
+    """String subclass used to verify accepted immutable inputs."""
+
+    __slots__ = ()
+
 
 class TestSiphashC(unittest.TestCase):
     """Test for siphashc module."""
 
+    @pytest.mark.skipif(
+        not sysconfig.get_config_var("Py_GIL_DISABLED"),
+        reason="requires free-threaded Python",
+    )
+    def test_gil_disabled(self: TestSiphashC) -> None:
+        """Test that importing the module does not enable the GIL."""
+        assert not sys._is_gil_enabled()  # noqa: SLF001
+
     def test_hash(self: TestSiphashC) -> None:
         """Test simple hashing."""
         result = siphash("sixteencharstrng", "i need a hash of this")
@@ -20,6 +45,104 @@
         result = siphash("0123456789ABCDEF", "a")
         assert result == 12398370950267227270  # noqa: PLR2004
 
+    def test_immutable_inputs(self: TestSiphashC) -> None:
+        """Test accepted immutable input types."""
+        expected = siphash(b"0123456789ABCDEF", b"a")
+
+        assert siphash("0123456789ABCDEF", "a") == expected
+        assert (
+            siphash(
+                BytesSubclass(b"0123456789ABCDEF"),
+                BytesSubclass(b"a"),
+            )
+            == expected
+        )
+        assert (
+            siphash(
+                StringSubclass("0123456789ABCDEF"),
+                StringSubclass("a"),
+            )
+            == expected
+        )
+
+    def test_rejects_other_inputs(self: TestSiphashC) -> None:
+        """Test rejection of mutable and generic buffer inputs."""
+        invalid_keys = (
+            bytearray(b"0123456789ABCDEF"),
+            memoryview(b"0123456789ABCDEF"),
+            object(),
+        )
+        invalid_plaintexts = (bytearray(b"a"), memoryview(b"a"), object())
+
+        for key in invalid_keys:
+            with pytest.raises(TypeError, match="key must be str or bytes"):
+                siphash(key, b"a")
+
+        for plaintext in invalid_plaintexts:
+            with pytest.raises(TypeError, match="plaintext must be str or 
bytes"):
+                siphash(b"0123456789ABCDEF", plaintext)
+
+    def test_argument_count(self: TestSiphashC) -> None:
+        """Test positional argument count errors."""
+        for args in ((), (b"key",), (b"key", b"plaintext", b"extra")):
+            with pytest.raises(TypeError) as error:
+                siphash(*args)
+            assert str(error.value) == (
+                f"siphash() takes exactly 2 arguments ({len(args)} given)"
+            )
+
+    def test_rejects_keywords(self: TestSiphashC) -> None:
+        """Test rejection of keyword arguments."""
+        with pytest.raises(
+            TypeError,
+            match=r"siphash\(\) takes no keyword arguments",
+        ):
+            siphash(key=b"0123456789ABCDEF", plaintext=b"a")
+
+    @pytest.mark.skipif(
+        bool(sysconfig.get_config_var("Py_GIL_DISABLED")),
+        reason="requires a GIL-enabled Python",
+    )
+    def test_gil_release_threshold(self: TestSiphashC) -> None:
+        """Test that only inputs at or above the threshold release the GIL."""
+        counter = 0
+        ready = threading.Event()
+        stop = threading.Event()
+
+        def count_in_thread() -> None:
+            nonlocal counter
+            ready.set()
+            while not stop.is_set():
+                counter += 1
+                time.sleep(0)
+
+        thread = threading.Thread(target=count_in_thread)
+        previous_interval = sys.getswitchinterval()
+        sys.setswitchinterval(1.0)
+        try:
+            thread.start()
+            assert ready.wait(timeout=5)
+
+            key = b"0123456789ABCDEF"
+            below_threshold = b"a" * (GIL_THRESHOLD - 1)
+            at_threshold = b"a" * GIL_THRESHOLD
+
+            before = counter
+            for _ in range(GIL_TEST_ITERATIONS):
+                siphash(key, below_threshold)
+            assert counter == before
+
+            before = counter
+            for _ in range(GIL_TEST_ITERATIONS):
+                siphash(key, at_threshold)
+            assert counter > before
+        finally:
+            stop.set()
+            sys.setswitchinterval(previous_interval)
+            thread.join(timeout=5)
+
+        assert not thread.is_alive()
+
     def test_errors(self: TestSiphashC) -> None:
         """Test error handling."""
         with pytest.raises(
@@ -106,8 +229,8 @@
             0xE51B38608EF25F57,
             0x958A324CEB064572,
         ]
-        k = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-        message = ""
+        k = bytes(range(16))
+        message = b""
         for i in range(64):
             assert siphash(k, message) == vectors[i]
-            message += chr(i)
+            message += bytes((i,))

Reply via email to