mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-132983: Add the compression.zstd
pacakge and tests (#133365)
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg@krypto.org> Co-authored-by: Tomas R. <tomas.roun8@gmail.com> Co-authored-by: Rogdham <contact@rogdham.net>
This commit is contained in:
parent
793402e217
commit
c273f59fb3
15 changed files with 3358 additions and 100 deletions
234
Lib/compression/zstd/__init__.py
Normal file
234
Lib/compression/zstd/__init__.py
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
"""Python bindings to the Zstandard (zstd) compression library (RFC-8878)."""
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
# compression.zstd
|
||||||
|
"COMPRESSION_LEVEL_DEFAULT",
|
||||||
|
"compress",
|
||||||
|
"CompressionParameter",
|
||||||
|
"decompress",
|
||||||
|
"DecompressionParameter",
|
||||||
|
"finalize_dict",
|
||||||
|
"get_frame_info",
|
||||||
|
"Strategy",
|
||||||
|
"train_dict",
|
||||||
|
|
||||||
|
# compression.zstd._zstdfile
|
||||||
|
"open",
|
||||||
|
"ZstdFile",
|
||||||
|
|
||||||
|
# _zstd
|
||||||
|
"get_frame_size",
|
||||||
|
"zstd_version",
|
||||||
|
"zstd_version_info",
|
||||||
|
"ZstdCompressor",
|
||||||
|
"ZstdDecompressor",
|
||||||
|
"ZstdDict",
|
||||||
|
"ZstdError",
|
||||||
|
)
|
||||||
|
|
||||||
|
import _zstd
|
||||||
|
import enum
|
||||||
|
from _zstd import *
|
||||||
|
from compression.zstd._zstdfile import ZstdFile, open, _nbytes
|
||||||
|
|
||||||
|
COMPRESSION_LEVEL_DEFAULT = _zstd._compressionLevel_values[0]
|
||||||
|
"""The default compression level for Zstandard, currently '3'."""
|
||||||
|
|
||||||
|
|
||||||
|
class FrameInfo:
|
||||||
|
"""Information about a Zstandard frame."""
|
||||||
|
__slots__ = 'decompressed_size', 'dictionary_id'
|
||||||
|
|
||||||
|
def __init__(self, decompressed_size, dictionary_id):
|
||||||
|
super().__setattr__('decompressed_size', decompressed_size)
|
||||||
|
super().__setattr__('dictionary_id', dictionary_id)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return (f'FrameInfo(decompressed_size={self.decompressed_size}, '
|
||||||
|
f'dictionary_id={self.dictionary_id})')
|
||||||
|
|
||||||
|
def __setattr__(self, name, _):
|
||||||
|
raise AttributeError(f"can't set attribute {name!r}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_frame_info(frame_buffer):
|
||||||
|
"""Get Zstandard frame information from a frame header.
|
||||||
|
|
||||||
|
*frame_buffer* is a bytes-like object. It should start from the beginning
|
||||||
|
of a frame, and needs to include at least the frame header (6 to 18 bytes).
|
||||||
|
|
||||||
|
The returned FrameInfo object has two attributes.
|
||||||
|
'decompressed_size' is the size in bytes of the data in the frame when
|
||||||
|
decompressed, or None when the decompressed size is unknown.
|
||||||
|
'dictionary_id' is an int in the range (0, 2**32). The special value 0
|
||||||
|
means that the dictionary ID was not recorded in the frame header,
|
||||||
|
the frame may or may not need a dictionary to be decoded,
|
||||||
|
and the ID of such a dictionary is not specified.
|
||||||
|
"""
|
||||||
|
return FrameInfo(*_zstd._get_frame_info(frame_buffer))
|
||||||
|
|
||||||
|
|
||||||
|
def train_dict(samples, dict_size):
|
||||||
|
"""Return a ZstdDict representing a trained Zstandard dictionary.
|
||||||
|
|
||||||
|
*samples* is an iterable of samples, where a sample is a bytes-like
|
||||||
|
object representing a file.
|
||||||
|
|
||||||
|
*dict_size* is the dictionary's maximum size, in bytes.
|
||||||
|
"""
|
||||||
|
if not isinstance(dict_size, int):
|
||||||
|
ds_cls = type(dict_size).__qualname__
|
||||||
|
raise TypeError(f'dict_size must be an int object, not {ds_cls!r}.')
|
||||||
|
|
||||||
|
samples = tuple(samples)
|
||||||
|
chunks = b''.join(samples)
|
||||||
|
chunk_sizes = tuple(_nbytes(sample) for sample in samples)
|
||||||
|
if not chunks:
|
||||||
|
raise ValueError("samples contained no data; can't train dictionary.")
|
||||||
|
dict_content = _zstd._train_dict(chunks, chunk_sizes, dict_size)
|
||||||
|
return ZstdDict(dict_content)
|
||||||
|
|
||||||
|
|
||||||
|
def finalize_dict(zstd_dict, /, samples, dict_size, level):
|
||||||
|
"""Return a ZstdDict representing a finalized Zstandard dictionary.
|
||||||
|
|
||||||
|
Given a custom content as a basis for dictionary, and a set of samples,
|
||||||
|
finalize *zstd_dict* by adding headers and statistics according to the
|
||||||
|
Zstandard dictionary format.
|
||||||
|
|
||||||
|
You may compose an effective dictionary content by hand, which is used as
|
||||||
|
basis dictionary, and use some samples to finalize a dictionary. The basis
|
||||||
|
dictionary may be a "raw content" dictionary. See *is_raw* in ZstdDict.
|
||||||
|
|
||||||
|
*samples* is an iterable of samples, where a sample is a bytes-like object
|
||||||
|
representing a file.
|
||||||
|
*dict_size* is the dictionary's maximum size, in bytes.
|
||||||
|
*level* is the expected compression level. The statistics for each
|
||||||
|
compression level differ, so tuning the dictionary to the compression level
|
||||||
|
can provide improvements.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(zstd_dict, ZstdDict):
|
||||||
|
raise TypeError('zstd_dict argument should be a ZstdDict object.')
|
||||||
|
if not isinstance(dict_size, int):
|
||||||
|
raise TypeError('dict_size argument should be an int object.')
|
||||||
|
if not isinstance(level, int):
|
||||||
|
raise TypeError('level argument should be an int object.')
|
||||||
|
|
||||||
|
samples = tuple(samples)
|
||||||
|
chunks = b''.join(samples)
|
||||||
|
chunk_sizes = tuple(_nbytes(sample) for sample in samples)
|
||||||
|
if not chunks:
|
||||||
|
raise ValueError("The samples are empty content, can't finalize the"
|
||||||
|
"dictionary.")
|
||||||
|
dict_content = _zstd._finalize_dict(zstd_dict.dict_content,
|
||||||
|
chunks, chunk_sizes,
|
||||||
|
dict_size, level)
|
||||||
|
return ZstdDict(dict_content)
|
||||||
|
|
||||||
|
def compress(data, level=None, options=None, zstd_dict=None):
|
||||||
|
"""Return Zstandard compressed *data* as bytes.
|
||||||
|
|
||||||
|
*level* is an int specifying the compression level to use, defaulting to
|
||||||
|
COMPRESSION_LEVEL_DEFAULT ('3').
|
||||||
|
*options* is a dict object that contains advanced compression
|
||||||
|
parameters. See CompressionParameter for more on options.
|
||||||
|
*zstd_dict* is a ZstdDict object, a pre-trained Zstandard dictionary. See
|
||||||
|
the function train_dict for how to train a ZstdDict on sample data.
|
||||||
|
|
||||||
|
For incremental compression, use a ZstdCompressor instead.
|
||||||
|
"""
|
||||||
|
comp = ZstdCompressor(level=level, options=options, zstd_dict=zstd_dict)
|
||||||
|
return comp.compress(data, mode=ZstdCompressor.FLUSH_FRAME)
|
||||||
|
|
||||||
|
def decompress(data, zstd_dict=None, options=None):
|
||||||
|
"""Decompress one or more frames of Zstandard compressed *data*.
|
||||||
|
|
||||||
|
*zstd_dict* is a ZstdDict object, a pre-trained Zstandard dictionary. See
|
||||||
|
the function train_dict for how to train a ZstdDict on sample data.
|
||||||
|
*options* is a dict object that contains advanced compression
|
||||||
|
parameters. See DecompressionParameter for more on options.
|
||||||
|
|
||||||
|
For incremental decompression, use a ZstdDecompressor instead.
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
while True:
|
||||||
|
decomp = ZstdDecompressor(options=options, zstd_dict=zstd_dict)
|
||||||
|
results.append(decomp.decompress(data))
|
||||||
|
if not decomp.eof:
|
||||||
|
raise ZstdError("Compressed data ended before the "
|
||||||
|
"end-of-stream marker was reached")
|
||||||
|
data = decomp.unused_data
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
return b"".join(results)
|
||||||
|
|
||||||
|
|
||||||
|
class CompressionParameter(enum.IntEnum):
|
||||||
|
"""Compression parameters."""
|
||||||
|
|
||||||
|
compression_level = _zstd._ZSTD_c_compressionLevel
|
||||||
|
window_log = _zstd._ZSTD_c_windowLog
|
||||||
|
hash_log = _zstd._ZSTD_c_hashLog
|
||||||
|
chain_log = _zstd._ZSTD_c_chainLog
|
||||||
|
search_log = _zstd._ZSTD_c_searchLog
|
||||||
|
min_match = _zstd._ZSTD_c_minMatch
|
||||||
|
target_length = _zstd._ZSTD_c_targetLength
|
||||||
|
strategy = _zstd._ZSTD_c_strategy
|
||||||
|
|
||||||
|
enable_long_distance_matching = _zstd._ZSTD_c_enableLongDistanceMatching
|
||||||
|
ldm_hash_log = _zstd._ZSTD_c_ldmHashLog
|
||||||
|
ldm_min_match = _zstd._ZSTD_c_ldmMinMatch
|
||||||
|
ldm_bucket_size_log = _zstd._ZSTD_c_ldmBucketSizeLog
|
||||||
|
ldm_hash_rate_log = _zstd._ZSTD_c_ldmHashRateLog
|
||||||
|
|
||||||
|
content_size_flag = _zstd._ZSTD_c_contentSizeFlag
|
||||||
|
checksum_flag = _zstd._ZSTD_c_checksumFlag
|
||||||
|
dict_id_flag = _zstd._ZSTD_c_dictIDFlag
|
||||||
|
|
||||||
|
nb_workers = _zstd._ZSTD_c_nbWorkers
|
||||||
|
job_size = _zstd._ZSTD_c_jobSize
|
||||||
|
overlap_log = _zstd._ZSTD_c_overlapLog
|
||||||
|
|
||||||
|
def bounds(self):
|
||||||
|
"""Return the (lower, upper) int bounds of a compression parameter.
|
||||||
|
|
||||||
|
Both the lower and upper bounds are inclusive.
|
||||||
|
"""
|
||||||
|
return _zstd._get_param_bounds(self.value, is_compress=True)
|
||||||
|
|
||||||
|
|
||||||
|
class DecompressionParameter(enum.IntEnum):
|
||||||
|
"""Decompression parameters."""
|
||||||
|
|
||||||
|
window_log_max = _zstd._ZSTD_d_windowLogMax
|
||||||
|
|
||||||
|
def bounds(self):
|
||||||
|
"""Return the (lower, upper) int bounds of a decompression parameter.
|
||||||
|
|
||||||
|
Both the lower and upper bounds are inclusive.
|
||||||
|
"""
|
||||||
|
return _zstd._get_param_bounds(self.value, is_compress=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Strategy(enum.IntEnum):
|
||||||
|
"""Compression strategies, listed from fastest to strongest.
|
||||||
|
|
||||||
|
Note that new strategies might be added in the future.
|
||||||
|
Only the order (from fast to strong) is guaranteed,
|
||||||
|
the numeric value might change.
|
||||||
|
"""
|
||||||
|
|
||||||
|
fast = _zstd._ZSTD_fast
|
||||||
|
dfast = _zstd._ZSTD_dfast
|
||||||
|
greedy = _zstd._ZSTD_greedy
|
||||||
|
lazy = _zstd._ZSTD_lazy
|
||||||
|
lazy2 = _zstd._ZSTD_lazy2
|
||||||
|
btlazy2 = _zstd._ZSTD_btlazy2
|
||||||
|
btopt = _zstd._ZSTD_btopt
|
||||||
|
btultra = _zstd._ZSTD_btultra
|
||||||
|
btultra2 = _zstd._ZSTD_btultra2
|
||||||
|
|
||||||
|
|
||||||
|
# Check validity of the CompressionParameter & DecompressionParameter types
|
||||||
|
_zstd._set_parameter_types(CompressionParameter, DecompressionParameter)
|
349
Lib/compression/zstd/_zstdfile.py
Normal file
349
Lib/compression/zstd/_zstdfile.py
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
import io
|
||||||
|
from os import PathLike
|
||||||
|
from _zstd import (ZstdCompressor, ZstdDecompressor, _ZSTD_DStreamSizes,
|
||||||
|
ZstdError)
|
||||||
|
from compression._common import _streams
|
||||||
|
|
||||||
|
__all__ = ("ZstdFile", "open")
|
||||||
|
|
||||||
|
_ZSTD_DStreamOutSize = _ZSTD_DStreamSizes[1]
|
||||||
|
|
||||||
|
_MODE_CLOSED = 0
|
||||||
|
_MODE_READ = 1
|
||||||
|
_MODE_WRITE = 2
|
||||||
|
|
||||||
|
|
||||||
|
def _nbytes(dat, /):
|
||||||
|
if isinstance(dat, (bytes, bytearray)):
|
||||||
|
return len(dat)
|
||||||
|
with memoryview(dat) as mv:
|
||||||
|
return mv.nbytes
|
||||||
|
|
||||||
|
|
||||||
|
class ZstdFile(_streams.BaseStream):
|
||||||
|
"""A file-like object providing transparent Zstandard (de)compression.
|
||||||
|
|
||||||
|
A ZstdFile can act as a wrapper for an existing file object, or refer
|
||||||
|
directly to a named file on disk.
|
||||||
|
|
||||||
|
ZstdFile provides a *binary* file interface. Data is read and returned as
|
||||||
|
bytes, and may only be written to objects that support the Buffer Protocol.
|
||||||
|
"""
|
||||||
|
|
||||||
|
FLUSH_BLOCK = ZstdCompressor.FLUSH_BLOCK
|
||||||
|
FLUSH_FRAME = ZstdCompressor.FLUSH_FRAME
|
||||||
|
|
||||||
|
def __init__(self, file, /, mode="r", *,
|
||||||
|
level=None, options=None, zstd_dict=None):
|
||||||
|
"""Open a Zstandard compressed file in binary mode.
|
||||||
|
|
||||||
|
*file* can be either an file-like object, or a file name to open.
|
||||||
|
|
||||||
|
*mode* can be "r" for reading (default), "w" for (over)writing, "x" for
|
||||||
|
creating exclusively, or "a" for appending. These can equivalently be
|
||||||
|
given as "rb", "wb", "xb" and "ab" respectively.
|
||||||
|
|
||||||
|
*level* is an optional int specifying the compression level to use,
|
||||||
|
or COMPRESSION_LEVEL_DEFAULT if not given.
|
||||||
|
|
||||||
|
*options* is an optional dict for advanced compression parameters.
|
||||||
|
See CompressionParameter and DecompressionParameter for the possible
|
||||||
|
options.
|
||||||
|
|
||||||
|
*zstd_dict* is an optional ZstdDict object, a pre-trained Zstandard
|
||||||
|
dictionary. See train_dict() to train ZstdDict on sample data.
|
||||||
|
"""
|
||||||
|
self._fp = None
|
||||||
|
self._close_fp = False
|
||||||
|
self._mode = _MODE_CLOSED
|
||||||
|
self._buffer = None
|
||||||
|
|
||||||
|
if not isinstance(mode, str):
|
||||||
|
raise ValueError("mode must be a str")
|
||||||
|
if options is not None and not isinstance(options, dict):
|
||||||
|
raise TypeError("options must be a dict or None")
|
||||||
|
mode = mode.removesuffix("b") # handle rb, wb, xb, ab
|
||||||
|
if mode == "r":
|
||||||
|
if level is not None:
|
||||||
|
raise TypeError("level is illegal in read mode")
|
||||||
|
self._mode = _MODE_READ
|
||||||
|
elif mode in {"w", "a", "x"}:
|
||||||
|
if level is not None and not isinstance(level, int):
|
||||||
|
raise TypeError("level must be int or None")
|
||||||
|
self._mode = _MODE_WRITE
|
||||||
|
self._compressor = ZstdCompressor(level=level, options=options,
|
||||||
|
zstd_dict=zstd_dict)
|
||||||
|
self._pos = 0
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid mode: {mode!r}")
|
||||||
|
|
||||||
|
if isinstance(file, (str, bytes, PathLike)):
|
||||||
|
self._fp = io.open(file, f'{mode}b')
|
||||||
|
self._close_fp = True
|
||||||
|
elif ((mode == 'r' and hasattr(file, "read"))
|
||||||
|
or (mode != 'r' and hasattr(file, "write"))):
|
||||||
|
self._fp = file
|
||||||
|
else:
|
||||||
|
raise TypeError("file must be a file-like object "
|
||||||
|
"or a str, bytes, or PathLike object")
|
||||||
|
|
||||||
|
if self._mode == _MODE_READ:
|
||||||
|
raw = _streams.DecompressReader(
|
||||||
|
self._fp,
|
||||||
|
ZstdDecompressor,
|
||||||
|
trailing_error=ZstdError,
|
||||||
|
zstd_dict=zstd_dict,
|
||||||
|
options=options,
|
||||||
|
)
|
||||||
|
self._buffer = io.BufferedReader(raw)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Flush and close the file.
|
||||||
|
|
||||||
|
May be called multiple times. Once the file has been closed,
|
||||||
|
any other operation on it will raise ValueError.
|
||||||
|
"""
|
||||||
|
if self._fp is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
if self._mode == _MODE_READ:
|
||||||
|
if getattr(self, '_buffer', None):
|
||||||
|
self._buffer.close()
|
||||||
|
self._buffer = None
|
||||||
|
elif self._mode == _MODE_WRITE:
|
||||||
|
self.flush(self.FLUSH_FRAME)
|
||||||
|
self._compressor = None
|
||||||
|
finally:
|
||||||
|
self._mode = _MODE_CLOSED
|
||||||
|
try:
|
||||||
|
if self._close_fp:
|
||||||
|
self._fp.close()
|
||||||
|
finally:
|
||||||
|
self._fp = None
|
||||||
|
self._close_fp = False
|
||||||
|
|
||||||
|
def write(self, data, /):
|
||||||
|
"""Write a bytes-like object *data* to the file.
|
||||||
|
|
||||||
|
Returns the number of uncompressed bytes written, which is
|
||||||
|
always the length of data in bytes. Note that due to buffering,
|
||||||
|
the file on disk may not reflect the data written until .flush()
|
||||||
|
or .close() is called.
|
||||||
|
"""
|
||||||
|
self._check_can_write()
|
||||||
|
|
||||||
|
length = _nbytes(data)
|
||||||
|
|
||||||
|
compressed = self._compressor.compress(data)
|
||||||
|
self._fp.write(compressed)
|
||||||
|
self._pos += length
|
||||||
|
return length
|
||||||
|
|
||||||
|
def flush(self, mode=FLUSH_BLOCK):
|
||||||
|
"""Flush remaining data to the underlying stream.
|
||||||
|
|
||||||
|
The mode argument can be FLUSH_BLOCK or FLUSH_FRAME. Abuse of this
|
||||||
|
method will reduce compression ratio, use it only when necessary.
|
||||||
|
|
||||||
|
If the program is interrupted afterwards, all data can be recovered.
|
||||||
|
To ensure saving to disk, also need to use os.fsync(fd).
|
||||||
|
|
||||||
|
This method does nothing in reading mode.
|
||||||
|
"""
|
||||||
|
if self._mode == _MODE_READ:
|
||||||
|
return
|
||||||
|
self._check_not_closed()
|
||||||
|
if mode not in {self.FLUSH_BLOCK, self.FLUSH_FRAME}:
|
||||||
|
raise ValueError("Invalid mode argument, expected either "
|
||||||
|
"ZstdFile.FLUSH_FRAME or "
|
||||||
|
"ZstdFile.FLUSH_BLOCK")
|
||||||
|
if self._compressor.last_mode == mode:
|
||||||
|
return
|
||||||
|
# Flush zstd block/frame, and write.
|
||||||
|
data = self._compressor.flush(mode)
|
||||||
|
self._fp.write(data)
|
||||||
|
if hasattr(self._fp, "flush"):
|
||||||
|
self._fp.flush()
|
||||||
|
|
||||||
|
def read(self, size=-1):
|
||||||
|
"""Read up to size uncompressed bytes from the file.
|
||||||
|
|
||||||
|
If size is negative or omitted, read until EOF is reached.
|
||||||
|
Returns b"" if the file is already at EOF.
|
||||||
|
"""
|
||||||
|
if size is None:
|
||||||
|
size = -1
|
||||||
|
self._check_can_read()
|
||||||
|
return self._buffer.read(size)
|
||||||
|
|
||||||
|
def read1(self, size=-1):
|
||||||
|
"""Read up to size uncompressed bytes, while trying to avoid
|
||||||
|
making multiple reads from the underlying stream. Reads up to a
|
||||||
|
buffer's worth of data if size is negative.
|
||||||
|
|
||||||
|
Returns b"" if the file is at EOF.
|
||||||
|
"""
|
||||||
|
self._check_can_read()
|
||||||
|
if size < 0:
|
||||||
|
# Note this should *not* be io.DEFAULT_BUFFER_SIZE.
|
||||||
|
# ZSTD_DStreamOutSize is the minimum amount to read guaranteeing
|
||||||
|
# a full block is read.
|
||||||
|
size = _ZSTD_DStreamOutSize
|
||||||
|
return self._buffer.read1(size)
|
||||||
|
|
||||||
|
def readinto(self, b):
|
||||||
|
"""Read bytes into b.
|
||||||
|
|
||||||
|
Returns the number of bytes read (0 for EOF).
|
||||||
|
"""
|
||||||
|
self._check_can_read()
|
||||||
|
return self._buffer.readinto(b)
|
||||||
|
|
||||||
|
def readinto1(self, b):
|
||||||
|
"""Read bytes into b, while trying to avoid making multiple reads
|
||||||
|
from the underlying stream.
|
||||||
|
|
||||||
|
Returns the number of bytes read (0 for EOF).
|
||||||
|
"""
|
||||||
|
self._check_can_read()
|
||||||
|
return self._buffer.readinto1(b)
|
||||||
|
|
||||||
|
def readline(self, size=-1):
|
||||||
|
"""Read a line of uncompressed bytes from the file.
|
||||||
|
|
||||||
|
The terminating newline (if present) is retained. If size is
|
||||||
|
non-negative, no more than size bytes will be read (in which
|
||||||
|
case the line may be incomplete). Returns b'' if already at EOF.
|
||||||
|
"""
|
||||||
|
self._check_can_read()
|
||||||
|
return self._buffer.readline(size)
|
||||||
|
|
||||||
|
def seek(self, offset, whence=io.SEEK_SET):
|
||||||
|
"""Change the file position.
|
||||||
|
|
||||||
|
The new position is specified by offset, relative to the
|
||||||
|
position indicated by whence. Possible values for whence are:
|
||||||
|
|
||||||
|
0: start of stream (default): offset must not be negative
|
||||||
|
1: current stream position
|
||||||
|
2: end of stream; offset must not be positive
|
||||||
|
|
||||||
|
Returns the new file position.
|
||||||
|
|
||||||
|
Note that seeking is emulated, so depending on the arguments,
|
||||||
|
this operation may be extremely slow.
|
||||||
|
"""
|
||||||
|
self._check_can_read()
|
||||||
|
|
||||||
|
# BufferedReader.seek() checks seekable
|
||||||
|
return self._buffer.seek(offset, whence)
|
||||||
|
|
||||||
|
def peek(self, size=-1):
|
||||||
|
"""Return buffered data without advancing the file position.
|
||||||
|
|
||||||
|
Always returns at least one byte of data, unless at EOF.
|
||||||
|
The exact number of bytes returned is unspecified.
|
||||||
|
"""
|
||||||
|
# Relies on the undocumented fact that BufferedReader.peek() always
|
||||||
|
# returns at least one byte (except at EOF)
|
||||||
|
self._check_can_read()
|
||||||
|
return self._buffer.peek(size)
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if ret := self._buffer.readline():
|
||||||
|
return ret
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def tell(self):
|
||||||
|
"""Return the current file position."""
|
||||||
|
self._check_not_closed()
|
||||||
|
if self._mode == _MODE_READ:
|
||||||
|
return self._buffer.tell()
|
||||||
|
elif self._mode == _MODE_WRITE:
|
||||||
|
return self._pos
|
||||||
|
|
||||||
|
def fileno(self):
|
||||||
|
"""Return the file descriptor for the underlying file."""
|
||||||
|
self._check_not_closed()
|
||||||
|
return self._fp.fileno()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
self._check_not_closed()
|
||||||
|
return self._fp.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mode(self):
|
||||||
|
return 'wb' if self._mode == _MODE_WRITE else 'rb'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def closed(self):
|
||||||
|
"""True if this file is closed."""
|
||||||
|
return self._mode == _MODE_CLOSED
|
||||||
|
|
||||||
|
def seekable(self):
|
||||||
|
"""Return whether the file supports seeking."""
|
||||||
|
return self.readable() and self._buffer.seekable()
|
||||||
|
|
||||||
|
def readable(self):
|
||||||
|
"""Return whether the file was opened for reading."""
|
||||||
|
self._check_not_closed()
|
||||||
|
return self._mode == _MODE_READ
|
||||||
|
|
||||||
|
def writable(self):
|
||||||
|
"""Return whether the file was opened for writing."""
|
||||||
|
self._check_not_closed()
|
||||||
|
return self._mode == _MODE_WRITE
|
||||||
|
|
||||||
|
|
||||||
|
def open(file, /, mode="rb", *, level=None, options=None, zstd_dict=None,
|
||||||
|
encoding=None, errors=None, newline=None):
|
||||||
|
"""Open a Zstandard compressed file in binary or text mode.
|
||||||
|
|
||||||
|
file can be either a file name (given as a str, bytes, or PathLike object),
|
||||||
|
in which case the named file is opened, or it can be an existing file object
|
||||||
|
to read from or write to.
|
||||||
|
|
||||||
|
The mode parameter can be "r", "rb" (default), "w", "wb", "x", "xb", "a",
|
||||||
|
"ab" for binary mode, or "rt", "wt", "xt", "at" for text mode.
|
||||||
|
|
||||||
|
The level, options, and zstd_dict parameters specify the settings the same
|
||||||
|
as ZstdFile.
|
||||||
|
|
||||||
|
When using read mode (decompression), the options parameter is a dict
|
||||||
|
representing advanced decompression options. The level parameter is not
|
||||||
|
supported in this case. When using write mode (compression), only one of
|
||||||
|
level, an int representing the compression level, or options, a dict
|
||||||
|
representing advanced compression options, may be passed. In both modes,
|
||||||
|
zstd_dict is a ZstdDict instance containing a trained Zstandard dictionary.
|
||||||
|
|
||||||
|
For binary mode, this function is equivalent to the ZstdFile constructor:
|
||||||
|
ZstdFile(filename, mode, ...). In this case, the encoding, errors and
|
||||||
|
newline parameters must not be provided.
|
||||||
|
|
||||||
|
For text mode, an ZstdFile object is created, and wrapped in an
|
||||||
|
io.TextIOWrapper instance with the specified encoding, error handling
|
||||||
|
behavior, and line ending(s).
|
||||||
|
"""
|
||||||
|
|
||||||
|
text_mode = "t" in mode
|
||||||
|
mode = mode.replace("t", "")
|
||||||
|
|
||||||
|
if text_mode:
|
||||||
|
if "b" in mode:
|
||||||
|
raise ValueError(f"Invalid mode: {mode!r}")
|
||||||
|
else:
|
||||||
|
if encoding is not None:
|
||||||
|
raise ValueError("Argument 'encoding' not supported in binary mode")
|
||||||
|
if errors is not None:
|
||||||
|
raise ValueError("Argument 'errors' not supported in binary mode")
|
||||||
|
if newline is not None:
|
||||||
|
raise ValueError("Argument 'newline' not supported in binary mode")
|
||||||
|
|
||||||
|
binary_file = ZstdFile(file, mode, level=level, options=options,
|
||||||
|
zstd_dict=zstd_dict)
|
||||||
|
|
||||||
|
if text_mode:
|
||||||
|
return io.TextIOWrapper(binary_file, encoding, errors, newline)
|
||||||
|
else:
|
||||||
|
return binary_file
|
|
@ -32,6 +32,13 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_LZMA_SUPPORTED = False
|
_LZMA_SUPPORTED = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from compression import zstd
|
||||||
|
del zstd
|
||||||
|
_ZSTD_SUPPORTED = True
|
||||||
|
except ImportError:
|
||||||
|
_ZSTD_SUPPORTED = False
|
||||||
|
|
||||||
_WINDOWS = os.name == 'nt'
|
_WINDOWS = os.name == 'nt'
|
||||||
posix = nt = None
|
posix = nt = None
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
|
@ -1006,6 +1013,8 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
|
||||||
tar_compression = 'bz2'
|
tar_compression = 'bz2'
|
||||||
elif _LZMA_SUPPORTED and compress == 'xz':
|
elif _LZMA_SUPPORTED and compress == 'xz':
|
||||||
tar_compression = 'xz'
|
tar_compression = 'xz'
|
||||||
|
elif _ZSTD_SUPPORTED and compress == 'zst':
|
||||||
|
tar_compression = 'zst'
|
||||||
else:
|
else:
|
||||||
raise ValueError("bad value for 'compress', or compression format not "
|
raise ValueError("bad value for 'compress', or compression format not "
|
||||||
"supported : {0}".format(compress))
|
"supported : {0}".format(compress))
|
||||||
|
@ -1134,6 +1143,10 @@ if _LZMA_SUPPORTED:
|
||||||
_ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
|
_ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')],
|
||||||
"xz'ed tar-file")
|
"xz'ed tar-file")
|
||||||
|
|
||||||
|
if _ZSTD_SUPPORTED:
|
||||||
|
_ARCHIVE_FORMATS['zstdtar'] = (_make_tarball, [('compress', 'zst')],
|
||||||
|
"zstd'ed tar-file")
|
||||||
|
|
||||||
def get_archive_formats():
|
def get_archive_formats():
|
||||||
"""Returns a list of supported formats for archiving and unarchiving.
|
"""Returns a list of supported formats for archiving and unarchiving.
|
||||||
|
|
||||||
|
@ -1174,7 +1187,7 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
|
||||||
|
|
||||||
'base_name' is the name of the file to create, minus any format-specific
|
'base_name' is the name of the file to create, minus any format-specific
|
||||||
extension; 'format' is the archive format: one of "zip", "tar", "gztar",
|
extension; 'format' is the archive format: one of "zip", "tar", "gztar",
|
||||||
"bztar", or "xztar". Or any other registered format.
|
"bztar", "zstdtar", or "xztar". Or any other registered format.
|
||||||
|
|
||||||
'root_dir' is a directory that will be the root directory of the
|
'root_dir' is a directory that will be the root directory of the
|
||||||
archive; ie. we typically chdir into 'root_dir' before creating the
|
archive; ie. we typically chdir into 'root_dir' before creating the
|
||||||
|
@ -1359,6 +1372,10 @@ if _LZMA_SUPPORTED:
|
||||||
_UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
|
_UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [],
|
||||||
"xz'ed tar-file")
|
"xz'ed tar-file")
|
||||||
|
|
||||||
|
if _ZSTD_SUPPORTED:
|
||||||
|
_UNPACK_FORMATS['zstdtar'] = (['.tar.zst', '.tzst'], _unpack_tarfile, [],
|
||||||
|
"zstd'ed tar-file")
|
||||||
|
|
||||||
def _find_unpack_format(filename):
|
def _find_unpack_format(filename):
|
||||||
for name, info in _UNPACK_FORMATS.items():
|
for name, info in _UNPACK_FORMATS.items():
|
||||||
for extension in info[0]:
|
for extension in info[0]:
|
||||||
|
|
|
@ -399,7 +399,17 @@ class _Stream:
|
||||||
self.exception = lzma.LZMAError
|
self.exception = lzma.LZMAError
|
||||||
else:
|
else:
|
||||||
self.cmp = lzma.LZMACompressor(preset=preset)
|
self.cmp = lzma.LZMACompressor(preset=preset)
|
||||||
|
elif comptype == "zst":
|
||||||
|
try:
|
||||||
|
from compression import zstd
|
||||||
|
except ImportError:
|
||||||
|
raise CompressionError("compression.zstd module is not available") from None
|
||||||
|
if mode == "r":
|
||||||
|
self.dbuf = b""
|
||||||
|
self.cmp = zstd.ZstdDecompressor()
|
||||||
|
self.exception = zstd.ZstdError
|
||||||
|
else:
|
||||||
|
self.cmp = zstd.ZstdCompressor()
|
||||||
elif comptype != "tar":
|
elif comptype != "tar":
|
||||||
raise CompressionError("unknown compression type %r" % comptype)
|
raise CompressionError("unknown compression type %r" % comptype)
|
||||||
|
|
||||||
|
@ -591,6 +601,8 @@ class _StreamProxy(object):
|
||||||
return "bz2"
|
return "bz2"
|
||||||
elif self.buf.startswith((b"\x5d\x00\x00\x80", b"\xfd7zXZ")):
|
elif self.buf.startswith((b"\x5d\x00\x00\x80", b"\xfd7zXZ")):
|
||||||
return "xz"
|
return "xz"
|
||||||
|
elif self.buf.startswith(b"\x28\xb5\x2f\xfd"):
|
||||||
|
return "zst"
|
||||||
else:
|
else:
|
||||||
return "tar"
|
return "tar"
|
||||||
|
|
||||||
|
@ -1817,11 +1829,13 @@ class TarFile(object):
|
||||||
'r:gz' open for reading with gzip compression
|
'r:gz' open for reading with gzip compression
|
||||||
'r:bz2' open for reading with bzip2 compression
|
'r:bz2' open for reading with bzip2 compression
|
||||||
'r:xz' open for reading with lzma compression
|
'r:xz' open for reading with lzma compression
|
||||||
|
'r:zst' open for reading with zstd compression
|
||||||
'a' or 'a:' open for appending, creating the file if necessary
|
'a' or 'a:' open for appending, creating the file if necessary
|
||||||
'w' or 'w:' open for writing without compression
|
'w' or 'w:' open for writing without compression
|
||||||
'w:gz' open for writing with gzip compression
|
'w:gz' open for writing with gzip compression
|
||||||
'w:bz2' open for writing with bzip2 compression
|
'w:bz2' open for writing with bzip2 compression
|
||||||
'w:xz' open for writing with lzma compression
|
'w:xz' open for writing with lzma compression
|
||||||
|
'w:zst' open for writing with zstd compression
|
||||||
|
|
||||||
'x' or 'x:' create a tarfile exclusively without compression, raise
|
'x' or 'x:' create a tarfile exclusively without compression, raise
|
||||||
an exception if the file is already created
|
an exception if the file is already created
|
||||||
|
@ -1831,16 +1845,20 @@ class TarFile(object):
|
||||||
if the file is already created
|
if the file is already created
|
||||||
'x:xz' create an lzma compressed tarfile, raise an exception
|
'x:xz' create an lzma compressed tarfile, raise an exception
|
||||||
if the file is already created
|
if the file is already created
|
||||||
|
'x:zst' create a zstd compressed tarfile, raise an exception
|
||||||
|
if the file is already created
|
||||||
|
|
||||||
'r|*' open a stream of tar blocks with transparent compression
|
'r|*' open a stream of tar blocks with transparent compression
|
||||||
'r|' open an uncompressed stream of tar blocks for reading
|
'r|' open an uncompressed stream of tar blocks for reading
|
||||||
'r|gz' open a gzip compressed stream of tar blocks
|
'r|gz' open a gzip compressed stream of tar blocks
|
||||||
'r|bz2' open a bzip2 compressed stream of tar blocks
|
'r|bz2' open a bzip2 compressed stream of tar blocks
|
||||||
'r|xz' open an lzma compressed stream of tar blocks
|
'r|xz' open an lzma compressed stream of tar blocks
|
||||||
|
'r|zst' open a zstd compressed stream of tar blocks
|
||||||
'w|' open an uncompressed stream for writing
|
'w|' open an uncompressed stream for writing
|
||||||
'w|gz' open a gzip compressed stream for writing
|
'w|gz' open a gzip compressed stream for writing
|
||||||
'w|bz2' open a bzip2 compressed stream for writing
|
'w|bz2' open a bzip2 compressed stream for writing
|
||||||
'w|xz' open an lzma compressed stream for writing
|
'w|xz' open an lzma compressed stream for writing
|
||||||
|
'w|zst' open a zstd compressed stream for writing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not name and not fileobj:
|
if not name and not fileobj:
|
||||||
|
@ -2006,12 +2024,48 @@ class TarFile(object):
|
||||||
t._extfileobj = False
|
t._extfileobj = False
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def zstopen(cls, name, mode="r", fileobj=None, level=None, options=None,
|
||||||
|
zstd_dict=None, **kwargs):
|
||||||
|
"""Open zstd compressed tar archive name for reading or writing.
|
||||||
|
Appending is not allowed.
|
||||||
|
"""
|
||||||
|
if mode not in ("r", "w", "x"):
|
||||||
|
raise ValueError("mode must be 'r', 'w' or 'x'")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from compression.zstd import ZstdFile, ZstdError
|
||||||
|
except ImportError:
|
||||||
|
raise CompressionError("compression.zstd module is not available") from None
|
||||||
|
|
||||||
|
fileobj = ZstdFile(
|
||||||
|
fileobj or name,
|
||||||
|
mode,
|
||||||
|
level=level,
|
||||||
|
options=options,
|
||||||
|
zstd_dict=zstd_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
t = cls.taropen(name, mode, fileobj, **kwargs)
|
||||||
|
except (ZstdError, EOFError) as e:
|
||||||
|
fileobj.close()
|
||||||
|
if mode == 'r':
|
||||||
|
raise ReadError("not a zstd file") from e
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
|
fileobj.close()
|
||||||
|
raise
|
||||||
|
t._extfileobj = False
|
||||||
|
return t
|
||||||
|
|
||||||
# All *open() methods are registered here.
|
# All *open() methods are registered here.
|
||||||
OPEN_METH = {
|
OPEN_METH = {
|
||||||
"tar": "taropen", # uncompressed tar
|
"tar": "taropen", # uncompressed tar
|
||||||
"gz": "gzopen", # gzip compressed tar
|
"gz": "gzopen", # gzip compressed tar
|
||||||
"bz2": "bz2open", # bzip2 compressed tar
|
"bz2": "bz2open", # bzip2 compressed tar
|
||||||
"xz": "xzopen" # lzma compressed tar
|
"xz": "xzopen", # lzma compressed tar
|
||||||
|
"zst": "zstopen" # zstd compressed tar
|
||||||
}
|
}
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
@ -2963,6 +3017,9 @@ def main():
|
||||||
'.tbz': 'bz2',
|
'.tbz': 'bz2',
|
||||||
'.tbz2': 'bz2',
|
'.tbz2': 'bz2',
|
||||||
'.tb2': 'bz2',
|
'.tb2': 'bz2',
|
||||||
|
# zstd
|
||||||
|
'.zst': 'zst',
|
||||||
|
'.tzst': 'zst',
|
||||||
}
|
}
|
||||||
tar_mode = 'w:' + compressions[ext] if ext in compressions else 'w'
|
tar_mode = 'w:' + compressions[ext] if ext in compressions else 'w'
|
||||||
tar_files = args.create
|
tar_files = args.create
|
||||||
|
|
|
@ -33,7 +33,7 @@ __all__ = [
|
||||||
"is_resource_enabled", "requires", "requires_freebsd_version",
|
"is_resource_enabled", "requires", "requires_freebsd_version",
|
||||||
"requires_gil_enabled", "requires_linux_version", "requires_mac_ver",
|
"requires_gil_enabled", "requires_linux_version", "requires_mac_ver",
|
||||||
"check_syntax_error",
|
"check_syntax_error",
|
||||||
"requires_gzip", "requires_bz2", "requires_lzma",
|
"requires_gzip", "requires_bz2", "requires_lzma", "requires_zstd",
|
||||||
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
|
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
|
||||||
"requires_IEEE_754", "requires_zlib",
|
"requires_IEEE_754", "requires_zlib",
|
||||||
"has_fork_support", "requires_fork",
|
"has_fork_support", "requires_fork",
|
||||||
|
@ -527,6 +527,13 @@ def requires_lzma(reason='requires lzma'):
|
||||||
lzma = None
|
lzma = None
|
||||||
return unittest.skipUnless(lzma, reason)
|
return unittest.skipUnless(lzma, reason)
|
||||||
|
|
||||||
|
def requires_zstd(reason='requires zstd'):
|
||||||
|
try:
|
||||||
|
from compression import zstd
|
||||||
|
except ImportError:
|
||||||
|
zstd = None
|
||||||
|
return unittest.skipUnless(zstd, reason)
|
||||||
|
|
||||||
def has_no_debug_ranges():
|
def has_no_debug_ranges():
|
||||||
try:
|
try:
|
||||||
import _testcapi
|
import _testcapi
|
||||||
|
|
|
@ -2153,6 +2153,10 @@ class TestArchives(BaseTest, unittest.TestCase):
|
||||||
def test_unpack_archive_bztar(self):
|
def test_unpack_archive_bztar(self):
|
||||||
self.check_unpack_tarball('bztar')
|
self.check_unpack_tarball('bztar')
|
||||||
|
|
||||||
|
@support.requires_zstd()
|
||||||
|
def test_unpack_archive_zstdtar(self):
|
||||||
|
self.check_unpack_tarball('zstdtar')
|
||||||
|
|
||||||
@support.requires_lzma()
|
@support.requires_lzma()
|
||||||
@unittest.skipIf(AIX and not _maxdataOK(), "AIX MAXDATA must be 0x20000000 or larger")
|
@unittest.skipIf(AIX and not _maxdataOK(), "AIX MAXDATA must be 0x20000000 or larger")
|
||||||
def test_unpack_archive_xztar(self):
|
def test_unpack_archive_xztar(self):
|
||||||
|
|
|
@ -38,6 +38,10 @@ try:
|
||||||
import lzma
|
import lzma
|
||||||
except ImportError:
|
except ImportError:
|
||||||
lzma = None
|
lzma = None
|
||||||
|
try:
|
||||||
|
from compression import zstd
|
||||||
|
except ImportError:
|
||||||
|
zstd = None
|
||||||
|
|
||||||
def sha256sum(data):
|
def sha256sum(data):
|
||||||
return sha256(data).hexdigest()
|
return sha256(data).hexdigest()
|
||||||
|
@ -48,6 +52,7 @@ tarname = support.findfile("testtar.tar", subdir="archivetestdata")
|
||||||
gzipname = os.path.join(TEMPDIR, "testtar.tar.gz")
|
gzipname = os.path.join(TEMPDIR, "testtar.tar.gz")
|
||||||
bz2name = os.path.join(TEMPDIR, "testtar.tar.bz2")
|
bz2name = os.path.join(TEMPDIR, "testtar.tar.bz2")
|
||||||
xzname = os.path.join(TEMPDIR, "testtar.tar.xz")
|
xzname = os.path.join(TEMPDIR, "testtar.tar.xz")
|
||||||
|
zstname = os.path.join(TEMPDIR, "testtar.tar.zst")
|
||||||
tmpname = os.path.join(TEMPDIR, "tmp.tar")
|
tmpname = os.path.join(TEMPDIR, "tmp.tar")
|
||||||
dotlessname = os.path.join(TEMPDIR, "testtar")
|
dotlessname = os.path.join(TEMPDIR, "testtar")
|
||||||
|
|
||||||
|
@ -90,6 +95,12 @@ class LzmaTest:
|
||||||
open = lzma.LZMAFile if lzma else None
|
open = lzma.LZMAFile if lzma else None
|
||||||
taropen = tarfile.TarFile.xzopen
|
taropen = tarfile.TarFile.xzopen
|
||||||
|
|
||||||
|
@support.requires_zstd()
|
||||||
|
class ZstdTest:
|
||||||
|
tarname = zstname
|
||||||
|
suffix = 'zst'
|
||||||
|
open = zstd.ZstdFile if zstd else None
|
||||||
|
taropen = tarfile.TarFile.zstopen
|
||||||
|
|
||||||
class ReadTest(TarTest):
|
class ReadTest(TarTest):
|
||||||
|
|
||||||
|
@ -271,6 +282,8 @@ class Bz2UstarReadTest(Bz2Test, UstarReadTest):
|
||||||
class LzmaUstarReadTest(LzmaTest, UstarReadTest):
|
class LzmaUstarReadTest(LzmaTest, UstarReadTest):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdUstarReadTest(ZstdTest, UstarReadTest):
|
||||||
|
pass
|
||||||
|
|
||||||
class ListTest(ReadTest, unittest.TestCase):
|
class ListTest(ReadTest, unittest.TestCase):
|
||||||
|
|
||||||
|
@ -375,6 +388,8 @@ class Bz2ListTest(Bz2Test, ListTest):
|
||||||
class LzmaListTest(LzmaTest, ListTest):
|
class LzmaListTest(LzmaTest, ListTest):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdListTest(ZstdTest, ListTest):
|
||||||
|
pass
|
||||||
|
|
||||||
class CommonReadTest(ReadTest):
|
class CommonReadTest(ReadTest):
|
||||||
|
|
||||||
|
@ -837,6 +852,8 @@ class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase):
|
||||||
class LzmaMiscReadTest(LzmaTest, MiscReadTestBase, unittest.TestCase):
|
class LzmaMiscReadTest(LzmaTest, MiscReadTestBase, unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdMiscReadTest(ZstdTest, MiscReadTestBase, unittest.TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
class StreamReadTest(CommonReadTest, unittest.TestCase):
|
class StreamReadTest(CommonReadTest, unittest.TestCase):
|
||||||
|
|
||||||
|
@ -909,6 +926,9 @@ class Bz2StreamReadTest(Bz2Test, StreamReadTest):
|
||||||
class LzmaStreamReadTest(LzmaTest, StreamReadTest):
|
class LzmaStreamReadTest(LzmaTest, StreamReadTest):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdStreamReadTest(ZstdTest, StreamReadTest):
|
||||||
|
pass
|
||||||
|
|
||||||
class TarStreamModeReadTest(StreamModeTest, unittest.TestCase):
|
class TarStreamModeReadTest(StreamModeTest, unittest.TestCase):
|
||||||
|
|
||||||
def test_stream_mode_no_cache(self):
|
def test_stream_mode_no_cache(self):
|
||||||
|
@ -925,6 +945,9 @@ class Bz2StreamModeReadTest(Bz2Test, TarStreamModeReadTest):
|
||||||
class LzmaStreamModeReadTest(LzmaTest, TarStreamModeReadTest):
|
class LzmaStreamModeReadTest(LzmaTest, TarStreamModeReadTest):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdStreamModeReadTest(ZstdTest, TarStreamModeReadTest):
|
||||||
|
pass
|
||||||
|
|
||||||
class DetectReadTest(TarTest, unittest.TestCase):
|
class DetectReadTest(TarTest, unittest.TestCase):
|
||||||
def _testfunc_file(self, name, mode):
|
def _testfunc_file(self, name, mode):
|
||||||
try:
|
try:
|
||||||
|
@ -986,6 +1009,8 @@ class Bz2DetectReadTest(Bz2Test, DetectReadTest):
|
||||||
class LzmaDetectReadTest(LzmaTest, DetectReadTest):
|
class LzmaDetectReadTest(LzmaTest, DetectReadTest):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdDetectReadTest(ZstdTest, DetectReadTest):
|
||||||
|
pass
|
||||||
|
|
||||||
class GzipBrokenHeaderCorrectException(GzipTest, unittest.TestCase):
|
class GzipBrokenHeaderCorrectException(GzipTest, unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
@ -1666,6 +1691,8 @@ class Bz2WriteTest(Bz2Test, WriteTest):
|
||||||
class LzmaWriteTest(LzmaTest, WriteTest):
|
class LzmaWriteTest(LzmaTest, WriteTest):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdWriteTest(ZstdTest, WriteTest):
|
||||||
|
pass
|
||||||
|
|
||||||
class StreamWriteTest(WriteTestBase, unittest.TestCase):
|
class StreamWriteTest(WriteTestBase, unittest.TestCase):
|
||||||
|
|
||||||
|
@ -1727,6 +1754,9 @@ class Bz2StreamWriteTest(Bz2Test, StreamWriteTest):
|
||||||
class LzmaStreamWriteTest(LzmaTest, StreamWriteTest):
|
class LzmaStreamWriteTest(LzmaTest, StreamWriteTest):
|
||||||
decompressor = lzma.LZMADecompressor if lzma else None
|
decompressor = lzma.LZMADecompressor if lzma else None
|
||||||
|
|
||||||
|
class ZstdStreamWriteTest(ZstdTest, StreamWriteTest):
|
||||||
|
decompressor = zstd.ZstdDecompressor if zstd else None
|
||||||
|
|
||||||
class _CompressedWriteTest(TarTest):
|
class _CompressedWriteTest(TarTest):
|
||||||
# This is not actually a standalone test.
|
# This is not actually a standalone test.
|
||||||
# It does not inherit WriteTest because it only makes sense with gz,bz2
|
# It does not inherit WriteTest because it only makes sense with gz,bz2
|
||||||
|
@ -2042,6 +2072,14 @@ class LzmaCreateTest(LzmaTest, CreateTest):
|
||||||
tobj.add(self.file_path)
|
tobj.add(self.file_path)
|
||||||
|
|
||||||
|
|
||||||
|
class ZstdCreateTest(ZstdTest, CreateTest):
|
||||||
|
|
||||||
|
# Unlike gz and bz2, zstd uses the level keyword instead of compresslevel.
|
||||||
|
# It does not allow for level to be specified when reading.
|
||||||
|
def test_create_with_level(self):
|
||||||
|
with tarfile.open(tmpname, self.mode, level=1) as tobj:
|
||||||
|
tobj.add(self.file_path)
|
||||||
|
|
||||||
class CreateWithXModeTest(CreateTest):
|
class CreateWithXModeTest(CreateTest):
|
||||||
|
|
||||||
prefix = "x"
|
prefix = "x"
|
||||||
|
@ -2523,6 +2561,8 @@ class Bz2AppendTest(Bz2Test, AppendTestBase, unittest.TestCase):
|
||||||
class LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase):
|
class LzmaAppendTest(LzmaTest, AppendTestBase, unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ZstdAppendTest(ZstdTest, AppendTestBase, unittest.TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
class LimitsTest(unittest.TestCase):
|
class LimitsTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -2835,7 +2875,7 @@ class CommandLineTest(unittest.TestCase):
|
||||||
support.findfile('tokenize_tests-no-coding-cookie-'
|
support.findfile('tokenize_tests-no-coding-cookie-'
|
||||||
'and-utf8-bom-sig-only.txt',
|
'and-utf8-bom-sig-only.txt',
|
||||||
subdir='tokenizedata')]
|
subdir='tokenizedata')]
|
||||||
for filetype in (GzipTest, Bz2Test, LzmaTest):
|
for filetype in (GzipTest, Bz2Test, LzmaTest, ZstdTest):
|
||||||
if not filetype.open:
|
if not filetype.open:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
@ -4257,7 +4297,7 @@ def setUpModule():
|
||||||
data = fobj.read()
|
data = fobj.read()
|
||||||
|
|
||||||
# Create compressed tarfiles.
|
# Create compressed tarfiles.
|
||||||
for c in GzipTest, Bz2Test, LzmaTest:
|
for c in GzipTest, Bz2Test, LzmaTest, ZstdTest:
|
||||||
if c.open:
|
if c.open:
|
||||||
os_helper.unlink(c.tarname)
|
os_helper.unlink(c.tarname)
|
||||||
testtarnames.append(c.tarname)
|
testtarnames.append(c.tarname)
|
||||||
|
|
|
@ -23,7 +23,7 @@ from test import archiver_tests
|
||||||
from test.support import script_helper, os_helper
|
from test.support import script_helper, os_helper
|
||||||
from test.support import (
|
from test.support import (
|
||||||
findfile, requires_zlib, requires_bz2, requires_lzma,
|
findfile, requires_zlib, requires_bz2, requires_lzma,
|
||||||
captured_stdout, captured_stderr, requires_subprocess,
|
requires_zstd, captured_stdout, captured_stderr, requires_subprocess,
|
||||||
cpython_only
|
cpython_only
|
||||||
)
|
)
|
||||||
from test.support.os_helper import (
|
from test.support.os_helper import (
|
||||||
|
@ -702,6 +702,10 @@ class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile,
|
||||||
unittest.TestCase):
|
unittest.TestCase):
|
||||||
compression = zipfile.ZIP_LZMA
|
compression = zipfile.ZIP_LZMA
|
||||||
|
|
||||||
|
@requires_zstd()
|
||||||
|
class ZstdTestsWithSourceFile(AbstractTestsWithSourceFile,
|
||||||
|
unittest.TestCase):
|
||||||
|
compression = zipfile.ZIP_ZSTANDARD
|
||||||
|
|
||||||
class AbstractTestZip64InSmallFiles:
|
class AbstractTestZip64InSmallFiles:
|
||||||
# These tests test the ZIP64 functionality without using large files,
|
# These tests test the ZIP64 functionality without using large files,
|
||||||
|
@ -1279,6 +1283,10 @@ class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
|
||||||
unittest.TestCase):
|
unittest.TestCase):
|
||||||
compression = zipfile.ZIP_LZMA
|
compression = zipfile.ZIP_LZMA
|
||||||
|
|
||||||
|
@requires_zstd()
|
||||||
|
class ZstdTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
|
||||||
|
unittest.TestCase):
|
||||||
|
compression = zipfile.ZIP_ZSTANDARD
|
||||||
|
|
||||||
class AbstractWriterTests:
|
class AbstractWriterTests:
|
||||||
|
|
||||||
|
@ -1348,6 +1356,9 @@ class Bzip2WriterTests(AbstractWriterTests, unittest.TestCase):
|
||||||
class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
|
class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
|
||||||
compression = zipfile.ZIP_LZMA
|
compression = zipfile.ZIP_LZMA
|
||||||
|
|
||||||
|
@requires_zstd()
|
||||||
|
class ZstdWriterTests(AbstractWriterTests, unittest.TestCase):
|
||||||
|
compression = zipfile.ZIP_ZSTANDARD
|
||||||
|
|
||||||
class PyZipFileTests(unittest.TestCase):
|
class PyZipFileTests(unittest.TestCase):
|
||||||
def assertCompiledIn(self, name, namelist):
|
def assertCompiledIn(self, name, namelist):
|
||||||
|
@ -2678,6 +2689,17 @@ class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
|
||||||
b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
|
b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
|
||||||
b'\x00>\x00\x00\x00\x00\x00')
|
b'\x00>\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
|
@requires_zstd()
|
||||||
|
class ZstdBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
|
||||||
|
compression = zipfile.ZIP_ZSTANDARD
|
||||||
|
zip_with_bad_crc = (
|
||||||
|
b'PK\x03\x04?\x00\x00\x00]\x00\x00\x00!\x00V\xb1\x17J\x14\x00'
|
||||||
|
b'\x00\x00\x0b\x00\x00\x00\x05\x00\x00\x00afile(\xb5/\xfd\x00'
|
||||||
|
b'XY\x00\x00Hello WorldPK\x01\x02?\x03?\x00\x00\x00]\x00\x00\x00'
|
||||||
|
b'!\x00V\xb0\x17J\x14\x00\x00\x00\x0b\x00\x00\x00\x05\x00\x00\x00'
|
||||||
|
b'\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00afilePK'
|
||||||
|
b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x007\x00\x00\x00'
|
||||||
|
b'\x00\x00')
|
||||||
|
|
||||||
class DecryptionTests(unittest.TestCase):
|
class DecryptionTests(unittest.TestCase):
|
||||||
"""Check that ZIP decryption works. Since the library does not
|
"""Check that ZIP decryption works. Since the library does not
|
||||||
|
@ -2905,6 +2927,10 @@ class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
|
||||||
unittest.TestCase):
|
unittest.TestCase):
|
||||||
compression = zipfile.ZIP_LZMA
|
compression = zipfile.ZIP_LZMA
|
||||||
|
|
||||||
|
@requires_zstd()
|
||||||
|
class ZstdTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
|
||||||
|
unittest.TestCase):
|
||||||
|
compression = zipfile.ZIP_ZSTANDARD
|
||||||
|
|
||||||
# Provide the tell() method but not seek()
|
# Provide the tell() method but not seek()
|
||||||
class Tellable:
|
class Tellable:
|
||||||
|
|
2507
Lib/test/test_zstd.py
Normal file
2507
Lib/test/test_zstd.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,11 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
lzma = None
|
lzma = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
from compression import zstd # We may need its compression method
|
||||||
|
except ImportError:
|
||||||
|
zstd = None
|
||||||
|
|
||||||
__all__ = ["BadZipFile", "BadZipfile", "error",
|
__all__ = ["BadZipFile", "BadZipfile", "error",
|
||||||
"ZIP_STORED", "ZIP_DEFLATED", "ZIP_BZIP2", "ZIP_LZMA",
|
"ZIP_STORED", "ZIP_DEFLATED", "ZIP_BZIP2", "ZIP_LZMA",
|
||||||
"is_zipfile", "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile",
|
"is_zipfile", "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile",
|
||||||
|
@ -58,12 +63,14 @@ ZIP_STORED = 0
|
||||||
ZIP_DEFLATED = 8
|
ZIP_DEFLATED = 8
|
||||||
ZIP_BZIP2 = 12
|
ZIP_BZIP2 = 12
|
||||||
ZIP_LZMA = 14
|
ZIP_LZMA = 14
|
||||||
|
ZIP_ZSTANDARD = 93
|
||||||
# Other ZIP compression methods not supported
|
# Other ZIP compression methods not supported
|
||||||
|
|
||||||
DEFAULT_VERSION = 20
|
DEFAULT_VERSION = 20
|
||||||
ZIP64_VERSION = 45
|
ZIP64_VERSION = 45
|
||||||
BZIP2_VERSION = 46
|
BZIP2_VERSION = 46
|
||||||
LZMA_VERSION = 63
|
LZMA_VERSION = 63
|
||||||
|
ZSTANDARD_VERSION = 63
|
||||||
# we recognize (but not necessarily support) all features up to that version
|
# we recognize (but not necessarily support) all features up to that version
|
||||||
MAX_EXTRACT_VERSION = 63
|
MAX_EXTRACT_VERSION = 63
|
||||||
|
|
||||||
|
@ -505,6 +512,8 @@ class ZipInfo:
|
||||||
min_version = max(BZIP2_VERSION, min_version)
|
min_version = max(BZIP2_VERSION, min_version)
|
||||||
elif self.compress_type == ZIP_LZMA:
|
elif self.compress_type == ZIP_LZMA:
|
||||||
min_version = max(LZMA_VERSION, min_version)
|
min_version = max(LZMA_VERSION, min_version)
|
||||||
|
elif self.compress_type == ZIP_ZSTANDARD:
|
||||||
|
min_version = max(ZSTANDARD_VERSION, min_version)
|
||||||
|
|
||||||
self.extract_version = max(min_version, self.extract_version)
|
self.extract_version = max(min_version, self.extract_version)
|
||||||
self.create_version = max(min_version, self.create_version)
|
self.create_version = max(min_version, self.create_version)
|
||||||
|
@ -766,6 +775,7 @@ compressor_names = {
|
||||||
14: 'lzma',
|
14: 'lzma',
|
||||||
18: 'terse',
|
18: 'terse',
|
||||||
19: 'lz77',
|
19: 'lz77',
|
||||||
|
93: 'zstd',
|
||||||
97: 'wavpack',
|
97: 'wavpack',
|
||||||
98: 'ppmd',
|
98: 'ppmd',
|
||||||
}
|
}
|
||||||
|
@ -785,6 +795,10 @@ def _check_compression(compression):
|
||||||
if not lzma:
|
if not lzma:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Compression requires the (missing) lzma module")
|
"Compression requires the (missing) lzma module")
|
||||||
|
elif compression == ZIP_ZSTANDARD:
|
||||||
|
if not zstd:
|
||||||
|
raise RuntimeError(
|
||||||
|
"Compression requires the (missing) compression.zstd module")
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("That compression method is not supported")
|
raise NotImplementedError("That compression method is not supported")
|
||||||
|
|
||||||
|
@ -798,9 +812,11 @@ def _get_compressor(compress_type, compresslevel=None):
|
||||||
if compresslevel is not None:
|
if compresslevel is not None:
|
||||||
return bz2.BZ2Compressor(compresslevel)
|
return bz2.BZ2Compressor(compresslevel)
|
||||||
return bz2.BZ2Compressor()
|
return bz2.BZ2Compressor()
|
||||||
# compresslevel is ignored for ZIP_LZMA
|
# compresslevel is ignored for ZIP_LZMA and ZIP_ZSTANDARD
|
||||||
elif compress_type == ZIP_LZMA:
|
elif compress_type == ZIP_LZMA:
|
||||||
return LZMACompressor()
|
return LZMACompressor()
|
||||||
|
elif compress_type == ZIP_ZSTANDARD:
|
||||||
|
return zstd.ZstdCompressor()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -815,6 +831,8 @@ def _get_decompressor(compress_type):
|
||||||
return bz2.BZ2Decompressor()
|
return bz2.BZ2Decompressor()
|
||||||
elif compress_type == ZIP_LZMA:
|
elif compress_type == ZIP_LZMA:
|
||||||
return LZMADecompressor()
|
return LZMADecompressor()
|
||||||
|
elif compress_type == ZIP_ZSTANDARD:
|
||||||
|
return zstd.ZstdDecompressor()
|
||||||
else:
|
else:
|
||||||
descr = compressor_names.get(compress_type)
|
descr = compressor_names.get(compress_type)
|
||||||
if descr:
|
if descr:
|
||||||
|
|
|
@ -2507,7 +2507,7 @@ maninstall: altmaninstall
|
||||||
XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax
|
XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax
|
||||||
LIBSUBDIRS= asyncio \
|
LIBSUBDIRS= asyncio \
|
||||||
collections \
|
collections \
|
||||||
compression compression/bz2 compression/gzip \
|
compression compression/bz2 compression/gzip compression/zstd \
|
||||||
compression/lzma compression/zlib compression/_common \
|
compression/lzma compression/zlib compression/_common \
|
||||||
concurrent concurrent/futures \
|
concurrent concurrent/futures \
|
||||||
csv \
|
csv \
|
||||||
|
|
|
@ -74,33 +74,33 @@ typedef struct {
|
||||||
|
|
||||||
static const ParameterInfo cp_list[] =
|
static const ParameterInfo cp_list[] =
|
||||||
{
|
{
|
||||||
{ZSTD_c_compressionLevel, "compressionLevel"},
|
{ZSTD_c_compressionLevel, "compression_level"},
|
||||||
{ZSTD_c_windowLog, "windowLog"},
|
{ZSTD_c_windowLog, "window_log"},
|
||||||
{ZSTD_c_hashLog, "hashLog"},
|
{ZSTD_c_hashLog, "hash_log"},
|
||||||
{ZSTD_c_chainLog, "chainLog"},
|
{ZSTD_c_chainLog, "chain_log"},
|
||||||
{ZSTD_c_searchLog, "searchLog"},
|
{ZSTD_c_searchLog, "search_log"},
|
||||||
{ZSTD_c_minMatch, "minMatch"},
|
{ZSTD_c_minMatch, "min_match"},
|
||||||
{ZSTD_c_targetLength, "targetLength"},
|
{ZSTD_c_targetLength, "target_length"},
|
||||||
{ZSTD_c_strategy, "strategy"},
|
{ZSTD_c_strategy, "strategy"},
|
||||||
|
|
||||||
{ZSTD_c_enableLongDistanceMatching, "enableLongDistanceMatching"},
|
{ZSTD_c_enableLongDistanceMatching, "enable_long_distance_matching"},
|
||||||
{ZSTD_c_ldmHashLog, "ldmHashLog"},
|
{ZSTD_c_ldmHashLog, "ldm_hash_log"},
|
||||||
{ZSTD_c_ldmMinMatch, "ldmMinMatch"},
|
{ZSTD_c_ldmMinMatch, "ldm_min_match"},
|
||||||
{ZSTD_c_ldmBucketSizeLog, "ldmBucketSizeLog"},
|
{ZSTD_c_ldmBucketSizeLog, "ldm_bucket_size_log"},
|
||||||
{ZSTD_c_ldmHashRateLog, "ldmHashRateLog"},
|
{ZSTD_c_ldmHashRateLog, "ldm_hash_rate_log"},
|
||||||
|
|
||||||
{ZSTD_c_contentSizeFlag, "contentSizeFlag"},
|
{ZSTD_c_contentSizeFlag, "content_size_flag"},
|
||||||
{ZSTD_c_checksumFlag, "checksumFlag"},
|
{ZSTD_c_checksumFlag, "checksum_flag"},
|
||||||
{ZSTD_c_dictIDFlag, "dictIDFlag"},
|
{ZSTD_c_dictIDFlag, "dict_id_flag"},
|
||||||
|
|
||||||
{ZSTD_c_nbWorkers, "nbWorkers"},
|
{ZSTD_c_nbWorkers, "nb_workers"},
|
||||||
{ZSTD_c_jobSize, "jobSize"},
|
{ZSTD_c_jobSize, "job_size"},
|
||||||
{ZSTD_c_overlapLog, "overlapLog"}
|
{ZSTD_c_overlapLog, "overlap_log"}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ParameterInfo dp_list[] =
|
static const ParameterInfo dp_list[] =
|
||||||
{
|
{
|
||||||
{ZSTD_d_windowLogMax, "windowLogMax"}
|
{ZSTD_d_windowLogMax, "window_log_max"}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -180,8 +180,8 @@ _zstd._train_dict
|
||||||
|
|
||||||
samples_bytes: PyBytesObject
|
samples_bytes: PyBytesObject
|
||||||
Concatenation of samples.
|
Concatenation of samples.
|
||||||
samples_size_list: object(subclass_of='&PyList_Type')
|
samples_sizes: object(subclass_of='&PyTuple_Type')
|
||||||
List of samples' sizes.
|
Tuple of samples' sizes.
|
||||||
dict_size: Py_ssize_t
|
dict_size: Py_ssize_t
|
||||||
The size of the dictionary.
|
The size of the dictionary.
|
||||||
/
|
/
|
||||||
|
@ -191,8 +191,8 @@ Internal function, train a zstd dictionary on sample data.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
_zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
||||||
PyObject *samples_size_list, Py_ssize_t dict_size)
|
PyObject *samples_sizes, Py_ssize_t dict_size)
|
||||||
/*[clinic end generated code: output=ee53c34c8f77886b input=b21d092c695a3a81]*/
|
/*[clinic end generated code: output=b5b4f36347c0addd input=2dce5b57d63923e2]*/
|
||||||
{
|
{
|
||||||
// TODO(emmatyping): The preamble and suffix to this function and _finalize_dict
|
// TODO(emmatyping): The preamble and suffix to this function and _finalize_dict
|
||||||
// are pretty similar. We should see if we can refactor them to share that code.
|
// are pretty similar. We should see if we can refactor them to share that code.
|
||||||
|
@ -209,7 +209,7 @@ _zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks_number = Py_SIZE(samples_size_list);
|
chunks_number = Py_SIZE(samples_sizes);
|
||||||
if ((size_t) chunks_number > UINT32_MAX) {
|
if ((size_t) chunks_number > UINT32_MAX) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"The number of samples should be <= %u.", UINT32_MAX);
|
"The number of samples should be <= %u.", UINT32_MAX);
|
||||||
|
@ -225,12 +225,11 @@ _zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
||||||
|
|
||||||
sizes_sum = 0;
|
sizes_sum = 0;
|
||||||
for (i = 0; i < chunks_number; i++) {
|
for (i = 0; i < chunks_number; i++) {
|
||||||
PyObject *size = PyList_GetItemRef(samples_size_list, i);
|
PyObject *size = PyTuple_GetItem(samples_sizes, i);
|
||||||
chunk_sizes[i] = PyLong_AsSize_t(size);
|
chunk_sizes[i] = PyLong_AsSize_t(size);
|
||||||
Py_DECREF(size);
|
|
||||||
if (chunk_sizes[i] == (size_t)-1 && PyErr_Occurred()) {
|
if (chunk_sizes[i] == (size_t)-1 && PyErr_Occurred()) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"Items in samples_size_list should be an int "
|
"Items in samples_sizes should be an int "
|
||||||
"object, with a value between 0 and %u.", SIZE_MAX);
|
"object, with a value between 0 and %u.", SIZE_MAX);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +238,7 @@ _zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
||||||
|
|
||||||
if (sizes_sum != Py_SIZE(samples_bytes)) {
|
if (sizes_sum != Py_SIZE(samples_bytes)) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"The samples size list doesn't match the concatenation's size.");
|
"The samples size tuple doesn't match the concatenation's size.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,8 +286,8 @@ _zstd._finalize_dict
|
||||||
Custom dictionary content.
|
Custom dictionary content.
|
||||||
samples_bytes: PyBytesObject
|
samples_bytes: PyBytesObject
|
||||||
Concatenation of samples.
|
Concatenation of samples.
|
||||||
samples_size_list: object(subclass_of='&PyList_Type')
|
samples_sizes: object(subclass_of='&PyTuple_Type')
|
||||||
List of samples' sizes.
|
Tuple of samples' sizes.
|
||||||
dict_size: Py_ssize_t
|
dict_size: Py_ssize_t
|
||||||
The size of the dictionary.
|
The size of the dictionary.
|
||||||
compression_level: int
|
compression_level: int
|
||||||
|
@ -301,9 +300,9 @@ Internal function, finalize a zstd dictionary.
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
_zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
||||||
PyBytesObject *samples_bytes,
|
PyBytesObject *samples_bytes,
|
||||||
PyObject *samples_size_list, Py_ssize_t dict_size,
|
PyObject *samples_sizes, Py_ssize_t dict_size,
|
||||||
int compression_level)
|
int compression_level)
|
||||||
/*[clinic end generated code: output=9c2a7d8c845cee93 input=08531a803d87c56f]*/
|
/*[clinic end generated code: output=5dc5b520fddba37f input=8afd42a249078460]*/
|
||||||
{
|
{
|
||||||
Py_ssize_t chunks_number;
|
Py_ssize_t chunks_number;
|
||||||
size_t *chunk_sizes = NULL;
|
size_t *chunk_sizes = NULL;
|
||||||
|
@ -319,7 +318,7 @@ _zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks_number = Py_SIZE(samples_size_list);
|
chunks_number = Py_SIZE(samples_sizes);
|
||||||
if ((size_t) chunks_number > UINT32_MAX) {
|
if ((size_t) chunks_number > UINT32_MAX) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"The number of samples should be <= %u.", UINT32_MAX);
|
"The number of samples should be <= %u.", UINT32_MAX);
|
||||||
|
@ -335,11 +334,11 @@ _zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
||||||
|
|
||||||
sizes_sum = 0;
|
sizes_sum = 0;
|
||||||
for (i = 0; i < chunks_number; i++) {
|
for (i = 0; i < chunks_number; i++) {
|
||||||
PyObject *size = PyList_GET_ITEM(samples_size_list, i);
|
PyObject *size = PyTuple_GetItem(samples_sizes, i);
|
||||||
chunk_sizes[i] = PyLong_AsSize_t(size);
|
chunk_sizes[i] = PyLong_AsSize_t(size);
|
||||||
if (chunk_sizes[i] == (size_t)-1 && PyErr_Occurred()) {
|
if (chunk_sizes[i] == (size_t)-1 && PyErr_Occurred()) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"Items in samples_size_list should be an int "
|
"Items in samples_sizes should be an int "
|
||||||
"object, with a value between 0 and %u.", SIZE_MAX);
|
"object, with a value between 0 and %u.", SIZE_MAX);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +347,7 @@ _zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
||||||
|
|
||||||
if (sizes_sum != Py_SIZE(samples_bytes)) {
|
if (sizes_sum != Py_SIZE(samples_bytes)) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"The samples size list doesn't match the concatenation's size.");
|
"The samples size tuple doesn't match the concatenation's size.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,18 +401,18 @@ success:
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
_zstd._get_param_bounds
|
_zstd._get_param_bounds
|
||||||
|
|
||||||
is_compress: bool
|
|
||||||
True for CParameter, False for DParameter.
|
|
||||||
parameter: int
|
parameter: int
|
||||||
The parameter to get bounds.
|
The parameter to get bounds.
|
||||||
|
is_compress: bool
|
||||||
|
True for CompressionParameter, False for DecompressionParameter.
|
||||||
|
|
||||||
Internal function, get CParameter/DParameter bounds.
|
Internal function, get CompressionParameter/DecompressionParameter bounds.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__get_param_bounds_impl(PyObject *module, int is_compress,
|
_zstd__get_param_bounds_impl(PyObject *module, int parameter,
|
||||||
int parameter)
|
int is_compress)
|
||||||
/*[clinic end generated code: output=b751dc710f89ef55 input=fb21ff96aff65df1]*/
|
/*[clinic end generated code: output=9892cd822f937e79 input=884cd1a01125267d]*/
|
||||||
{
|
{
|
||||||
ZSTD_bounds bound;
|
ZSTD_bounds bound;
|
||||||
if (is_compress) {
|
if (is_compress) {
|
||||||
|
@ -515,30 +514,30 @@ _zstd__get_frame_info_impl(PyObject *module, Py_buffer *frame_buffer)
|
||||||
_zstd._set_parameter_types
|
_zstd._set_parameter_types
|
||||||
|
|
||||||
c_parameter_type: object(subclass_of='&PyType_Type')
|
c_parameter_type: object(subclass_of='&PyType_Type')
|
||||||
CParameter IntEnum type object
|
CompressionParameter IntEnum type object
|
||||||
d_parameter_type: object(subclass_of='&PyType_Type')
|
d_parameter_type: object(subclass_of='&PyType_Type')
|
||||||
DParameter IntEnum type object
|
DecompressionParameter IntEnum type object
|
||||||
|
|
||||||
Internal function, set CParameter/DParameter types for validity check.
|
Internal function, set CompressionParameter/DecompressionParameter types for validity check.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__set_parameter_types_impl(PyObject *module, PyObject *c_parameter_type,
|
_zstd__set_parameter_types_impl(PyObject *module, PyObject *c_parameter_type,
|
||||||
PyObject *d_parameter_type)
|
PyObject *d_parameter_type)
|
||||||
/*[clinic end generated code: output=a13d4890ccbd2873 input=3e7d0d37c3a1045a]*/
|
/*[clinic end generated code: output=a13d4890ccbd2873 input=4535545d903853d3]*/
|
||||||
{
|
{
|
||||||
_zstd_state* const mod_state = get_zstd_state(module);
|
_zstd_state* const mod_state = get_zstd_state(module);
|
||||||
|
|
||||||
if (!PyType_Check(c_parameter_type) || !PyType_Check(d_parameter_type)) {
|
if (!PyType_Check(c_parameter_type) || !PyType_Check(d_parameter_type)) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"The two arguments should be CParameter and "
|
"The two arguments should be CompressionParameter and "
|
||||||
"DParameter types.");
|
"DecompressionParameter types.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_XDECREF(mod_state->CParameter_type);
|
Py_XDECREF(mod_state->CParameter_type);
|
||||||
Py_INCREF(c_parameter_type);
|
Py_INCREF(c_parameter_type);
|
||||||
mod_state->CParameter_type = (PyTypeObject*) c_parameter_type;
|
mod_state->CParameter_type = (PyTypeObject*)c_parameter_type;
|
||||||
|
|
||||||
Py_XDECREF(mod_state->DParameter_type);
|
Py_XDECREF(mod_state->DParameter_type);
|
||||||
Py_INCREF(d_parameter_type);
|
Py_INCREF(d_parameter_type);
|
||||||
|
|
76
Modules/_zstd/clinic/_zstdmodule.c.h
generated
76
Modules/_zstd/clinic/_zstdmodule.c.h
generated
|
@ -10,15 +10,15 @@ preserve
|
||||||
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
|
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
|
||||||
|
|
||||||
PyDoc_STRVAR(_zstd__train_dict__doc__,
|
PyDoc_STRVAR(_zstd__train_dict__doc__,
|
||||||
"_train_dict($module, samples_bytes, samples_size_list, dict_size, /)\n"
|
"_train_dict($module, samples_bytes, samples_sizes, dict_size, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Internal function, train a zstd dictionary on sample data.\n"
|
"Internal function, train a zstd dictionary on sample data.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" samples_bytes\n"
|
" samples_bytes\n"
|
||||||
" Concatenation of samples.\n"
|
" Concatenation of samples.\n"
|
||||||
" samples_size_list\n"
|
" samples_sizes\n"
|
||||||
" List of samples\' sizes.\n"
|
" Tuple of samples\' sizes.\n"
|
||||||
" dict_size\n"
|
" dict_size\n"
|
||||||
" The size of the dictionary.");
|
" The size of the dictionary.");
|
||||||
|
|
||||||
|
@ -27,14 +27,14 @@ PyDoc_STRVAR(_zstd__train_dict__doc__,
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
_zstd__train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
|
||||||
PyObject *samples_size_list, Py_ssize_t dict_size);
|
PyObject *samples_sizes, Py_ssize_t dict_size);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__train_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
_zstd__train_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
PyBytesObject *samples_bytes;
|
PyBytesObject *samples_bytes;
|
||||||
PyObject *samples_size_list;
|
PyObject *samples_sizes;
|
||||||
Py_ssize_t dict_size;
|
Py_ssize_t dict_size;
|
||||||
|
|
||||||
if (!_PyArg_CheckPositional("_train_dict", nargs, 3, 3)) {
|
if (!_PyArg_CheckPositional("_train_dict", nargs, 3, 3)) {
|
||||||
|
@ -45,11 +45,11 @@ _zstd__train_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
samples_bytes = (PyBytesObject *)args[0];
|
samples_bytes = (PyBytesObject *)args[0];
|
||||||
if (!PyList_Check(args[1])) {
|
if (!PyTuple_Check(args[1])) {
|
||||||
_PyArg_BadArgument("_train_dict", "argument 2", "list", args[1]);
|
_PyArg_BadArgument("_train_dict", "argument 2", "tuple", args[1]);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
samples_size_list = args[1];
|
samples_sizes = args[1];
|
||||||
{
|
{
|
||||||
Py_ssize_t ival = -1;
|
Py_ssize_t ival = -1;
|
||||||
PyObject *iobj = _PyNumber_Index(args[2]);
|
PyObject *iobj = _PyNumber_Index(args[2]);
|
||||||
|
@ -62,7 +62,7 @@ _zstd__train_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
}
|
}
|
||||||
dict_size = ival;
|
dict_size = ival;
|
||||||
}
|
}
|
||||||
return_value = _zstd__train_dict_impl(module, samples_bytes, samples_size_list, dict_size);
|
return_value = _zstd__train_dict_impl(module, samples_bytes, samples_sizes, dict_size);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -70,7 +70,7 @@ exit:
|
||||||
|
|
||||||
PyDoc_STRVAR(_zstd__finalize_dict__doc__,
|
PyDoc_STRVAR(_zstd__finalize_dict__doc__,
|
||||||
"_finalize_dict($module, custom_dict_bytes, samples_bytes,\n"
|
"_finalize_dict($module, custom_dict_bytes, samples_bytes,\n"
|
||||||
" samples_size_list, dict_size, compression_level, /)\n"
|
" samples_sizes, dict_size, compression_level, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Internal function, finalize a zstd dictionary.\n"
|
"Internal function, finalize a zstd dictionary.\n"
|
||||||
|
@ -79,8 +79,8 @@ PyDoc_STRVAR(_zstd__finalize_dict__doc__,
|
||||||
" Custom dictionary content.\n"
|
" Custom dictionary content.\n"
|
||||||
" samples_bytes\n"
|
" samples_bytes\n"
|
||||||
" Concatenation of samples.\n"
|
" Concatenation of samples.\n"
|
||||||
" samples_size_list\n"
|
" samples_sizes\n"
|
||||||
" List of samples\' sizes.\n"
|
" Tuple of samples\' sizes.\n"
|
||||||
" dict_size\n"
|
" dict_size\n"
|
||||||
" The size of the dictionary.\n"
|
" The size of the dictionary.\n"
|
||||||
" compression_level\n"
|
" compression_level\n"
|
||||||
|
@ -92,7 +92,7 @@ PyDoc_STRVAR(_zstd__finalize_dict__doc__,
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
_zstd__finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
|
||||||
PyBytesObject *samples_bytes,
|
PyBytesObject *samples_bytes,
|
||||||
PyObject *samples_size_list, Py_ssize_t dict_size,
|
PyObject *samples_sizes, Py_ssize_t dict_size,
|
||||||
int compression_level);
|
int compression_level);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -101,7 +101,7 @@ _zstd__finalize_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
PyBytesObject *custom_dict_bytes;
|
PyBytesObject *custom_dict_bytes;
|
||||||
PyBytesObject *samples_bytes;
|
PyBytesObject *samples_bytes;
|
||||||
PyObject *samples_size_list;
|
PyObject *samples_sizes;
|
||||||
Py_ssize_t dict_size;
|
Py_ssize_t dict_size;
|
||||||
int compression_level;
|
int compression_level;
|
||||||
|
|
||||||
|
@ -118,11 +118,11 @@ _zstd__finalize_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
samples_bytes = (PyBytesObject *)args[1];
|
samples_bytes = (PyBytesObject *)args[1];
|
||||||
if (!PyList_Check(args[2])) {
|
if (!PyTuple_Check(args[2])) {
|
||||||
_PyArg_BadArgument("_finalize_dict", "argument 3", "list", args[2]);
|
_PyArg_BadArgument("_finalize_dict", "argument 3", "tuple", args[2]);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
samples_size_list = args[2];
|
samples_sizes = args[2];
|
||||||
{
|
{
|
||||||
Py_ssize_t ival = -1;
|
Py_ssize_t ival = -1;
|
||||||
PyObject *iobj = _PyNumber_Index(args[3]);
|
PyObject *iobj = _PyNumber_Index(args[3]);
|
||||||
|
@ -139,29 +139,29 @@ _zstd__finalize_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
if (compression_level == -1 && PyErr_Occurred()) {
|
if (compression_level == -1 && PyErr_Occurred()) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
return_value = _zstd__finalize_dict_impl(module, custom_dict_bytes, samples_bytes, samples_size_list, dict_size, compression_level);
|
return_value = _zstd__finalize_dict_impl(module, custom_dict_bytes, samples_bytes, samples_sizes, dict_size, compression_level);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_zstd__get_param_bounds__doc__,
|
PyDoc_STRVAR(_zstd__get_param_bounds__doc__,
|
||||||
"_get_param_bounds($module, /, is_compress, parameter)\n"
|
"_get_param_bounds($module, /, parameter, is_compress)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Internal function, get CParameter/DParameter bounds.\n"
|
"Internal function, get CompressionParameter/DecompressionParameter bounds.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" is_compress\n"
|
|
||||||
" True for CParameter, False for DParameter.\n"
|
|
||||||
" parameter\n"
|
" parameter\n"
|
||||||
" The parameter to get bounds.");
|
" The parameter to get bounds.\n"
|
||||||
|
" is_compress\n"
|
||||||
|
" True for CompressionParameter, False for DecompressionParameter.");
|
||||||
|
|
||||||
#define _ZSTD__GET_PARAM_BOUNDS_METHODDEF \
|
#define _ZSTD__GET_PARAM_BOUNDS_METHODDEF \
|
||||||
{"_get_param_bounds", _PyCFunction_CAST(_zstd__get_param_bounds), METH_FASTCALL|METH_KEYWORDS, _zstd__get_param_bounds__doc__},
|
{"_get_param_bounds", _PyCFunction_CAST(_zstd__get_param_bounds), METH_FASTCALL|METH_KEYWORDS, _zstd__get_param_bounds__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__get_param_bounds_impl(PyObject *module, int is_compress,
|
_zstd__get_param_bounds_impl(PyObject *module, int parameter,
|
||||||
int parameter);
|
int is_compress);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_zstd__get_param_bounds(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
_zstd__get_param_bounds(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
|
@ -178,7 +178,7 @@ _zstd__get_param_bounds(PyObject *module, PyObject *const *args, Py_ssize_t narg
|
||||||
} _kwtuple = {
|
} _kwtuple = {
|
||||||
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
|
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
|
||||||
.ob_hash = -1,
|
.ob_hash = -1,
|
||||||
.ob_item = { &_Py_ID(is_compress), &_Py_ID(parameter), },
|
.ob_item = { &_Py_ID(parameter), &_Py_ID(is_compress), },
|
||||||
};
|
};
|
||||||
#undef NUM_KEYWORDS
|
#undef NUM_KEYWORDS
|
||||||
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
|
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
|
||||||
|
@ -187,7 +187,7 @@ _zstd__get_param_bounds(PyObject *module, PyObject *const *args, Py_ssize_t narg
|
||||||
# define KWTUPLE NULL
|
# define KWTUPLE NULL
|
||||||
#endif // !Py_BUILD_CORE
|
#endif // !Py_BUILD_CORE
|
||||||
|
|
||||||
static const char * const _keywords[] = {"is_compress", "parameter", NULL};
|
static const char * const _keywords[] = {"parameter", "is_compress", NULL};
|
||||||
static _PyArg_Parser _parser = {
|
static _PyArg_Parser _parser = {
|
||||||
.keywords = _keywords,
|
.keywords = _keywords,
|
||||||
.fname = "_get_param_bounds",
|
.fname = "_get_param_bounds",
|
||||||
|
@ -195,23 +195,23 @@ _zstd__get_param_bounds(PyObject *module, PyObject *const *args, Py_ssize_t narg
|
||||||
};
|
};
|
||||||
#undef KWTUPLE
|
#undef KWTUPLE
|
||||||
PyObject *argsbuf[2];
|
PyObject *argsbuf[2];
|
||||||
int is_compress;
|
|
||||||
int parameter;
|
int parameter;
|
||||||
|
int is_compress;
|
||||||
|
|
||||||
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
|
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
|
||||||
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
|
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
|
||||||
if (!args) {
|
if (!args) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
is_compress = PyObject_IsTrue(args[0]);
|
parameter = PyLong_AsInt(args[0]);
|
||||||
if (is_compress < 0) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
parameter = PyLong_AsInt(args[1]);
|
|
||||||
if (parameter == -1 && PyErr_Occurred()) {
|
if (parameter == -1 && PyErr_Occurred()) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
return_value = _zstd__get_param_bounds_impl(module, is_compress, parameter);
|
is_compress = PyObject_IsTrue(args[1]);
|
||||||
|
if (is_compress < 0) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
return_value = _zstd__get_param_bounds_impl(module, parameter, is_compress);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -360,12 +360,12 @@ PyDoc_STRVAR(_zstd__set_parameter_types__doc__,
|
||||||
"_set_parameter_types($module, /, c_parameter_type, d_parameter_type)\n"
|
"_set_parameter_types($module, /, c_parameter_type, d_parameter_type)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Internal function, set CParameter/DParameter types for validity check.\n"
|
"Internal function, set CompressionParameter/DecompressionParameter types for validity check.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" c_parameter_type\n"
|
" c_parameter_type\n"
|
||||||
" CParameter IntEnum type object\n"
|
" CompressionParameter IntEnum type object\n"
|
||||||
" d_parameter_type\n"
|
" d_parameter_type\n"
|
||||||
" DParameter IntEnum type object");
|
" DecompressionParameter IntEnum type object");
|
||||||
|
|
||||||
#define _ZSTD__SET_PARAMETER_TYPES_METHODDEF \
|
#define _ZSTD__SET_PARAMETER_TYPES_METHODDEF \
|
||||||
{"_set_parameter_types", _PyCFunction_CAST(_zstd__set_parameter_types), METH_FASTCALL|METH_KEYWORDS, _zstd__set_parameter_types__doc__},
|
{"_set_parameter_types", _PyCFunction_CAST(_zstd__set_parameter_types), METH_FASTCALL|METH_KEYWORDS, _zstd__set_parameter_types__doc__},
|
||||||
|
@ -429,4 +429,4 @@ _zstd__set_parameter_types(PyObject *module, PyObject *const *args, Py_ssize_t n
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=077c8ea2b11fb188 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=189c462236a7096c input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -71,14 +71,14 @@ _PyZstd_set_c_parameters(ZstdCompressor *self, PyObject *level_or_options,
|
||||||
if (Py_TYPE(key) == mod_state->DParameter_type) {
|
if (Py_TYPE(key) == mod_state->DParameter_type) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Key of compression option dict should "
|
"Key of compression option dict should "
|
||||||
"NOT be DParameter.");
|
"NOT be DecompressionParameter.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int key_v = PyLong_AsInt(key);
|
int key_v = PyLong_AsInt(key);
|
||||||
if (key_v == -1 && PyErr_Occurred()) {
|
if (key_v == -1 && PyErr_Occurred()) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"Key of options dict should be a CParameter attribute.");
|
"Key of options dict should be a CompressionParameter attribute.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ _PyZstd_set_d_parameters(ZstdDecompressor *self, PyObject *options)
|
||||||
if (Py_TYPE(key) == mod_state->CParameter_type) {
|
if (Py_TYPE(key) == mod_state->CParameter_type) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Key of decompression options dict should "
|
"Key of decompression options dict should "
|
||||||
"NOT be CParameter.");
|
"NOT be CompressionParameter.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ _PyZstd_set_d_parameters(ZstdDecompressor *self, PyObject *options)
|
||||||
int key_v = PyLong_AsInt(key);
|
int key_v = PyLong_AsInt(key);
|
||||||
if (key_v == -1 && PyErr_Occurred()) {
|
if (key_v == -1 && PyErr_Occurred()) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"Key of options dict should be a DParameter attribute.");
|
"Key of options dict should be a DecompressionParameter attribute.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue