diff --git a/Lib/compression/_common/_streams.py b/Lib/compression/_common/_streams.py index 9f367d4e30440f7..3450d39e741b074 100644 --- a/Lib/compression/_common/_streams.py +++ b/Lib/compression/_common/_streams.py @@ -115,8 +115,13 @@ def readall(self): # sys.maxsize means the max length of output buffer is unlimited, # so that the whole input buffer can be decompressed within one # .decompress() call. - while data := self.read(sys.maxsize): - chunks.append(data) + try: + while data := self.read(sys.maxsize): + chunks.append(data) + except EOFError as exc: + if chunks: + exc.partial_data = b"".join(chunks) + raise return b"".join(chunks) diff --git a/Lib/gzip.py b/Lib/gzip.py index 5b6ebcfef45c3ad..b917bc05bed67b4 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -677,9 +677,10 @@ def compress(data, compresslevel=_COMPRESS_LEVEL_TRADEOFF, *, mtime=0): return header + gzip_data[10:] -def decompress(data): +def decompress(data, *, partial=False): """Decompress a gzip compressed string in one shot. Return the decompressed string. + If partial is True, returns data decompressed prior to an unexpected EOF. """ decompressed_members = [] while True: @@ -691,8 +692,14 @@ def decompress(data): # Read all the data except the header decompressed = do.decompress(data[fp.tell():]) if not do.eof or len(do.unused_data) < 8: - raise EOFError("Compressed file ended before the end-of-stream " + if partial and decompressed: + decompressed_members.append(decompressed) + return b"".join(decompressed_members) + exc = EOFError("Compressed file ended before the end-of-stream " "marker was reached") + if decompressed: + exc.partial_data = decompressed + raise exc crc, length = struct.unpack("