Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Doc/library/gzip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
27 changes: 22 additions & 5 deletions Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@

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.

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -515,7 +520,7 @@ def _rewind(self):
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.
"""
Expand All @@ -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 == "-":
Expand All @@ -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")
Expand Down
32 changes: 30 additions & 2 deletions Lib/test/test_gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
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')

Expand Down Expand Up @@ -746,10 +746,38 @@ def test_compress_infile_outfile(self):
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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).