(De)compression of files
------------------------
-.. class:: BZ2File(filename=None, mode='r', buffering=None, compresslevel=9, \*, fileobj=None)
+.. class:: BZ2File(filename, mode='r', buffering=None, compresslevel=9)
Open a bzip2-compressed file.
- The :class:`BZ2File` can wrap an existing :term:`file object` (given by
- *fileobj*), or operate directly on a named file (named by *filename*).
- Exactly one of these two parameters should be provided.
+ If *filename* is a :class:`str` or :class:`bytes` object, open the named file
+ directly. Otherwise, *filename* should be a :term:`file object`, which will
+ be used to read or write the compressed data.
The *mode* argument can be either ``'r'`` for reading (default), ``'w'`` for
- overwriting, or ``'a'`` for appending. If *fileobj* is provided, a mode of
- ``'w'`` does not truncate the file, and is instead equivalent to ``'a'``.
+ overwriting, or ``'a'`` for appending. If *filename* is a file object (rather
+ than an actual file name), a mode of ``'w'`` does not truncate the file, and
+ is instead equivalent to ``'a'``.
The *buffering* argument is ignored. Its use is deprecated.
:meth:`read1` and :meth:`readinto` methods were added.
.. versionchanged:: 3.3
- The *fileobj* argument to the constructor was added.
+ Support was added for *filename* being a :term:`file object` instead of an
+ actual filename.
.. versionchanged:: 3.3
The ``'a'`` (append) mode was added, along with support for reading
returned as bytes, and data to be written should be given as bytes.
"""
- def __init__(self, filename=None, mode="r", buffering=None,
- compresslevel=9, *, fileobj=None):
+ def __init__(self, filename, mode="r", buffering=None, compresslevel=9):
"""Open a bzip2-compressed file.
- If filename is given, open the named file. Otherwise, operate on
- the file object given by fileobj. Exactly one of these two
- parameters should be provided.
+ If filename is a str or bytes object, is gives the name of the file to
+ be opened. Otherwise, it should be a file object, which will be used to
+ read or write the compressed data.
mode can be 'r' for reading (default), 'w' for (over)writing, or
'a' for appending.
else:
raise ValueError("Invalid mode: {!r}".format(mode))
- if filename is not None and fileobj is None:
+ if isinstance(filename, (str, bytes)):
self._fp = open(filename, mode)
self._closefp = True
self._mode = mode_code
- elif fileobj is not None and filename is None:
- self._fp = fileobj
+ elif hasattr(filename, "read") or hasattr(filename, "write"):
+ self._fp = filename
self._mode = mode_code
else:
- raise ValueError("Must give exactly one of filename and fileobj")
+ raise TypeError("filename must be a str or bytes object, or a file")
def close(self):
"""Flush and close the file.
with open(self.filename, "wb") as f:
f.write(self.DATA * streams)
+ def testBadArgs(self):
+ with self.assertRaises(TypeError):
+ BZ2File(123.456)
+ with self.assertRaises(ValueError):
+ BZ2File("/dev/null", "z")
+ with self.assertRaises(ValueError):
+ BZ2File("/dev/null", "rx")
+ with self.assertRaises(ValueError):
+ BZ2File("/dev/null", "rbt")
+ with self.assertRaises(ValueError):
+ BZ2File("/dev/null", compresslevel=0)
+ with self.assertRaises(ValueError):
+ BZ2File("/dev/null", compresslevel=10)
+
def testRead(self):
self.createTempFile()
with BZ2File(self.filename) as bz2f:
def testFileno(self):
self.createTempFile()
with open(self.filename, 'rb') as rawf:
- bz2f = BZ2File(fileobj=rawf)
+ bz2f = BZ2File(rawf)
try:
self.assertEqual(bz2f.fileno(), rawf.fileno())
finally:
self.assertRaises(ValueError, bz2f.fileno)
def testSeekable(self):
- bz2f = BZ2File(fileobj=BytesIO(self.DATA))
+ bz2f = BZ2File(BytesIO(self.DATA))
try:
self.assertTrue(bz2f.seekable())
bz2f.read()
bz2f.close()
self.assertRaises(ValueError, bz2f.seekable)
- bz2f = BZ2File(fileobj=BytesIO(), mode="w")
+ bz2f = BZ2File(BytesIO(), mode="w")
try:
self.assertFalse(bz2f.seekable())
finally:
src = BytesIO(self.DATA)
src.seekable = lambda: False
- bz2f = BZ2File(fileobj=src)
+ bz2f = BZ2File(src)
try:
self.assertFalse(bz2f.seekable())
finally:
self.assertRaises(ValueError, bz2f.seekable)
def testReadable(self):
- bz2f = BZ2File(fileobj=BytesIO(self.DATA))
+ bz2f = BZ2File(BytesIO(self.DATA))
try:
self.assertTrue(bz2f.readable())
bz2f.read()
bz2f.close()
self.assertRaises(ValueError, bz2f.readable)
- bz2f = BZ2File(fileobj=BytesIO(), mode="w")
+ bz2f = BZ2File(BytesIO(), mode="w")
try:
self.assertFalse(bz2f.readable())
finally:
self.assertRaises(ValueError, bz2f.readable)
def testWritable(self):
- bz2f = BZ2File(fileobj=BytesIO(self.DATA))
+ bz2f = BZ2File(BytesIO(self.DATA))
try:
self.assertFalse(bz2f.writable())
bz2f.read()
bz2f.close()
self.assertRaises(ValueError, bz2f.writable)
- bz2f = BZ2File(fileobj=BytesIO(), mode="w")
+ bz2f = BZ2File(BytesIO(), mode="w")
try:
self.assertTrue(bz2f.writable())
finally:
def testReadBytesIO(self):
with BytesIO(self.DATA) as bio:
- with BZ2File(fileobj=bio) as bz2f:
+ with BZ2File(bio) as bz2f:
self.assertRaises(TypeError, bz2f.read, None)
self.assertEqual(bz2f.read(), self.TEXT)
self.assertFalse(bio.closed)
def testPeekBytesIO(self):
with BytesIO(self.DATA) as bio:
- with BZ2File(fileobj=bio) as bz2f:
+ with BZ2File(bio) as bz2f:
pdata = bz2f.peek()
self.assertNotEqual(len(pdata), 0)
self.assertTrue(self.TEXT.startswith(pdata))
def testWriteBytesIO(self):
with BytesIO() as bio:
- with BZ2File(fileobj=bio, mode="w") as bz2f:
+ with BZ2File(bio, "w") as bz2f:
self.assertRaises(TypeError, bz2f.write)
bz2f.write(self.TEXT)
self.assertEqual(self.decompress(bio.getvalue()), self.TEXT)
def testSeekForwardBytesIO(self):
with BytesIO(self.DATA) as bio:
- with BZ2File(fileobj=bio) as bz2f:
+ with BZ2File(bio) as bz2f:
self.assertRaises(TypeError, bz2f.seek)
bz2f.seek(150)
self.assertEqual(bz2f.read(), self.TEXT[150:])
def testSeekBackwardsBytesIO(self):
with BytesIO(self.DATA) as bio:
- with BZ2File(fileobj=bio) as bz2f:
+ with BZ2File(bio) as bz2f:
bz2f.read(500)
bz2f.seek(-150, 1)
self.assertEqual(bz2f.read(), self.TEXT[500-150:])