https://github.com/python/cpython/commit/117bb29f6bc41953a5e5fa50ab670cfce1d9f7a7
commit: 117bb29f6bc41953a5e5fa50ab670cfce1d9f7a7
branch: 3.14
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: AA-Turner <9087854+aa-tur...@users.noreply.github.com>
date: 2025-05-28T17:25:06+01:00
summary:

[3.14] gh-132983: Split ``_zstd_set_c_parameters`` (GH-133921) (#134838)

gh-132983: Split ``_zstd_set_c_parameters`` (GH-133921)
(cherry picked from commit 11f7a939debd7731d1cb79ed84a473fa87c279c8)

Co-authored-by: Adam Turner <9087854+aa-tur...@users.noreply.github.com>

files:
M Lib/compression/zstd/_zstdfile.py
M Lib/test/test_zstd.py
M Modules/_zstd/_zstdmodule.c
M Modules/_zstd/_zstdmodule.h
M Modules/_zstd/compressor.c
M Modules/_zstd/decompressor.c

diff --git a/Lib/compression/zstd/_zstdfile.py 
b/Lib/compression/zstd/_zstdfile.py
index 8770e576f509f4..d709f5efc658fa 100644
--- a/Lib/compression/zstd/_zstdfile.py
+++ b/Lib/compression/zstd/_zstdfile.py
@@ -1,7 +1,6 @@
 import io
 from os import PathLike
-from _zstd import (ZstdCompressor, ZstdDecompressor, ZstdError,
-                   ZSTD_DStreamOutSize)
+from _zstd import ZstdCompressor, ZstdDecompressor, ZSTD_DStreamOutSize
 from compression._common import _streams
 
 __all__ = ('ZstdFile', 'open')
diff --git a/Lib/test/test_zstd.py b/Lib/test/test_zstd.py
index 34c7c721b1ad32..1562c29d2e53a3 100644
--- a/Lib/test/test_zstd.py
+++ b/Lib/test/test_zstd.py
@@ -65,6 +65,10 @@
 
 SUPPORT_MULTITHREADING = False
 
+C_INT_MIN = -(2**31)
+C_INT_MAX = (2**31) - 1
+
+
 def setUpModule():
     global SUPPORT_MULTITHREADING
     SUPPORT_MULTITHREADING = CompressionParameter.nb_workers.bounds() != (0, 0)
@@ -196,14 +200,21 @@ def test_simple_compress_bad_args(self):
         self.assertRaises(TypeError, ZstdCompressor, zstd_dict=b"abcd1234")
         self.assertRaises(TypeError, ZstdCompressor, zstd_dict={1: 2, 3: 4})
 
-        with self.assertRaises(ValueError):
-            ZstdCompressor(2**31)
-        with self.assertRaises(ValueError):
-            ZstdCompressor(options={2**31: 100})
+        # valid range for compression level is [-(1<<17), 22]
+        msg = r'illegal compression level {}; the valid range is \[-?\d+, 
-?\d+\]'
+        with self.assertRaisesRegex(ValueError, msg.format(C_INT_MAX)):
+            ZstdCompressor(C_INT_MAX)
+        with self.assertRaisesRegex(ValueError, msg.format(C_INT_MIN)):
+            ZstdCompressor(C_INT_MIN)
+        msg = r'illegal compression level; the valid range is \[-?\d+, -?\d+\]'
+        with self.assertRaisesRegex(ValueError, msg):
+            ZstdCompressor(level=-(2**1000))
+        with self.assertRaisesRegex(ValueError, msg):
+            ZstdCompressor(level=2**1000)
 
-        with self.assertRaises(ZstdError):
+        with self.assertRaises(ValueError):
             ZstdCompressor(options={CompressionParameter.window_log: 100})
-        with self.assertRaises(ZstdError):
+        with self.assertRaises(ValueError):
             ZstdCompressor(options={3333: 100})
 
         # Method bad arguments
@@ -254,18 +265,32 @@ def test_compress_parameters(self):
              }
         ZstdCompressor(options=d)
 
