diff --git a/patoolib/__init__.py b/patoolib/__init__.py index 5aaf887..1b15d0a 100644 --- a/patoolib/__init__.py +++ b/patoolib/__init__.py @@ -25,7 +25,7 @@ import importlib from .configuration import App, Version as __version__ __all__ = ['list_formats', 'list_archive', 'extract_archive', 'test_archive', 'create_archive', 'diff_archives', 'search_archive', 'repack_archive', - 'recompress_archive'] + 'recompress_archive', 'program_supports_compression'] # Supported archive commands @@ -285,6 +285,18 @@ ProgramModules = { } +def program_supports_compression (program, compression): + """Decide if the given program supports the compression natively. + @return: True iff the program supports the given compression format + natively, else False. + """ + if program in ('tar', ): + return compression in ('gzip', 'bzip2', 'xz', 'lzip', 'compress', 'lzma') + py_lzma + elif program in ('star', 'bsdtar', 'py_tarfile'): + return compression in ('gzip', 'bzip2') + py_lzma + return False + + from . import util def get_archive_format (filename): @@ -337,16 +349,6 @@ def find_archive_program (format, command, program=None): raise util.PatoolError("could not find an executable program to %s format %s; candidates are (%s)," % (command, format, ",".join(programs))) -def program_supports_compression (program, compression): - """Decide if the given program supports the compression natively. - @return: True iff the program supports the given compression format - natively, else False. - """ - if program in ('tar', 'star', 'bsdtar', 'py_tarfile'): - return compression in ('gzip', 'bzip2') + py_lzma - return False - - def list_formats (): """Print information about available archive formats to stdout.""" print("Archive programs of", App) diff --git a/patoolib/util.py b/patoolib/util.py index 5975e75..e0976bd 100644 --- a/patoolib/util.py +++ b/patoolib/util.py @@ -24,7 +24,7 @@ import tempfile import time import traceback import locale -from . import configuration, ArchiveMimetypes, ArchiveCompressions +from . import configuration, ArchiveMimetypes, ArchiveCompressions, program_supports_compression try: from shutil import which except ImportError: @@ -314,7 +314,12 @@ def guess_mime_file (filename): elif mime2 in ArchiveMimetypes: mime = mime2 encoding = get_file_mime_encoding(outparts) - return mime, encoding + # Only return mime and encoding if the given mime can natively support the encoding. + if program_supports_compression(ArchiveMimetypes.get(mime), encoding): + return mime, encoding + else: + # If encoding is None, default back to `mime`. + return Encoding2Mime.get(encoding, mime), None def guess_mime_file_mime (file_prog, filename): diff --git a/tests/__init__.py b/tests/__init__.py index a806764..7c35d5f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -34,7 +34,7 @@ def _need_func(testfunc, name, description): def check_func(func): def newfunc(*args, **kwargs): if not testfunc(name): - raise pytest.skip("%s %r is not available" % (description, name)) + pytest.skip("%s %r is not available" % (description, name)) return func(*args, **kwargs) setattr(newfunc, fnameattr, getattr(func, fnameattr)) return newfunc @@ -53,7 +53,7 @@ def needs_program(name): def needs_one_program(programs): """Decorator skipping test if not one of given programs are available.""" - return _need_func(lambda x: all(map(patoolib.util.find_program, x)), programs, 'programs') + return _need_func(lambda x: any(map(patoolib.util.find_program, x)), programs, 'programs') def needs_module(name): @@ -72,9 +72,9 @@ def needs_codec (program, codec): def check_prog (f): def newfunc (*args, **kwargs): if not patoolib.util.find_program(program): - raise pytest.skip("program `%s' not available" % program) + pytest.skip("program `%s' not available" % program) if not has_codec(program, codec): - raise pytest.skip("codec `%s' for program `%s' not available" % (codec, program)) + pytest.skip("codec `%s' for program `%s' not available" % (codec, program)) return f(*args, **kwargs) setattr(newfunc, fnameattr, getattr(f, fnameattr)) return newfunc @@ -95,7 +95,7 @@ def skip_on_travis(): def check_func(func): def newfunc(*args, **kwargs): if "TRAVIS" in os.environ: - raise pytest.skip("Skip on TRAVIS CI build.") + pytest.skip("Skip on TRAVIS CI build.") return func(*args, **kwargs) setattr(newfunc, fnameattr, getattr(func, fnameattr)) return newfunc diff --git a/tests/archives/test_tar.py b/tests/archives/test_tar.py index 9de8d4b..7f31730 100644 --- a/tests/archives/test_tar.py +++ b/tests/archives/test_tar.py @@ -69,6 +69,7 @@ class TestTar (ArchiveTest): self.archive_commands('t.tgz.foo', skip_create=True) @needs_program('file') + @needs_program('compress') @needs_codec(program, 'compress') def test_tar_z_file (self): self.archive_commands('t.tar.Z.foo', skip_create=True) diff --git a/tests/data/t.rar.gz b/tests/data/t.rar.gz new file mode 100644 index 0000000..ccde84c Binary files /dev/null and b/tests/data/t.rar.gz differ diff --git a/tests/data/t.rar.gz.foo b/tests/data/t.rar.gz.foo new file mode 100644 index 0000000..ccde84c Binary files /dev/null and b/tests/data/t.rar.gz.foo differ diff --git a/tests/test_mime.py b/tests/test_mime.py index 15f1c51..2360da8 100644 --- a/tests/test_mime.py +++ b/tests/test_mime.py @@ -138,6 +138,7 @@ class TestMime (unittest.TestCase): self.mime_test_file("t.zpaq", "application/zpaq") self.mime_test_file("t.zpaq.foo", "application/zpaq") + @needs_program('file') @needs_program('lzip') def test_mime_file_lzip (self): @@ -149,6 +150,12 @@ class TestMime (unittest.TestCase): self.mime_test_file("t.tar.bz2.foo", "application/x-tar", "bzip2") self.mime_test_file("t.tbz2.foo", "application/x-tar", "bzip2") + @needs_program('file') + def test_nested_gzip (self): + # Ensure that a file that doesn't natively support encoding does not see the encoding + self.mime_test_file("t.rar.gz", "application/gzip") + self.mime_test_file("t.rar.gz.foo", "application/gzip") + @needs_program('file') @needs_program('gzip') def test_mime_file_gzip (self):