Skip to content

Commit e033965

Browse files
Address review comments
* Explain in a comment why the result of sscanf() is not checked. * Merge make_zlib_version() and make_zlibng_version() into a single make_version_info(). * Rename the static names for the *_version_info named tuples, so that they match the name of the type. * Tell in the bz2 docs that bzlib_version and bzlib_version_info are the version of the library loaded at runtime, and that the version used for building the module is not available. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 95b58f7 commit e033965

5 files changed

Lines changed: 79 additions & 99 deletions

File tree

Doc/library/bz2.rst

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,21 +311,26 @@ One-shot (de)compression
311311
Miscellaneous
312312
-------------
313313

314-
Information about the version of the bzip2 compression library in use
315-
is available through the following constants:
314+
Information about the version of the bzip2 compression library
315+
actually loaded by the interpreter is available through the following
316+
constants.
317+
The version used for building the module is not available,
318+
because the bzip2 library does not provide it.
316319

317320

318321
.. data:: bzlib_version
319322

320-
The version string of the bzip2 compression library.
323+
The version string of the bzip2 compression library
324+
actually loaded by the interpreter.
321325

322326
.. versionadded:: next
323327

324328

325329
.. data:: bzlib_version_info
326330

327331
A named tuple containing the three components of the bzip2 compression
328-
library version: *major*, *minor*, and *patch*. All values are integers.
332+
library version actually loaded by the interpreter:
333+
*major*, *minor*, and *patch*. All values are integers.
329334
The components can also be accessed by name, so ``bz2.bzlib_version_info[0]``
330335
is equivalent to ``bz2.bzlib_version_info.major`` and so on.
331336

Modules/_bz2module.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -748,27 +748,32 @@ static PyType_Spec bz2_decompressor_type_spec = {
748748
};
749749

750750

