Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-msgpack for openSUSE:Factory checked in at 2026-10-30 18:03:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-msgpack (Old) and /work/SRC/openSUSE:Factory/.python-msgpack.new.1255 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-msgpack" Fri Oct 30 18:03:45 2026 rev:23 rq:1393622 version:1.2.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-msgpack/python-msgpack.changes 2026-10-06 19:13:43.922742836 +0200 +++ /work/SRC/openSUSE:Factory/.python-msgpack.new.1255/python-msgpack.changes 2026-10-30 18:04:17.635153909 +0100 @@ -1,0 +2,14 @@ +Wed Oct 28 18:56:51 UTC 2026 - Marcus Rueckert <[email protected]> + +- Uppdate to 1.2.4: (GHSA-j586-36cw-2gc2) + - fallback: pass object_pairs_hook a list of pairs by @youdie006 + in #744 + - fallback: leave the object unread when a header type does not + match by @Shaisolaris in #748 + - Bump the all-dependencies group with 3 updates by + @dependabot[bot] in #749 + - fallback: return bytes from Unpacker.read_bytes by @Cherith1222 + in #747 + - Run tracemalloc tests sequentially by @methane in #758 + +------------------------------------------------------------------- Old: ---- msgpack-1.2.3.tar.gz New: ---- msgpack-1.2.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-msgpack.spec ++++++ --- /var/tmp/diff_new_pack.dNlQXB/_old 2026-10-30 18:04:22.698365925 +0100 +++ /var/tmp/diff_new_pack.dNlQXB/_new 2026-10-30 18:04:22.705366218 +0100 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-msgpack -Version: 1.2.3 +Version: 1.2.4 Release: 0 Summary: MessagePack (de)serializer License: Apache-2.0 ++++++ msgpack-1.2.3.tar.gz -> msgpack-1.2.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/PKG-INFO new/msgpack-1.2.4/PKG-INFO --- old/msgpack-1.2.3/PKG-INFO 2026-09-29 04:30:26.223456900 +0200 +++ new/msgpack-1.2.4/PKG-INFO 2026-10-26 18:09:40.613909700 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: msgpack -Version: 1.2.3 +Version: 1.2.4 Summary: MessagePack serializer Author-email: Inada Naoki <[email protected]> License-Expression: Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/msgpack/__init__.py new/msgpack-1.2.4/msgpack/__init__.py --- old/msgpack-1.2.3/msgpack/__init__.py 2026-09-29 03:41:54.464199800 +0200 +++ new/msgpack-1.2.4/msgpack/__init__.py 2026-10-26 18:04:34.442975300 +0100 @@ -4,8 +4,8 @@ from .exceptions import * # noqa: F403 from .ext import ExtType, Timestamp -version = (1, 2, 3) -__version__ = "1.2.3" +version = (1, 2, 4) +__version__ = "1.2.4" if os.environ.get("MSGPACK_PUREPYTHON"): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/msgpack/fallback.py new/msgpack-1.2.4/msgpack/fallback.py --- old/msgpack-1.2.3/msgpack/fallback.py 2026-09-29 03:41:54.464795800 +0200 +++ new/msgpack-1.2.4/msgpack/fallback.py 2026-10-26 18:04:34.443244700 +0100 @@ -356,7 +356,8 @@ def read_bytes(self, n): ret = self._read(n, raise_outofdata=False) self._consume() - return ret + # The C extension returns bytes. A bytearray slice cannot be a dict key. + return bytes(ret) def _read(self, n, raise_outofdata=True): # (int) -> bytearray @@ -501,10 +502,13 @@ if execute == EX_READ_ARRAY_HEADER: if typ != TYPE_ARRAY: + # Leave the object unread, as the C extension does. + self._buff_i = self._buf_checkpoint raise ValueError("Expected array") return n if execute == EX_READ_MAP_HEADER: if typ != TYPE_MAP: + self._buff_i = self._buf_checkpoint raise ValueError("Expected map") return n # TODO should we eliminate the recursion? @@ -514,7 +518,7 @@ # TODO check whether we need to call `list_hook` self._unpack(EX_SKIP) return - ret = newlist_hint(n) + ret = newlist_hint(min(n, 10000)) for i in range(n): ret.append(self._unpack(EX_CONSTRUCT)) if self._list_hook is not None: @@ -529,15 +533,15 @@ self._unpack(EX_SKIP) return if self._object_pairs_hook is not None: - - def _gen(): - for _ in range(n): - key = self._unpack(EX_CONSTRUCT) - if self._strict_map_key and type(key) not in (str, bytes): - raise ValueError("%s is not allowed for map key" % str(type(key))) - yield key, self._unpack(EX_CONSTRUCT) - - ret = self._object_pairs_hook(_gen()) + # Pass a list, as the C extension does, so the whole map is + # consumed even if the hook does not iterate it. + pairs = [] + for _ in range(n): + key = self._unpack(EX_CONSTRUCT) + if self._strict_map_key and type(key) not in (str, bytes): + raise ValueError("%s is not allowed for map key" % str(type(key))) + pairs.append((key, self._unpack(EX_CONSTRUCT))) + ret = self._object_pairs_hook(pairs) else: ret = {} for _ in range(n): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/msgpack/unpack.h new/msgpack-1.2.4/msgpack/unpack.h --- old/msgpack-1.2.3/msgpack/unpack.h 2026-09-29 03:41:54.464795800 +0200 +++ new/msgpack-1.2.4/msgpack/unpack.h 2026-10-26 18:04:34.443780700 +0100 @@ -17,6 +17,7 @@ */ #define MSGPACK_EMBED_STACK_SIZE (1024) +#define MSGPACK_MAX_PREALLOC (10000) #include "unpack_define.h" typedef struct unpack_user { @@ -131,7 +132,9 @@ PyErr_Format(PyExc_ValueError, "%u exceeds max_array_len(%zd)", n, u->max_array_len); return -1; } - PyObject *p = u->use_list ? PyList_New(n) : PyTuple_New(n); + /* Large tuples are built as lists and converted when complete. */ + PyObject *p = n > MSGPACK_MAX_PREALLOC ? PyList_New(MSGPACK_MAX_PREALLOC) : + (u->use_list ? PyList_New(n) : PyTuple_New(n)); if (!p) return -1; @@ -139,13 +142,24 @@ return 0; } +/* Consumes o on both success and failure; borrows the list. */ +static inline int unpack_list_item(PyObject *list, unsigned int current, PyObject *o) +{ + if (current < MSGPACK_MAX_PREALLOC) { + PyList_SET_ITEM(list, current, o); + return 0; + } + int ret = PyList_Append(list, o); + Py_DECREF(o); + return ret; +} + /* Consumes o on both success and failure; borrows the container. */ static inline int unpack_callback_array_item(unpack_user* u, unsigned int current, msgpack_unpack_object* c, msgpack_unpack_object o) { - if (u->use_list) - PyList_SET_ITEM(*c, current, o); - else - PyTuple_SET_ITEM(*c, current, o); + if (PyList_CheckExact(*c)) + return unpack_list_item(*c, current, o); + PyTuple_SET_ITEM(*c, current, o); return 0; } @@ -153,6 +167,13 @@ * failure. The original reference is consumed in either case. */ static inline int unpack_callback_array_end(unpack_user* u, msgpack_unpack_object* c) { + if (!u->use_list && PyList_CheckExact(*c)) { + PyObject *tuple = PyList_AsTuple(*c); + Py_DECREF(*c); + *c = tuple; + if (!tuple) + return -1; + } if (u->list_hook) { PyObject *new_c = PyObject_CallFunctionObjArgs(u->list_hook, *c, NULL); Py_DECREF(*c); @@ -171,7 +192,7 @@ } PyObject *p; if (u->has_pairs_hook) { - p = PyList_New(n); // Or use tuple? + p = PyList_New(n > MSGPACK_MAX_PREALLOC ? MSGPACK_MAX_PREALLOC : n); } else { p = PyDict_New(); @@ -200,8 +221,7 @@ Py_DECREF(v); if (!item) return -1; - PyList_SET_ITEM(*c, current, item); - return 0; + return unpack_list_item(*c, current, item); } int ret = PyDict_SetItem(*c, k, v); Py_DECREF(k); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/msgpack.egg-info/PKG-INFO new/msgpack-1.2.4/msgpack.egg-info/PKG-INFO --- old/msgpack-1.2.3/msgpack.egg-info/PKG-INFO 2026-09-29 04:30:26.199741100 +0200 +++ new/msgpack-1.2.4/msgpack.egg-info/PKG-INFO 2026-10-26 18:09:40.596446800 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: msgpack -Version: 1.2.3 +Version: 1.2.4 Summary: MessagePack serializer Author-email: Inada Naoki <[email protected]> License-Expression: Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/test/test_except.py new/msgpack-1.2.4/test/test_except.py --- old/msgpack-1.2.3/test/test_except.py 2026-09-29 03:41:54.466057500 +0200 +++ new/msgpack-1.2.4/test/test_except.py 2026-10-26 18:04:34.444218900 +0100 @@ -4,7 +4,7 @@ import gc import tracemalloc -from pytest import raises +from pytest import mark, raises from msgpack import ExtType, FormatError, OutOfData, StackError, Unpacker, packb, unpackb @@ -103,6 +103,7 @@ unpacker.skip() [email protected]_unsafe(reason="tracemalloc changes process-wide state and measures all threads") def test_no_memory_leak_on_nested_invalid_tag() -> None: """Regression test: unpacking nested arrays containing an invalid tag must not leak objects.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/test/test_limits.py new/msgpack-1.2.4/test/test_limits.py --- old/msgpack-1.2.3/test/test_limits.py 2026-09-29 03:41:54.466057500 +0200 +++ new/msgpack-1.2.4/test/test_limits.py 2026-10-26 18:04:34.444218900 +0100 @@ -1,10 +1,12 @@ #!/usr/bin/env python import sysconfig +import tracemalloc import pytest from msgpack import ( ExtType, + OutOfData, Packer, PackOverflowError, PackValueError, @@ -118,6 +120,63 @@ unpacker.unpack() [email protected]("size", [9999, 10000, 10001, 20001]) [email protected]("use_list", [False, True]) +def test_array_preallocation_boundary(size, use_list): + value = list(range(size)) + expected = value if use_list else tuple(value) + packed = packb(value) + assert unpackb(packed, use_list=use_list, list_hook=lambda obj: obj) == expected + + unpacker = Unpacker(use_list=use_list) + # Suspend after crossing the preallocation boundary. + unpacker.feed(packed[:-1]) + with pytest.raises(OutOfData): + unpacker.unpack() + unpacker.feed(packed[-1:]) + assert unpacker.unpack() == expected + + [email protected]("size", [9999, 10000, 10001, 20001]) +def test_pairs_preallocation_boundary(size): + value = {str(i): i for i in range(size)} + expected = list(value.items()) + packed = packb(value) + assert unpackb(packed, object_pairs_hook=list) == expected + + unpacker = Unpacker(object_pairs_hook=list) + unpacker.feed(packed[:-1]) + with pytest.raises(OutOfData): + unpacker.unpack() + unpacker.feed(packed[-1:]) + assert unpacker.unpack() == expected + + [email protected]("kind", ["list", "tuple", "pairs"]) [email protected]_unsafe(reason="tracemalloc changes process-wide state and measures all threads") +def test_nested_headers_preallocation(kind): + packer = Packer() + header = ( + packer.pack_map_header(100_000) if kind == "pairs" else packer.pack_array_header(100_000) + ) + unpacker = Unpacker( + use_list=kind != "tuple", object_pairs_hook=list if kind == "pairs" else None + ) + # Map headers nest in key position, so no completed pairs are needed. + unpacker.feed(header * 16) + already_tracing = tracemalloc.is_tracing() + tracemalloc.start() + try: + before = tracemalloc.get_traced_memory()[0] + with pytest.raises(OutOfData): + unpacker.unpack() + # Full preallocation would retain over 12 MB in the C unpacker. + assert tracemalloc.get_traced_memory()[0] - before < 4 * 1024 * 1024 + finally: + if not already_tracing: + tracemalloc.stop() + + def test_max_ext_len(): d = ExtType(42, b"abc") packed = packb(d) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/test/test_obj.py new/msgpack-1.2.4/test/test_obj.py --- old/msgpack-1.2.3/test/test_obj.py 2026-09-29 03:41:54.466057500 +0200 +++ new/msgpack-1.2.4/test/test_obj.py 2026-10-26 18:04:34.444218900 +0100 @@ -41,6 +41,18 @@ assert unpacked[1] == prod_sum +def test_decode_pairs_hook_receives_list(): + def reject_duplicate_keys(pairs): + keys = [k for k, _ in pairs] + assert len(keys) == len(set(keys)) + return dict(pairs) + + packed = packb([{"a": 1, "b": 2}, 3]) + assert unpackb(packed, object_pairs_hook=reject_duplicate_keys) == [{"a": 1, "b": 2}, 3] + assert unpackb(packed, object_pairs_hook=lambda pairs: pairs[0]) == [("a", 1), 3] + assert unpackb(packed, object_pairs_hook=lambda pairs: None) == [None, 3] + + def test_only_one_obj_hook(): with raises(TypeError): unpackb(b"", object_hook=lambda x: x, object_pairs_hook=lambda x: x) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/test/test_read_size.py new/msgpack-1.2.4/test/test_read_size.py --- old/msgpack-1.2.3/test/test_read_size.py 2026-09-29 03:41:54.466057500 +0200 +++ new/msgpack-1.2.4/test/test_read_size.py 2026-10-26 18:04:34.444218900 +0100 @@ -1,5 +1,9 @@ """Test Unpacker's read_array_header and read_map_header methods""" +from io import BytesIO + +from pytest import raises + from msgpack import OutOfData, Unpacker, packb UnexpectedTypeException = ValueError @@ -70,3 +74,31 @@ assert 0, "should raise exception" except UnexpectedTypeException: assert 1, "okay" + + +def test_incorrect_type_does_not_consume_object(): + packed = packb(1) + packb("abc") + packb({"a": 1}) + packb([2]) + unpackers = [Unpacker(), Unpacker(BytesIO(packed))] + unpackers[0].feed(packed) + for unpacker in unpackers: + with raises(UnexpectedTypeException): + unpacker.read_array_header() + assert unpacker.tell() == 0 + assert unpacker.unpack() == 1 + + with raises(UnexpectedTypeException): + unpacker.read_map_header() + assert unpacker.unpack() == "abc" + + # A map is not an array: the stream must stay in sync. + with raises(UnexpectedTypeException): + unpacker.read_array_header() + assert unpacker.read_map_header() == 1 + assert unpacker.unpack() == "a" + assert unpacker.unpack() == 1 + + with raises(UnexpectedTypeException): + unpacker.read_map_header() + assert unpacker.read_array_header() == 1 + assert unpacker.unpack() == 2 + assert unpacker.tell() == len(packed) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-1.2.3/test/test_sequnpack.py new/msgpack-1.2.4/test/test_sequnpack.py --- old/msgpack-1.2.3/test/test_sequnpack.py 2026-09-29 03:41:54.466057500 +0200 +++ new/msgpack-1.2.4/test/test_sequnpack.py 2026-10-26 18:04:34.444218900 +0100 @@ -112,6 +112,29 @@ assert next(u) == 1 +def test_read_bytes_returns_bytes(): + # Finding 4 of #683: the fallback used to return a bytearray slice. + unpacker = Unpacker() + unpacker.feed(b"foobar") + assert unpacker.unpack() == ord(b"f") + got = unpacker.read_bytes(3) + assert got == b"oob" + assert type(got) is bytes + assert {got: 1}[b"oob"] == 1 + assert unpacker.unpack() == ord(b"a") + + short = Unpacker(io.BytesIO(b"ab")).read_bytes(5) + assert short == b"ab" + assert type(short) is bytes + + zero = Unpacker() + zero.feed(b"z") + assert zero.read_bytes(0) == b"" + got = zero.read_bytes(1) + assert got == b"z" + assert type(got) is bytes + + def test_issue124(): unpacker = Unpacker() unpacker.feed(b"\xa1?\xa1!")
