bpo-34969: Add --fast, --best on the gzip CLI (GH-9833)
This commit is contained in:
parent
fe62d877e3
commit
3e28eed9ec
|
@ -222,25 +222,26 @@ Once executed the :mod:`gzip` module keeps the input file(s).
|
||||||
.. versionchanged:: 3.8
|
.. versionchanged:: 3.8
|
||||||
|
|
||||||
Add a new command line interface with a usage.
|
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
|
Command line options
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. cmdoption:: file
|
.. cmdoption:: file
|
||||||
|
|
||||||
.. code-block:: shell-session
|
|
||||||
|
|
||||||
$ python -m gzip file
|
|
||||||
|
|
||||||
If *file* is not specified, read from :attr:`sys.stdin`.
|
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
|
.. cmdoption:: -d, --decompress
|
||||||
|
|
||||||
Decompress the given file
|
Decompress the given file.
|
||||||
|
|
||||||
.. code-block:: shell-session
|
|
||||||
|
|
||||||
$ python -m gzip -d file.gz
|
|
||||||
|
|
||||||
.. cmdoption:: -h, --help
|
.. cmdoption:: -h, --help
|
||||||
|
|
||||||
|
|
27
Lib/gzip.py
27
Lib/gzip.py
|
@ -17,7 +17,12 @@ FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
|
||||||
|
|
||||||
READ, WRITE = 1, 2
|
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):
|
encoding=None, errors=None, newline=None):
|
||||||
"""Open a gzip-compressed file in binary or text mode.
|
"""Open a gzip-compressed file in binary or text mode.
|
||||||
|
|
||||||
|
@ -121,7 +126,7 @@ class GzipFile(_compression.BaseStream):
|
||||||
myfileobj = None
|
myfileobj = None
|
||||||
|
|
||||||
def __init__(self, filename=None, mode=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.
|
"""Constructor for the GzipFile class.
|
||||||
|
|
||||||
At least one of fileobj and filename must be given a
|
At least one of fileobj and filename must be given a
|
||||||
|
@ -515,7 +520,7 @@ class _GzipReader(_compression.DecompressReader):
|
||||||
super()._rewind()
|
super()._rewind()
|
||||||
self._new_member = True
|
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.
|
"""Compress data in one shot and return the compressed string.
|
||||||
Optional argument is the compression level, in range of 0-9.
|
Optional argument is the compression level, in range of 0-9.
|
||||||
"""
|
"""
|
||||||
|
@ -537,10 +542,21 @@ def main():
|
||||||
parser = ArgumentParser(description=
|
parser = ArgumentParser(description=
|
||||||
"A simple command line interface for the gzip module: act like gzip, "
|
"A simple command line interface for the gzip module: act like gzip, "
|
||||||
"but do not delete the input file.")
|
"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")
|
help="act like gunzip instead of gzip")
|
||||||
|
|
||||||
parser.add_argument("args", nargs="*", default=["-"], metavar='file')
|
parser.add_argument("args", nargs="*", default=["-"], metavar='file')
|
||||||
args = parser.parse_args()
|
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:
|
for arg in args.args:
|
||||||
if args.decompress:
|
if args.decompress:
|
||||||
if arg == "-":
|
if arg == "-":
|
||||||
|
@ -555,7 +571,8 @@ def main():
|
||||||
else:
|
else:
|
||||||
if arg == "-":
|
if arg == "-":
|
||||||
f = sys.stdin.buffer
|
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:
|
else:
|
||||||
f = builtins.open(arg, "rb")
|
f = builtins.open(arg, "rb")
|
||||||
g = open(arg + ".gz", "wb")
|
g = open(arg + ".gz", "wb")
|
||||||
|
|
|
@ -12,7 +12,7 @@ import unittest
|
||||||
from subprocess import PIPE, Popen
|
from subprocess import PIPE, Popen
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import _4G, bigmemtest
|
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')
|
gzip = support.import_module('gzip')
|
||||||
|
|
||||||
|
@ -746,10 +746,38 @@ class TestCommandLine(unittest.TestCase):
|
||||||
rc, out, err = assert_python_ok('-m', 'gzip', local_testgzip)
|
rc, out, err = assert_python_ok('-m', 'gzip', local_testgzip)
|
||||||
|
|
||||||
self.assertTrue(os.path.exists(gzipname))
|
self.assertTrue(os.path.exists(gzipname))
|
||||||
self.assertEqual(rc, 0)
|
|
||||||
self.assertEqual(out, b'')
|
self.assertEqual(out, b'')
|
||||||
self.assertEqual(err, 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):
|
def test_main(verbose=None):
|
||||||
support.run_unittest(TestGzip, TestOpen, TestCommandLine)
|
support.run_unittest(TestGzip, TestOpen, TestCommandLine)
|
||||||
|
|
|
@ -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).
|
Loading…
Reference in New Issue