diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index b52dd1a11aa..a93f3774385 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 - - $ python -m gzip file - If *file* is not specified, read from :attr:`sys.stdin`. +.. cmdoption:: --fast + + Indicates the fastest compression method (less compression). + +.. cmdoption:: --best + + Indicates the slowest compression method (best compression). + .. cmdoption:: -d, --decompress - Decompress the given file - - .. code-block:: shell-session - - $ python -m gzip -d file.gz + Decompress the given file. .. cmdoption:: -h, --help diff --git a/Lib/gzip.py b/Lib/gzip.py index a34d01ae36e..151ff1405b1 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 b072ce4682c..1e8b41f07b3 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 00000000000..e3b71326140 --- /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).