Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyzstd/__init__.py: 47%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from collections.abc import Callable, Mapping
2from enum import IntEnum
3from io import TextIOWrapper
4from os import PathLike
5import sys
6from typing import (
7 BinaryIO,
8 ClassVar,
9 Literal,
10 NamedTuple,
11 NoReturn,
12 TypeAlias,
13 cast,
14 overload,
15)
16import warnings
18if sys.version_info < (3, 14):
19 from backports import zstd
20else:
21 from compression import zstd
23if sys.version_info < (3, 13):
24 from typing_extensions import deprecated
25else:
26 from warnings import deprecated
28if sys.version_info < (3, 12):
29 from typing_extensions import Buffer
30else:
31 from collections.abc import Buffer
33from pyzstd._version import __version__ # noqa: F401
35__doc__ = """\
36Python bindings to Zstandard (zstd) compression library, the API style is
37similar to Python's bz2/lzma/zlib modules.
39Command line interface of this module: python -m pyzstd --help
41Documentation: https://pyzstd.readthedocs.io
42GitHub: https://github.com/Rogdham/pyzstd
43PyPI: https://pypi.org/project/pyzstd"""
45__all__ = (
46 "CParameter",
47 "DParameter",
48 "EndlessZstdDecompressor",
49 "RichMemZstdCompressor",
50 "SeekableFormatError",
51 "SeekableZstdFile",
52 "Strategy",
53 "ZstdCompressor",
54 "ZstdDecompressor",
55 "ZstdDict",
56 "ZstdError",
57 "ZstdFile",
58 "compress",
59 "compress_stream",
60 "compressionLevel_values",
61 "decompress",
62 "decompress_stream",
63 "finalize_dict",
64 "get_frame_info",
65 "get_frame_size",
66 "open",
67 "richmem_compress",
68 "train_dict",
69 "zstd_support_multithread",
70 "zstd_version",
71 "zstd_version_info",
72)
75class _DeprecatedPlaceholder:
76 def __repr__(self) -> str:
77 return "<DEPRECATED>"
80_DEPRECATED_PLACEHOLDER = _DeprecatedPlaceholder()
83Strategy = zstd.Strategy
84ZstdError = zstd.ZstdError
85ZstdDict = zstd.ZstdDict
86train_dict = zstd.train_dict
87finalize_dict = zstd.finalize_dict
88get_frame_info = zstd.get_frame_info
89get_frame_size = zstd.get_frame_size
90zstd_version = zstd.zstd_version
91zstd_version_info = zstd.zstd_version_info
94class CParameter(IntEnum):
95 """Compression parameters"""
97 compressionLevel = zstd.CompressionParameter.compression_level # noqa: N815
98 windowLog = zstd.CompressionParameter.window_log # noqa: N815
99 hashLog = zstd.CompressionParameter.hash_log # noqa: N815
100 chainLog = zstd.CompressionParameter.chain_log # noqa: N815
101 searchLog = zstd.CompressionParameter.search_log # noqa: N815
102 minMatch = zstd.CompressionParameter.min_match # noqa: N815
103 targetLength = zstd.CompressionParameter.target_length # noqa: N815
104 strategy = zstd.CompressionParameter.strategy
105 targetCBlockSize = 130 # not part of PEP-784 # noqa: N815
107 enableLongDistanceMatching = zstd.CompressionParameter.enable_long_distance_matching # noqa: N815
108 ldmHashLog = zstd.CompressionParameter.ldm_hash_log # noqa: N815
109 ldmMinMatch = zstd.CompressionParameter.ldm_min_match # noqa: N815
110 ldmBucketSizeLog = zstd.CompressionParameter.ldm_bucket_size_log # noqa: N815
111 ldmHashRateLog = zstd.CompressionParameter.ldm_hash_rate_log # noqa: N815
113 contentSizeFlag = zstd.CompressionParameter.content_size_flag # noqa: N815
114 checksumFlag = zstd.CompressionParameter.checksum_flag # noqa: N815
115 dictIDFlag = zstd.CompressionParameter.dict_id_flag # noqa: N815
117 nbWorkers = zstd.CompressionParameter.nb_workers # noqa: N815
118 jobSize = zstd.CompressionParameter.job_size # noqa: N815
119 overlapLog = zstd.CompressionParameter.overlap_log # noqa: N815
121 def bounds(self) -> tuple[int, int]:
122 """Return lower and upper bounds of a compression parameter, both inclusive."""
123 return zstd.CompressionParameter(self).bounds()
126class DParameter(IntEnum):
127 """Decompression parameters"""
129 windowLogMax = zstd.DecompressionParameter.window_log_max # noqa: N815
131 def bounds(self) -> tuple[int, int]:
132 """Return lower and upper bounds of a decompression parameter, both inclusive."""
133 return zstd.DecompressionParameter(self).bounds()
136_LevelOrOption: TypeAlias = int | Mapping[int, int] | None
137_Option: TypeAlias = Mapping[int, int] | None
138_ZstdDict: TypeAlias = ZstdDict | tuple[ZstdDict, int] | None
139_StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
142def _convert_level_or_option(
143 level_or_option: _LevelOrOption | _Option, mode: str
144) -> Mapping[int, int] | None:
145 """Transform pyzstd params into PEP-784 `options` param"""
146 if not isinstance(mode, str):
147 raise TypeError(f"Invalid mode type: {mode}")
148 read_mode = mode.startswith("r")
149 if isinstance(level_or_option, int):
150 if read_mode:
151 raise TypeError(
152 "In read mode (decompression), level_or_option argument "
153 "should be a dict object, that represents decompression "
154 "option. It doesn't support int type compression level "
155 "in this case."
156 )
157 return {
158 CParameter.compressionLevel: level_or_option,
159 }
160 if level_or_option is not None:
161 invalid_class = CParameter if read_mode else DParameter
162 for key in level_or_option:
163 if isinstance(key, invalid_class):
164 raise TypeError(
165 "Key of compression option dict should "
166 f"NOT be {invalid_class.__name__}."
167 )
168 return level_or_option
171class ZstdCompressor:
172 """A streaming compressor. Thread-safe at method level."""
174 CONTINUE: ClassVar[Literal[0]] = zstd.ZstdCompressor.CONTINUE
175 """Used for mode parameter in .compress() method.
177 Collect more data, encoder decides when to output compressed result, for optimal
178 compression ratio. Usually used for traditional streaming compression.
179 """
181 FLUSH_BLOCK: ClassVar[Literal[1]] = zstd.ZstdCompressor.FLUSH_BLOCK
182 """Used for mode parameter in .compress(), .flush() methods.
184 Flush any remaining data, but don't close the current frame. Usually used for
185 communication scenarios.
187 If there is data, it creates at least one new block, that can be decoded
188 immediately on reception. If no remaining data, no block is created, return b''.
190 Note: Abuse of this mode will reduce compression ratio. Use it only when
191 necessary.
192 """
194 FLUSH_FRAME: ClassVar[Literal[2]] = zstd.ZstdCompressor.FLUSH_FRAME
195 """Used for mode parameter in .compress(), .flush() methods.
197 Flush any remaining data, and close the current frame. Usually used for
198 traditional flush.
200 Since zstd data consists of one or more independent frames, data can still be
201 provided after a frame is closed.
203 Note: Abuse of this mode will reduce compression ratio, and some programs can
204 only decompress single frame data. Use it only when necessary.
205 """
207 def __init__(
208 self, level_or_option: _LevelOrOption = None, zstd_dict: _ZstdDict = None
209 ) -> None:
210 """Initialize a ZstdCompressor object.
212 Parameters
213 level_or_option: When it's an int object, it represents the compression level.
214 When it's a dict object, it contains advanced compression
215 parameters.
216 zstd_dict: A ZstdDict object, pre-trained zstd dictionary.
217 """
218 zstd_dict = cast(
219 "ZstdDict | None", zstd_dict
220 ) # https://github.com/python/typeshed/pull/15113
221 self._compressor = zstd.ZstdCompressor(
222 options=_convert_level_or_option(level_or_option, "w"), zstd_dict=zstd_dict
223 )
225 def compress(
226 self, data: Buffer, mode: Literal[0, 1, 2] = zstd.ZstdCompressor.CONTINUE
227 ) -> bytes:
228 """Provide data to the compressor object.
229 Return a chunk of compressed data if possible, or b'' otherwise.
231 Parameters
232 data: A bytes-like object, data to be compressed.
233 mode: Can be these 3 values .CONTINUE, .FLUSH_BLOCK, .FLUSH_FRAME.
234 """
235 return self._compressor.compress(data, mode)
237 def flush(self, mode: Literal[1, 2] = zstd.ZstdCompressor.FLUSH_FRAME) -> bytes:
238 """Flush any remaining data in internal buffer.
240 Since zstd data consists of one or more independent frames, the compressor
241 object can still be used after this method is called.
243 Parameter
244 mode: Can be these 2 values .FLUSH_FRAME, .FLUSH_BLOCK.
245 """
246 return self._compressor.flush(mode)
248 def _set_pledged_input_size(self, size: int | None) -> None:
249 """*This is an undocumented method, because it may be used incorrectly.*
251 Set uncompressed content size of a frame, the size will be written into the
252 frame header.
253 1, If called when (.last_mode != .FLUSH_FRAME), a RuntimeError will be raised.
254 2, If the actual size doesn't match the value, a ZstdError will be raised, and
255 the last compressed chunk is likely to be lost.
256 3, The size is only valid for one frame, then it restores to "unknown size".
258 Parameter
259 size: Uncompressed content size of a frame, None means "unknown size".
260 """
261 return self._compressor.set_pledged_input_size(size)
263 @property
264 def last_mode(self) -> Literal[0, 1, 2]:
265 """The last mode used to this compressor object, its value can be .CONTINUE,
266 .FLUSH_BLOCK, .FLUSH_FRAME. Initialized to .FLUSH_FRAME.
268 It can be used to get the current state of a compressor, such as, data flushed,
269 a frame ended.
270 """
271 return self._compressor.last_mode
273 def __reduce__(self) -> NoReturn:
274 raise TypeError(f"Cannot pickle {type(self)} object.")
277class ZstdDecompressor:
278 """A streaming decompressor, it stops after a frame is decompressed.
279 Thread-safe at method level."""
281 def __init__(self, zstd_dict: _ZstdDict = None, option: _Option = None) -> None:
282 """Initialize a ZstdDecompressor object.
284 Parameters
285 zstd_dict: A ZstdDict object, pre-trained zstd dictionary.
286 option: A dict object that contains advanced decompression parameters.
287 """
288 zstd_dict = cast(
289 "ZstdDict | None", zstd_dict
290 ) # https://github.com/python/typeshed/pull/15113
291 self._decompressor = zstd.ZstdDecompressor(
292 zstd_dict=zstd_dict, options=_convert_level_or_option(option, "r")
293 )
295 def decompress(self, data: Buffer, max_length: int = -1) -> bytes:
296 """Decompress data, return a chunk of decompressed data if possible, or b''
297 otherwise.
299 It stops after a frame is decompressed.
301 Parameters
302 data: A bytes-like object, zstd data to be decompressed.
303 max_length: Maximum size of returned data. When it is negative, the size of
304 output buffer is unlimited. When it is nonnegative, returns at
305 most max_length bytes of decompressed data.
306 """
307 return self._decompressor.decompress(data, max_length)
309 @property
310 def eof(self) -> bool:
311 """True means the end of the first frame has been reached. If decompress data
312 after that, an EOFError exception will be raised."""
313 return self._decompressor.eof
315 @property
316 def needs_input(self) -> bool:
317 """If the max_length output limit in .decompress() method has been reached, and
318 the decompressor has (or may has) unconsumed input data, it will be set to
319 False. In this case, pass b'' to .decompress() method may output further data.
320 """
321 return self._decompressor.needs_input
323 @property
324 def unused_data(self) -> bytes:
325 """A bytes object. When ZstdDecompressor object stops after a frame is
326 decompressed, unused input data after the frame. Otherwise this will be b''."""
327 return self._decompressor.unused_data
329 def __reduce__(self) -> NoReturn:
330 raise TypeError(f"Cannot pickle {type(self)} object.")
333class EndlessZstdDecompressor:
334 """A streaming decompressor, accepts multiple concatenated frames.
335 Thread-safe at method level."""
337 def __init__(self, zstd_dict: _ZstdDict = None, option: _Option = None) -> None:
338 """Initialize an EndlessZstdDecompressor object.
340 Parameters
341 zstd_dict: A ZstdDict object, pre-trained zstd dictionary.
342 option: A dict object that contains advanced decompression parameters.
343 """
344 self._zstd_dict = cast(
345 "ZstdDict | None", zstd_dict
346 ) # https://github.com/python/typeshed/pull/15113
347 self._options = _convert_level_or_option(option, "r")
348 self._reset()
350 def _reset(self, data: bytes = b"") -> None:
351 self._decompressor = zstd.ZstdDecompressor(
352 zstd_dict=self._zstd_dict, options=self._options
353 )
354 self._buffer = data
355 self._at_frame_edge = not data
357 def decompress(self, data: Buffer, max_length: int = -1) -> bytes:
358 """Decompress data, return a chunk of decompressed data if possible, or b''
359 otherwise.
361 Parameters
362 data: A bytes-like object, zstd data to be decompressed.
363 max_length: Maximum size of returned data. When it is negative, the size of
364 output buffer is unlimited. When it is nonnegative, returns at
365 most max_length bytes of decompressed data.
366 """
367 if not isinstance(data, bytes) or not isinstance(max_length, int):
368 raise TypeError
369 self._buffer += data
370 self._at_frame_edge &= not self._buffer
371 out = b""
372 while True:
373 try:
374 out += self._decompressor.decompress(self._buffer, max_length)
375 except ZstdError:
376 self._reset()
377 raise
378 if self._decompressor.eof:
379 self._reset(self._decompressor.unused_data)
380 max_length -= len(out)
381 else:
382 self._buffer = b""
383 break
384 return out
386 @property
387 def at_frame_edge(self) -> bool:
388 """True when both the input and output streams are at a frame edge, means a
389 frame is completely decoded and fully flushed, or the decompressor just be
390 initialized.
392 This flag could be used to check data integrity in some cases.
393 """
394 return self._at_frame_edge
396 @property
397 def needs_input(self) -> bool:
398 """If the max_length output limit in .decompress() method has been reached, and
399 the decompressor has (or may has) unconsumed input data, it will be set to
400 False. In this case, pass b'' to .decompress() method may output further data.
401 """
402 return not self._buffer and (
403 self._at_frame_edge or self._decompressor.needs_input
404 )
406 def __reduce__(self) -> NoReturn:
407 raise TypeError(f"Cannot pickle {type(self)} object.")
410def compress(
411 data: Buffer, level_or_option: _LevelOrOption = None, zstd_dict: _ZstdDict = None
412) -> bytes:
413 """Compress a block of data, return a bytes object.
415 Compressing b'' will get an empty content frame (9 bytes or more).
417 Parameters
418 data: A bytes-like object, data to be compressed.
419 level_or_option: When it's an int object, it represents compression level.
420 When it's a dict object, it contains advanced compression
421 parameters.
422 zstd_dict: A ZstdDict object, pre-trained dictionary for compression.
423 """
424 zstd_dict = cast(
425 "ZstdDict | None", zstd_dict
426 ) # https://github.com/python/typeshed/pull/15113
427 return zstd.compress(
428 data,
429 options=_convert_level_or_option(level_or_option, "w"),
430 zstd_dict=zstd_dict,
431 )
434def decompress(
435 data: Buffer, zstd_dict: _ZstdDict = None, option: _Option = None
436) -> bytes:
437 """Decompress a zstd data, return a bytes object.
439 Support multiple concatenated frames.
441 Parameters
442 data: A bytes-like object, compressed zstd data.
443 zstd_dict: A ZstdDict object, pre-trained zstd dictionary.
444 option: A dict object, contains advanced decompression parameters.
445 """
446 zstd_dict = cast(
447 "ZstdDict | None", zstd_dict
448 ) # https://github.com/python/typeshed/pull/15113
449 return zstd.decompress(
450 data, options=_convert_level_or_option(option, "r"), zstd_dict=zstd_dict
451 )
454@deprecated(
455 "See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.RichMemZstdCompressor"
456)
457class RichMemZstdCompressor:
458 def __init__(
459 self, level_or_option: _LevelOrOption = None, zstd_dict: _ZstdDict = None
460 ) -> None:
461 self._options = _convert_level_or_option(level_or_option, "w")
462 self._zstd_dict = cast(
463 "ZstdDict | None", zstd_dict
464 ) # https://github.com/python/typeshed/pull/15113
466 def compress(self, data: Buffer) -> bytes:
467 return zstd.compress(data, options=self._options, zstd_dict=self._zstd_dict)
469 def __reduce__(self) -> NoReturn:
470 raise TypeError(f"Cannot pickle {type(self)} object.")
473richmem_compress = deprecated(
474 "See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.richmem_compress"
475)(compress)
478class ZstdFile(zstd.ZstdFile):
479 """A file object providing transparent zstd (de)compression.
481 A ZstdFile can act as a wrapper for an existing file object, or refer
482 directly to a named file on disk.
484 Note that ZstdFile provides a *binary* file interface - data read is
485 returned as bytes, and data to be written should be an object that
486 supports the Buffer Protocol.
487 """
489 def __init__(
490 self,
491 filename: _StrOrBytesPath | BinaryIO,
492 mode: Literal["r", "rb", "w", "wb", "x", "xb", "a", "ab"] = "r",
493 *,
494 level_or_option: _LevelOrOption | _Option = None,
495 zstd_dict: _ZstdDict = None,
496 read_size: int | _DeprecatedPlaceholder = _DEPRECATED_PLACEHOLDER,
497 write_size: int | _DeprecatedPlaceholder = _DEPRECATED_PLACEHOLDER,
498 ) -> None:
499 """Open a zstd compressed file in binary mode.
501 filename can be either an actual file name (given as a str, bytes, or
502 PathLike object), in which case the named file is opened, or it can be
503 an existing file object to read from or write to.
505 mode can be "r" for reading (default), "w" for (over)writing, "x" for
506 creating exclusively, or "a" for appending. These can equivalently be
507 given as "rb", "wb", "xb" and "ab" respectively.
509 Parameters
510 level_or_option: When it's an int object, it represents compression
511 level. When it's a dict object, it contains advanced compression
512 parameters. Note, in read mode (decompression), it can only be a
513 dict object, that represents decompression option. It doesn't
514 support int type compression level in this case.
515 zstd_dict: A ZstdDict object, pre-trained dictionary for compression /
516 decompression.
517 """
518 if read_size != _DEPRECATED_PLACEHOLDER:
519 warnings.warn(
520 "pyzstd.ZstdFile()'s read_size parameter is deprecated",
521 DeprecationWarning,
522 stacklevel=2,
523 )
524 if write_size != _DEPRECATED_PLACEHOLDER:
525 warnings.warn(
526 "pyzstd.ZstdFile()'s write_size parameter is deprecated",
527 DeprecationWarning,
528 stacklevel=2,
529 )
530 zstd_dict = cast(
531 "ZstdDict | None", zstd_dict
532 ) # https://github.com/python/typeshed/pull/15113
533 super().__init__(
534 filename,
535 mode,
536 options=_convert_level_or_option(level_or_option, mode),
537 zstd_dict=zstd_dict,
538 )
541@overload
542def open( # noqa: A001
543 filename: _StrOrBytesPath | BinaryIO,
544 mode: Literal["r", "rb", "w", "wb", "a", "ab", "x", "xb"] = "rb",
545 *,
546 level_or_option: _LevelOrOption | _Option = None,
547 zstd_dict: _ZstdDict = None,
548 encoding: None = None,
549 errors: None = None,
550 newline: None = None,
551) -> zstd.ZstdFile: ...
554@overload
555def open( # noqa: A001
556 filename: _StrOrBytesPath | BinaryIO,
557 mode: Literal["rt", "wt", "at", "xt"],
558 *,
559 level_or_option: _LevelOrOption | _Option = None,
560 zstd_dict: _ZstdDict = None,
561 encoding: str | None = None,
562 errors: str | None = None,
563 newline: str | None = None,
564) -> TextIOWrapper: ...
567def open( # noqa: A001
568 filename: _StrOrBytesPath | BinaryIO,
569 mode: Literal[
570 "r", "rb", "w", "wb", "a", "ab", "x", "xb", "rt", "wt", "at", "xt"
571 ] = "rb",
572 *,
573 level_or_option: _LevelOrOption | _Option = None,
574 zstd_dict: _ZstdDict = None,
575 encoding: str | None = None,
576 errors: str | None = None,
577 newline: str | None = None,
578) -> zstd.ZstdFile | TextIOWrapper:
579 """Open a zstd compressed file in binary or text mode.
581 filename can be either an actual file name (given as a str, bytes, or
582 PathLike object), in which case the named file is opened, or it can be an
583 existing file object to read from or write to.
585 The mode parameter can be "r", "rb" (default), "w", "wb", "x", "xb", "a",
586 "ab" for binary mode, or "rt", "wt", "xt", "at" for text mode.
588 The level_or_option and zstd_dict parameters specify the settings, as for
589 ZstdCompressor, ZstdDecompressor and ZstdFile.
591 When using read mode (decompression), the level_or_option parameter can
592 only be a dict object, that represents decompression option. It doesn't
593 support int type compression level in this case.
595 For binary mode, this function is equivalent to the ZstdFile constructor:
596 ZstdFile(filename, mode, ...). In this case, the encoding, errors and
597 newline parameters must not be provided.
599 For text mode, an ZstdFile object is created, and wrapped in an
600 io.TextIOWrapper instance with the specified encoding, error handling
601 behavior, and line ending(s).
602 """
603 zstd_dict = cast(
604 "ZstdDict | None", zstd_dict
605 ) # https://github.com/python/typeshed/pull/15113
606 return zstd.open(
607 filename,
608 mode,
609 options=_convert_level_or_option(level_or_option, mode),
610 zstd_dict=zstd_dict,
611 encoding=encoding,
612 errors=errors,
613 newline=newline,
614 )
617def _create_callback(
618 output_stream: BinaryIO | None,
619 callback: Callable[[int, int, memoryview, memoryview], None] | None,
620) -> Callable[[int, int, bytes, bytes], None]:
621 if output_stream is None:
622 if callback is None:
623 raise TypeError(
624 "At least one of output_stream argument and callback argument should be non-None."
625 )
627 def cb(
628 total_input: int, total_output: int, data_in: bytes, data_out: bytes
629 ) -> None:
630 callback(
631 total_input, total_output, memoryview(data_in), memoryview(data_out)
632 )
634 elif callback is None:
636 def cb(
637 total_input: int, # noqa: ARG001
638 total_output: int, # noqa: ARG001
639 data_in: bytes, # noqa: ARG001
640 data_out: bytes,
641 ) -> None:
642 output_stream.write(data_out)
644 else:
646 def cb(
647 total_input: int, total_output: int, data_in: bytes, data_out: bytes
648 ) -> None:
649 output_stream.write(data_out)
650 callback(
651 total_input, total_output, memoryview(data_in), memoryview(data_out)
652 )
654 return cb
657@deprecated(
658 "See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.compress_stream"
659)
660def compress_stream(
661 input_stream: BinaryIO,
662 output_stream: BinaryIO | None,
663 *,
664 level_or_option: _LevelOrOption = None,
665 zstd_dict: _ZstdDict = None,
666 pledged_input_size: int | None = None,
667 read_size: int = 131_072,
668 write_size: int | _DeprecatedPlaceholder = _DEPRECATED_PLACEHOLDER, # noqa: ARG001
669 callback: Callable[[int, int, memoryview, memoryview], None] | None = None,
670) -> tuple[int, int]:
671 """Compresses input_stream and writes the compressed data to output_stream, it
672 doesn't close the streams.
674 ----
675 DEPRECATION NOTICE
676 The (de)compress_stream are deprecated and will be removed in a future version.
677 See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives
678 ----
680 If input stream is b'', nothing will be written to output stream.
682 Return a tuple, (total_input, total_output), the items are int objects.
684 Parameters
685 input_stream: Input stream that has a .readinto(b) method.
686 output_stream: Output stream that has a .write(b) method. If use callback
687 function, this parameter can be None.
688 level_or_option: When it's an int object, it represents the compression
689 level. When it's a dict object, it contains advanced compression
690 parameters.
691 zstd_dict: A ZstdDict object, pre-trained zstd dictionary.
692 pledged_input_size: If set this parameter to the size of input data, the
693 size will be written into the frame header. If the actual input data
694 doesn't match it, a ZstdError will be raised.
695 read_size: Input buffer size, in bytes.
696 callback: A callback function that accepts four parameters:
697 (total_input, total_output, read_data, write_data), the first two are
698 int objects, the last two are readonly memoryview objects.
699 """
700 if not hasattr(input_stream, "read"):
701 raise TypeError("input_stream argument should have a .read() method.")
702 if output_stream is not None and not hasattr(output_stream, "write"):
703 raise TypeError("output_stream argument should have a .write() method.")
704 if read_size < 1:
705 raise ValueError("read_size argument should be a positive number.")
706 callback = _create_callback(output_stream, callback)
707 total_input = 0
708 total_output = 0
709 compressor = ZstdCompressor(level_or_option, zstd_dict)
710 if pledged_input_size is not None and pledged_input_size != 2**64 - 1:
711 compressor._set_pledged_input_size(pledged_input_size) # noqa: SLF001
712 while data_in := input_stream.read(read_size):
713 total_input += len(data_in)
714 data_out = compressor.compress(data_in)
715 total_output += len(data_out)
716 callback(total_input, total_output, data_in, data_out)
717 if not total_input:
718 return total_input, total_output
719 data_out = compressor.flush()
720 total_output += len(data_out)
721 callback(total_input, total_output, b"", data_out)
722 return total_input, total_output
725@deprecated(
726 "See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.decompress_stream"
727)
728def decompress_stream(
729 input_stream: BinaryIO,
730 output_stream: BinaryIO | None,
731 *,
732 zstd_dict: _ZstdDict = None,
733 option: _Option = None,
734 read_size: int = 131_075,
735 write_size: int = 131_072,
736 callback: Callable[[int, int, memoryview, memoryview], None] | None = None,
737) -> tuple[int, int]:
738 """Decompresses input_stream and writes the decompressed data to output_stream,
739 it doesn't close the streams.
741 ----
742 DEPRECATION NOTICE
743 The (de)compress_stream are deprecated and will be removed in a future version.
744 See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives
745 ----
747 Supports multiple concatenated frames.
749 Return a tuple, (total_input, total_output), the items are int objects.
751 Parameters
752 input_stream: Input stream that has a .readinto(b) method.
753 output_stream: Output stream that has a .write(b) method. If use callback
754 function, this parameter can be None.
755 zstd_dict: A ZstdDict object, pre-trained zstd dictionary.
756 option: A dict object, contains advanced decompression parameters.
757 read_size: Input buffer size, in bytes.
758 write_size: Output buffer size, in bytes.
759 callback: A callback function that accepts four parameters:
760 (total_input, total_output, read_data, write_data), the first two are
761 int objects, the last two are readonly memoryview objects.
762 """
763 if not hasattr(input_stream, "read"):
764 raise TypeError("input_stream argument should have a .read() method.")
765 if output_stream is not None and not hasattr(output_stream, "write"):
766 raise TypeError("output_stream argument should have a .write() method.")
767 if read_size < 1 or write_size < 1:
768 raise ValueError(
769 "read_size argument and write_size argument should be positive numbers."
770 )
771 callback = _create_callback(output_stream, callback)
772 total_input = 0
773 total_output = 0
774 decompressor = EndlessZstdDecompressor(zstd_dict, option)
775 while True:
776 if decompressor.needs_input:
777 data_in = input_stream.read(read_size)
778 if not data_in:
779 break
780 else:
781 data_in = b""
782 total_input += len(data_in)
783 data_out = decompressor.decompress(data_in, write_size)
784 total_output += len(data_out)
785 callback(total_input, total_output, data_in, data_out)
786 if not decompressor.at_frame_edge:
787 raise ZstdError(
788 "Decompression failed: zstd data ends in an incomplete frame,"
789 " maybe the input data was truncated."
790 f" Total input {total_input} bytes, total output {total_output} bytes."
791 )
792 return total_input, total_output
795class CompressionValues(NamedTuple):
796 default: int
797 min: int
798 max: int
801compressionLevel_values = CompressionValues( # noqa: N816
802 zstd.COMPRESSION_LEVEL_DEFAULT, *CParameter.compressionLevel.bounds()
803)
804zstd_support_multithread = CParameter.nbWorkers.bounds() != (0, 0)
807# import here to avoid circular dependency issues
808from ._seekable_zstdfile import SeekableFormatError, SeekableZstdFile # noqa: E402