From 8a99f2a84ebae58ee15949e05fb0cb629aab5b37 Mon Sep 17 00:00:00 2001 From: Parker Loflin Date: Thu, 5 Nov 2026 16:48:27 -0500 Subject: [PATCH] Make IsalError picklable The class was created as "igzip_lib.IsalError", so pickle looked for it in a module named igzip_lib, which does not exist. An error raised in a worker process could not be sent to the parent process. --- CHANGELOG.rst | 8 ++++++++ src/isal/igzip_libmodule.c | 3 ++- tests/test_igzip_lib.py | 13 ++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d65c0609..38d753e6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,14 @@ Changelog .. This document is user facing. Please word the changes in such a way .. that users understand how the changes affect the new version. +version 1.10.0-dev +------------------ ++ Fix pickling of ``isal_zlib.error`` (``igzip_lib.IsalError``). An error + raised in a ``multiprocessing`` worker process did not reach the parent + process. Tracebacks now show ``isal.igzip_lib.IsalError`` instead of + ``igzip_lib.IsalError``. + + version 1.9.1 ----------------- + Fix BrokenPipeError when piping ``python -m isal.igzip`` into ``head``, diff --git a/src/isal/igzip_libmodule.c b/src/isal/igzip_libmodule.c index d2896bb3..16c041fd 100644 --- a/src/isal/igzip_libmodule.c +++ b/src/isal/igzip_libmodule.c @@ -696,7 +696,8 @@ PyInit_igzip_lib(void) #endif - IsalError = PyErr_NewException("igzip_lib.IsalError", NULL, NULL); + /* The full module name lets pickle find the class. */ + IsalError = PyErr_NewException("isal.igzip_lib.IsalError", NULL, NULL); if (IsalError == NULL) { return NULL; } diff --git a/tests/test_igzip_lib.py b/tests/test_igzip_lib.py index c057f353..f0cc434d 100644 --- a/tests/test_igzip_lib.py +++ b/tests/test_igzip_lib.py @@ -19,7 +19,7 @@ import zlib from typing import NamedTuple -from isal import igzip_lib +from isal import igzip_lib, isal_zlib from isal.igzip_lib import ( COMP_DEFLATE, COMP_GZIP, COMP_GZIP_NO_HDR, COMP_ZLIB, COMP_ZLIB_NO_HDR, DECOMP_DEFLATE, DECOMP_GZIP, DECOMP_GZIP_NO_HDR, DECOMP_GZIP_NO_HDR_VER, @@ -239,6 +239,17 @@ def test_failure(self): with pytest.raises(igzip_lib.IsalError): igzd.decompress(self.BAD_DATA * 30) + @pytest.mark.parametrize("module", [igzip_lib, isal_zlib]) + def test_failure_pickle(self, module): + # multiprocessing pickles an error raised in a worker process to send + # it to the parent process. + with pytest.raises(igzip_lib.IsalError) as raised: + module.decompress(self.BAD_DATA) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + error = pickle.loads(pickle.dumps(raised.value, proto)) + assert type(error) is igzip_lib.IsalError + assert error.args == raised.value.args + def test_dictionary(self): compressor = zlib.compressobj(zdict=b"bla") data = compressor.compress(b"bladiebla") + compressor.flush()