-        # larger than signed int, ValueError
         d1 = d.copy()
-        d1[CompressionParameter.ldm_bucket_size_log] = 2**31
-        self.assertRaises(ValueError, ZstdCompressor, options=d1)
+        # larger than signed int
+        d1[CompressionParameter.ldm_bucket_size_log] = C_INT_MAX
+        with self.assertRaises(ValueError):
+            ZstdCompressor(options=d1)
+        # smaller than signed int
+        d1[CompressionParameter.ldm_bucket_size_log] = C_INT_MIN
+        with self.assertRaises(ValueError):
+            ZstdCompressor(options=d1)
 
-        # clamp compressionLevel
+        # out of bounds compression level
         level_min, level_max = CompressionParameter.compression_level.bounds()
-        compress(b'', level_max+1)
-        compress(b'', level_min-1)
-
-        compress(b'', 
options={CompressionParameter.compression_level:level_max+1})
-        compress(b'', 
options={CompressionParameter.compression_level:level_min-1})
+        with self.assertRaises(ValueError):
+            compress(b'', level_max+1)
+        with self.assertRaises(ValueError):
+            compress(b'', level_min-1)
+        with self.assertRaises(ValueError):
+            compress(b'', 2**1000)
+        with self.assertRaises(ValueError):
+            compress(b'', -(2**1000))
+        with self.assertRaises(ValueError):
+            compress(b'', options={
+                CompressionParameter.compression_level: level_max+1})
+        with self.assertRaises(ValueError):
+            compress(b'', options={
+                CompressionParameter.compression_level: level_min-1})
 
         # zstd lib doesn't support MT compression
         if not SUPPORT_MULTITHREADING:
@@ -278,19 +303,19 @@ def test_compress_parameters(self):
 
         # out of bounds error msg
         option = {CompressionParameter.window_log:100}
-        with self.assertRaisesRegex(ZstdError,
-                (r'Error when setting zstd compression parameter "window_log", 
'
-                 r'it should \d+ <= value <= \d+, provided value is 100\. '
-                 r'\((?:32|64)-bit build\)')):
+        with self.assertRaisesRegex(
+            ValueError,
+            "compression parameter 'window_log' received an illegal value 100; 
"
+            r'the valid range is \[-?\d+, -?\d+\]',
+        ):
             compress(b'', options=option)
 
     def test_unknown_compression_parameter(self):
         KEY = 100001234
         option = {CompressionParameter.compression_level: 10,
                   KEY: 200000000}
