Skip to content

Commit d44dd9b

Browse files
committed
Split _zstd_set_c_parameters
1 parent 27ed645 commit d44dd9b

File tree

3 files changed

+98
-87
lines changed

3 files changed

+98
-87
lines changed

Lib/test/test_zstd.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,11 @@ def test_simple_compress_bad_args(self):
196196
self.assertRaises(TypeError, ZstdCompressor, zstd_dict=b"abcd1234")
197197
self.assertRaises(TypeError, ZstdCompressor, zstd_dict={1: 2, 3: 4})
198198

199+
# valid compression level range is [-(1<<17), 22]
199200
with self.assertRaises(ValueError):
200201
ZstdCompressor(2**31)
202+
with self.assertRaises(ValueError):
203+
ZstdCompressor(level=-(2**31))
201204
with self.assertRaises(ValueError):
202205
ZstdCompressor(options={2**31: 100})
203206

@@ -261,8 +264,10 @@ def test_compress_parameters(self):
261264

262265
# clamp compressionLevel
263266
level_min, level_max = CompressionParameter.compression_level.bounds()
264-
compress(b'', level_max+1)
265-
compress(b'', level_min-1)
267+
with self.assertRaises(ValueError):
268+
compress(b'', level_max+1)
269+
with self.assertRaises(ValueError):
270+
compress(b'', level_min-1)
266271

267272
compress(b'', options={CompressionParameter.compression_level:level_max+1})
268273
compress(b'', options={CompressionParameter.compression_level:level_min-1})

Modules/_zstd/clinic/compressor.c.h

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_zstd/compressor.c

