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

251 statements  

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 

17 

18if sys.version_info < (3, 14): 

19 from backports import zstd 

20else: 

21 from compression import zstd 

22 

23if sys.version_info < (3, 13): 

24 from typing_extensions import deprecated 

25else: 

26 from warnings import deprecated 

27 

28if sys.version_info < (3, 12): 

29 from typing_extensions import Buffer 

30else: 

31 from collections.abc import Buffer 

32 

33from pyzstd._version import __version__ # noqa: F401 

34 

35__doc__ = """\ 

36Python bindings to Zstandard (zstd) compression library, the API style is 

37similar to Python's bz2/lzma/zlib modules. 

38 

39Command line interface of this module: python -m pyzstd --help 

40 

41Documentation: https://pyzstd.readthedocs.io 

42GitHub: https://github.com/Rogdham/pyzstd 

43PyPI: https://pypi.org/project/pyzstd""" 

44 

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) 

73 

74 

75class _DeprecatedPlaceholder: 

76 def __repr__(self) -> str: 

77 return "<DEPRECATED>" 

78 

79 

80_DEPRECATED_PLACEHOLDER = _DeprecatedPlaceholder() 

81 

82 

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 

92 

93 

94class CParameter(IntEnum): 

95 """Compression parameters""" 

96 

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 

106 

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 

112 

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 

116 

117 nbWorkers = zstd.CompressionParameter.nb_workers # noqa: N815 

118 jobSize = zstd.CompressionParameter.job_size # noqa: N815 

119 overlapLog = zstd.CompressionParameter.overlap_log # noqa: N815 

120 

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() 

124 

125 

126class DParameter(IntEnum): 

127 """Decompression parameters""" 

128 

129 windowLogMax = zstd.DecompressionParameter.window_log_max # noqa: N815 

130 

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() 

134 

135 

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] 

140 

141 

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 

169 

170 

171class ZstdCompressor: 

172 """A streaming compressor. Thread-safe at method level.""" 

173 

174 CONTINUE: ClassVar[Literal[0]] = zstd.ZstdCompressor.CONTINUE 

175 """Used for mode parameter in .compress() method. 

176 

177 Collect more data, encoder decides when to output compressed result, for optimal 

178 compression ratio. Usually used for traditional streaming compression. 

179 """ 

180 

181 FLUSH_BLOCK: ClassVar[Literal[1]] = zstd.ZstdCompressor.FLUSH_BLOCK 

182 """Used for mode parameter in .compress(), .flush() methods. 

183 

184 Flush any remaining data, but don't close the current frame. Usually used for 

185 communication scenarios. 

186 

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''. 

189 

190 Note: Abuse of this mode will reduce compression ratio. Use it only when 

191 necessary. 

192 """ 

193 

194 FLUSH_FRAME: ClassVar[Literal[2]] = zstd.ZstdCompressor.FLUSH_FRAME 

195 """Used for mode parameter in .compress(), .flush() methods. 

196 

197 Flush any remaining data, and close the current frame. Usually used for 

198 traditional flush. 

199 

200 Since zstd data consists of one or more independent frames, data can still be 

201 provided after a frame is closed. 

202 

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 """ 

206 

207 def __init__( 

208 self, level_or_option: _LevelOrOption = None, zstd_dict: _ZstdDict = None 

209 ) -> None: 

210 """Initialize a ZstdCompressor object. 

211 

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 ) 

224 

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. 

230 

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) 

236 

237 def flush(self, mode: Literal[1, 2] = zstd.ZstdCompressor.FLUSH_FRAME) -> bytes: 

238 """Flush any remaining data in internal buffer. 

239 

240 Since zstd data consists of one or more independent frames, the compressor 

241 object can still be used after this method is called. 

242 

243 Parameter 

244 mode: Can be these 2 values .FLUSH_FRAME, .FLUSH_BLOCK. 

245 """ 

246 return self._compressor.flush(mode) 

247 

248 def _set_pledged_input_size(self, size: int | None) -> None: 

249 """*This is an undocumented method, because it may be used incorrectly.* 

250 

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". 

257 

258 Parameter 

259 size: Uncompressed content size of a frame, None means "unknown size". 

