mirror of
https://github.com/python/cpython.git
synced 2026-10-28 18:35:21 +08:00
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:
1 parent
fd0970c0ab
commit
a844747b07
18 files changed
+718
-36
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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::
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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'."""
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user