Skip to content

Commit 1746868

Browse files
committed
feat: deprecate (de)compress_stream functions
1 parent 3cc40fa commit 1746868

File tree

10 files changed

+270
-248
lines changed

10 files changed

+270
-248
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
77
- Upgrade zstd source code from v1.5.6 to [v1.5.7](https://github.com/facebook/zstd/releases/tag/v1.5.7)
88
- Raise an exception when attempting to decompress empty data
99
- Add `ZstdFile.name` property
10+
- Deprecate `(de)compress_stream` functions
1011
- Build wheels for Windows ARM64
1112
- Support for PyPy 3.11
1213

docs/deprecated.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.. title:: pyzstd module: deprecations
2+
3+
:py:func:`compress_stream`
4+
--------------------------
5+
6+
.. sourcecode:: python
7+
8+
# before
9+
with io.open(input_file_path, 'rb') as ifh:
10+
with io.open(output_file_path, 'wb') as ofh:
11+
compress_stream(ifh, ofh, level_or_option=5)
12+
13+
# after
14+
with io.open(input_file_path, 'rb') as ifh:
15+
with pyzstd.open(output_file_path, 'w', level_or_option=5) as ofh:
16+
shutil.copyfileobj(ifh, ofh)
17+
18+
.. hint::
19+
Instead of the ``read_size`` and ``write_size`` parameters, you can use
20+
:py:func:`shutil.copyfileobj`'s ``length`` parameter.
21+
22+
*Deprecated in version 0.17.0.*
23+
24+
25+
:py:func:`decompress_stream`
26+
--------------------------
27+
28+
.. sourcecode:: python
29+
30+
# before
31+
with io.open(input_file_path, 'rb') as ifh:
32+
with io.open(output_file_path, 'wb') as ofh:
33+
decompress_stream(ifh, ofh)
34+
35+
# after
36+
with pyzstd.open(input_file_path) as ifh:
37+
with io.open(output_file_path, 'wb') as ofh:
38+
shutil.copyfileobj(ifh, ofh)
39+
40+
.. hint::
41+
Instead of the ``read_size`` and ``write_size`` parameters, you can use
42+
:py:func:`shutil.copyfileobj`'s ``length`` parameter.
43+
44+
*Deprecated in version 0.17.0.*

docs/index.rst

Lines changed: 15 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -154,79 +154,12 @@ Rich memory compression
154154
Streaming compression
155155
---------------------
156156

157-
This section contains:
157+
You can use :py:class:`ZstdFile` for compressing data as needed. Advanced users may be interested in:
158158

159-
* function :py:func:`compress_stream`, a fast and convenient function.
160159
* class :py:class:`ZstdCompressor`, similar to compressors in Python standard library.
161160

162161
It would be nice to know some knowledge about zstd data, see :ref:`frame and block<frame_block>`.
163162

164-
.. py:function:: compress_stream(input_stream, output_stream, *, level_or_option=None, zstd_dict=None, pledged_input_size=None, read_size=131_072, write_size=131_591, callback=None)
165-
166-
A fast and convenient function, compresses *input_stream* and writes the compressed data to *output_stream*, it doesn't close the streams.
167-
168-
If input stream is ``b''``, nothing will be written to output stream.
169-
170-
This function tries to zero-copy as much as possible. If the OS has read prefetching and write buffer, it may perform the tasks (read/compress/write) in parallel to some degree.
171-
172-
The default values of *read_size* and *write_size* parameters are the buffer sizes recommended by zstd, increasing them may be faster, and reduces the number of callback function calls.
173-
174-
.. versionadded:: 0.14.2
175-
176-
:param input_stream: Input stream that has a `.readinto(b) <https://docs.python.org/3/library/io.html#io.RawIOBase.readinto>`_ method.
177-
:param output_stream: Output stream that has a `.write(b) <https://docs.python.org/3/library/io.html#io.RawIOBase.write>`_ method. If use *callback* function, this parameter can be ``None``.
178-
:param level_or_option: When it's an ``int`` object, it represents :ref:`compression level<compression_level>`. When it's a ``dict`` object, it contains :ref:`advanced compression parameters<CParameter>`. The default value ``None`` means to use zstd's default compression level/parameters.
179-
:type level_or_option: int or dict
180-
:param zstd_dict: Pre-trained dictionary for compression.
181-
:type zstd_dict: ZstdDict
182-
:param pledged_input_size: If set this parameter to the size of input data, the :ref:`size<content_size>` will be written into the frame header. If the actual input data doesn't match it, a :py:class:`ZstdError` exception will be raised. It may increase compression ratio slightly, and help decompression code to allocate output buffer faster.
183-
:type pledged_input_size: int
184-
:param read_size: Input buffer size, in bytes.
185-
:type read_size: int
186-
:param write_size: Output buffer size, in bytes.
187-
:type write_size: int
188-
:param callback: A callback function that accepts four parameters: ``(total_input, total_output, read_data, write_data)``. The first two are ``int`` objects. The last two are readonly `memoryview <https://docs.python.org/3/library/stdtypes.html#memory-views>`_ objects, if want to reference the data (or its slice) outside the callback function, `convert <https://docs.python.org/3/library/stdtypes.html#memoryview.tobytes>`_ them to ``bytes`` objects. If input stream is ``b''``, the callback function will not be called.
189-
:type callback: callable
190-
:return: A 2-item tuple, ``(total_input, total_output)``, the items are ``int`` objects.
191-
192-
.. sourcecode:: python
193-
194-
# compress an input file, and write to an output file.
195-
with io.open(input_file_path, 'rb') as ifh:
196-
with io.open(output_file_path, 'wb') as ofh:
197-
compress_stream(ifh, ofh, level_or_option=5)
198-
199-
# compress a bytes object, and write to a file.
200-
with io.BytesIO(raw_dat) as bi:
201-
with io.open(output_file_path, 'wb') as ofh:
202-
compress_stream(bi, ofh, pledged_input_size=len(raw_dat))
203-
204-
# Compress an input file, obtain a bytes object.
205-
# It's faster than reading a file and compressing it in
206-
# memory, tested on Ubuntu(Python3.8)/Windows(Python3.9).
207-
# Maybe the OS has prefetching, it can read and compress
208-
# data in parallel to some degree, reading file from HDD
209-
# is the bottleneck in this case.
210-
with io.open(input_file_path, 'rb') as ifh:
211-
with io.BytesIO() as bo:
212-
compress_stream(ifh, bo)
213-
compressed_dat = bo.getvalue()
214-
215-
# Print progress using callback function
216-
def compress_print_progress(input_file_path, output_file_path):
217-
input_file_size = os.path.getsize(input_file_path)
218-
219-
def func(total_input, total_output, read_data, write_data):
220-
# If input stream is empty, the callback function
221-
# will not be called. So no ZeroDivisionError here.
222-
percent = 100 * total_input / input_file_size
223-
print(f'Progress: {percent:.1f}%', end='\r')
224-
225-
with io.open(input_file_path, 'rb') as ifh:
226-
with io.open(output_file_path, 'wb') as ofh:
227-
compress_stream(ifh, ofh, callback=func)
228-
229-
230163
.. py:class:: ZstdCompressor
231164
232165
A streaming compressor. It's thread-safe at method level.
@@ -316,76 +249,11 @@ Streaming compression
316249
Streaming decompression
317250
-----------------------
318251

319-
This section contains:
252+
You can use :py:class:`ZstdFile` for decompressing data as needed. Advanced users may be interested in:
320253

321-
* function :py:func:`decompress_stream`, a fast and convenient function.
322254
* class :py:class:`ZstdDecompressor`, similar to decompressors in Python standard library.
323255
* class :py:class:`EndlessZstdDecompressor`, a decompressor accepts multiple concatenated :ref:`frames<frame_block>`.
324256

325-
.. py:function:: decompress_stream(input_stream, output_stream, *, zstd_dict=None, option=None, read_size=131_075, write_size=131_072, callback=None)
326-
327-
A fast and convenient function, decompresses *input_stream* and writes the decompressed data to *output_stream*, it doesn't close the streams.
328-
329-
Supports multiple concatenated :ref:`frames<frame_block>`.
330-
331-
This function tries to zero-copy as much as possible. If the OS has read prefetching and write buffer, it may perform the tasks (read/decompress/write) in parallel to some degree.
332-
333-
The default values of *read_size* and *write_size* parameters are the buffer sizes recommended by zstd, increasing them may be faster, and reduces the number of callback function calls.
334-
335-
.. versionadded:: 0.14.2
336-
337-
:param input_stream: Input stream that has a `.readinto(b) <https://docs.python.org/3/library/io.html#io.RawIOBase.readinto>`_ method.
338-
:param output_stream: Output stream that has a `.write(b) <https://docs.python.org/3/library/io.html#io.RawIOBase.write>`_ method. If use *callback* function, this parameter can be ``None``.
339-
:param zstd_dict: Pre-trained dictionary for decompression.
340-
:type zstd_dict: ZstdDict
341-
:param option: A ``dict`` object, contains :ref:`advanced decompression parameters<DParameter>`.
342-
:type option: dict
343-
:param read_size: Input buffer size, in bytes.
344-
:type read_size: int
345-
:param write_size: Output buffer size, in bytes.
346-
:type write_size: int
347-
:param callback: A callback function that accepts four parameters: ``(total_input, total_output, read_data, write_data)``. The first two are ``int`` objects. The last two are readonly `memoryview <https://docs.python.org/3/library/stdtypes.html#memory-views>`_ objects, if want to reference the data (or its slice) outside the callback function, `convert <https://docs.python.org/3/library/stdtypes.html#memoryview.tobytes>`_ them to ``bytes`` objects. If input stream is ``b''``, the callback function will not be called.
348-
:type callback: callable
349-
:return: A 2-item tuple, ``(total_input, total_output)``, the items are ``int`` objects.
350-
:raises ZstdError: If decompression fails.
351-
352-
.. sourcecode:: python
353-
354-
# decompress an input file, and write to an output file.
355-
with io.open(input_file_path, 'rb') as ifh:
356-
with io.open(output_file_path, 'wb') as ofh:
357-
decompress_stream(ifh, ofh)
358-
359-
# decompress a bytes object, and write to a file.
360-
with io.BytesIO(compressed_dat) as bi:
361-
with io.open(output_file_path, 'wb') as ofh:
362-
decompress_stream(bi, ofh)
363-
364-
# Decompress an input file, obtain a bytes object.
365-
# It's faster than reading a file and decompressing it in
366-
# memory, tested on Ubuntu(Python3.8)/Windows(Python3.9).
367-
# Maybe the OS has prefetching, it can read and decompress
368-
# data in parallel to some degree, reading file from HDD
369-
# is the bottleneck in this case.
370-
with io.open(input_file_path, 'rb') as ifh:
371-
with io.BytesIO() as bo:
372-
decompress_stream(ifh, bo)
373-
decompressed_dat = bo.getvalue()
374-
375-
# Print progress using callback function
376-
def decompress_print_progress(input_file_path, output_file_path):
377-
input_file_size = os.path.getsize(input_file_path)
378-
379-
def func(total_input, total_output, read_data, write_data):
380-
# If input stream is empty, the callback function
381-
# will not be called. So no ZeroDivisionError here.
382-
percent = 100 * total_input / input_file_size
383-
print(f'Progress: {percent:.1f}%', end='\r')
384-
385-
with io.open(input_file_path, 'rb') as ifh:
386-
with io.open(output_file_path, 'wb') as ofh:
387-
decompress_stream(ifh, ofh, callback=func)
388-
389257

390258
.. py:class:: ZstdDecompressor
391259
@@ -1210,7 +1078,6 @@ Advanced parameters
12101078
* :py:func:`richmem_compress` function
12111079
* :py:class:`ZstdCompressor` class using a single :py:attr:`~ZstdCompressor.FLUSH_FRAME` mode
12121080
* :py:class:`RichMemZstdCompressor` class
1213-
* :py:func:`compress_stream` function setting *pledged_input_size* parameter
12141081

12151082
The field in frame header is 1/2/4/8 bytes, depending on size value. It may help decompression code to allocate output buffer faster.
12161083

@@ -1537,16 +1404,16 @@ Use with tarfile module
15371404

15381405
import contextlib
15391406
import io
1407+
import shutil
15401408
import tarfile
15411409
import tempfile
1542-
from pyzstd import decompress_stream
1410+
import pyzstd
15431411

15441412
@contextlib.contextmanager
1545-
def ZstdTarReader(name, *, zstd_dict=None, option=None, **kwargs):
1413+
def ZstdTarReader(name, *, zstd_dict=None, level_or_option=None, **kwargs):
15461414
with tempfile.TemporaryFile() as tmp_file:
1547-
with io.open(name, 'rb') as ifh:
1548-
decompress_stream(ifh, tmp_file,
1549-
zstd_dict=zstd_dict, option=option)
1415+
with pyzstd.open(name, level_or_option=level_or_option, zstd_dict=zstd_dict) as ifh:
1416+
shutil.copyfile(ifh, tmp_file)
15501417
tmp_file.seek(0)
15511418
with tarfile.TarFile(fileobj=tmp_file, **kwargs) as tar:
15521419
yield tar
@@ -1718,3 +1585,11 @@ Build pyzstd module with options
17181585
3️⃣ Disable mremap output buffer on CPython+Linux.
17191586

17201587
On CPython(3.5~3.12)+Linux, pyzstd uses another output buffer code that can utilize the ``mremap`` mechanism, which brings some performance improvements. If this causes problems, you may use ``--no-mremap`` option to disable this code.
1588+
1589+
1590+
Deprecations
1591+
>>>>>>>>>>>>
1592+
1593+
See `list of deprecations with alternatives <./deprecated.html>`_.
1594+
1595+
Also, note that `unsupported Python versions <https://devguide.python.org/versions/#supported-versions>` are not tested against and have no wheels uploaded on PyPI.

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ def do_setup():
204204
url='https://github.com/Rogdham/pyzstd',
205205
license='BSD-3-Clause',
206206
python_requires='>=3.5',
207+
install_requires=["typing-extensions>=4.13.2 ; python_version<'3.13'"],
207208

208209
classifiers=[
209210
"Development Status :: 5 - Production/Stable",
@@ -229,7 +230,7 @@ def do_setup():
229230
test_suite='tests'
230231
)
231232

232-
if sys.version_info < (3, 8):
233+
if sys.version_info < (3, 9):
233234
print()
234235
print("WARNING")
235236
print(" Python {} has reached end of life.".format(platform.python_version()))

src/__init__.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
_ZSTD_DStreamSizes,
1818
_finalize_dict,
1919
_train_dict,
20-
compress_stream,
20+
compress_stream as _compress_stream,
2121
compressionLevel_values,
2222
decompress,
23-
decompress_stream,
23+
decompress_stream as _decompress_stream,
2424
get_frame_info,
2525
get_frame_size,
2626
zstd_version,
@@ -46,10 +46,10 @@
4646
_ZSTD_DStreamSizes,
4747
_finalize_dict,
4848
_train_dict,
49-
compress_stream,
49+
compress_stream as _compress_stream,
5050
compressionLevel_values,
5151
decompress,
52-
decompress_stream,
52+
decompress_stream as _decompress_stream,
5353
get_frame_info,
5454
get_frame_size,
5555
zstd_version,
@@ -67,6 +67,14 @@
6767
from .zstdfile import ZstdFile, open
6868
from .seekable_zstdfile import SeekableFormatError, SeekableZstdFile
6969

70+
from functools import wraps
71+
72+
try:
73+
from warnings import deprecated
74+
except ImportError:
75+
from typing_extensions import deprecated
76+
77+
7078
__version__ = '0.16.2'
7179

7280
__doc__ = '''\
@@ -223,3 +231,14 @@ def finalize_dict(zstd_dict, samples, dict_size, level):
223231
dict_size, level)
224232

225233
return ZstdDict(dict_content)
234+
235+
236+
@wraps(_compress_stream)
237+
@deprecated("See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.compress_stream")
238+
def compress_stream(*args, **kwargs):
239+
return _compress_stream(*args, **kwargs)
240+
241+
@wraps(_decompress_stream)
242+
@deprecated("See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.decompress_stream")
243+
def decompress_stream(*args, **kwargs):
244+
return _decompress_stream(*args, **kwargs)

src/__init__.pyi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ from typing import overload, Dict, ByteString, Optional, Union, Callable, \
55
Iterable, Literal, ClassVar, Tuple, NamedTuple, BinaryIO, \
66
TextIO
77

8+
try:
9+
from warnings import deprecated
10+
except ImportError:
11+
from typing_extensions import deprecated
12+
813
__version__: str
914
zstd_version: str
1015
zstd_version_info: Tuple[int, int, int]
@@ -146,13 +151,15 @@ def decompress(data: ByteString,
146151
zstd_dict: Union[None, ZstdDict, ZstdDictInfo] = None,
147152
option: Optional[Dict[DParameter, int]] = None) -> bytes: ...
148153

154+
@deprecated("See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.compress_stream")
149155
def compress_stream(input_stream: BinaryIO, output_stream: Union[BinaryIO, None], *,
150156
level_or_option: Union[None, int, Dict[CParameter, int]] = None,
151157
zstd_dict: Union[None, ZstdDict, ZstdDictInfo] = None,
152158
pledged_input_size: Optional[int] = None,
153159
read_size: int = 131_072, write_size: int = 131_591,
154160
callback: Optional[Callable[[int, int, memoryview, memoryview], None]] = None) -> Tuple[int, int]: ...
155161

162+
@deprecated("See https://pyzstd.readthedocs.io/en/stable/deprecated.html for alternatives to pyzstd.decompress_stream")
156163
def decompress_stream(input_stream: BinaryIO, output_stream: Union[BinaryIO, None], *,
157164
zstd_dict: Union[None, ZstdDict, ZstdDictInfo] = None,
158165
option: Optional[Dict[DParameter, int]] = None,

0 commit comments

Comments
 (0)