Index: Doc/library/tarfile.rst =================================================================== --- Doc/library/tarfile.rst (revision 88932) +++ Doc/library/tarfile.rst (working copy) @@ -372,7 +372,11 @@ :meth:`read`, :meth:`readline`, :meth:`readlines`, :meth:`seek`, :meth:`tell`, and :meth:`close`, and also supports iteration over its lines. + .. versionchanged:: 3.3 + The file-like object provides a no-op `flush` method, so that it can + be wrapped using :class:`io.TextIOWrapper`. + .. method:: TarFile.add(name, arcname=None, recursive=True, exclude=None, *, filter=None) Add the file *name* to the archive. *name* may be any type of file Index: Lib/tarfile.py =================================================================== --- Lib/tarfile.py (revision 88932) +++ Lib/tarfile.py (working copy) @@ -893,6 +893,9 @@ self.buffer = b"" self.fileobj.seek(self.position) + def flush(self): + pass + def close(self): """Close the file object. """ Index: Lib/test/test_tarfile.py =================================================================== --- Lib/test/test_tarfile.py (revision 88932) +++ Lib/test/test_tarfile.py (working copy) @@ -442,6 +442,17 @@ self.assertTrue((len(data), md5sum(data)) == (tarinfo.size, md5_regtype), "regular file extraction failed") + def test_fileobj_regular_file_textiowrapper(self): + tarinfo = self.tar.next() # get "regtype" (can't use getmember) + fobj = self.tar.extractfile(tarinfo) + with io.TextIOWrapper(fobj) as fobj_wrapped: + data = fobj_wrapped.read() + data_bytes = data.encode() + self.assertTrue((len(data_bytes), md5sum(data_bytes)) == + (tarinfo.size, md5_regtype), + "regular file extraction using TextIOWrapper " + "failed") + def test_provoke_stream_error(self): tarinfos = self.tar.getmembers() f = self.tar.extractfile(tarinfos[0]) # read the first member