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:19 +02:00
parent ce46aed13e
commit 75ba21a77d
3 changed files with 25 additions and 7 deletions

View File

@ -1508,10 +1508,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):
@ -1681,7 +1682,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'")
t = cls(name, filemode, t = cls(name, filemode,
@ -1690,7 +1691,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")
@ -1699,7 +1700,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)
@ -1708,7 +1709,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:
@ -1734,7 +1735,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

@ -213,6 +213,7 @@ class CommonReadTest(ReadTest):
class MiscReadTest(CommonReadTest): class MiscReadTest(CommonReadTest):
taropen = tarfile.TarFile.taropen
def test_no_name_argument(self): def test_no_name_argument(self):
fobj = open(self.tarname, "rb") fobj = open(self.tarname, "rb")
@ -233,6 +234,17 @@ class MiscReadTest(CommonReadTest):
tar = tarfile.open(fileobj=fobj, mode=self.mode) tar = tarfile.open(fileobj=fobj, mode=self.mode)
self.assertEqual(tar.name, None) self.assertEqual(tar.name, None)
def test_illegal_mode_arg(self):
with open(tmpname, 'wb'):
pass
self.addCleanup(os.unlink, tmpname)
with self.assertRaisesRegexp(ValueError, 'mode must be '):
tar = self.taropen(tmpname, 'q')
with self.assertRaisesRegexp(ValueError, 'mode must be '):
tar = self.taropen(tmpname, 'rw')
with self.assertRaisesRegexp(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.
@ -1543,6 +1555,7 @@ class LinkEmulationTest(ReadTest):
class GzipMiscReadTest(MiscReadTest): class GzipMiscReadTest(MiscReadTest):
tarname = gzipname tarname = gzipname
mode = "r:gz" mode = "r:gz"
taropen = tarfile.TarFile.gzopen
class GzipUstarReadTest(UstarReadTest): class GzipUstarReadTest(UstarReadTest):
tarname = gzipname tarname = gzipname
mode = "r:gz" mode = "r:gz"
@ -1558,6 +1571,7 @@ class GzipStreamWriteTest(StreamWriteTest):
class Bz2MiscReadTest(MiscReadTest): class Bz2MiscReadTest(MiscReadTest):
tarname = bz2name tarname = bz2name
mode = "r:bz2" mode = "r:bz2"
taropen = tarfile.TarFile.bz2open
class Bz2UstarReadTest(UstarReadTest): class Bz2UstarReadTest(UstarReadTest):
tarname = bz2name tarname = bz2name
mode = "r:bz2" mode = "r:bz2"

View File

@ -35,6 +35,9 @@ Core and Builtins
Library Library
------- -------
- Issue #20245: The open functions in the tarfile module now correctly handle
empty mode.
- Issue #20086: Restored the use of locale-independent mapping instead of - Issue #20086: Restored the use of locale-independent mapping instead of
locale-dependent str.lower() in locale.normalize(). locale-dependent str.lower() in locale.normalize().