Lines changed: 84 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -45,98 +45,101 @@ typedef struct {
4545
#include "clinic/compressor.c.h"
4646

4747
static int
48-
_zstd_set_c_parameters(ZstdCompressor *self, PyObject *level_or_options,
49-
const char *arg_name, const char* arg_type)
48+
_zstd_set_c_level(ZstdCompressor *self, const Py_ssize_t level)
5049
{
51-
size_t zstd_ret;
52-
_zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self));
53-
if (mod_state == NULL) {
50+
/* Set integer compression level */
51+
const int min_level = ZSTD_minCLevel();
52+
const int max_level = ZSTD_maxCLevel();
53+
if (level < min_level || level > max_level) {
54+
PyErr_Format(PyExc_ValueError,
55+
"compression level %zd not in valid range %d <= level <= %d.",
56+
level, min_level, max_level);
5457
return -1;
5558
}
5659

57-
/* Integer compression level */
58-
if (PyLong_Check(level_or_options)) {
59-
int level = PyLong_AsInt(level_or_options);
60-
if (level == -1 && PyErr_Occurred()) {
61-
PyErr_Format(PyExc_ValueError,
62-
"Compression level should be an int value between %d and %d.",
63-
ZSTD_minCLevel(), ZSTD_maxCLevel());
64-
return -1;
65-
}
66-
67-
/* Save for generating ZSTD_CDICT */
68-
self->compression_level = level;
60+
/* Save for generating ZSTD_CDICT */
61+
self->compression_level = (int)level;
6962

70-
/* Set compressionLevel to compression context */
71-
zstd_ret = ZSTD_CCtx_setParameter(self->cctx,
72-
ZSTD_c_compressionLevel,
73-
level);
63+
/* Set compressionLevel to compression context */
64+
const size_t zstd_ret = ZSTD_CCtx_setParameter(
65+
self->cctx, ZSTD_c_compressionLevel, (int)level);
7466

75-
/* Check error */
76-
if (ZSTD_isError(zstd_ret)) {
77-
set_zstd_error(mod_state, ERR_SET_C_LEVEL, zstd_ret);
67+
/* Check error */
68+
if (ZSTD_isError(zstd_ret)) {
69+
const _zstd_state* const st = PyType_GetModuleState(Py_TYPE(self));
70+
if (st == NULL) {
7871
return -1;
7972
}
80-
return 0;
73+
set_zstd_error(st, ERR_SET_C_LEVEL, zstd_ret);
74+
return -1;
8175
}
76+
return 0;
77+
}
8278

83-
/* Options dict */
84-
if (PyDict_Check(level_or_options)) {
85-
PyObject *key, *value;
86-
Py_ssize_t pos = 0;
79+
static int
80+
_zstd_set_c_parameters(ZstdCompressor *self, PyObject *options)
81+
{
82+
/* Set options dict */
83+
_zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self));
84+
if (mod_state == NULL) {
85+
return -1;
86+
}
8787

88-
while (PyDict_Next(level_or_options, &pos, &key, &value)) {
89-
/* Check key type */
90-
if (Py_TYPE(key) == mod_state->DParameter_type) {
91-
PyErr_SetString(PyExc_TypeError,
92-
"Key of compression option dict should "
93-
"NOT be DecompressionParameter.");
94-
return -1;
95-
}
88+
if (!PyDict_Check(options)) {
89+
PyErr_Format(PyExc_TypeError, "invalid type for options, expected dict");
90+
return -1;
91+
}
9692

97-
int key_v = PyLong_AsInt(key);
98-
if (key_v == -1 && PyErr_Occurred()) {
99-
PyErr_SetString(PyExc_ValueError,
100-
"Key of options dict should be a CompressionParameter attribute.");
101-
return -1;
102-
}
93+
Py_ssize_t pos = 0;
94+
PyObject *key, *value;
95+
while (PyDict_Next(options, &pos, &key, &value)) {
96+
/* Check key type */
97+
if (Py_TYPE(key) == mod_state->DParameter_type) {
98+
PyErr_SetString(PyExc_TypeError,
99+
"key should NOT be DecompressionParameter.");
100+
return -1;
101+
}
103102

104-
// TODO(emmatyping): check bounds when there is a value error here for better
105-
// error message?
106-
int value_v = PyLong_AsInt(value);
107-
if (value_v == -1 && PyErr_Occurred()) {
108-
PyErr_SetString(PyExc_ValueError,
109-
"Value of option dict should be an int.");
110-
return -1;
111-
}
103+
const int key_v = PyLong_AsInt(key);
104+
if (key_v == -1 && PyErr_Occurred()) {
105+
PyErr_SetString(PyExc_ValueError,
106+
"key should be a CompressionParameter attribute.");
107+
return -1;
108+
}
112109

113-
if (key_v == ZSTD_c_compressionLevel) {
114-
/* Save for generating ZSTD_CDICT */
115-
self->compression_level = value_v;
116-
}
117-
else if (key_v == ZSTD_c_nbWorkers) {
118-
/* From the zstd library docs:
119-
1. When nbWorkers >= 1, triggers asynchronous mode when
120-
used with ZSTD_compressStream2().
121-
2, Default value is `0`, aka "single-threaded mode" : no
122-
worker is spawned, compression is performed inside
123-
caller's thread, all invocations are blocking. */
124-
if (value_v != 0) {
125-
self->use_multithread = 1;
126-
}
127-
}
110+
// TODO(emmatyping): check bounds when there is a value error here for better
111+
// error message?
112+
int value_v = PyLong_AsInt(value);
113+
if (value_v == -1 && PyErr_Occurred()) {
114+
PyErr_SetString(PyExc_ValueError,
115+
"options dict value should be an int.");
116+
return -1;
117+
}
128118

129-
/* Set parameter to compression context */
130-
zstd_ret = ZSTD_CCtx_setParameter(self->cctx, key_v, value_v);
131-
if (ZSTD_isError(zstd_ret)) {
132-
set_parameter_error(mod_state, 1, key_v, value_v);
133-
return -1;
119+
if (key_v == ZSTD_c_compressionLevel) {
120+
/* Save for generating ZSTD_CDICT */
121+
self->compression_level = value_v;
122+
}
123+
else if (key_v == ZSTD_c_nbWorkers) {
124+
/* From the zstd library docs:
125+
1. When nbWorkers >= 1, triggers asynchronous mode when
126+
used with ZSTD_compressStream2().
127+
2, Default value is `0`, aka "single-threaded mode" : no
128+
worker is spawned, compression is performed inside
129+
caller's thread, all invocations are blocking. */
130+
if (value_v != 0) {
131+
self->use_multithread = 1;
134132
}
135133
}
136-
return 0;
134+
135+
/* Set parameter to compression context */
136+
const size_t zstd_ret = ZSTD_CCtx_setParameter(self->cctx, key_v, value_v);
137+
if (ZSTD_isError(zstd_ret)) {
138+
set_parameter_error(mod_state, 1, key_v, value_v);
139+
return -1;
140+
}
137141
}
138-
PyErr_Format(PyExc_TypeError, "Invalid type for %s. Expected %s", arg_name, arg_type);
139-
return -1;
142+
return 0;
140143
}
141144

142145
static void
@@ -314,7 +317,7 @@ _zstd_load_c_dict(ZstdCompressor *self, PyObject *dict)
314317
/*[clinic input]
315318
@classmethod
316319
_zstd.ZstdCompressor.__new__ as _zstd_ZstdCompressor_new
317-
level: object = None
320+
level: Py_ssize_t(c_default='PY_SSIZE_T_MIN', accept={int, NoneType}) = None
318321
The compression level to use. Defaults to COMPRESSION_LEVEL_DEFAULT.
319322
options: object = None
320323
A dict object that contains advanced compression parameters.
@@ -328,9 +331,9 @@ function instead.
328331
[clinic start generated code]*/
329332

330333
static PyObject *
331-
_zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level,
334+
_zstd_ZstdCompressor_new_impl(PyTypeObject *type, Py_ssize_t level,
332335
PyObject *options, PyObject *zstd_dict)
333-
/*[clinic end generated code: output=cdef61eafecac3d7 input=92de0211ae20ffdc]*/
336+
/*[clinic end generated code: output=a857ec0dc29fc5e2 input=9899740b24d11319]*/
334337
{
335338
ZstdCompressor* self = PyObject_GC_New(ZstdCompressor, type);
336339
if (self == NULL) {
@@ -353,20 +356,20 @@ _zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level,
353356
/* Last mode */
354357
self->last_mode = ZSTD_e_end;
355358

356-
if (level != Py_None && options != Py_None) {
359+
if (level != PY_SSIZE_T_MIN && options != Py_None) {
357360
PyErr_SetString(PyExc_RuntimeError, "Only one of level or options should be used.");
358361
goto error;
359362
}
360363

361364
/* Set compressLevel/options to compression context */
362-
if (level != Py_None) {
363-
if (_zstd_set_c_parameters(self, level, "level", "int") < 0) {
365+
if (level != PY_SSIZE_T_MIN) {
366+
if (_zstd_set_c_level(self, level) < 0) {
364367
goto error;
365368
}
366369
}
367370

368371
if (options != Py_None) {
369-
if (_zstd_set_c_parameters(self, options, "options", "dict") < 0) {
372+
if (_zstd_set_c_parameters(self, options) < 0) {
370373
goto error;
371374
}
372375
}

0 commit comments

Comments
 (0)