Issue #20245: The open functions in the tarfile module now correctly handle empty mode.

This commit is contained in:
Serhiy Storchaka 2014-01-18 15:35:37 +02:00
parent af69fe2311
commit 53ad0cd284
3 changed files with 25 additions and 7 deletions

View File

@ -1429,10 +1429,11 @@ class TarFile(object):
can be determined, `mode' is overridden by `fileobj's mode. can be determined, `mode' is overridden by `fileobj's mode.
`fileobj' is not closed, when TarFile is closed. `fileobj' is not closed, when TarFile is closed.
""" """
if len(mode) > 1 or mode not in "raw": modes = {"r": "rb", "a": "r+b", "w": "wb"}
if mode not in modes:
raise ValueError("mode must be 'r', 'a' or 'w'") raise ValueError("mode must be 'r', 'a' or 'w'")
self.mode = mode self.mode = mode
self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] self._mode = modes[mode]
if not fileobj: if not fileobj:
if self.mode == "a" and not os.path.exists(name): if self.mode == "a" and not os.path.exists(name):
@ -1588,7 +1589,7 @@ class TarFile(object):
filemode = filemode or "r" filemode = filemode or "r"
comptype = comptype or "tar" comptype = comptype or "tar"
if filemode not in "rw": if filemode not in ("r", "w"):
raise ValueError("mode must be 'r' or 'w'") raise ValueError("mode must be 'r' or 'w'")
stream = _Stream(name, filemode, comptype, fileobj, bufsize) stream = _Stream(name, filemode, comptype, fileobj, bufsize)
@ -1600,7 +1601,7 @@ class TarFile(object):
t._extfileobj = False t._extfileobj = False
return t return t
elif mode in "aw": elif mode in ("a", "w"):
return cls.taropen(name, mode, fileobj, **kwargs) return cls.taropen(name, mode, fileobj, **kwargs)
raise ValueError("undiscernible mode") raise ValueError("undiscernible mode")
@ -1609,7 +1610,7 @@ class TarFile(object):
def taropen(cls, name, mode="r", fileobj=None, **kwargs): def taropen(cls, name, mode="r", fileobj=None, **kwargs):
"""Open uncompressed tar archive name for reading or writing. """Open uncompressed tar archive name for reading or writing.
""" """
if len(mode) > 1 or mode not in "raw": if mode not in ("r", "a", "w"):
raise ValueError("mode must be 'r', 'a' or 'w'") raise ValueError("mode must be 'r', 'a' or 'w'")
return cls(name, mode, fileobj, **kwargs) return cls(name, mode, fileobj, **kwargs)
@ -1618,7 +1619,7 @@ class TarFile(object):
"""Open gzip compressed tar archive name for reading or writing. """Open gzip compressed tar archive name for reading or writing.
Appending is not allowed. Appending is not allowed.
""" """
if len(mode) > 1 or mode not in "rw": if mode not in ("r", "w"):
raise ValueError("mode must be 'r' or 'w'") raise ValueError("mode must be 'r' or 'w'")
try: try:
@ -1649,7 +1650,7 @@ class TarFile(object):
"""Open bzip2 compressed tar archive name for reading or writing. """Open bzip2 compressed tar archive name for reading or writing.
Appending is not allowed. Appending is not allowed.
""" """
if len(mode) > 1 or mode not in "rw": if mode not in ("r", "w"):
raise ValueError("mode must be 'r' or 'w'.") raise ValueError("mode must be 'r' or 'w'.")
try: try:

View File

@ -41,6 +41,7 @@ class TarTest:
tarname = tarname tarname = tarname
suffix = '' suffix = ''
open = io.FileIO open = io.FileIO
taropen = tarfile.TarFile.taropen
@property @property
def mode(self): def mode(self):
@ -51,18 +52,21 @@ class GzipTest:
tarname = gzipname tarname = gzipname
suffix = 'gz' suffix = 'gz'
open = gzip.GzipFile if gzip else None open = gzip.GzipFile if gzip else None
taropen = tarfile.TarFile.gzopen
@support.requires_bz2 @support.requires_bz2
class Bz2Test: class Bz2Test:
tarname = bz2name tarname = bz2name
suffix = 'bz2' suffix = 'bz2'
open = bz2.BZ2File if bz2 else None open = bz2.BZ2File if bz2 else None
taropen = tarfile.TarFile.bz2open
@support.requires_lzma @support.requires_lzma
class LzmaTest: class LzmaTest:
tarname = xzname tarname = xzname
suffix = 'xz' suffix = 'xz'
open = lzma.LZMAFile if lzma else None open = lzma.LZMAFile if lzma else None
taropen = tarfile.TarFile.xzopen
class ReadTest(TarTest): class ReadTest(TarTest):
@ -287,6 +291,16 @@ class MiscReadTestBase(CommonReadTest):
with tarfile.open(fileobj=fobj, mode=self.mode) as tar: with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
self.assertEqual(tar.name, None) self.assertEqual(tar.name, None)
def test_illegal_mode_arg(self):
with open(tmpname, 'wb'):
pass
with self.assertRaisesRegex(ValueError, 'mode must be '):
tar = self.taropen(tmpname, 'q')
with self.assertRaisesRegex(ValueError, 'mode must be '):
tar = self.taropen(tmpname, 'rw')
with self.assertRaisesRegex(ValueError, 'mode must be '):
tar = self.taropen(tmpname, '')
def test_fileobj_with_offset(self): def test_fileobj_with_offset(self):
# Skip the first member and store values from the second member # Skip the first member and store values from the second member
# of the testtar. # of the testtar.

View File

@ -43,6 +43,9 @@ Core and Builtins
Library Library
------- -------
- Issue #20245: The open functions in the tarfile module now correctly handle
empty mode.
- Issue #20242: Fixed basicConfig() format strings for the alternative - Issue #20242: Fixed basicConfig() format strings for the alternative
formatting styles. Thanks to kespindler for the bug report and patch. formatting styles. Thanks to kespindler for the bug report and patch.