260 """ 

261 return self._compressor.set_pledged_input_size(size) 

262 

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. 

267 

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 

272 

273 def __reduce__(self) -> NoReturn: 

274 raise TypeError(f"Cannot pickle {type(self)} object.") 

275 

276 

277class ZstdDecompressor: 

278 """A streaming decompressor, it stops after a frame is decompressed. 

279 Thread-safe at method level.""" 

280 

281 def __init__(self, zstd_dict: _ZstdDict = None, option: _Option = None) -> None: 

282 """Initialize a ZstdDecompressor object. 

283 

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 ) 

294 

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. 

298 

299 It stops after a frame is decompressed. 

300 

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) 

308 

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 

314 

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 

322 

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 

328 

329 def __reduce__(self) -> NoReturn: 

330 raise TypeError(f"Cannot pickle {type(self)} object.") 

331 

332 

333class EndlessZstdDecompressor: 

334 """A streaming decompressor, accepts multiple concatenated frames. 

335 Thread-safe at method level.""" 

336 

337 def __init__(self, zstd_dict: _ZstdDict = None, option: _Option = None) -> None: 

338 """Initialize an EndlessZstdDecompressor object. 

339 

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() 

349 

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 

356 

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. 

360 

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 

385 

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. 

391 

392 This flag could be used to check data integrity in some cases. 

393 """ 

394 return self._at_frame_edge 

395 

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 ) 

405 

406 def __reduce__(self) -> NoReturn: 

407 raise TypeError(f"Cannot pickle {type(self)} object.") 

408 

409 

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. 

414 

415 Compressing b'' will get an empty content frame (9 bytes or more). 

416 

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 ) 

432 

433 

434def decompress( 

435 data: Buffer, zstd_dict: _ZstdDict = None, option: _Option = None 

436) -> bytes: 

437 """Decompress a zstd data, return a bytes object. 

438 

439 Support multiple concatenated frames. 

440 

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 ) 

452 

453 

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 

465 

466 def compress(self, data: Buffer) -> bytes: 

467 return zstd.compress(data, options=self._options, zstd_dict=self._zstd_dict) 

468 

469 def __reduce__(self) -> NoReturn: 

470 raise TypeError(f"Cannot pickle {type(self)} object.") 

471 

472 

473richmem_compress = deprecated( 

474 "See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.richmem_compress" 

475)(compress) 

476 

477 

478class ZstdFile(zstd.ZstdFile): 

479 """A file object providing transparent zstd (de)compression. 

480 

481 A ZstdFile can act as a wrapper for an existing file object, or refer 

482 directly to a named file on disk. 

483 

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 """ 

488 

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. 

500 

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. 

504 

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. 

508 

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 ) 

539 

540 

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: ... 

552 

553 

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: ... 

565 

566 

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. 

580 

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. 

584 

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. 

587 

588 The level_or_option and zstd_dict parameters specify the settings, as for 

589 ZstdCompressor, ZstdDecompressor and ZstdFile. 

590 

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. 

594 

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. 

598 

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 ) 

615 

616 

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 ) 

626 

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 ) 

633 

634 elif callback is None: 

635 

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) 

643 

644 else: 

645 

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 ) 

653 

654 return cb 

655 

656 

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. 

673 

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 ---- 

679 

680 If input stream is b'', nothing will be written to output stream. 

681 

682 Return a tuple, (total_input, total_output), the items are int objects. 

683 

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 

723 

724 

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. 

740 

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 ---- 

746 

747 Supports multiple concatenated frames. 

748 

749 Return a tuple, (total_input, total_output), the items are int objects. 

750 

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 

793 

794 

795class CompressionValues(NamedTuple): 

796 default: int 

797 min: int 

798 max: int 

799 

800 

801compressionLevel_values = CompressionValues( # noqa: N816 

802 zstd.COMPRESSION_LEVEL_DEFAULT, *CParameter.compressionLevel.bounds() 

803) 

804zstd_support_multithread = CParameter.nbWorkers.bounds() != (0, 0) 

805 

806 

807# import here to avoid circular dependency issues 

808from ._seekable_zstdfile import SeekableFormatError, SeekableZstdFile # noqa: E402