diff options
author | R David Murray <rdmurray@bitdance.com> | 2013-03-07 16:43:58 -0500 |
---|---|---|
committer | R David Murray <rdmurray@bitdance.com> | 2013-03-07 16:43:58 -0500 |
commit | c2051f1fa112c1dc2b28d65e597eda85cb2e56ea (patch) | |
tree | 4740415dcb2c2ae56d4cbe11616cdc02922b6661 /Lib/gzip.py | |
parent | 9979ecb3f2a13f92284f6d1d6e419101d48ec211 (diff) | |
parent | 5ac5e0bf7238d635e4f2079d13083c61a886d9de (diff) | |
download | cpython-c2051f1fa112c1dc2b28d65e597eda85cb2e56ea.tar.gz |
Merge: #14645: Generator now emits correct linesep for all parts.
Previously the parts of the message retained whatever linesep they had on
read, which means if the messages weren't read in univeral newline mode, the
line endings could well be inconsistent. In general sending it via smtplib
would result in them getting fixed, but it is better to generate them
correctly to begin with. Also, the new send_message method of smtplib does
not do the fixup, so that method is producing rfc-invalid output without this
fix.
Diffstat (limited to 'Lib/gzip.py')
-rw-r--r-- | Lib/gzip.py | 96 |
1 files changed, 70 insertions, 26 deletions
diff --git a/Lib/gzip.py b/Lib/gzip.py index 8fb1ed06c9..d7da02ca1b 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -16,31 +16,54 @@ FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16 READ, WRITE = 1, 2 -def U32(i): - """Return i as an unsigned integer, assuming it fits in 32 bits. - If it's >= 2GB when viewed as a 32-bit unsigned int, return a long. - """ - if i < 0: - i += 1 << 32 - return i +def open(filename, mode="rb", compresslevel=9, + encoding=None, errors=None, newline=None): + """Open a gzip-compressed file in binary or text mode. -def LOWU32(i): - """Return the low-order 32 bits, as a non-negative int""" - return i & 0xFFFFFFFF + The filename argument can be an actual filename (a str or bytes object), or + an existing file object to read from or write to. -def write32u(output, value): - # The L format writes the bit pattern correctly whether signed - # or unsigned. - output.write(struct.pack("<L", value)) + The mode argument can be "r", "rb", "w", "wb", "a" or "ab" for binary mode, + or "rt", "wt" or "at" for text mode. The default mode is "rb", and the + default compresslevel is 9. -def open(filename, mode="rb", compresslevel=9): - """Shorthand for GzipFile(filename, mode, compresslevel). + For binary mode, this function is equivalent to the GzipFile constructor: + GzipFile(filename, mode, compresslevel). In this case, the encoding, errors + and newline arguments must not be provided. - The filename argument is required; mode defaults to 'rb' - and compresslevel defaults to 9. + For text mode, a GzipFile object is created, and wrapped in an + io.TextIOWrapper instance with the specified encoding, error handling + behavior, and line ending(s). """ - return GzipFile(filename, mode, compresslevel) + if "t" in mode: + if "b" in mode: + raise ValueError("Invalid mode: %r" % (mode,)) + 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") + + gz_mode = mode.replace("t", "") + if isinstance(filename, (str, bytes)): + binary_file = GzipFile(filename, gz_mode, compresslevel) + elif hasattr(filename, "read") or hasattr(filename, "write"): + binary_file = GzipFile(None, gz_mode, compresslevel, filename) + else: + raise TypeError("filename must be a str or bytes object, or a file") + + if "t" in mode: + return io.TextIOWrapper(binary_file, encoding, errors, newline) + else: + return binary_file + +def write32u(output, value): + # The L format writes the bit pattern correctly whether signed + # or unsigned. + output.write(struct.pack("<L", value)) class _PaddedFile: """Minimal read-only file object that prepends a string to the contents @@ -103,7 +126,7 @@ class GzipFile(io.BufferedIOBase): the exception of the readinto() and truncate() methods. This class only supports opening files in binary mode. If you need to open a - compressed file in text mode, wrap your GzipFile with an io.TextIOWrapper. + compressed file in text mode, use the gzip.open() function. """ @@ -151,7 +174,7 @@ class GzipFile(io.BufferedIOBase): """ if mode and ('t' in mode or 'U' in mode): - raise IOError("Mode " + mode + " not supported") + raise ValueError("Invalid mode: {!r}".format(mode)) if mode and 'b' not in mode: mode += 'b' if fileobj is None: @@ -161,10 +184,9 @@ class GzipFile(io.BufferedIOBase): if not isinstance(filename, (str, bytes)): filename = '' if mode is None: - if hasattr(fileobj, 'mode'): mode = fileobj.mode - else: mode = 'rb' + mode = getattr(fileobj, 'mode', 'rb') - if mode[0:1] == 'r': + if mode.startswith('r'): self.mode = READ # Set flag indicating start of a new member self._new_member = True @@ -179,7 +201,7 @@ class GzipFile(io.BufferedIOBase): self.min_readsize = 100 fileobj = _PaddedFile(fileobj) - elif mode[0:1] == 'w' or mode[0:1] == 'a': + elif mode.startswith(('w', 'a')): self.mode = WRITE self._init_write(filename) self.compress = zlib.compressobj(compresslevel, @@ -188,7 +210,7 @@ class GzipFile(io.BufferedIOBase): zlib.DEF_MEM_LEVEL, 0) else: - raise IOError("Mode " + mode + " not supported") + raise ValueError("Invalid mode: {!r}".format(mode)) self.fileobj = fileobj self.offset = 0 @@ -352,6 +374,28 @@ class GzipFile(io.BufferedIOBase): self.offset += size return chunk + def read1(self, size=-1): + self._check_closed() + if self.mode != READ: + import errno + raise IOError(errno.EBADF, "read1() on write-only GzipFile object") + + if self.extrasize <= 0 and self.fileobj is None: + return b'' + + # For certain input data, a single call to _read() may not return + # any data. In this case, retry until we get some data or reach EOF. + while self.extrasize <= 0 and self._read(): + pass + if size < 0 or size > self.extrasize: + size = self.extrasize + + offset = self.offset - self.extrastart + chunk = self.extrabuf[offset: offset + size] + self.extrasize -= size + self.offset += size + return chunk + def peek(self, n): if self.mode != READ: import errno |