From 1121377cdb0bef5a4a07699ae3d93c69a1f47071 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 6 Aug 2014 18:50:19 +0300 Subject: Issue #5411: Added support for the "xztar" format in the shutil module. --- Doc/library/shutil.rst | 8 +++++++- Lib/shutil.py | 27 +++++++++++++++++++++++---- Lib/test/test_shutil.py | 8 ++++++++ Misc/NEWS | 2 ++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 7a62367..9a3aa82 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -469,7 +469,8 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. *base_name* is the name of the file to create, including the path, minus any format-specific extension. *format* is the archive format: one of - "zip", "tar", "bztar" (if the :mod:`bz2` module is available) or "gztar". + "zip", "tar", "bztar" (if the :mod:`bz2` module is available), "xztar" + (if the :mod:`lzma` module is available) or "gztar". *root_dir* is a directory that will be the root directory of the archive; for example, we typically chdir into *root_dir* before creating the @@ -487,6 +488,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. *logger* must be an object compatible with :pep:`282`, usually an instance of :class:`logging.Logger`. + .. versionchanged:: 3.4 + Added support for the *xztar* format. + .. function:: get_archive_formats() @@ -497,6 +501,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. - *gztar*: gzip'ed tar-file - *bztar*: bzip2'ed tar-file (if the :mod:`bz2` module is available.) + - *xztar*: xz'ed tar-file (if the :mod:`lzma` module is available.) - *tar*: uncompressed tar file - *zip*: ZIP file @@ -567,6 +572,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. - *gztar*: gzip'ed tar-file - *bztar*: bzip2'ed tar-file (if the :mod:`bz2` module is available.) + - *xztar*: xz'ed tar-file (if the :mod:`lzma` module is available.) - *tar*: uncompressed tar file - *zip*: ZIP file diff --git a/Lib/shutil.py b/Lib/shutil.py index b59017b..344d9d3 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -21,6 +21,13 @@ except ImportError: _BZ2_SUPPORTED = False try: + import lzma + del lzma + _LZMA_SUPPORTED = True +except ImportError: + _LZMA_SUPPORTED = False + +try: from pwd import getpwnam except ImportError: getpwnam = None @@ -580,14 +587,14 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "bzip2", or None. + 'compress' must be "gzip" (the default), "bzip2", "xz", or None. 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_name' + ".tar", possibly plus - the appropriate compression extension (".gz", or ".bz2"). + the appropriate compression extension (".gz", ".bz2", or ".xz"). Returns the output filename. """ @@ -598,6 +605,10 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, tar_compression['bzip2'] = 'bz2' compress_ext['bzip2'] = '.bz2' + if _LZMA_SUPPORTED: + tar_compression['xz'] = 'xz' + compress_ext['xz'] = '.xz' + # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext: raise ValueError("bad value for 'compress', or compression format not " @@ -684,6 +695,10 @@ if _BZ2_SUPPORTED: _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file") +if _LZMA_SUPPORTED: + _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')], + "xz'ed tar-file") + def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -872,7 +887,7 @@ def _unpack_zipfile(filename, extract_dir): zip.close() def _unpack_tarfile(filename, extract_dir): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` """ try: tarobj = tarfile.open(filename) @@ -891,9 +906,13 @@ _UNPACK_FORMATS = { } if _BZ2_SUPPORTED: - _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [], "bzip2'ed tar-file") +if _LZMA_SUPPORTED: + _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [], + "xz'ed tar-file") + def _find_unpack_format(filename): for name, info in _UNPACK_FORMATS.items(): for extension in info[0]: diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 098d58e..511efa6 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -32,6 +32,12 @@ try: except ImportError: BZ2_SUPPORTED = False +try: + import lzma + LZMA_SUPPORTED = True +except ImportError: + LZMA_SUPPORTED = False + TESTFN2 = TESTFN + "2" try: @@ -1156,6 +1162,8 @@ class TestShutil(unittest.TestCase): formats = ['tar', 'gztar', 'zip'] if BZ2_SUPPORTED: formats.append('bztar') + if LZMA_SUPPORTED: + formats.append('xztar') for format in formats: tmpdir = self.mkdtemp() diff --git a/Misc/NEWS b/Misc/NEWS index 932e239..877384f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -112,6 +112,8 @@ Core and Builtins Library ------- +- Issue #5411: Added support for the "xztar" format in the shutil module. + - Issue #21975: Fixed crash when using uninitialized sqlite3.Row (in particular when unpickling pickled sqlite3.Row). sqlite3.Row is now initialized in the __new__() method. -- cgit v0.12