Skip to content

Commit f4d2dfd

Browse files
StanFromIrelandvstinner
authored andcommitted
[3.14] zlib.rst: Link to constants and deduplicate text (pythonGH-140115)
* Link to compression setting constants from compression functions * De-duplicate descriptions of the constants (cherry picked from commit 091e851) Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 2699643 commit f4d2dfd

File tree

2 files changed

+217
-18
lines changed

2 files changed

+217
-18
lines changed

Doc/library/zlib.rst

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,20 @@ The available exception and functions in this module are:
4444
.. versionchanged:: 3.0
4545
The result is always unsigned.
4646

47-
.. function:: compress(data, /, level=-1, wbits=MAX_WBITS)
47+
.. function:: compress(data, /, level=Z_DEFAULT_COMPRESSION, wbits=MAX_WBITS)
4848

4949
Compresses the bytes in *data*, returning a bytes object containing compressed data.
5050
*level* is an integer from ``0`` to ``9`` or ``-1`` controlling the level of compression;
51-
``1`` (Z_BEST_SPEED) is fastest and produces the least compression, ``9`` (Z_BEST_COMPRESSION)
52-
is slowest and produces the most. ``0`` (Z_NO_COMPRESSION) is no compression.
53-
The default value is ``-1`` (Z_DEFAULT_COMPRESSION). Z_DEFAULT_COMPRESSION represents a default
54-
compromise between speed and compression (currently equivalent to level 6).
51+
See :const:`Z_BEST_SPEED` (``1``), :const:`Z_BEST_COMPRESSION` (``9``),
52+
:const:`Z_NO_COMPRESSION` (``0``), and the default,
53+
:const:`Z_DEFAULT_COMPRESSION` (``-1``) for more information about these values.
5554

5655
.. _compress-wbits:
5756

5857
The *wbits* argument controls the size of the history buffer (or the
5958
"window size") used when compressing data, and whether a header and
6059
trailer is included in the output. It can take several ranges of values,
61-
defaulting to ``15`` (MAX_WBITS):
60+
defaulting to ``15`` (:const:`MAX_WBITS`):
6261

6362
* +9 to +15: The base-two logarithm of the window size, which
6463
therefore ranges between 512 and 32768. Larger values produce
@@ -82,17 +81,15 @@ The available exception and functions in this module are:
8281
The *wbits* parameter is now available to set window bits and
8382
compression type.
8483

85-
.. function:: compressobj(level=-1, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY[, zdict])
84+
.. function:: compressobj(level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY[, zdict])
8685

8786
Returns a compression object, to be used for compressing data streams that won't
8887
fit into memory at once.
8988

9089
*level* is the compression level -- an integer from ``0`` to ``9`` or ``-1``.
91-
A value of ``1`` (Z_BEST_SPEED) is fastest and produces the least compression,
92-
while a value of ``9`` (Z_BEST_COMPRESSION) is slowest and produces the most.
93-
``0`` (Z_NO_COMPRESSION) is no compression. The default value is ``-1`` (Z_DEFAULT_COMPRESSION).
94-
Z_DEFAULT_COMPRESSION represents a default compromise between speed and compression
95-
(currently equivalent to level 6).
90+
See :const:`Z_BEST_SPEED` (``1``), :const:`Z_BEST_COMPRESSION` (``9``),
91+
:const:`Z_NO_COMPRESSION` (``0``), and the default,
92+
:const:`Z_DEFAULT_COMPRESSION` (``-1``) for more information about these values.
9693

9794
*method* is the compression algorithm. Currently, the only supported value is
9895
:const:`DEFLATED`.
@@ -107,7 +104,7 @@ The available exception and functions in this module are:
107104

108105
*strategy* is used to tune the compression algorithm. Possible values are
109106
:const:`Z_DEFAULT_STRATEGY`, :const:`Z_FILTERED`, :const:`Z_HUFFMAN_ONLY`,
110-
:const:`Z_RLE` (zlib 1.2.0.1) and :const:`Z_FIXED` (zlib 1.2.2.2).
107+
:const:`Z_RLE` and :const:`Z_FIXED`.
111108