-        pattern = (r'Invalid zstd compression parameter.*?'
-                   fr'"unknown parameter \(key {KEY}\)"')
-        with self.assertRaisesRegex(ZstdError, pattern):
+        pattern = rf"invalid compression parameter 'unknown parameter \(key 
{KEY}\)'"
+        with self.assertRaisesRegex(ValueError, pattern):
             ZstdCompressor(options=option)
 
     @unittest.skipIf(not SUPPORT_MULTITHREADING,
@@ -385,12 +410,22 @@ def test_simple_decompress_bad_args(self):
         self.assertRaises(TypeError, ZstdDecompressor, options=b'abc')
 
         with self.assertRaises(ValueError):
-            ZstdDecompressor(options={2**31 : 100})
+            ZstdDecompressor(options={C_INT_MAX: 100})
+        with self.assertRaises(ValueError):
+            ZstdDecompressor(options={C_INT_MIN: 100})
+        with self.assertRaises(ValueError):
+            ZstdDecompressor(options={0: C_INT_MAX})
+        with self.assertRaises(OverflowError):
+            ZstdDecompressor(options={2**1000: 100})
+        with self.assertRaises(OverflowError):
+            ZstdDecompressor(options={-(2**1000): 100})
+        with self.assertRaises(OverflowError):
+            ZstdDecompressor(options={0: -(2**1000)})
 
-        with self.assertRaises(ZstdError):
-            
ZstdDecompressor(options={DecompressionParameter.window_log_max:100})
-        with self.assertRaises(ZstdError):
-            ZstdDecompressor(options={3333 : 100})
+        with self.assertRaises(ValueError):
+            ZstdDecompressor(options={DecompressionParameter.window_log_max: 
100})
+        with self.assertRaises(ValueError):
+            ZstdDecompressor(options={3333: 100})
 
         empty = compress(b'')
         lzd = ZstdDecompressor()
@@ -403,26 +438,52 @@ def test_decompress_parameters(self):
         d = {DecompressionParameter.window_log_max : 15}
         ZstdDecompressor(options=d)
 
-        # larger than signed int, ValueError
         d1 = d.copy()
-        d1[DecompressionParameter.window_log_max] = 2**31
-        self.assertRaises(ValueError, ZstdDecompressor, None, d1)
+        # larger than signed int
+        d1[DecompressionParameter.window_log_max] = 2**1000
+        with self.assertRaises(OverflowError):
+            ZstdDecompressor(None, d1)
+        # smaller than signed int
+        d1[DecompressionParameter.window_log_max] = -(2**1000)
+        with self.assertRaises(OverflowError):
+            ZstdDecompressor(None, d1)
+
+        d1[DecompressionParameter.window_log_max] = C_INT_MAX
+        with self.assertRaises(ValueError):
+            ZstdDecompressor(None, d1)
+        d1[DecompressionParameter.window_log_max] = C_INT_MIN
+        with self.assertRaises(ValueError):
+            ZstdDecompressor(None, d1)
 
         # out of bounds error msg
         options = {DecompressionParameter.window_log_max:100}
-        with self.assertRaisesRegex(ZstdError,
-                (r'Error when setting zstd decompression parameter 
"window_log_max", '
-                 r'it should \d+ <= value <= \d+, provided value is 100\. '
-                 r'\((?:32|64)-bit build\)')):
+        with self.assertRaisesRegex(
+            ValueError,
+            "decompression parameter 'window_log_max' received an illegal 
value 100; "
+            r'the valid range is \[-?\d+, -?\d+\]',
+        ):
+            decompress(b'', options=options)
+
+        # out of bounds deecompression parameter
+        options[DecompressionParameter.window_log_max] = C_INT_MAX
+        with self.assertRaises(ValueError):
+            decompress(b'', options=options)
+        options[DecompressionParameter.window_log_max] = C_INT_MIN
+        with self.assertRaises(ValueError):
+            decompress(b'', options=options)
+        options[DecompressionParameter.window_log_max] = 2**1000
+        with self.assertRaises(OverflowError):
+            decompress(b'', options=options)
+        options[DecompressionParameter.window_log_max] = -(2**1000)
+        with self.assertRaises(OverflowError):
             decompress(b'', options=options)
 
     def test_unknown_decompression_parameter(self):
         KEY = 100001234
         options = {DecompressionParameter.window_log_max: 
DecompressionParameter.window_log_max.bounds()[1],
                   KEY: 200000000}
-        pattern = (r'Invalid zstd decompression parameter.*?'
-                   fr'"unknown parameter \(key {KEY}\)"')
-        with self.assertRaisesRegex(ZstdError, pattern):
+        pattern = rf"invalid decompression parameter 'unknown parameter \(key 
{KEY}\)'"
+        with self.assertRaisesRegex(ValueError, pattern):
             ZstdDecompressor(options=options)
 
     def test_decompress_epilogue_flags(self):
@@ -1425,11 +1486,11 @@ def test_init_bad_mode(self):
             ZstdFile(io.BytesIO(COMPRESSED_100_PLUS_32KB), "rw")
 
         with self.assertRaisesRegex(TypeError,
-                                    r"NOT be a CompressionParameter"):
+                                    r"not be a CompressionParameter"):
             ZstdFile(io.BytesIO(), 'rb',
                      options={CompressionParameter.compression_level:5})
         with self.assertRaisesRegex(TypeError,
-                                    r"NOT be a DecompressionParameter"):
+                                    r"not be a DecompressionParameter"):
             ZstdFile(io.BytesIO(), 'wb',
                      options={DecompressionParameter.window_log_max:21})
 
