Skip to content

Commit 825aab9

Browse files
sthserhiy-storchaka
authored andcommitted
bpo-27300: Add the errors parameter to tempfile classes. (GH-6696)
1 parent 0e61dff commit 825aab9

File tree

4 files changed

+41
-24
lines changed

4 files changed

+41
-24
lines changed

Doc/library/tempfile.rst

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ is recommended to use keyword arguments for clarity.
3131

3232
The module defines the following user-callable items:
3333

34-
.. function:: TemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None)
34+
.. function:: TemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)
3535

3636
Return a :term:`file-like object` that can be used as a temporary storage area.
3737
The file is created securely, using the same rules as :func:`mkstemp`. It will be destroyed as soon
@@ -49,7 +49,7 @@ The module defines the following user-callable items:
4949
The *mode* parameter defaults to ``'w+b'`` so that the file created can
5050
be read and written without being closed. Binary mode is used so that it
5151
behaves consistently on all platforms without regard for the data that is
52-
stored. *buffering*, *encoding* and *newline* are interpreted as for
52+
stored. *buffering*, *encoding*, *errors* and *newline* are interpreted as for
5353
:func:`open`.
5454

5555
The *dir*, *prefix* and *suffix* parameters have the same meaning and
@@ -66,8 +66,11 @@ The module defines the following user-callable items:
6666

6767
The :py:data:`os.O_TMPFILE` flag is now used if available.
6868

69+
.. versionchanged:: 3.8
70+
Added *errors* parameter.
6971

70-
.. function:: NamedTemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True)
72+
73+
.. function:: NamedTemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True, *, errors=None)
7174

7275
This function operates exactly as :func:`TemporaryFile` does, except that
7376
the file is guaranteed to have a visible name in the file system (on
@@ -82,8 +85,11 @@ The module defines the following user-callable items:
8285
attribute is the underlying true file object. This file-like object can
8386
be used in a :keyword:`with` statement, just like a normal file.
8487

88+
.. versionchanged:: 3.8
89+
Added *errors* parameter.
90+
8591

86-
.. function:: SpooledTemporaryFile(max_size=0, mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None)
92+
.. function:: SpooledTemporaryFile(max_size=0, mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)
8793

8894
This function operates exactly as :func:`TemporaryFile` does, except that
8995
data is spooled in memory until the file size exceeds *max_size*, or
@@ -104,6 +110,9 @@ The module defines the following user-callable items:
104110
.. versionchanged:: 3.3
105111
the truncate method now accepts a ``size`` argument.
106112

113+
.. versionchanged:: 3.8
114+
Added *errors* parameter.
115+
107116

108117
.. function:: TemporaryDirectory(suffix=None, prefix=None, dir=None)
109118

Lib/tempfile.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ def __iter__(self):
519519

520520
def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
521521
newline=None, suffix=None, prefix=None,
522-
dir=None, delete=True):
522+
dir=None, delete=True, *, errors=None):
523523
"""Create and return a temporary file.
524524
Arguments:
525525
'prefix', 'suffix', 'dir' -- as for mkstemp.
@@ -528,6 +528,7 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
528528
'encoding' -- the encoding argument to io.open (default None)
529529
'newline' -- the newline argument to io.open (default None)
530530
'delete' -- whether the file is deleted on close (default True).
531+
'errors' -- the errors argument to io.open (default None)
531532
The file is created as mkstemp() would do it.
532533
533534
Returns an object with a file-like interface; the name of the file
@@ -547,7 +548,7 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
547548
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
548549
try:
549550
file = _io.open(fd, mode, buffering=buffering,
550-
newline=newline, encoding=encoding)
551+
newline=newline, encoding=encoding, errors=errors)
551552

552553
return _TemporaryFileWrapper(file, name, delete)
553554
except BaseException:
@@ -568,14 +569,15 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
568569

569570
def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
570571
newline=None, suffix=None, prefix=None,
571-
dir=None):
572+
dir=None, *, errors=None):
572573
"""Create and return a temporary file.
573574
Arguments:
574575
'prefix', 'suffix', 'dir' -- as for mkstemp.
575576
'mode' -- the mode argument to io.open (default "w+b").
576577
'buffering' -- the buffer size argument to io.open (default -1).
577578
'encoding' -- the encoding argument to io.open (default None)
578579
'newline' -- the newline argument to io.open (default None)
580+
'errors' -- the errors argument to io.open (default None)
579581
The file is created as mkstemp() would do it.
580582
581583
Returns an object with a file-like interface. The file has no
@@ -609,7 +611,8 @@ def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
609611
else:
610612
try:
611613
return _io.open(fd, mode, buffering=buffering,
612-
newline=newline, encoding=encoding)
614+
newline=newline, encoding=encoding,
615+
errors=errors)
613616
except:
614617
_os.close(fd)
615618
raise
@@ -619,7 +622,7 @@ def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
619622
try:
620623
_os.unlink(name)
621624
return _io.open(fd, mode, buffering=buffering,
622-
newline=newline, encoding=encoding)
625+
newline=newline, encoding=encoding, errors=errors)
623626
except:
624627
_os.close(fd)
625628
raise
@@ -633,7 +636,7 @@ class SpooledTemporaryFile:
633636

634637
def __init__(self, max_size=0, mode='w+b', buffering=-1,
635638
encoding=None, newline=None,
636-
suffix=None, prefix=None, dir=None):
639+
suffix=None, prefix=None, dir=None, *, errors=None):
637640
if 'b' in mode:
638641
self._file = _io.BytesIO()
639642
else:
@@ -646,7 +649,7 @@ def __init__(self, max_size=0, mode='w+b', buffering=-1,
646649
self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
647650
'suffix': suffix, 'prefix': prefix,
648651
'encoding': encoding, 'newline': newline,
649-
'dir': dir}
652+
'dir': dir, 'errors': errors}
650653

651654
def _check(self, file):
652655
if self._rolled: return
@@ -692,12 +695,11 @@ def closed(self):
692695

693696
@property
694697
def encoding(self):
695-
try:
696-
return self._file.encoding
697-
except AttributeError:
698-
if 'b' in self._TemporaryFileArgs['mode']:
699-
raise
700-
return self._TemporaryFileArgs['encoding']
698+
return self._file.encoding
699+
700+
@property
701+
def errors(self):
702+
return self._file.errors
701703

702704
def fileno(self):
703705
self.rollover()
@@ -725,12 +727,7 @@ def name(self):
725727

726728
@property
727729
def newlines(self):
728-
try:
729-
return self._file.newlines
730-
except AttributeError:
731-
if 'b' in self._TemporaryFileArgs['mode']:
732-
raise
733-
return self._TemporaryFileArgs['newline']
730+
return self._file.newlines
734731

735732
def read(self, *args):
736733
return self._file.read(*args)

Lib/test/test_tempfile.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,8 @@ def test_properties(self):
10941094
f.newlines
10951095
with self.assertRaises(AttributeError):
10961096
f.encoding
1097+
with self.assertRaises(AttributeError):
1098+
f.errors
10971099

10981100
f.write(b'x')
10991101
self.assertTrue(f._rolled)
@@ -1103,6 +1105,8 @@ def test_properties(self):
11031105
f.newlines
11041106
with self.assertRaises(AttributeError):
11051107
f.encoding
1108+
with self.assertRaises(AttributeError):
1109+
f.errors
11061110

11071111
def test_text_mode(self):
11081112
# Creating a SpooledTemporaryFile with a text mode should produce
@@ -1119,6 +1123,7 @@ def test_text_mode(self):
11191123
self.assertIsNone(f.name)
11201124
self.assertIsNone(f.newlines)
11211125
self.assertIsNone(f.encoding)
1126+
self.assertIsNone(f.errors)
11221127

11231128
f.write("xyzzy\n")
11241129
f.seek(0)
@@ -1132,10 +1137,12 @@ def test_text_mode(self):
11321137
self.assertIsNotNone(f.name)
11331138
self.assertEqual(f.newlines, os.linesep)
11341139
self.assertIsNotNone(f.encoding)
1140+
self.assertIsNotNone(f.errors)
11351141

11361142
def test_text_newline_and_encoding(self):
11371143
f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10,
1138-
newline='', encoding='utf-8')
1144+
newline='', encoding='utf-8',
1145+
errors='ignore')
11391146
f.write("\u039B\r\n")
11401147
f.seek(0)
11411148
self.assertEqual(f.read(), "\u039B\r\n")
@@ -1144,6 +1151,7 @@ def test_text_newline_and_encoding(self):
11441151
self.assertIsNone(f.name)
11451152
self.assertIsNone(f.newlines)
11461153
self.assertIsNone(f.encoding)
1154+
self.assertIsNone(f.errors)
11471155

11481156
f.write("\u039B" * 20 + "\r\n")
11491157
f.seek(0)
@@ -1153,6 +1161,7 @@ def test_text_newline_and_encoding(self):
11531161
self.assertIsNotNone(f.name)
11541162
self.assertIsNotNone(f.newlines)
11551163
self.assertEqual(f.encoding, 'utf-8')
1164+
self.assertEqual(f.errors, 'ignore')
11561165

11571166
def test_context_manager_before_rollover(self):
11581167
# A SpooledTemporaryFile can be used as a context manager
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The file classes in *tempfile* now accept an *errors* parameter that
2+
complements the already existing *encoding*. Patch by Stephan Hohe.

0 commit comments

Comments
 (0)