112109
*zdict* is a predefined compression dictionary. This is a sequence of bytes
113110
(such as a :class:`bytes` object) containing subsequences that are expected
@@ -221,7 +218,7 @@ Compression objects support the following methods:
221218
All pending input is processed, and a bytes object containing the remaining compressed
222219
output is returned. *mode* can be selected from the constants
223220
:const:`Z_NO_FLUSH`, :const:`Z_PARTIAL_FLUSH`, :const:`Z_SYNC_FLUSH`,
224-
:const:`Z_FULL_FLUSH`, :const:`Z_BLOCK` (zlib 1.2.3.4), or :const:`Z_FINISH`,
221+
:const:`Z_FULL_FLUSH`, :const:`Z_BLOCK`, or :const:`Z_FINISH`,
225222
defaulting to :const:`Z_FINISH`. Except :const:`Z_FINISH`, all constants
226223
allow compressing further bytestrings of data, while :const:`Z_FINISH` finishes the
227224
compressed stream and prevents compressing any more data. After calling :meth:`flush`
@@ -339,24 +336,25 @@ behavior:
339336

340337
.. data:: Z_NO_COMPRESSION
341338

342-
Compression level ``0``.
339+
Compression level ``0``; no compression.
343340

344341
.. versionadded:: 3.6
345342

346343

347344
.. data:: Z_BEST_SPEED
348345

349-
Compression level ``1``.
346+
Compression level ``1``; fastest and produces the least compression.
350347

351348

352349
.. data:: Z_BEST_COMPRESSION
353350

354-
Compression level ``9``.
351+
Compression level ``9``; slowest and produces the most compression.
355352

356353

357354
.. data:: Z_DEFAULT_COMPRESSION
358355

359-
Default compression level (``-1``).
356+
Default compression level (``-1``); a compromise between speed and
357+
compression. Currently equivalent to compression level ``6``.
360358

361359

362360
.. data:: Z_DEFAULT_STRATEGY

Lib/zipfile/__init__.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import threading
1515
import time
1616

17+
from compression._common import _streams
18+
1719
try:
1820
import zlib # We may need its compression method
1921
crc32 = zlib.crc32
@@ -881,6 +883,205 @@ def _get_decompressor(compress_type):
881883
raise NotImplementedError("compression type %d" % (compress_type,))
882884

883885

