gh-117404: Add structured version info for compression modules (GH-150567)

Add constants which provide information about the version of the
compression library used for building the module and the version
actually loaded:

* zlib: ZLIB_VERSION_INFO, zlib_version_info, ZLIBNG_VERSION_INFO,
  and zlib_version as an alias of ZLIB_RUNTIME_VERSION
* bz2: bzlib_version, bzlib_version_info
* lzma: LZMA_VERSION, lzma_version, LZMA_VERSION_INFO, lzma_version_info
* compression.zstd: ZSTD_VERSION, ZSTD_VERSION_INFO

Make compression.zstd.zstd_version_info a named tuple.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serhiy StorchakaandClaude Opus 5 authored and GitHub committed 2026-09-14 10:39:11 +03:00
1 parent fd0970c0ab
commit a844747b07
18 files changed
+718 -36

No files matched your search

+30
View File
@@ -307,6 +307,36 @@ One-shot (de)compression
.. versionchanged:: 3.3
Support for multi-stream inputs was added.
Miscellaneous
-------------
Information about the version of the bzip2 compression library
actually loaded by the interpreter is available through the following
constants.
The version used for building the module is not available,
because the bzip2 library does not provide it.
.. data:: bzlib_version
The version string of the bzip2 compression library
actually loaded by the interpreter.
.. versionadded:: next
.. data:: bzlib_version_info
A named tuple containing the three components of the bzip2 compression
library version actually loaded by the interpreter:
*major*, *minor*, and *patch*. All values are integers.
The components can also be accessed by name, so ``bz2.bzlib_version_info[0]``
is equivalent to ``bz2.bzlib_version_info.major`` and so on.
.. versionadded:: next
.. _bz2-usage-examples:
Examples of usage
+38 -3
View File
@@ -827,10 +827,45 @@ Miscellaneous
The default compression level for Zstandard: ``3``.
.. attribute:: zstd_version_info
Information about the version of the zstd library in use is available through
the following constants:
Version number of the runtime zstd library as a tuple of integers
(major, minor, release).
.. data:: ZSTD_VERSION
The version string of the zstd library that was used for building the module.
This may be different from the zstd library actually used at runtime, which
is available as :const:`zstd_version`.
.. versionadded:: next
.. data:: zstd_version
The version string of the zstd library actually loaded by the interpreter.
.. data:: ZSTD_VERSION_INFO
A named tuple containing the three components of the zstd library
version that was used for building the module:
*major*, *minor*, and *patch*. All values are integers.
The components can also be accessed by name, so ``zstd.ZSTD_VERSION_INFO[0]``
is equivalent to ``zstd.ZSTD_VERSION_INFO.major`` and so on.
This may be different from the zstd library actually used at runtime, which
is available as :const:`zstd_version_info`.
.. versionadded:: next
.. data:: zstd_version_info
A named tuple containing the version of the zstd library
actually loaded by the interpreter,
with the same fields as :const:`ZSTD_VERSION_INFO`.
.. versionchanged:: next
It is now a named tuple.
Examples
+44
View File
@@ -314,6 +314,50 @@ Miscellaneous
feature set.
Information about the version of the lzma library in use is available through
the following constants:
.. data:: LZMA_VERSION
The version string of the lzma library that was used for building the module.
This may be different from the lzma library actually used at runtime, which
is available as :const:`lzma_version`.
.. versionadded:: next
.. data:: lzma_version
The version string of the lzma library actually loaded by the interpreter.
.. versionadded:: next
.. data:: LZMA_VERSION_INFO
A named tuple containing the four components of the lzma library
version that was used for building the module:
*major*, *minor*, *patch*, and *stability*.
All values except *stability* are integers; *stability* is ``'alpha'``,
``'beta'``, or ``'stable'``.
The components can also be accessed by name, so ``lzma.LZMA_VERSION_INFO[0]``
is equivalent to ``lzma.LZMA_VERSION_INFO.major`` and so on.
This may be different from the lzma library actually used at runtime, which
is available as :const:`lzma_version_info`.
.. versionadded:: next
.. data:: lzma_version_info
A named tuple containing the version of the lzma library
actually loaded by the interpreter,
with the same fields as :const:`LZMA_VERSION_INFO`.
.. versionadded:: next
.. _filter-chain-specs:
Specifying custom filter chains
+43 -5
View File
@@ -479,27 +479,65 @@ the following constants:
The version string of the zlib library that was used for building the module.
This may be different from the zlib library actually used at runtime, which
is available as :const:`ZLIB_RUNTIME_VERSION`.
is available as :const:`zlib_version`.
.. data:: ZLIB_RUNTIME_VERSION
zlib_version
The version string of the zlib library actually loaded by the interpreter.
.. versionadded:: 3.3
The :const:`!ZLIB_RUNTIME_VERSION` constant.
.. versionadded:: next
The :const:`!zlib_version` alias.
.. data:: ZLIB_VERSION_INFO
A named tuple containing the four components of the zlib library
version that was used for building the module:
*major*, *minor*, *revision*, and *subversion*.
All values are integers.
The components can also be accessed by name, so ``zlib.ZLIB_VERSION_INFO[0]``
is equivalent to ``zlib.ZLIB_VERSION_INFO.major`` and so on.
This may be different from the zlib library actually used at runtime, which
is available as :const:`zlib_version_info`.
.. versionadded:: next
.. data:: zlib_version_info
A named tuple containing the version of the zlib library
actually loaded by the interpreter,
with the same fields as :const:`ZLIB_VERSION_INFO`.
.. versionadded:: next
The following constants are only present if zlib-ng was used to build
the module:
.. data:: ZLIBNG_VERSION
The version string of the zlib-ng library that was used for building the
module if zlib-ng was used. When present, the :data:`ZLIB_VERSION` and
:data:`ZLIB_RUNTIME_VERSION` constants reflect the version of the zlib API
module if zlib-ng was used. When present, the :const:`ZLIB_VERSION` and
:const:`zlib_version` constants reflect the version of the zlib API
provided by zlib-ng.
If zlib-ng was not used to build the module, this constant will be absent.
.. versionadded:: 3.14
.. data:: ZLIBNG_VERSION_INFO
A named tuple containing the three components of the zlib-ng library
version that was used for building the module:
*major*, *minor*, and *revision*. All values are integers.
.. versionadded:: next
.. seealso::
+31
View File
@@ -116,6 +116,13 @@ asyncio
socket file created for *path*.
(Contributed by Sam Bull in :gh:`94984`.)
bz2
---
* Added constants :const:`~bz2.bzlib_version` and
:const:`~bz2.bzlib_version_info` which provide information about
the version of the bzip2 compression library in use.
(Contributed by Serhiy Storchaka in :gh:`117404`.)
codecs
------
@@ -127,6 +134,14 @@ codecs
even when a built-in codec of the same name exists.
(Contributed by Serhiy Storchaka in :gh:`152997`.)
compression.zstd
----------------
* Added constants :const:`~compression.zstd.ZSTD_VERSION` and
:const:`~compression.zstd.ZSTD_VERSION_INFO` which provide information
about the version of the zstd library that was used for building the module.
:const:`~compression.zstd.zstd_version_info` is now a named tuple.
(Contributed by Serhiy Storchaka in :gh:`117404`.)
concurrent.futures
------------------
@@ -439,6 +454,11 @@ lzma
requires ``lzma`` 5.4.0 or newer while RISC-V requires 5.6.0 or newer.
(Contributed by Chien Wong in :gh:`115988`.)
* Added constants :const:`~lzma.LZMA_VERSION`, :const:`~lzma.lzma_version`,
:const:`~lzma.LZMA_VERSION_INFO`, and :const:`~lzma.lzma_version_info`,
which provide information about the version of the lzma library in use.
(Contributed by Serhiy Storchaka in :gh:`117404`.)
math
----
@@ -747,6 +767,17 @@ zipfile
by the local file entries of removed members.
(Contributed by Danny Lin in :gh:`51067`.)
zlib
----
* Added constants :const:`~zlib.ZLIB_VERSION_INFO`,
:const:`~zlib.zlib_version_info`, and :const:`~zlib.ZLIBNG_VERSION_INFO`,
which provide information about the version of the zlib and the zlib-ng
libraries in use.
Added :const:`~zlib.zlib_version` as an alias of
:const:`~zlib.ZLIB_RUNTIME_VERSION`.
(Contributed by Serhiy Storchaka in :gh:`117404`.)
.. Add improved modules above alphabetically, not here at the end.
Optimizations
+4 -2
View File
@@ -5,7 +5,8 @@ This module provides a file interface, classes for incremental
"""
__all__ = ["BZ2File", "BZ2Compressor", "BZ2Decompressor",
"open", "compress", "decompress"]
"open", "compress", "decompress",
"bzlib_version", "bzlib_version_info"]
__author__ = "Nadeem Vawda <nadeem.vawda@gmail.com>"
@@ -14,7 +15,8 @@ from compression._common import _streams
import io
import os
from _bz2 import BZ2Compressor, BZ2Decompressor
from _bz2 import (BZ2Compressor, BZ2Decompressor,
bzlib_version, bzlib_version_info)
# Value 0 no longer used
+4 -5
View File
@@ -20,6 +20,8 @@ __all__ = (
'get_frame_size',
'zstd_version',
'zstd_version_info',
'ZSTD_VERSION',
'ZSTD_VERSION_INFO',
'ZstdCompressor',
'ZstdDecompressor',
'ZstdDict',
@@ -29,13 +31,10 @@ __all__ = (
import _zstd
import enum
from _zstd import (ZstdCompressor, ZstdDecompressor, ZstdDict, ZstdError,
get_frame_size, zstd_version)
get_frame_size, zstd_version, ZSTD_VERSION,
zstd_version_info, ZSTD_VERSION_INFO)
from compression.zstd._zstdfile import ZstdFile, open, _nbytes
# zstd_version_number is (MAJOR * 100 * 100 + MINOR * 100 + RELEASE)
zstd_version_info = (*divmod(_zstd.zstd_version_number // 100, 100),
_zstd.zstd_version_number % 100)
"""Version number of the runtime zstd library as a tuple of integers."""
COMPRESSION_LEVEL_DEFAULT = _zstd.ZSTD_CLEVEL_DEFAULT
"""The default compression level for Zstandard, currently '3'."""
+1
View File
@@ -20,6 +20,7 @@ __all__ = [
"LZMACompressor", "LZMADecompressor", "LZMAFile", "LZMAError",
"open", "compress", "decompress", "is_check_supported",
"lzma_version", "lzma_version_info", "LZMA_VERSION", "LZMA_VERSION_INFO",
]
import builtins
+24 -2
View File
@@ -711,17 +711,37 @@ def collect_zlib(info_add):
except ImportError:
return
attributes = ('ZLIB_VERSION', 'ZLIB_RUNTIME_VERSION', 'ZLIBNG_VERSION')
attributes = ('ZLIB_VERSION', 'zlib_version', 'ZLIBNG_VERSION')
copy_attributes(info_add, zlib, 'zlib.%s', attributes)
def collect_bz2(info_add):
try:
import _bz2
except ImportError:
return
attributes = ('bzlib_version',)
copy_attributes(info_add, _bz2, 'bz2.%s', attributes)
def collect_lzma(info_add):
try:
import _lzma
except ImportError:
return
attributes = ('LZMA_VERSION', 'lzma_version')
copy_attributes(info_add, _lzma, 'lzma.%s', attributes)
def collect_zstd(info_add):
try:
import _zstd
except ImportError:
return
attributes = ('zstd_version',)
attributes = ('ZSTD_VERSION', 'zstd_version')
copy_attributes(info_add, _zstd, 'zstd.%s', attributes)
@@ -1328,6 +1348,7 @@ def collect_info(info):
collect_urandom,
collect_builtins,
collect_bz2,
collect_cc,
collect_curses,
collect_datetime,
@@ -1338,6 +1359,7 @@ def collect_info(info):
collect_gdbm,
collect_get_config,
collect_locale,
collect_lzma,
collect_os,
collect_platform,
collect_pwd,
+27
View File
@@ -1222,6 +1222,33 @@ class OpenTest(BaseTest):
self.assertEqual(f.readlines(), [text])
class MiscTests(unittest.TestCase):
def test_bzlib_version(self):
if support.verbose:
print(f'bzlib_version = {bz2.bzlib_version}', flush=True)
print(f'bzlib_version_info = {bz2.bzlib_version_info}', flush=True)
v = bz2.bzlib_version_info
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 3)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.patch, int)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.patch)
self.assertGreaterEqual(v.major, 0)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.patch, 0)
# The version string can have a suffix, e.g. "1.0.8, 13-Jul-2019"
# for bzip2 or "1.1.0-libbz2-rs-sys-0.2.5" for libbz2-rs.
self.assertStartsWith(bz2.bzlib_version, '%d.%d.%d' % v)
def tearDownModule():
support.reap_children()
+35
View File
@@ -1513,6 +1513,41 @@ class OpenTestCase(unittest.TestCase):
class MiscellaneousTestCase(unittest.TestCase):
def _test_lzma_version(self, v, string):
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 4)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v[3], str)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.patch, int)
self.assertIsInstance(v.stability, str)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.patch)
self.assertEqual(v[3], v.stability)
self.assertGreaterEqual(v.major, 0)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.patch, 0)
self.assertIn(v.stability, {'alpha', 'beta', 'stable'})
if v.stability == 'stable':
self.assertEqual(string, '%d.%d.%d' % v[:3])
else:
self.assertStartsWith(string, '%d.%d.%d%s' % v)
def test_lzma_version(self):
if support.verbose:
print(f'LZMA_VERSION = {lzma.LZMA_VERSION}', flush=True)
print(f'lzma_version = {lzma.lzma_version}', flush=True)
print(f'LZMA_VERSION_INFO = {lzma.LZMA_VERSION_INFO}', flush=True)
print(f'lzma_version_info = {lzma.lzma_version_info}', flush=True)
self._test_lzma_version(lzma.LZMA_VERSION_INFO, lzma.LZMA_VERSION)
self._test_lzma_version(lzma.lzma_version_info, lzma.lzma_version)
self.assertEqual(lzma.LZMA_VERSION_INFO[0], lzma.lzma_version_info[0])
def test_is_check_supported(self):
# CHECK_NONE and CHECK_CRC32 should always be supported,
# regardless of the options liblzma was compiled with.
+71 -11
View File
@@ -19,20 +19,17 @@ requires_Decompress_copy = unittest.skipUnless(
'requires Decompress.copy()')
def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION):
def _parse_version(version):
# Register "1.2.3" as "1.2.3.0"
# or "1.2.0-linux","1.2.0.f","1.2.0.f-linux"
v = zlib_version.split('-', 1)[0].split('.')
if len(v) < 4:
v = version.split('-', 1)[0].split('.')
if not v[-1].isnumeric():
v.pop()
while len(v) < 4:
v.append('0')
elif not v[-1].isnumeric():
v[-1] = '0'
return tuple(map(int, v))
ZLIB_RUNTIME_VERSION_TUPLE = _zlib_runtime_version_tuple()
# bpo-46623: When a hardware accelerator is used (currently only on s390x),
# using different ways to compress data with zlib can produce different
# compressed data.
@@ -71,7 +68,70 @@ class VersionTestCase(unittest.TestCase):
# the minor versions will match (even on the machine on which the module
# was compiled), and the API is stable between minor versions, so
# testing only the major versions avoids spurious failures.
self.assertEqual(zlib.ZLIB_RUNTIME_VERSION[0], zlib.ZLIB_VERSION[0])
self.assertEqual(zlib.zlib_version.split('.')[0],
zlib.ZLIB_VERSION.split('.')[0])
self.assertEqual(zlib.zlib_version_info[0],
zlib.ZLIB_VERSION_INFO[0])
def _test_zlib_version(self, v):
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 4)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v[3], int)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.revision, int)
self.assertIsInstance(v.subversion, int)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.revision)
self.assertEqual(v[3], v.subversion)
self.assertGreaterEqual(v.major, 0)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.revision, 0)
self.assertGreaterEqual(v.subversion, 0)
def test_zlib_version(self):
if support.verbose:
print(f'ZLIB_VERSION = {zlib.ZLIB_VERSION}', flush=True)
print(f'zlib_version = {zlib.zlib_version}', flush=True)
print(f'ZLIB_VERSION_INFO = {zlib.ZLIB_VERSION_INFO}', flush=True)
print(f'zlib_version_info = {zlib.zlib_version_info}', flush=True)
self._test_zlib_version(zlib.ZLIB_VERSION_INFO)
self.assertEqual(zlib.ZLIB_VERSION_INFO,
_parse_version(zlib.ZLIB_VERSION))
self._test_zlib_version(zlib.zlib_version_info)
self.assertEqual(zlib.zlib_version_info,
_parse_version(zlib.zlib_version))
self.assertEqual(zlib.ZLIB_RUNTIME_VERSION, zlib.zlib_version)
def _test_zlibng_version(self, v):
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 3)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.revision, int)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.revision)
self.assertGreaterEqual(v.major, 0)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.revision, 0)
@unittest.skipUnless(hasattr(zlib, 'ZLIBNG_VERSION'), 'requires zlib-ng')
def test_zlibng_version(self):
if support.verbose:
print(f'ZLIBNG_VERSION = {zlib.ZLIBNG_VERSION}', flush=True)
print(f'ZLIBNG_VERSION_INFO = {zlib.ZLIBNG_VERSION_INFO}',
flush=True)
self._test_zlibng_version(zlib.ZLIBNG_VERSION_INFO)
self.assertEqual(zlib.ZLIBNG_VERSION,
'%d.%d.%d' % zlib.ZLIBNG_VERSION_INFO)
class ChecksumTestCase(unittest.TestCase):
@@ -607,7 +667,7 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
'Z_PARTIAL_FLUSH']
# Z_BLOCK has a known failure prior to 1.2.5.3
if ZLIB_RUNTIME_VERSION_TUPLE >= (1, 2, 5, 3):
if zlib.zlib_version_info >= (1, 2, 5, 3):
sync_opt.append('Z_BLOCK')
sync_opt = [getattr(zlib, opt) for opt in sync_opt
@@ -935,7 +995,7 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
def test_wbits(self):
# wbits=0 only supported since zlib v1.2.3.5
supports_wbits_0 = ZLIB_RUNTIME_VERSION_TUPLE >= (1, 2, 3, 5)
supports_wbits_0 = zlib.zlib_version_info >= (1, 2, 3, 5)
co = zlib.compressobj(level=1, wbits=15)
zlib15 = co.compress(HAMLET_SCENE) + co.flush()
+28 -5
View File
@@ -9,6 +9,7 @@ import unittest
import tempfile
import threading
from test import support
from test.support.import_helper import import_module
from test.support import threading_helper
from test.support import _1M
@@ -24,8 +25,6 @@ from compression.zstd import (
ZstdDecompressor,
ZstdDict,
ZstdError,
zstd_version,
zstd_version_info,
COMPRESSION_LEVEL_DEFAULT,
get_frame_info,
get_frame_size,
@@ -133,9 +132,33 @@ def setUpModule():
class FunctionsTestCase(unittest.TestCase):
def test_version(self):
s = ".".join((str(i) for i in zstd_version_info))
self.assertEqual(s, zstd_version)
def _test_zstd_version(self, v, string):
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 3)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.patch, int)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.patch)
self.assertGreaterEqual(v.major, 0)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.patch, 0)
self.assertEqual(string, '%d.%d.%d' % v)
def test_zstd_version(self):
if support.verbose:
print(f'ZSTD_VERSION = {zstd.ZSTD_VERSION}', flush=True)
print(f'zstd_version = {zstd.zstd_version}', flush=True)
print(f'ZSTD_VERSION_INFO = {zstd.ZSTD_VERSION_INFO}', flush=True)
print(f'zstd_version_info = {zstd.zstd_version_info}', flush=True)
self._test_zstd_version(zstd.ZSTD_VERSION_INFO, zstd.ZSTD_VERSION)
self._test_zstd_version(zstd.zstd_version_info, zstd.zstd_version)
self.assertEqual(zstd.ZSTD_VERSION_INFO[0], zstd.zstd_version_info[0])
def test_compressionLevel_values(self):
min, max = CompressionParameter.compression_level.bounds()
@@ -0,0 +1,5 @@
Add a number of constants in modules :mod:`zlib`, :mod:`bz2`, :mod:`lzma`,
and :mod:`compression.zstd`, which provide information about the version of
libraries that were used for building the module and that are actually
loaded.
Make :const:`compression.zstd.zstd_version_info` a named tuple.
+73
View File
@@ -747,6 +747,61 @@ static PyType_Spec bz2_decompressor_type_spec = {
.slots = bz2_decompressor_type_slots,
};
PyDoc_STRVAR(bzlib_version_info__doc__,
"_bz2.bzlib_version_info\n\
\n\
Bzlib version information as a named tuple.");
static PyStructSequence_Field bzlib_version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"patch", "Patch release number"},
{0}
};
static PyStructSequence_Desc bzlib_version_info_desc = {
"_bz2.bzlib_version_info", /* name */
bzlib_version_info__doc__, /* doc */
bzlib_version_info_fields, /* fields */
3
};
/* BZ2_bzlibVersion() returns a string with a trailing suffix, for example
"1.0.8, 13-Jul-2019" for bzip2 or "1.1.0-libbz2-rs-sys-0.2.5" for
libbz2-rs. sscanf() stops at the suffix; components which were not
parsed are left zero. This is deliberate -- a zero is more useful
here than a hard error. */
static PyObject *
make_bzlib_version_info(PyTypeObject *type, const char *string)
{
PyObject *version;
int pos = 0;
unsigned int major = 0, minor = 0, patch = 0;
sscanf(string, "%u.%u.%u", &major, &minor, &patch);
version = PyStructSequence_New(type);
if (version == NULL) {
return NULL;
}
#define SetIntItem(VALUE) \
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromUnsignedLong(VALUE)); \
if (PyErr_Occurred()) { \
Py_DECREF(version); \
return NULL; \
}
SetIntItem(major)
SetIntItem(minor)
SetIntItem(patch)
#undef SetIntItem
return version;
}
/* Module initialization. */
static int
@@ -771,6 +826,24 @@ _bz2_exec(PyObject *module)
return -1;
}
/* bzlib_version */
if (PyModule_Add(module, "bzlib_version",
PyUnicode_FromString(BZ2_bzlibVersion())) < 0)
{
return -1;
}
PyTypeObject *version_type;
version_type = PyStructSequence_NewType(&bzlib_version_info_desc);
if (version_type == NULL) {
return -1;
}
if (PyModule_Add(module, "bzlib_version_info",
make_bzlib_version_info(version_type, BZ2_bzlibVersion())) < 0)
{
Py_DECREF(version_type);
return -1;
}
Py_DECREF(version_type);
return 0;
}
+83
View File
@@ -1509,6 +1509,62 @@ _lzma__decode_filter_properties_impl(PyObject *module, lzma_vli filter_id,
return result;
}
PyDoc_STRVAR(lzma_version_info__doc__,
"_lzma.lzma_version_info\n\
\n\
Lzma version information as a named tuple.");
static PyStructSequence_Field lzma_version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"patch", "Patch release number"},
{"stability", "'alpha', 'beta', or 'stable'"},
{0}
};
static PyStructSequence_Desc lzma_version_info_desc = {
"_lzma.lzma_version_info", /* name */
lzma_version_info__doc__, /* doc */
lzma_version_info_fields, /* fields */
4
};
static PyObject *
make_lzma_version_info(PyTypeObject *type, unsigned int number)
{
PyObject *version;
int pos = 0;
unsigned int major = number / 10000000u;
unsigned int minor = (number % 10000000u) / 10000u;
unsigned int patch = (number % 10000u) / 10u;
unsigned int stability = number % 10u;
const char *stability_string = (stability == 0) ? "alpha"
: (stability == 1) ? "beta"
: "stable";
version = PyStructSequence_New(type);
if (version == NULL) {
return NULL;
}
#define SetItem(VALUE) \
PyStructSequence_SET_ITEM(version, pos++, VALUE); \
if (PyErr_Occurred()) { \
Py_DECREF(version); \
return NULL; \
}
SetItem(PyLong_FromUnsignedLong(major))
SetItem(PyLong_FromUnsignedLong(minor))
SetItem(PyLong_FromUnsignedLong(patch))
SetItem(PyUnicode_FromString(stability_string))
#undef SetItem
return version;
}
/* Some of our constants are more than 32 bits wide, so PyModule_AddIntConstant
would not work correctly on platforms with 32-bit longs. */
static int
@@ -1603,6 +1659,33 @@ lzma_exec(PyObject *module)
return -1;
}
/* lzma_version */
if (PyModule_Add(module, "LZMA_VERSION",
PyUnicode_FromString(LZMA_VERSION_STRING)) < 0) {
return -1;
}
if (PyModule_Add(module, "lzma_version",
PyUnicode_FromString(lzma_version_string())) < 0) {
return -1;
}
PyTypeObject *version_type;
version_type = PyStructSequence_NewType(&lzma_version_info_desc);
if (version_type == NULL) {
return -1;
}
if (PyModule_Add(module, "LZMA_VERSION_INFO",
make_lzma_version_info(version_type, LZMA_VERSION)) < 0)
{
Py_DECREF(version_type);
return -1;
}
if (PyModule_Add(module, "lzma_version_info",
make_lzma_version_info(version_type, lzma_version_number())) < 0)
{
Py_DECREF(version_type);
return -1;
}
Py_DECREF(version_type);
return 0;
}
+69 -3
View File
@@ -567,6 +567,55 @@ static PyMethodDef _zstd_methods[] = {
{NULL, NULL}
};
PyDoc_STRVAR(zstd_version_info__doc__,
"_zstd.zstd_version_info\n\
\n\
Zstd version information as a named tuple.");
static PyStructSequence_Field zstd_version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"patch", "Patch release number"},
{0}
};
static PyStructSequence_Desc zstd_version_info_desc = {
"_zstd.zstd_version_info", /* name */
zstd_version_info__doc__, /* doc */
zstd_version_info_fields, /* fields */
3
};
static PyObject *
make_zstd_version_info(PyTypeObject *type, unsigned int number)
{
PyObject *version;
int pos = 0;
unsigned int major = number / 10000u;
unsigned int minor = (number % 10000u) / 100u;
unsigned int patch = number % 100u;
version = PyStructSequence_New(type);
if (version == NULL) {
return NULL;
}
#define SetIntItem(VALUE) \
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromUnsignedLong(VALUE)); \
if (PyErr_Occurred()) { \
Py_DECREF(version); \
return NULL; \
}
SetIntItem(major)
SetIntItem(minor)
SetIntItem(patch)
#undef SetIntItem
return version;
}
static int
_zstd_exec(PyObject *m)
{
@@ -619,15 +668,32 @@ do { \
}
/* Add constants */
if (PyModule_AddIntConstant(m, "zstd_version_number",
ZSTD_versionNumber()) < 0) {
if (PyModule_AddStringConstant(m, "ZSTD_VERSION",
ZSTD_VERSION_STRING) < 0) {
return -1;
}
if (PyModule_AddStringConstant(m, "zstd_version",
ZSTD_versionString()) < 0) {
return -1;
}
PyTypeObject *version_type;
version_type = PyStructSequence_NewType(&zstd_version_info_desc);
if (version_type == NULL) {
return -1;
}
if (PyModule_Add(m, "ZSTD_VERSION_INFO",
make_zstd_version_info(version_type, ZSTD_VERSION_NUMBER)) < 0)
{
Py_DECREF(version_type);
return -1;
}
if (PyModule_Add(m, "zstd_version_info",
make_zstd_version_info(version_type, ZSTD_versionNumber())) < 0)
{
Py_DECREF(version_type);
return -1;
}
Py_DECREF(version_type);
#if ZSTD_VERSION_NUMBER >= 10500
if (PyModule_AddIntConstant(m, "ZSTD_CLEVEL_DEFAULT",
+108
View File
@@ -2077,6 +2077,77 @@ zlib_getattr(PyObject *self, PyObject *args)
return NULL;
}
PyDoc_STRVAR(zlib_version_info__doc__,
"zlib.zlib_version_info\n\
\n\
Zlib version information as a named tuple.");
static PyStructSequence_Field zlib_version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"revision", "Revision release number"},
{"subversion", "Subversion release number"},
{0}
};
static PyStructSequence_Desc zlib_version_info_desc = {
"zlib.zlib_version_info", /* name */
zlib_version_info__doc__, /* doc */
zlib_version_info_fields, /* fields */
4
};
#ifdef ZLIBNG_VERSION
PyDoc_STRVAR(zlibng_version_info__doc__,
"zlib.zlibng_version_info\n\
\n\
Zlib-ng version information as a named tuple.");
static PyStructSequence_Field zlibng_version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"revision", "Revision release number"},
{0}
};
static PyStructSequence_Desc zlibng_version_info_desc = {
"zlib.zlibng_version_info", /* name */
zlibng_version_info__doc__, /* doc */
zlibng_version_info_fields, /* fields */
3
};
#endif // ZLIBNG_VERSION
/* Create a named tuple from the first *size* components of a version string
like "1.2.11" or "1.2.11.1". sscanf() is expected to fail on trailing
garbage and on versions with fewer components (for example "1.2.0.f" or
"1.3.1.zlib-ng"); the components which were not parsed are left zero.
This is deliberate -- a zero is more useful here than a hard error. */
static PyObject *
make_version_info(PyTypeObject *type, const char *string, Py_ssize_t size)
{
unsigned int components[4] = {0, 0, 0, 0};
assert(size <= (Py_ssize_t)Py_ARRAY_LENGTH(components));
sscanf(string, "%u.%u.%u.%u",
&components[0], &components[1], &components[2], &components[3]);
PyObject *version = PyStructSequence_New(type);
if (version == NULL) {
return NULL;
}
for (Py_ssize_t i = 0; i < size; i++) {
PyObject *item = PyLong_FromUnsignedLong(components[i]);
if (item == NULL) {
Py_DECREF(version);
return NULL;
}
PyStructSequence_SET_ITEM(version, i, item);
}
return version;
}
static PyMethodDef zlib_methods[] =
{
ZLIB_ADLER32_METHODDEF
@@ -2272,10 +2343,16 @@ zlib_exec(PyObject *mod)
#ifdef Z_TREES // 1.2.3.4, only for inflate
ZLIB_ADD_INT_MACRO(Z_TREES);
#endif
/* zlib_version */
if (PyModule_Add(mod, "ZLIB_VERSION",
PyUnicode_FromString(ZLIB_VERSION)) < 0) {
return -1;
}
if (PyModule_Add(mod, "zlib_version",
PyUnicode_FromString(zlibVersion())) < 0) {
return -1;
}
if (PyModule_Add(mod, "ZLIB_RUNTIME_VERSION",
PyUnicode_FromString(zlibVersion())) < 0) {
return -1;
@@ -2285,6 +2362,37 @@ zlib_exec(PyObject *mod)
PyUnicode_FromString(ZLIBNG_VERSION)) < 0) {
return -1;
}
#endif
PyTypeObject *version_type;
version_type = PyStructSequence_NewType(&zlib_version_info_desc);
if (version_type == NULL) {
return -1;
}
if (PyModule_Add(mod, "ZLIB_VERSION_INFO",
make_version_info(version_type, ZLIB_VERSION, 4)) < 0)
{
Py_DECREF(version_type);
return -1;
}
if (PyModule_Add(mod, "zlib_version_info",
make_version_info(version_type, zlibVersion(), 4)) < 0)
{
Py_DECREF(version_type);
return -1;
}
Py_DECREF(version_type);
#ifdef ZLIBNG_VERSION
version_type = PyStructSequence_NewType(&zlibng_version_info_desc);
if (version_type == NULL) {
return -1;
}
if (PyModule_Add(mod, "ZLIBNG_VERSION_INFO",
make_version_info(version_type, ZLIBNG_VERSION, 3)) < 0)
{
Py_DECREF(version_type);
return -1;
}
Py_DECREF(version_type);
#endif
return 0;
}