From b930d63cb10cd228301413c643a0b83e5efae5d2 Mon Sep 17 00:00:00 2001 From: guoci Date: Thu, 4 Oct 2018 17:26:16 -0400 Subject: [PATCH 1/5] Add `mtime` argument to `gzip.compress` --- Doc/library/gzip.rst | 4 ++-- Lib/gzip.py | 4 ++-- Lib/test/test_gzip.py | 10 ++++++++++ .../Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index a57307b0e49921..171210975c452f 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -157,10 +157,10 @@ The module defines the following items: Accepts a :term:`path-like object`. -.. function:: compress(data, compresslevel=9) +.. function:: compress(data, compresslevel=9, mtime=None) Compress the *data*, returning a :class:`bytes` object containing - the compressed data. *compresslevel* has the same meaning as in + the compressed data. *compresslevel* and *mtime* has the same meaning as in the :class:`GzipFile` constructor above. .. versionadded:: 3.2 diff --git a/Lib/gzip.py b/Lib/gzip.py index 151ff1405b164c..304f464fce72d4 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -520,12 +520,12 @@ def _rewind(self): super()._rewind() self._new_member = True -def compress(data, compresslevel=_COMPRESS_LEVEL_BEST): +def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, mtime=None): """Compress data in one shot and return the compressed string. Optional argument is the compression level, in range of 0-9. """ buf = io.BytesIO() - with GzipFile(fileobj=buf, mode='wb', compresslevel=compresslevel) as f: + with GzipFile(fileobj=buf, mode='wb', compresslevel=compresslevel, mtime=mtime) as f: f.write(data) return buf.getvalue() diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index 1e8b41f07b3ecf..ac851d6080fb93 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -499,6 +499,16 @@ def test_compress(self): with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f: self.assertEqual(f.read(), data) + def test_compress_mtime(self): + mtime = 123456789 + for data in [data1, data2]: + for args in [(1, mtime), (6, mtime), (9, mtime)]: + datac = gzip.compress(data, *args) + self.assertEqual(type(datac), bytes) + with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f: + f.read(1) # to set mtime attribute + self.assertEqual(f.mtime, mtime) + def test_decompress(self): for data in (data1, data2): buf = io.BytesIO() diff --git a/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst b/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst new file mode 100644 index 00000000000000..3c6b824e1f61e5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst @@ -0,0 +1 @@ +Add `mtime` argument to `gzip.compress` for reproducible output. From 968168c61b1649ce9696ef143822a55d0d6a5512 Mon Sep 17 00:00:00 2001 From: guoci Date: Thu, 11 Oct 2018 17:14:58 -0400 Subject: [PATCH 2/5] resolve issues from review --- Doc/library/gzip.rst | 2 ++ Lib/test/test_gzip.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 171210975c452f..c088675f3705d4 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -164,6 +164,8 @@ The module defines the following items: the :class:`GzipFile` constructor above. .. versionadded:: 3.2 + .. versionchanged:: 3.8 + Added *mtime* argument .. function:: decompress(data) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index ac851d6080fb93..09272b1efe3fc2 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -503,11 +503,12 @@ def test_compress_mtime(self): mtime = 123456789 for data in [data1, data2]: for args in [(1, mtime), (6, mtime), (9, mtime)]: - datac = gzip.compress(data, *args) - self.assertEqual(type(datac), bytes) - with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f: - f.read(1) # to set mtime attribute - self.assertEqual(f.mtime, mtime) + with self.subTest(data=data,args=args): + datac = gzip.compress(data, *args) + self.assertEqual(type(datac), bytes) + with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f: + f.read(1) # to set mtime attribute + self.assertEqual(f.mtime, mtime) def test_decompress(self): for data in (data1, data2): From 66659eb5519d8ed2cef1798558541ecdc607ab56 Mon Sep 17 00:00:00 2001 From: guoci Date: Sun, 14 Oct 2018 12:06:01 -0400 Subject: [PATCH 3/5] correct grammar in the documentation --- Doc/library/gzip.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index c088675f3705d4..c0dc54fce25b2f 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -160,7 +160,7 @@ The module defines the following items: .. function:: compress(data, compresslevel=9, mtime=None) Compress the *data*, returning a :class:`bytes` object containing - the compressed data. *compresslevel* and *mtime* has the same meaning as in + the compressed data. *compresslevel* and *mtime* have the same meaning as in the :class:`GzipFile` constructor above. .. versionadded:: 3.2 From 88749c8444c1721841367f6256c82b84dad2743e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 5 Nov 2018 14:54:24 -0500 Subject: [PATCH 4/5] Apply suggestion Co-Authored-By: guoci --- Lib/test/test_gzip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index 09272b1efe3fc2..16fb39c2c97f3f 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -503,7 +503,7 @@ def test_compress_mtime(self): mtime = 123456789 for data in [data1, data2]: for args in [(1, mtime), (6, mtime), (9, mtime)]: - with self.subTest(data=data,args=args): + with self.subTest(data=data, args=args): datac = gzip.compress(data, *args) self.assertEqual(type(datac), bytes) with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f: From 6f465cc07aba91c83264453ba33b5befba3b8a95 Mon Sep 17 00:00:00 2001 From: guoci Date: Mon, 5 Nov 2018 16:03:31 -0500 Subject: [PATCH 5/5] resolve issues in review --- Doc/library/gzip.rst | 4 ++-- Doc/whatsnew/3.8.rst | 7 +++++++ Lib/gzip.py | 2 +- Lib/test/test_gzip.py | 4 ++-- Misc/ACKS | 1 + .../next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst | 1 + 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index c0dc54fce25b2f..8850a33f4abb90 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -157,7 +157,7 @@ The module defines the following items: Accepts a :term:`path-like object`. -.. function:: compress(data, compresslevel=9, mtime=None) +.. function:: compress(data, compresslevel=9, *, mtime=None) Compress the *data*, returning a :class:`bytes` object containing the compressed data. *compresslevel* and *mtime* have the same meaning as in @@ -165,7 +165,7 @@ The module defines the following items: .. versionadded:: 3.2 .. versionchanged:: 3.8 - Added *mtime* argument + Added the *mtime* parameter for reproducible output. .. function:: decompress(data) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 566c369c85bd45..ec2a8225549427 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -128,6 +128,13 @@ asyncio On Windows, the default event loop is now :class:`~asyncio.ProactorEventLoop`. +gzip +---- + +Added the *mtime* parameter to :func:`gzip.compress` for reproducible output. +(Contributed by Guo Ci Teo in :issue:`34898`.) + + idlelib and IDLE ---------------- diff --git a/Lib/gzip.py b/Lib/gzip.py index 304f464fce72d4..948fec293e23d9 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -520,7 +520,7 @@ def _rewind(self): super()._rewind() self._new_member = True -def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, mtime=None): +def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, *, mtime=None): """Compress data in one shot and return the compressed string. Optional argument is the compression level, in range of 0-9. """ diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index 16fb39c2c97f3f..2c8f854c643670 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -502,9 +502,9 @@ def test_compress(self): def test_compress_mtime(self): mtime = 123456789 for data in [data1, data2]: - for args in [(1, mtime), (6, mtime), (9, mtime)]: + for args in [(), (1,), (6,), (9,)]: with self.subTest(data=data, args=args): - datac = gzip.compress(data, *args) + datac = gzip.compress(data, *args, mtime=mtime) self.assertEqual(type(datac), bytes) with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f: f.read(1) # to set mtime attribute diff --git a/Misc/ACKS b/Misc/ACKS index 89fb0c7000b45e..aba60945a1e200 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1615,6 +1615,7 @@ Monty Taylor Anatoly Techtonik Martin Teichmann Gustavo Temple +Guo Ci Teo Mikhail Terekhov Victor TerrĂ³n Pablo Galindo diff --git a/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst b/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst index 3c6b824e1f61e5..4c0a061daf9f9e 100644 --- a/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst +++ b/Misc/NEWS.d/next/Library/2018-10-04-17-23-43.bpo-34898.Wo2PoJ.rst @@ -1 +1,2 @@ Add `mtime` argument to `gzip.compress` for reproducible output. +Patch by Guo Ci Teo. \ No newline at end of file