886+
# Value 0 no longer used
887+
_MODE_READ = 1
888+
# Value 2 no longer used
889+
_MODE_WRITE = 3
890+
891+
class _DeflateFile(_streams.BaseStream):
892+
893+
"""A file object providing transparent Deflate (de)compression.
894+
895+
A _DeflateFile can act as a wrapper for an existing file object, or
896+
refer directly to a named file on disk.
897+
898+
Note that _DeflateFile provides a *binary* file interface - data read
899+
is returned as bytes, and data to be written must be given as bytes.
900+
"""
901+
902+
def __init__(self, filename=None, mode="r", *,
903+
level=zlib.Z_DEFAULT_COMPRESSION, method=zlib.DEFLATED,
904+
wbits=zlib.MAX_WBITS, memLevel=zlib.DEF_MEM_LEVEL,
905+
strategy=zlib.Z_DEFAULT_STRATEGY, zdict=None):
906+
"""Open an Deflate-compressed file in binary mode.
907+
908+
TODO(emmatyping): docstring
909+
"""
910+
self._fp = None
911+
self._closefp = False
912+
self._mode = None
913+
914+
if mode in ("r", "rb"):
915+
mode_code = _MODE_READ
916+
elif mode in ("w", "wb", "a", "ab", "x", "xb"):
917+
mode_code = _MODE_WRITE
918+
self._compressor = zlib.compressobj(level, method, wbits, memLevel,
919+
strategy, zdict)
920+
self._pos = 0
921+
else:
922+
raise ValueError("Invalid mode: {!r}".format(mode))
923+
924+
if isinstance(filename, (str, bytes, os.PathLike)):
925+
if "b" not in mode:
926+
mode += "b"
927+
self._fp = io.open(filename, mode)
928+
self._closefp = True
929+
self._mode = mode_code
930+
elif hasattr(filename, "read") or hasattr(filename, "write"):
931+
self._fp = filename
932+
self._mode = mode_code
933+
else:
934+
raise TypeError("filename must be a str, bytes, file or PathLike object")
935+
936+
if self._mode == _MODE_READ:
937+
raw = _streams.DecompressReader(self._fp, zlib.decompressobj,
938+
trailing_error=zlib.error, wbits=wbits, zdict=zdict)
939+
self._buffer = io.BufferedReader(raw)
940+
941+
def close(self):
942+
"""Flush and close the file.
943+
944+
May be called more than once without error. Once the file is
945+
closed, any other operation on it will raise a ValueError.
946+
"""
947+
if self.closed:
948+
return
949+
try:
950+
if self._mode == _MODE_READ:
951+
self._buffer.close()
952+
self._buffer = None
953+
elif self._mode == _MODE_WRITE:
954+
self._fp.write(self._compressor.flush())
955+
self._compressor = None
956+
finally:
957+
try:
958+
if self._closefp:
959+
self._fp.close()
960+
finally:
961+
self._fp = None
962+
self._closefp = False
963+
964+
@property
965+
def closed(self):
966+
"""True if this file is closed."""
967+
return self._fp is None
968+
969+
@property
970+
def name(self):
971+
self._check_not_closed()
972+
return self._fp.name
973+
974+
@property
975+
def mode(self):
976+
return 'wb' if self._mode == _MODE_WRITE else 'rb'
977+
978+
def fileno(self):
979+
"""Return the file descriptor for the underlying file."""
980+
self._check_not_closed()
981+
return self._fp.fileno()
982+
983+
def seekable(self):
984+
"""Return whether the file supports seeking."""
985+
return self.readable() and self._buffer.seekable()
986+
987+
def readable(self):
988+
"""Return whether the file was opened for reading."""
989+
self._check_not_closed()
990+
return self._mode == _MODE_READ
991+
992+
def writable(self):
993+
"""Return whether the file was opened for writing."""
994+
self._check_not_closed()
995+
return self._mode == _MODE_WRITE
996+
997+
def peek(self, size=-1):
998+
"""Return buffered data without advancing the file position.
999+
1000+
Always returns at least one byte of data, unless at EOF.
1001+
The exact number of bytes returned is unspecified.
1002+
"""
1003+
self._check_can_read()
1004+
# Relies on the undocumented fact that BufferedReader.peek() always
1005+
# returns at least one byte (except at EOF)
1006+
return self._buffer.peek(size)
1007+
1008+
def read(self, size=-1):
1009+
"""Read up to size uncompressed bytes from the file.
1010+
1011+
If size is negative or omitted, read until EOF is reached.
1012+
Returns b"" if the file is already at EOF.
1013+
"""
1014+
self._check_can_read()
1015+
return self._buffer.read(size)
1016+
1017+
def read1(self, size=-1):
1018+
"""Read up to size uncompressed bytes, while trying to avoid
1019+
making multiple reads from the underlying stream. Reads up to a
1020+
buffer's worth of data if size is negative.
1021+
1022+
Returns b"" if the file is at EOF.
1023+
"""
1024+
self._check_can_read()
1025+
if size < 0:
1026+
size = io.DEFAULT_BUFFER_SIZE
1027+
return self._buffer.read1(size)
1028+
1029+
def readline(self, size=-1):
1030+
"""Read a line of uncompressed bytes from the file.
1031+
1032+
The terminating newline (if present) is retained. If size is
1033+
non-negative, no more than size bytes will be read (in which
1034+
case the line may be incomplete). Returns b'' if already at EOF.
1035+
"""
1036+
self._check_can_read()
1037+
return self._buffer.readline(size)
1038+
1039+
def write(self, data):
1040+
"""Write a bytes object to the file.
1041+
1042+
Returns the number of uncompressed bytes written, which is
1043+
always the length of data in bytes. Note that due to buffering,
1044+
the file on disk may not reflect the data written until close()
1045+
is called.
1046+
"""
1047+
self._check_can_write()
1048+
if isinstance(data, (bytes, bytearray)):
1049+
length = len(data)
1050+
else:
1051+
# accept any data that supports the buffer protocol
1052+
data = memoryview(data)
1053+
length = data.nbytes
1054+
1055+
compressed = self._compressor.compress(data)
1056+
self._fp.write(compressed)
1057+
self._pos += length
1058+
return length
1059+
1060+
def seek(self, offset, whence=io.SEEK_SET):
1061+
"""Change the file position.
1062+
1063+
The new position is specified by offset, relative to the
1064+
position indicated by whence. Possible values for whence are:
1065+
1066+
0: start of stream (default): offset must not be negative
1067+
1: current stream position
1068+
2: end of stream; offset must not be positive
1069+
1070+
Returns the new file position.
1071+
1072+
Note that seeking is emulated, so depending on the parameters,
1073+
this operation may be extremely slow.
1074+
"""
1075+
self._check_can_seek()
1076+
return self._buffer.seek(offset, whence)
1077+
1078+
def tell(self):
1079+
"""Return the current file position."""
1080+
self._check_not_closed()
1081+
if self._mode == _MODE_READ:
1082+
return self._buffer.tell()
1083+
return self._pos
1084+
8841085
class _SharedFile:
8851086
def __init__(self, file, pos, close, lock, writing):
8861087
self._file = file

0 commit comments

Comments
 (0)