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,))