Skip to content

gh-132983: Split _zstd_set_c_parameters #133921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

AA-Turner
Copy link
Member

@AA-Turner AA-Turner commented May 12, 2025

The current _zstd_set_c_parameters shares little between the two possible (int or dict) paths. By splitting the function, we can now use the Py_ssize_t AC converter.

One slight change worth noting is that the constructor won't raise an error when level is $-2^{63}$ but will just silently use the default. cc @erlend-aasland if there's a better method/sentinel we can use in the clinic to detect if the value has been set or not.

>>> _zstd.ZstdCompressor(level=-(1<<63)+1)
Traceback (most recent call last):
  File "<python-input-17>", line 1, in <module>
    _zstd.ZstdCompressor(level=-(1<<63)+1)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
ValueError: compression level -9223372036854775807 not in valid range -131072 <= level <= 22.
>>> _zstd.ZstdCompressor(level=-(1<<63))
<compression.zstd.ZstdCompressor object at 0x7f61875b2210>

I also think it might be worth considering removing the level XOR options check, as we could adopt the rule that a compression level set in an options dict overrides the level parameter. I can see reasonable arguments to keep the status quo, however, so I've not done this yet.

A

cc @Rogdham

_zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self));
if (mod_state == NULL) {
/* Set integer compression level */
const int min_level = ZSTD_minCLevel();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to use all these consts. They just distract.

"Value of option dict should be an int.");
return -1;
}
const int key_v = PyLong_AsInt(key);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key and value are borrowed references. Incref them before calling PyLong_AsInt().

return -1;
}
const int key_v = PyLong_AsInt(key);
if (key_v == -1 && PyErr_Occurred()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not override arbitrary exceptions. Check the type of exception before replacing it.

}
const int key_v = PyLong_AsInt(key);
if (key_v == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it was a TypeError, it is preferable to keep a TypeError. If it was an OverflowError, it can be replaced with ValueError, but TypeError may be appropriate too in this context. Or what set_parameter_error() sets for invalid key values.

const int key_v = PyLong_AsInt(key);
if (key_v == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError,
"key should be a CompressionParameter attribute.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No period at the end of the error message which is not a full sentence.

Comment on lines +112 to +115
int value_v = PyLong_AsInt(value);
if (value_v == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError,
"options dict value should be an int.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Comment on lines +199 to 205
# valid compression level range is [-(1<<17), 22]
with self.assertRaises(ValueError):
ZstdCompressor(2**31)
with self.assertRaises(ValueError):
ZstdCompressor(level=-(2**31))
with self.assertRaises(ValueError):
ZstdCompressor(options={2**31: 100})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test also for values out any C integer range: 2**1000 and -2**1000.

Comment on lines +267 to +270
with self.assertRaises(ValueError):
compress(b'', level_max+1)
with self.assertRaises(ValueError):
compress(b'', level_min-1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

@serhiy-storchaka
Copy link
Member

if there's a better method/sentinel we can use in the clinic to detect if the value has been set or not

No, there is not. You cannot distinguish the passed value from the default value. It is better to not using Argument Clinic for conversion of this parameter.

BTW, Py_ssize_t is the same as int on 32-bit platforms, so there is good reason to use it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants