Issue #19223: Add support for the 'x' mode to the bz2 module.
Patch by Tim Heaney and Vajrasky Kok.
This commit is contained in:
parent
42ca98217c
commit
8a9e99cffc
|
@ -37,8 +37,8 @@ All of the classes in this module may safely be accessed from multiple threads.
|
|||
file object to read from or write to.
|
||||
|
||||
The *mode* argument can be any of ``'r'``, ``'rb'``, ``'w'``, ``'wb'``,
|
||||
``'a'``, or ``'ab'`` for binary mode, or ``'rt'``, ``'wt'``, or ``'at'`` for
|
||||
text mode. The default is ``'rb'``.
|
||||
``'x'``, ``'xb'``, ``'a'`` or ``'ab'`` for binary mode, or ``'rt'``,
|
||||
``'wt'``, ``'xt'``, or ``'at'`` for text mode. The default is ``'rb'``.
|
||||
|
||||
The *compresslevel* argument is an integer from 1 to 9, as for the
|
||||
:class:`BZ2File` constructor.
|
||||
|
@ -54,6 +54,9 @@ All of the classes in this module may safely be accessed from multiple threads.
|
|||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
The ``'x'`` (exclusive creation) mode was added.
|
||||
|
||||
|
||||
.. class:: BZ2File(filename, mode='r', buffering=None, compresslevel=9)
|
||||
|
||||
|
@ -64,8 +67,9 @@ All of the classes in this module may safely be accessed from multiple threads.
|
|||
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. These can equivalently be given as
|
||||
``'rb'``, ``'wb'``, and ``'ab'`` respectively.
|
||||
overwriting, ``'x'`` for exclusive creation, or ``'a'`` for appending. These
|
||||
can equivalently be given as ``'rb'``, ``'wb'``, ``'xb'`` and ``'ab'``
|
||||
respectively.
|
||||
|
||||
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'``.
|
||||
|
@ -108,6 +112,9 @@ All of the classes in this module may safely be accessed from multiple threads.
|
|||
The ``'a'`` (append) mode was added, along with support for reading
|
||||
multi-stream files.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
The ``'x'`` (exclusive creation) mode was added.
|
||||
|
||||
|
||||
Incremental (de)compression
|
||||
---------------------------
|
||||
|
|
16
Lib/bz2.py
16
Lib/bz2.py
|
@ -49,12 +49,12 @@ class BZ2File(io.BufferedIOBase):
|
|||
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. These can equivalently be given as 'rb',
|
||||
'wb', and 'ab'.
|
||||
'x' for creating exclusively, or 'a' for appending. These can
|
||||
equivalently be given as 'rb', 'wb', 'xb', and 'ab'.
|
||||
|
||||
buffering is ignored. Its use is deprecated.
|
||||
|
||||
If mode is 'w' or 'a', compresslevel can be a number between 1
|
||||
If mode is 'w', 'x' or 'a', compresslevel can be a number between 1
|
||||
and 9 specifying the level of compression: 1 produces the least
|
||||
compression, and 9 (default) produces the most compression.
|
||||
|
||||
|
@ -87,6 +87,10 @@ class BZ2File(io.BufferedIOBase):
|
|||
mode = "wb"
|
||||
mode_code = _MODE_WRITE
|
||||
self._compressor = BZ2Compressor(compresslevel)
|
||||
elif mode in ("x", "xb"):
|
||||
mode = "xb"
|
||||
mode_code = _MODE_WRITE
|
||||
self._compressor = BZ2Compressor(compresslevel)
|
||||
elif mode in ("a", "ab"):
|
||||
mode = "ab"
|
||||
mode_code = _MODE_WRITE
|
||||
|
@ -443,9 +447,9 @@ def open(filename, mode="rb", compresslevel=9,
|
|||
The filename argument can be an actual filename (a str or bytes
|
||||
object), or an existing file object to read from or write to.
|
||||
|
||||
The mode argument can be "r", "rb", "w", "wb", "a" or "ab" for
|
||||
binary mode, or "rt", "wt" or "at" for text mode. The default mode
|
||||
is "rb", and the default compresslevel is 9.
|
||||
The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or
|
||||
"ab" for binary mode, or "rt", "wt", "xt" or "at" for text mode.
|
||||
The default mode is "rb", and the default compresslevel is 9.
|
||||
|
||||
For binary mode, this function is equivalent to the BZ2File
|
||||
constructor: BZ2File(filename, mode, compresslevel). In this case,
|
||||
|
|
|
@ -8,6 +8,7 @@ import os
|
|||
import random
|
||||
import subprocess
|
||||
import sys
|
||||
from test.support import unlink
|
||||
|
||||
try:
|
||||
import threading
|
||||
|
@ -715,49 +716,67 @@ class OpenTest(BaseTest):
|
|||
return bz2.open(*args, **kwargs)
|
||||
|
||||
def test_binary_modes(self):
|
||||
with self.open(self.filename, "wb") as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT)
|
||||
with self.open(self.filename, "rb") as f:
|
||||
self.assertEqual(f.read(), self.TEXT)
|
||||
with self.open(self.filename, "ab") as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT * 2)
|
||||
for mode in ("wb", "xb"):
|
||||
if mode == "xb":
|
||||
unlink(self.filename)
|
||||
with self.open(self.filename, mode) as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT)
|
||||
with self.open(self.filename, "rb") as f:
|
||||
self.assertEqual(f.read(), self.TEXT)
|
||||
with self.open(self.filename, "ab") as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT * 2)
|
||||
|
||||
def test_implicit_binary_modes(self):
|
||||
# Test implicit binary modes (no "b" or "t" in mode string).
|
||||
with self.open(self.filename, "w") as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT)
|
||||
with self.open(self.filename, "r") as f:
|
||||
self.assertEqual(f.read(), self.TEXT)
|
||||
with self.open(self.filename, "a") as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT * 2)
|
||||
for mode in ("w", "x"):
|
||||
if mode == "x":
|
||||
unlink(self.filename)
|
||||
with self.open(self.filename, mode) as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT)
|
||||
with self.open(self.filename, "r") as f:
|
||||
self.assertEqual(f.read(), self.TEXT)
|
||||
with self.open(self.filename, "a") as f:
|
||||
f.write(self.TEXT)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read())
|
||||
self.assertEqual(file_data, self.TEXT * 2)
|
||||
|
||||
def test_text_modes(self):
|
||||
text = self.TEXT.decode("ascii")
|
||||
text_native_eol = text.replace("\n", os.linesep)
|
||||
with self.open(self.filename, "wt") as f:
|
||||
f.write(text)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read()).decode("ascii")
|
||||
self.assertEqual(file_data, text_native_eol)
|
||||
with self.open(self.filename, "rt") as f:
|
||||
self.assertEqual(f.read(), text)
|
||||
with self.open(self.filename, "at") as f:
|
||||
f.write(text)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read()).decode("ascii")
|
||||
self.assertEqual(file_data, text_native_eol * 2)
|
||||
for mode in ("wt", "xt"):
|
||||
if mode == "xt":
|
||||
unlink(self.filename)
|
||||
with self.open(self.filename, mode) as f:
|
||||
f.write(text)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read()).decode("ascii")
|
||||
self.assertEqual(file_data, text_native_eol)
|
||||
with self.open(self.filename, "rt") as f:
|
||||
self.assertEqual(f.read(), text)
|
||||
with self.open(self.filename, "at") as f:
|
||||
f.write(text)
|
||||
with open(self.filename, "rb") as f:
|
||||
file_data = self.decompress(f.read()).decode("ascii")
|
||||
self.assertEqual(file_data, text_native_eol * 2)
|
||||
|
||||
def test_x_mode(self):
|
||||
for mode in ("x", "xb", "xt"):
|
||||
unlink(self.filename)
|
||||
with self.open(self.filename, mode) as f:
|
||||
pass
|
||||
with self.assertRaises(FileExistsError):
|
||||
with self.open(self.filename, mode) as f:
|
||||
pass
|
||||
|
||||
def test_fileobj(self):
|
||||
with self.open(BytesIO(self.DATA), "r") as f:
|
||||
|
@ -772,6 +791,8 @@ class OpenTest(BaseTest):
|
|||
# Test invalid parameter combinations.
|
||||
self.assertRaises(ValueError,
|
||||
self.open, self.filename, "wbt")
|
||||
self.assertRaises(ValueError,
|
||||
self.open, self.filename, "xbt")
|
||||
self.assertRaises(ValueError,
|
||||
self.open, self.filename, "rb", encoding="utf-8")
|
||||
self.assertRaises(ValueError,
|
||||
|
|
|
@ -54,8 +54,8 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #19201: Add "x" mode (exclusive creation) in opening file to lzma
|
||||
module. Patch by Tim Heaney and Vajrasky Kok.
|
||||
- Issues #19201, #19223: Add "x" mode (exclusive creation) in opening file to
|
||||
bz2 and lzma modules. Patches by Tim Heaney and Vajrasky Kok.
|
||||
|
||||
- Fix a reference count leak in _sre.
|
||||
|
||||
|
|
Loading…
Reference in New Issue