@@ -1440,19 +1501,19 @@ def test_init_bad_check(self):
         with self.assertRaises(TypeError):
             ZstdFile(io.BytesIO(), "w", level='asd')
         # CHECK_UNKNOWN and anything above CHECK_ID_MAX should be invalid.
-        with self.assertRaises(ZstdError):
+        with self.assertRaises(ValueError):
             ZstdFile(io.BytesIO(), "w", options={999:9999})
-        with self.assertRaises(ZstdError):
+        with self.assertRaises(ValueError):
             ZstdFile(io.BytesIO(), "w", 
options={CompressionParameter.window_log:99})
 
         with self.assertRaises(TypeError):
             ZstdFile(io.BytesIO(COMPRESSED_100_PLUS_32KB), "r", options=33)
 
-        with self.assertRaises(ValueError):
+        with self.assertRaises(OverflowError):
             ZstdFile(io.BytesIO(COMPRESSED_100_PLUS_32KB),
                              
options={DecompressionParameter.window_log_max:2**31})
 
-        with self.assertRaises(ZstdError):
+        with self.assertRaises(ValueError):
             ZstdFile(io.BytesIO(COMPRESSED_100_PLUS_32KB),
                              options={444:333})
 
@@ -1468,7 +1529,7 @@ def test_init_close_fp(self):
             tmp_f.write(DAT_130K_C)
             filename = tmp_f.name
 
-        with self.assertRaises(ValueError):
+        with self.assertRaises(TypeError):
             ZstdFile(filename, options={'a':'b'})
 
         # for PyPy
diff --git a/Modules/_zstd/_zstdmodule.c b/Modules/_zstd/_zstdmodule.c
index 56ad999e5cd4e4..5ad697d2b83dd6 100644
--- a/Modules/_zstd/_zstdmodule.c
+++ b/Modules/_zstd/_zstdmodule.c
@@ -103,16 +103,13 @@ static const ParameterInfo dp_list[] = {
 };
 
 void
