Skip to content

Commit dd754ca

Browse files
woodruffwethanfurman
authored andcommitted
bpo-29435: Allow is_tarfile to take a filelike obj (GH-18090)
`is_tarfile()` now supports `name` being a file or file-like object.
1 parent 41f0ef6 commit dd754ca

File tree

5 files changed

+45
-2
lines changed

5 files changed

+45
-2
lines changed

Doc/library/tarfile.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ Some facts and figures:
159159
.. function:: is_tarfile(name)
160160

161161
Return :const:`True` if *name* is a tar archive file, that the :mod:`tarfile`
162-
module can read.
162+
module can read. *name* may be a :class:`str`, file, or file-like object.
163+
164+
.. versionchanged:: 3.9
165+
Support for file and file-like objects.
163166

164167

165168
The :mod:`tarfile` module defines the following exceptions:

Lib/tarfile.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2461,9 +2461,14 @@ def __exit__(self, type, value, traceback):
24612461
def is_tarfile(name):
24622462
"""Return True if name points to a tar archive that we
24632463
are able to handle, else return False.
2464+
2465+
'name' should be a string, file, or file-like object.
24642466
"""
24652467
try:
2466-
t = open(name)
2468+
if hasattr(name, "read"):
2469+
t = open(fileobj=name)
2470+
else:
2471+
t = open(name)
24672472
t.close()
24682473
return True
24692474
except TarError:

Lib/test/test_tarfile.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,38 @@ class LzmaListTest(LzmaTest, ListTest):
319319

320320
class CommonReadTest(ReadTest):
321321

322+
def test_is_tarfile_erroneous(self):
323+
with open(tmpname, "wb"):
324+
pass
325+
326+
# is_tarfile works on filenames
327+
self.assertFalse(tarfile.is_tarfile(tmpname))
328+
329+
# is_tarfile works on path-like objects
330+
self.assertFalse(tarfile.is_tarfile(pathlib.Path(tmpname)))
331+
332+
# is_tarfile works on file objects
333+
with open(tmpname, "rb") as fobj:
334+
self.assertFalse(tarfile.is_tarfile(fobj))
335+
336+
# is_tarfile works on file-like objects
337+
self.assertFalse(tarfile.is_tarfile(io.BytesIO(b"invalid")))
338+
339+
def test_is_tarfile_valid(self):
340+
# is_tarfile works on filenames
341+
self.assertTrue(tarfile.is_tarfile(self.tarname))
342+
343+
# is_tarfile works on path-like objects
344+
self.assertTrue(tarfile.is_tarfile(pathlib.Path(self.tarname)))
345+
346+
# is_tarfile works on file objects
347+
with open(self.tarname, "rb") as fobj:
348+
self.assertTrue(tarfile.is_tarfile(fobj))
349+
350+
# is_tarfile works on file-like objects
351+
with open(self.tarname, "rb") as fobj:
352+
self.assertTrue(tarfile.is_tarfile(io.BytesIO(fobj.read())))
353+
322354
def test_empty_tarfile(self):
323355
# Test for issue6123: Allow opening empty archives.
324356
# This test checks if tarfile.open() is able to open an empty tar

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,7 @@ Klaus-Juergen Wolf
18561856
Dan Wolfe
18571857
Richard Wolff
18581858
Adam Woodbeck
1859+
William Woodruff
18591860
Steven Work
18601861
Gordon Worley
18611862
Darren Worrall
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Allow :func:`tarfile.is_tarfile` to be used with file and file-like
2+
objects, like :func:`zipfile.is_zipfile`. Patch by William Woodruff.

0 commit comments

Comments
 (0)