Skip to content

Commit 3271d2c

Browse files
committed
Split _zstd_set_c_parameters
1 parent 27ed645 commit 3271d2c

File tree

3 files changed

+97
-84
lines changed

3 files changed

+97
-84
lines changed

Lib/test/test_zstd.py

Lines changed: 3 additions & 0 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

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: 87 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -45,98 +45,105 @@ 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;
50+
/* Set integer compression level */
5251
_zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self));
5352
if (mod_state == NULL) {
5453
return -1;
5554
}
5655

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-
}
56+
const int min_level = ZSTD_minCLevel();
57+
const int max_level = ZSTD_maxCLevel();
58+
if (level < min_level || level > max_level) {
59+
PyErr_Format(PyExc_ValueError,
60+
"compression level %zd not in valid range %d <= level <= %d.",
61+
level, min_level, max_level);
62+
return -1;
63+
}
6664

67-
/* Save for generating ZSTD_CDICT */
68-
self->compression_level = level;
65+
/* Save for generating ZSTD_CDICT */
66+
self->compression_level = (int)level;
6967

70-
/* Set compressionLevel to compression context */
71-
zstd_ret = ZSTD_CCtx_setParameter(self->cctx,
72-
ZSTD_c_compressionLevel,
73-
level);
68+
/* Set compressionLevel to compression context */
69+
size_t zstd_ret = ZSTD_CCtx_setParameter(
70+
self->cctx, ZSTD_c_compressionLevel, (int)level);
7471

75-
/* Check error */
76-
if (ZSTD_isError(zstd_ret)) {
77-
set_zstd_error(mod_state, ERR_SET_C_LEVEL, zstd_ret);
78-
return -1;
79-
}
80-
return 0;
72+
/* Check error */
73+
if (ZSTD_isError(zstd_ret)) {
74+
set_zstd_error(mod_state, ERR_SET_C_LEVEL, zstd_ret);
75+
return -1;
76+
}
77+
return 0;
78+
}
79+
80+
static int
81+
_zstd_set_c_parameters(ZstdCompressor *self, PyObject *options)
82+
{
83+
/* Set options dict */
84+
size_t zstd_ret;
85+
_zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self));
86+
if (mod_state == NULL) {
87+
return -1;
8188
}
8289

83-
/* Options dict */
84-
if (PyDict_Check(level_or_options)) {
85-
PyObject *key, *value;
86-
Py_ssize_t pos = 0;
90+
if (!PyDict_Check(options)) {
91+
PyErr_Format(PyExc_TypeError, "Invalid type for options, expected dict");
92+
return -1;
93+
}
8794

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-
}
95+
PyObject *key, *value;
96+
Py_ssize_t pos = 0;
9697

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-
}
98+
while (PyDict_Next(options, &pos, &key, &value)) {
99+
/* Check key type */
100+
if (Py_TYPE(key) == mod_state->DParameter_type) {
101+
PyErr_SetString(PyExc_TypeError,
102+
"Key of compression option dict should "
103+
"NOT be DecompressionParameter.");
104+
return -1;
105+
}
103106

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-
}
107+
int key_v = PyLong_AsInt(key);
108+
if (key_v == -1 && PyErr_Occurred()) {
109+
PyErr_SetString(PyExc_ValueError,
110+
"Key of options dict should be a CompressionParameter attribute.");
111+
return -1;
112+
}
112113

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-
}
114+
// TODO(emmatyping): check bounds when there is a value error here for better
115+
// error message?
116+
int value_v = PyLong_AsInt(value);
117+
if (value_v == -1 && PyErr_Occurred()) {
118+
PyErr_SetString(PyExc_ValueError,
119+
"Value of option dict should be an int.");
120+
return -1;
121+
}
128122

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;
123+
if (key_v == ZSTD_c_compressionLevel) {
124+
/* Save for generating ZSTD_CDICT */
125+
self->compression_level = value_v;
126+
}
127+
else if (key_v == ZSTD_c_nbWorkers) {
128+
/* From the zstd library docs:
129+
1. When nbWorkers >= 1, triggers asynchronous mode when
130+
used with ZSTD_compressStream2().
131+
2, Default value is `0`, aka "single-threaded mode" : no
132+
worker is spawned, compression is performed inside
133+
caller's thread, all invocations are blocking. */
134+
if (value_v != 0) {
135+
self->use_multithread = 1;
134136
}
135137
}
136-
return 0;
138+
139+
/* Set parameter to compression context */
140+
zstd_ret = ZSTD_CCtx_setParameter(self->cctx, key_v, value_v);
141+
if (ZSTD_isError(zstd_ret)) {
142+
set_parameter_error(mod_state, 1, key_v, value_v);
143+
return -1;
144+
}
137145
}
138-
PyErr_Format(PyExc_TypeError, "Invalid type for %s. Expected %s", arg_name, arg_type);
139-
return -1;
146+
return 0;
140147
}
141148

142149
static void
@@ -314,7 +321,7 @@ _zstd_load_c_dict(ZstdCompressor *self, PyObject *dict)
314321
/*[clinic input]
315322
@classmethod
316323
_zstd.ZstdCompressor.__new__ as _zstd_ZstdCompressor_new
317-
level: object = None
324+
level: Py_ssize_t(c_default='PY_SSIZE_T_MIN', accept={int, NoneType}) = None
318325
The compression level to use. Defaults to COMPRESSION_LEVEL_DEFAULT.
319326
options: object = None
320327
A dict object that contains advanced compression parameters.
@@ -328,9 +335,9 @@ function instead.
328335
[clinic start generated code]*/
329336

330337
static PyObject *
331-
_zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level,
338+
_zstd_ZstdCompressor_new_impl(PyTypeObject *type, Py_ssize_t level,
332339
PyObject *options, PyObject *zstd_dict)
333-
/*[clinic end generated code: output=cdef61eafecac3d7 input=92de0211ae20ffdc]*/
340+
/*[clinic end generated code: output=a857ec0dc29fc5e2 input=9899740b24d11319]*/
334341
{
335342
ZstdCompressor* self = PyObject_GC_New(ZstdCompressor, type);
336343
if (self == NULL) {
@@ -353,20 +360,20 @@ _zstd_ZstdCompressor_new_impl(PyTypeObject *type, PyObject *level,
353360
/* Last mode */
354361
self->last_mode = ZSTD_e_end;
355362

356-
if (level != Py_None && options != Py_None) {
363+
if (level != PY_SSIZE_T_MIN && options != Py_None) {
357364
PyErr_SetString(PyExc_RuntimeError, "Only one of level or options should be used.");
358365
goto error;
359366
}
360367

361368
/* Set compressLevel/options to compression context */
362-
if (level != Py_None) {
363-
if (_zstd_set_c_parameters(self, level, "level", "int") < 0) {
369+
if (level != PY_SSIZE_T_MIN) {
370+
if (_zstd_set_c_level(self, level) < 0) {
364371
goto error;
365372
}
366373
}
367374

368375
if (options != Py_None) {
369-
if (_zstd_set_c_parameters(self, options, "options", "dict") < 0) {
376+
if (_zstd_set_c_parameters(self, options) < 0) {
370377
goto error;
371378
}
372379
}

0 commit comments

Comments
 (0)