751-
PyDoc_STRVAR(bzlib_version__doc__,
751+
PyDoc_STRVAR(bzlib_version_info__doc__,
752752
"_bz2.bzlib_version_info\n\
753753
\n\
754754
Bzlib version information as a named tuple.");
755755

756-
static PyStructSequence_Field bzlib_version_fields[] = {
756+
static PyStructSequence_Field bzlib_version_info_fields[] = {
757757
{"major", "Major release number"},
758758
{"minor", "Minor release number"},
759759
{"patch", "Patch release number"},
760760
{0}
761761
};
762762

763-
static PyStructSequence_Desc bzlib_version_desc = {
764-
"_bz2.bzlib_version_info", /* name */
765-
bzlib_version__doc__, /* doc */
766-
bzlib_version_fields, /* fields */
763+
static PyStructSequence_Desc bzlib_version_info_desc = {
764+
"_bz2.bzlib_version_info", /* name */
765+
bzlib_version_info__doc__, /* doc */
766+
bzlib_version_info_fields, /* fields */
767767
3
768768
};
769769

770+
/* BZ2_bzlibVersion() returns a string with a trailing suffix, for example
771+
"1.0.8, 13-Jul-2019" for bzip2 or "1.1.0-libbz2-rs-sys-0.2.5" for
772+
libbz2-rs. sscanf() stops at the suffix; components which were not
773+
parsed are left zero. This is deliberate -- a zero is more useful
774+
here than a hard error. */
770775
static PyObject *
771-
make_bzlib_version(PyTypeObject *type, const char *string)
776+
make_bzlib_version_info(PyTypeObject *type, const char *string)
772777
{
773778
PyObject *version;
774779
int pos = 0;
@@ -828,12 +833,12 @@ _bz2_exec(PyObject *module)
828833
return -1;
829834
}
830835
PyTypeObject *version_type;
831-
version_type = PyStructSequence_NewType(&bzlib_version_desc);
836+
version_type = PyStructSequence_NewType(&bzlib_version_info_desc);
832837
if (version_type == NULL) {
833838
return -1;
834839
}
835840
if (PyModule_Add(module, "bzlib_version_info",
836-
make_bzlib_version(version_type, BZ2_bzlibVersion())) < 0)
841+
make_bzlib_version_info(version_type, BZ2_bzlibVersion())) < 0)
837842
{
838843
Py_DECREF(version_type);
839844
return -1;

Modules/_lzmamodule.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,28 +1510,28 @@ _lzma__decode_filter_properties_impl(PyObject *module, lzma_vli filter_id,
15101510
}
15111511

15121512

1513-
PyDoc_STRVAR(lzma_version__doc__,
1513+
PyDoc_STRVAR(lzma_version_info__doc__,
15141514
"_lzma.lzma_version_info\n\
15151515
\n\
15161516
Lzma version information as a named tuple.");
15171517

1518-
static PyStructSequence_Field lzma_version_fields[] = {
1518+
static PyStructSequence_Field lzma_version_info_fields[] = {
15191519
{"major", "Major release number"},
15201520
{"minor", "Minor release number"},
15211521
{"patch", "Patch release number"},
15221522
{"stability", "'alpha', 'beta', or 'stable'"},
15231523
{0}
15241524
};
15251525

1526-
static PyStructSequence_Desc lzma_version_desc = {
1527-
"_lzma.lzma_version_info", /* name */
1528-
lzma_version__doc__, /* doc */
1529-
lzma_version_fields, /* fields */
1526+
static PyStructSequence_Desc lzma_version_info_desc = {
1527+
"_lzma.lzma_version_info", /* name */
1528+
lzma_version_info__doc__, /* doc */
1529+
lzma_version_info_fields, /* fields */
15301530
4
15311531
};
15321532

15331533
static PyObject *
1534-
make_lzma_version(PyTypeObject *type, unsigned int number)
1534+
make_lzma_version_info(PyTypeObject *type, unsigned int number)
15351535
{
15361536
PyObject *version;
15371537
int pos = 0;
@@ -1669,18 +1669,18 @@ lzma_exec(PyObject *module)
16691669
return -1;
16701670
}
16711671
PyTypeObject *version_type;
1672-
version_type = PyStructSequence_NewType(&lzma_version_desc);
1672+
version_type = PyStructSequence_NewType(&lzma_version_info_desc);
16731673
if (version_type == NULL) {
16741674
return -1;
16751675
}
16761676
if (PyModule_Add(module, "LZMA_VERSION_INFO",
1677-
make_lzma_version(version_type, LZMA_VERSION)) < 0)
1677+
make_lzma_version_info(version_type, LZMA_VERSION)) < 0)
16781678
{
16791679
Py_DECREF(version_type);
16801680
return -1;
16811681
}
16821682
if (PyModule_Add(module, "lzma_version_info",
1683-
make_lzma_version(version_type, lzma_version_number())) < 0)
1683+
make_lzma_version_info(version_type, lzma_version_number())) < 0)
16841684
{
16851685
Py_DECREF(version_type);
16861686
return -1;

Modules/_zstd/_zstdmodule.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -571,27 +571,27 @@ static PyMethodDef _zstd_methods[] = {
571571
{NULL, NULL}
572572
};
573573

574-
PyDoc_STRVAR(zstd_version__doc__,
574+
PyDoc_STRVAR(zstd_version_info__doc__,
575575
"_zstd.zstd_version_info\n\
576576
\n\
577577
Zstd version information as a named tuple.");
578578

579-
static PyStructSequence_Field zstd_version_fields[] = {
579+
static PyStructSequence_Field zstd_version_info_fields[] = {
580580
{"major", "Major release number"},
581581
{"minor", "Minor release number"},
582582
{"patch", "Patch release number"},
583583
{0}
584584
};
585585

586-
static PyStructSequence_Desc zstd_version_desc = {
587-
"_zstd.zstd_version_info", /* name */
588-
zstd_version__doc__, /* doc */
589-
zstd_version_fields, /* fields */
586+
static PyStructSequence_Desc zstd_version_info_desc = {
587+
"_zstd.zstd_version_info", /* name */
588+
zstd_version_info__doc__, /* doc */
589+
zstd_version_info_fields, /* fields */
590590
3
591591
};
592592

593593
static PyObject *
594-
make_zstd_version(PyTypeObject *type, unsigned int number)
594+
make_zstd_version_info(PyTypeObject *type, unsigned int number)
595595
{
596596
PyObject *version;
597597
int pos = 0;
@@ -681,18 +681,18 @@ do { \
681681
return -1;
682682
}
683683
PyTypeObject *version_type;
684-
version_type = PyStructSequence_NewType(&zstd_version_desc);
684+
version_type = PyStructSequence_NewType(&zstd_version_info_desc);
685685
if (version_type == NULL) {
686686
return -1;
687687
}
688688
if (PyModule_Add(m, "ZSTD_VERSION_INFO",
689-
make_zstd_version(version_type, ZSTD_VERSION_NUMBER)) < 0)
689+
make_zstd_version_info(version_type, ZSTD_VERSION_NUMBER)) < 0)
690690
{
691691
Py_DECREF(version_type);
692692
return -1;
693693
}
694694
if (PyModule_Add(m, "zstd_version_info",
695-
make_zstd_version(version_type, ZSTD_versionNumber())) < 0)
695+
make_zstd_version_info(version_type, ZSTD_versionNumber())) < 0)
696696
{
697697
Py_DECREF(version_type);
698698
return -1;

Modules/zlibmodule.c

Lines changed: 36 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,105 +2060,75 @@ zlib_getattr(PyObject *self, PyObject *args)
20602060
return NULL;
20612061
}
20622062

2063-
PyDoc_STRVAR(zlib_version__doc__,
2063+
PyDoc_STRVAR(zlib_version_info__doc__,
20642064
"zlib.zlib_version_info\n\
20652065
\n\
20662066
Zlib version information as a named tuple.");
20672067

2068-
static PyStructSequence_Field zlib_version_fields[] = {
2068+
static PyStructSequence_Field zlib_version_info_fields[] = {
20692069
{"major", "Major release number"},
20702070
{"minor", "Minor release number"},
20712071
{"revision", "Revision release number"},
20722072
{"subversion", "Subversion release number"},
20732073
{0}
20742074
};
20752075

2076-
static PyStructSequence_Desc zlib_version_desc = {
2077-
"zlib.zlib_version_info", /* name */
2078-
zlib_version__doc__, /* doc */
2079-
zlib_version_fields, /* fields */
2076+
static PyStructSequence_Desc zlib_version_info_desc = {
2077+
"zlib.zlib_version_info", /* name */
2078+
zlib_version_info__doc__, /* doc */
2079+
zlib_version_info_fields, /* fields */
20802080
4
20812081
};
20822082

2083-
static PyObject *
2084-
make_zlib_version(PyTypeObject *type, const char *string)
2085-
{
2086-
PyObject *version;
2087-
int pos = 0;
2088-
unsigned int major = 0, minor = 0, revision = 0, subversion = 0;
2089-
2090-
sscanf(string, "%u.%u.%u.%u", &major, &minor, &revision, &subversion);
2091-
2092-
version = PyStructSequence_New(type);
2093-
if (version == NULL) {
2094-
return NULL;
2095-
}
2096-
2097-
#define SetIntItem(VALUE) \
2098-
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromUnsignedLong(VALUE)); \
2099-
if (PyErr_Occurred()) { \
2100-
Py_DECREF(version); \
2101-
return NULL; \
2102-
}
2103-
2104-
SetIntItem(major)
2105-
SetIntItem(minor)
2106-
SetIntItem(revision)
2107-
SetIntItem(subversion)
2108-
#undef SetIntItem
2109-
2110-
return version;
2111-
}
2112-
21132083
#ifdef ZLIBNG_VERSION
2114-
PyDoc_STRVAR(zlibng_version__doc__,
2084+
PyDoc_STRVAR(zlibng_version_info__doc__,
21152085
"zlib.zlibng_version_info\n\
21162086
\n\
21172087
Zlib-ng version information as a named tuple.");
21182088

2119-
static PyStructSequence_Field zlibng_version_fields[] = {
2089+
static PyStructSequence_Field zlibng_version_info_fields[] = {
21202090
{"major", "Major release number"},
21212091
{"minor", "Minor release number"},
21222092
{"revision", "Revision release number"},
21232093
{0}
21242094
};
21252095

2126-
static PyStructSequence_Desc zlibng_version_desc = {
2127-
"zlib.zlibng_version_info", /* name */
2128-
zlibng_version__doc__, /* doc */
2129-
zlibng_version_fields, /* fields */
2096+
static PyStructSequence_Desc zlibng_version_info_desc = {
2097+
"zlib.zlibng_version_info", /* name */
2098+
zlibng_version_info__doc__, /* doc */
2099+
zlibng_version_info_fields, /* fields */
21302100
3
21312101
};
2102+
#endif // ZLIBNG_VERSION
21322103

2104+
/* Create a named tuple from the first *size* components of a version string
2105+
like "1.2.11" or "1.2.11.1". sscanf() is expected to fail on trailing
2106+
garbage and on versions with fewer components (for example "1.2.0.f" or
2107+
"1.3.1.zlib-ng"); the components which were not parsed are left zero.
2108+
This is deliberate -- a zero is more useful here than a hard error. */
21332109
static PyObject *
2134-
make_zlibng_version(PyTypeObject *type, const char *string)
2110+
make_version_info(PyTypeObject *type, const char *string, Py_ssize_t size)
21352111
{
2136-
PyObject *version;
2137-
int pos = 0;
2138-
unsigned int major = 0, minor = 0, revision = 0;
2112+
unsigned int components[4] = {0, 0, 0, 0};
2113+
assert(size <= (Py_ssize_t)Py_ARRAY_LENGTH(components));
21392114

2140-
sscanf(string, "%u.%u.%u", &major, &minor, &revision);
2115+
sscanf(string, "%u.%u.%u.%u",
2116+
&components[0], &components[1], &components[2], &components[3]);
21412117

2142-
version = PyStructSequence_New(type);
2118+
PyObject *version = PyStructSequence_New(type);
21432119
if (version == NULL) {
21442120
return NULL;
21452121
}
2146-
2147-
#define SetIntItem(VALUE) \
2148-
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromUnsignedLong(VALUE)); \
2149-
if (PyErr_Occurred()) { \
2150-
Py_DECREF(version); \
2151-
return NULL; \
2122+
for (Py_ssize_t i = 0; i < size; i++) {
2123+
PyObject *item = PyLong_FromUnsignedLong(components[i]);
2124+
if (item == NULL) {
2125+
Py_DECREF(version);
2126+
return NULL;
2127+
}
2128+
PyStructSequence_SET_ITEM(version, i, item);
21522129
}
2153-
2154-
SetIntItem(major)
2155-
SetIntItem(minor)
2156-
SetIntItem(revision)
2157-
#undef SetIntItem
2158-
21592130
return version;
21602131
}
2161-
#endif // ZLIBNG_VERSION
21622132

21632133

21642134
static PyMethodDef zlib_methods[] =
@@ -2377,30 +2347,30 @@ zlib_exec(PyObject *mod)
23772347
}
23782348
#endif
23792349
PyTypeObject *version_type;
2380-
version_type = PyStructSequence_NewType(&zlib_version_desc);
2350+
version_type = PyStructSequence_NewType(&zlib_version_info_desc);
23812351
if (version_type == NULL) {
23822352
return -1;
23832353
}
23842354
if (PyModule_Add(mod, "ZLIB_VERSION_INFO",
2385-
make_zlib_version(version_type, ZLIB_VERSION)) < 0)
2355+
make_version_info(version_type, ZLIB_VERSION, 4)) < 0)
23862356
{
23872357
Py_DECREF(version_type);
23882358
return -1;
23892359
}
23902360
if (PyModule_Add(mod, "zlib_version_info",
2391-
make_zlib_version(version_type, zlibVersion())) < 0)
2361+
make_version_info(version_type, zlibVersion(), 4)) < 0)
23922362
{
23932363
Py_DECREF(version_type);
23942364
return -1;
23952365
}
23962366
Py_DECREF(version_type);
23972367
#ifdef ZLIBNG_VERSION
2398-
version_type = PyStructSequence_NewType(&zlibng_version_desc);
2368+
version_type = PyStructSequence_NewType(&zlibng_version_info_desc);
23992369
if (version_type == NULL) {
24002370
return -1;
24012371
}
24022372
if (PyModule_Add(mod, "ZLIBNG_VERSION_INFO",
2403-
make_zlibng_version(version_type, ZLIBNG_VERSION)) < 0)
2373+
make_version_info(version_type, ZLIBNG_VERSION, 3)) < 0)
24042374
{
24052375
Py_DECREF(version_type);
24062376
return -1;

0 commit comments

Comments
 (0)