-set_parameter_error(const _zstd_state* const state, int is_compress,
-                    int key_v, int value_v)
+set_parameter_error(int is_compress, int key_v, int value_v)
 {
     ParameterInfo const *list;
     int list_size;
-    char const *name;
     char *type;
     ZSTD_bounds bounds;
-    int i;
-    char pos_msg[128];
+    char pos_msg[64];
 
     if (is_compress) {
         list = cp_list;
@@ -126,8 +123,8 @@ set_parameter_error(const _zstd_state* const state, int 
is_compress,
     }
 
     /* Find parameter's name */
-    name = NULL;
-    for (i = 0; i < list_size; i++) {
+    char const *name = NULL;
+    for (int i = 0; i < list_size; i++) {
         if (key_v == (list+i)->parameter) {
             name = (list+i)->parameter_name;
             break;
@@ -149,20 +146,16 @@ set_parameter_error(const _zstd_state* const state, int 
is_compress,
         bounds = ZSTD_dParam_getBounds(key_v);
     }
     if (ZSTD_isError(bounds.error)) {
-        PyErr_Format(state->ZstdError,
-                     "Invalid zstd %s parameter \"%s\".",
+        PyErr_Format(PyExc_ValueError, "invalid %s parameter '%s'",
                      type, name);
         return;
     }
 
     /* Error message */
-    PyErr_Format(state->ZstdError,
-                 "Error when setting zstd %s parameter \"%s\", it "
-                 "should %d <= value <= %d, provided value is %d. "
-                 "(%d-bit build)",
-                 type, name,
-                 bounds.lowerBound, bounds.upperBound, value_v,
-                 8*(int)sizeof(Py_ssize_t));
+    PyErr_Format(PyExc_ValueError,
+        "%s parameter '%s' received an illegal value %d; "
+        "the valid range is [%d, %d]",
+        type, name, value_v, bounds.lowerBound, bounds.upperBound);
 }
 
 static inline _zstd_state*
diff --git a/Modules/_zstd/_zstdmodule.h b/Modules/_zstd/_zstdmodule.h
index b36486442c6567..1f4160f474f0b0 100644
--- a/Modules/_zstd/_zstdmodule.h
+++ b/Modules/_zstd/_zstdmodule.h
@@ -49,7 +49,6 @@ set_zstd_error(const _zstd_state* const state,
                const error_type type, size_t zstd_ret);
 
 extern void
-set_parameter_error(const _zstd_state* const state, int is_compress,
-                    int key_v, int value_v);
+set_parameter_error(int is_compress, int key_v, int value_v);
 
 #endif  // !ZSTD_MODULE_H
diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c
index 31cb8c535c05a6..1143ef6215b6b6 100644
--- a/Modules/_zstd/compressor.c
+++ b/Modules/_zstd/compressor.c
@@ -49,98 +49,106 @@ typedef struct {
 #include "clinic/compressor.c.h"
 
 static int
-_zstd_set_c_parameters(ZstdCompressor *self, PyObject *level_or_options,
-                       const char *arg_name, const char* arg_type)
+_zstd_set_c_level(ZstdCompressor *self, int level)
 {
-    size_t zstd_ret;
-    _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
-    if (mod_state == NULL) {
+    /* Set integer compression level */
+    int min_level = ZSTD_minCLevel();
+    int max_level = ZSTD_maxCLevel();
+    if (level < min_level || level > max_level) {
+        PyErr_Format(PyExc_ValueError,
+        "illegal compression level %d; the valid range is [%d, %d]",
+            level, min_level, max_level);
         return -1;
     }
 
-    /* Integer compression level */
-    if (PyLong_Check(level_or_options)) {
-        int level = PyLong_AsInt(level_or_options);
-        if (level == -1 && PyErr_Occurred()) {
-            PyErr_Format(PyExc_ValueError,
-                         "Compression level should be an int value between "
-                         "%d and %d.", ZSTD_minCLevel(), ZSTD_maxCLevel());
+    /* Save for generating ZSTD_CDICT */
+    self->compression_level = level;
+
+    /* Set compressionLevel to compression context */
+    size_t zstd_ret = ZSTD_CCtx_setParameter(
+        self->cctx, ZSTD_c_compressionLevel, level);
+
+    /* Check error */
+    if (ZSTD_isError(zstd_ret)) {
+        _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+        if (mod_state == NULL) {
             return -1;
         }
+        set_zstd_error(mod_state, ERR_SET_C_LEVEL, zstd_ret);
+        return -1;
+    }
+    return 0;
+}
 
-        /* Save for generating ZSTD_CDICT */
-        self->compression_level = level;
+static int
+_zstd_set_c_parameters(ZstdCompressor *self, PyObject *options)
+{
+    _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+    if (mod_state == NULL) {
+        return -1;
+    }
 
-        /* Set compressionLevel to compression context */
-        zstd_ret = ZSTD_CCtx_setParameter(self->cctx,
-                                          ZSTD_c_compressionLevel,
-                                          level);
+    if (!PyDict_Check(options)) {
+        PyErr_Format(PyExc_TypeError,
+             "ZstdCompressor() argument 'options' must be dict, not %T",
+             options);
+        return -1;
+    }
 
-        /* Check error */
-        if (ZSTD_isError(zstd_ret)) {
-            set_zstd_error(mod_state, ERR_SET_C_LEVEL, zstd_ret);
+    Py_ssize_t pos = 0;
+    PyObject *key, *value;
+    while (PyDict_Next(options, &pos, &key, &value)) {
+        /* Check key type */
+        if (Py_TYPE(key) == mod_state->DParameter_type) {
+            PyErr_SetString(PyExc_TypeError,
+                "compression options dictionary key must not be a "
+                "DecompressionParameter attribute");
             return -1;
         }
-        return 0;
-    }
 
-    /* Options dict */
-    if (PyDict_Check(level_or_options)) {
-        PyObject *key, *value;
-        Py_ssize_t pos = 0;
+        Py_INCREF(key);
+        Py_INCREF(value);
+        int key_v = PyLong_AsInt(key);
+        Py_DECREF(key);
+        if (key_v == -1 && PyErr_Occurred()) {
+            Py_DECREF(value);
+            return -1;
+        }
 
-        while (PyDict_Next(level_or_options, &pos, &key, &value)) {
-            /* Check key type */
-            if (Py_TYPE(key) == mod_state->DParameter_type) {
-                PyErr_SetString(PyExc_TypeError,
-                                "Key of compression options dict should "
-                                "NOT be a DecompressionParameter attribute.");
-                return -1;
-            }
+        int value_v = PyLong_AsInt(value);
+        Py_DECREF(value);
+        if (value_v == -1 && PyErr_Occurred()) {
+            return -1;
+        }
 
-            int key_v = PyLong_AsInt(key);
-            if (key_v == -1 && PyErr_Occurred()) {
-                PyErr_SetString(PyExc_ValueError,
-                                "Key of options dict should be either a "
-                                "CompressionParameter attribute or an int.");
+        if (key_v == ZSTD_c_compressionLevel) {
+            if (_zstd_set_c_level(self, value_v) < 0) {
                 return -1;
             }
-
-            int value_v = PyLong_AsInt(value);
-            if (value_v == -1 && PyErr_Occurred()) {
-                PyErr_SetString(PyExc_ValueError,
-                                "Value of options dict should be an int.");
-                return -1;
+            continue;
+        }
+        if (key_v == ZSTD_c_nbWorkers) {
+            /* From the zstd library docs:
+               1. When nbWorkers >= 1, triggers asynchronous mode when
+                  used with ZSTD_compressStream2().
+               2, Default value is `0`, aka "single-threaded mode" : no
+                  worker is spawned, compression is performed inside
+                  caller's thread, all invocations are blocking. */
+            if (value_v != 0) {
+                self->use_multithread = 1;
             }
+        }
 
-            if (key_v == ZSTD_c_compressionLevel) {
-                /* Save for generating ZSTD_CDICT */
-                self->compression_level = value_v;
-            }
-            else if (key_v == ZSTD_c_nbWorkers) {
-                /* From the zstd library docs:
-                   1. When nbWorkers >= 1, triggers asynchronous mode when
-                      used with ZSTD_compressStream2().
-                   2, Default value is `0`, aka "single-threaded mode" : no
-                      worker is spawned, compression is performed inside
-                      caller's thread, all invocations are blocking. */
-                if (value_v != 0) {
-                    self->use_multithread = 1;
-                }
-            }
+        /* Set parameter to compression context */
+        size_t zstd_ret = ZSTD_CCtx_setParameter(self->cctx, key_v, value_v);
 
-            /* Set parameter to compression context */
-            zstd_ret = ZSTD_CCtx_setParameter(self->cctx, key_v, value_v);
-            if (ZSTD_isError(zstd_ret)) {
-                set_parameter_error(mod_state, 1, key_v, value_v);
-                return -1;
-            }
+        /* Check error */
+        if (ZSTD_isError(zstd_ret)) {
+            set_parameter_error(1, key_v, value_v);
+            return -1;
         }
-        return 0;
     }
-    PyErr_Format(PyExc_TypeError,
-                 "Invalid type for %s. Expected %s", arg_name, arg_type);
-    return -1;
+    return 0;
 }
 
 static void
@@ -361,20 +369,35 @@ _zstd_ZstdCompressor_new_impl(PyTypeObject *type, 
PyObject *level,
     self->last_mode = ZSTD_e_end;
 
     if (level != Py_None && options != Py_None) {
-        PyErr_SetString(PyExc_RuntimeError,
+        PyErr_SetString(PyExc_TypeError,
                         "Only one of level or options should be used.");
         goto error;
     }
 
-    /* Set compressLevel/options to compression context */
+    /* Set compression level */
     if (level != Py_None) {
-        if (_zstd_set_c_parameters(self, level, "level", "int") < 0) {
+        if (!PyLong_Check(level)) {
+            PyErr_SetString(PyExc_TypeError,
+                "invalid type for level, expected int");
+            goto error;
+        }
+        int level_v = PyLong_AsInt(level);
+        if (level_v == -1 && PyErr_Occurred()) {
+            if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+                PyErr_Format(PyExc_ValueError,
+                    "illegal compression level; the valid range is [%d, %d]",
+                    ZSTD_minCLevel(), ZSTD_maxCLevel());
+            }
+            goto error;
+        }
+        if (_zstd_set_c_level(self, level_v) < 0) {
             goto error;
         }
     }
 
+    /* Set options dictionary */
     if (options != Py_None) {
-        if (_zstd_set_c_parameters(self, options, "options", "dict") < 0) {
+        if (_zstd_set_c_parameters(self, options) < 0) {
             goto error;
         }
     }
diff --git a/Modules/_zstd/decompressor.c b/Modules/_zstd/decompressor.c
index d084f0847c72dd..616ead049ca719 100644
--- a/Modules/_zstd/decompressor.c
+++ b/Modules/_zstd/decompressor.c
@@ -88,56 +88,52 @@ _get_DDict(ZstdDict *self)
     return self->d_dict;
 }
 
-/* Set decompression parameters to decompression context */
 static int
 _zstd_set_d_parameters(ZstdDecompressor *self, PyObject *options)
 {
-    size_t zstd_ret;
-    PyObject *key, *value;
-    Py_ssize_t pos;
     _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
     if (mod_state == NULL) {
         return -1;
     }
 
     if (!PyDict_Check(options)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "options argument should be dict object.");
+        PyErr_Format(PyExc_TypeError,
+             "ZstdDecompressor() argument 'options' must be dict, not %T",
+             options);
         return -1;
     }
 
-    pos = 0;
+    Py_ssize_t pos = 0;
+    PyObject *key, *value;
     while (PyDict_Next(options, &pos, &key, &value)) {
         /* Check key type */
         if (Py_TYPE(key) == mod_state->CParameter_type) {
             PyErr_SetString(PyExc_TypeError,
-                            "Key of decompression options dict should "
-                            "NOT be a CompressionParameter attribute.");
+                "compression options dictionary key must not be a "
+                "CompressionParameter attribute");
             return -1;
         }
 
-        /* Both key & value should be 32-bit signed int */
+        Py_INCREF(key);
+        Py_INCREF(value);
         int key_v = PyLong_AsInt(key);
+        Py_DECREF(key);
         if (key_v == -1 && PyErr_Occurred()) {
-            PyErr_SetString(PyExc_ValueError,
-                            "Key of options dict should be either a "
-                            "DecompressionParameter attribute or an int.");
             return -1;
         }
 
         int value_v = PyLong_AsInt(value);
+        Py_DECREF(value);
         if (value_v == -1 && PyErr_Occurred()) {
-            PyErr_SetString(PyExc_ValueError,
-                            "Value of options dict should be an int.");
             return -1;
         }
 
         /* Set parameter to compression context */
-        zstd_ret = ZSTD_DCtx_setParameter(self->dctx, key_v, value_v);
+        size_t zstd_ret = ZSTD_DCtx_setParameter(self->dctx, key_v, value_v);
 
         /* Check error */
         if (ZSTD_isError(zstd_ret)) {
-            set_parameter_error(mod_state, 0, key_v, value_v);
+            set_parameter_error(0, key_v, value_v);
             return -1;
         }
     }
@@ -583,7 +579,7 @@ _zstd_ZstdDecompressor_new_impl(PyTypeObject *type, 
PyObject *zstd_dict,
         self->dict = zstd_dict;
     }
 
-    /* Set option to decompression context */
+    /* Set options dictionary */
     if (options != Py_None) {
         if (_zstd_set_d_parameters(self, options) < 0) {
             goto error;

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to