From 3e28eed9ec2249bb11ad0db4629271b7ce9b7918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Sat, 3 Nov 2018 16:24:23 +0100 Subject: bpo-34969: Add --fast, --best on the gzip CLI (GH-9833) --- Doc/library/gzip.rst | 15 +++++----- Lib/gzip.py | 27 ++++++++++++++---- Lib/test/test_gzip.py | 32 ++++++++++++++++++++-- .../2018-10-13-07-46-50.bpo-34969.Mfnhjb.rst | 3 ++ 4 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-10-13-07-46-50.bpo-34969.Mfnhjb.rst diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index b52dd1a..a93f377 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -222,25 +222,26 @@ Once executed the :mod:`gzip` module keeps the input file(s). .. versionchanged:: 3.8 Add a new command line interface with a usage. + By default, when you will execute the CLI, the default compression level is 6. Command line options ^^^^^^^^^^^^^^^^^^^^ .. cmdoption:: file - .. code-block:: shell-session + If *file* is not specified, read from :attr:`sys.stdin`. - $ python -m gzip file +.. cmdoption:: --fast - If *file* is not specified, read from :attr:`sys.stdin`. + Indicates the fastest compression method (less compression). -.. cmdoption:: -d, --decompress +.. cmdoption:: --best - Decompress the given file + Indicates the slowest compression method (best compression). - .. code-block:: shell-session +.. cmdoption:: -d, --decompress - $ python -m gzip -d file.gz + Decompress the given file. .. cmdoption:: -h, --help diff --git a/Lib/gzip.py b/Lib/gzip.py index a34d01a..151ff14 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -17,7 +17,12 @@ FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16 READ, WRITE = 1, 2 -def open(filename, mode="rb", compresslevel=9, +_COMPRESS_LEVEL_FAST = 1 +_COMPRESS_LEVEL_TRADEOFF = 6 +_COMPRESS_LEVEL_BEST = 9 + + +def open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_BEST, encoding=None, errors=None, newline=None): """Open a gzip-compressed file in binary or text mode. @@ -121,7 +126,7 @@ class GzipFile(_compression.BaseStream): myfileobj = None def __init__(self, filename=None, mode=None, - compresslevel=9, fileobj=None, mtime=None): + compresslevel=_COMPRESS_LEVEL_BEST, fileobj=None, mtime=None): """Constructor for the GzipFile class. At least one of fileobj and filename must be given a @@ -515,7 +520,7 @@ class _GzipReader(_compression.DecompressReader): super()._rewind() self._new_member = True -def compress(data, compresslevel=9): +def compress(data, compresslevel=_COMPRESS_LEVEL_BEST): """Compress data in one shot and return the compressed string. Optional argument is the compression level, in range of 0-9. """ @@ -537,10 +542,21 @@ def main(): parser = ArgumentParser(description= "A simple command line interface for the gzip module: act like gzip, " "but do not delete the input file.") - parser.add_argument("-d", "--decompress", action="store_true", + group = parser.add_mutually_exclusive_group() + group.add_argument('--fast', action='store_true', help='compress faster') + group.add_argument('--best', action='store_true', help='compress better') + group.add_argument("-d", "--decompress", action="store_true", help="act like gunzip instead of gzip") + parser.add_argument("args", nargs="*", default=["-"], metavar='file') args = parser.parse_args() + + compresslevel = _COMPRESS_LEVEL_TRADEOFF + if args.fast: + compresslevel = _COMPRESS_LEVEL_FAST + elif args.best: + compresslevel = _COMPRESS_LEVEL_BEST + for arg in args.args: if args.decompress: if arg == "-": @@ -555,7 +571,8 @@ def main(): else: if arg == "-": f = sys.stdin.buffer - g = GzipFile(filename="", mode="wb", fileobj=sys.stdout.buffer) + g = GzipFile(filename="", mode="wb", fileobj=sys.stdout.buffer, + compresslevel=compresslevel) else: f = builtins.open(arg, "rb") g = open(arg + ".gz", "wb") diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index b072ce4..1e8b41f 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -12,7 +12,7 @@ import unittest from subprocess import PIPE, Popen from test import support from test.support import _4G, bigmemtest -from test.support.script_helper import assert_python_ok +from test.support.script_helper import assert_python_ok, assert_python_failure gzip = support.import_module('gzip') @@ -746,10 +746,38 @@ class TestCommandLine(unittest.TestCase): rc, out, err = assert_python_ok('-m', 'gzip', local_testgzip) self.assertTrue(os.path.exists(gzipname)) - self.assertEqual(rc, 0) self.assertEqual(out, b'') self.assertEqual(err, b'') + @create_and_remove_directory(TEMPDIR) + def test_compress_infile_outfile(self): + for compress_level in ('--fast', '--best'): + with self.subTest(compress_level=compress_level): + local_testgzip = os.path.join(TEMPDIR, 'testgzip') + gzipname = local_testgzip + '.gz' + self.assertFalse(os.path.exists(gzipname)) + + with open(local_testgzip, 'wb') as fp: + fp.write(self.data) + + rc, out, err = assert_python_ok('-m', 'gzip', compress_level, local_testgzip) + + self.assertTrue(os.path.exists(gzipname)) + self.assertEqual(out, b'') + self.assertEqual(err, b'') + os.remove(gzipname) + self.assertFalse(os.path.exists(gzipname)) + + def test_compress_fast_best_are_exclusive(self): + rc, out, err = assert_python_failure('-m', 'gzip', '--fast', '--best') + self.assertIn(b"error: argument --best: not allowed with argument --fast", err) + self.assertEqual(out, b'') + + def test_decompress_cannot_have_flags_compression(self): + rc, out, err = assert_python_failure('-m', 'gzip', '--fast', '-d') + self.assertIn(b'error: argument -d/--decompress: not allowed with argument --fast', err) + self.assertEqual(out, b'') + def test_main(verbose=None): support.run_unittest(TestGzip, TestOpen, TestCommandLine) diff --git a/Misc/NEWS.d/next/Library/2018-10-13-07-46-50.bpo-34969.Mfnhjb.rst b/Misc/NEWS.d/next/Library/2018-10-13-07-46-50.bpo-34969.Mfnhjb.rst new file mode 100644 index 0000000..e3b7132 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-13-07-46-50.bpo-34969.Mfnhjb.rst @@ -0,0 +1,3 @@ +gzip: Add --fast, --best on the gzip CLI, these parameters will be used for the +fast compression method (quick) or the best method compress (slower, but smaller +file). Also, change the default compression level to 6 (tradeoff). -- cgit v0.12