Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Lib/_pyio.py
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,7 @@ class FileIO(RawIOBase):
_writable = False
_appending = False
_seekable = None
_truncate = False
_closefd = True

def __init__(self, file, mode='r', closefd=True, opener=None):
Expand Down Expand Up @@ -1553,6 +1554,7 @@ def __init__(self, file, mode='r', closefd=True, opener=None):
flags = 0
elif 'w' in mode:
self._writable = True
self._truncate = True
flags = os.O_CREAT | os.O_TRUNC
elif 'a' in mode:
self._writable = True
Expand Down Expand Up @@ -1877,7 +1879,10 @@ def mode(self):
return 'ab'
elif self._readable:
if self._writable:
return 'rb+'
if self._truncate:
return 'wb+'
else:
return 'rb+'
else:
return 'rb'
else:
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,8 @@ def testModeStrings(self):
# test that the mode attribute is correct for various mode strings
# given as init args
try:
for modes in [('w', 'wb'), ('wb', 'wb'), ('wb+', 'rb+'),
('w+b', 'rb+'), ('a', 'ab'), ('ab', 'ab'),
for modes in [('w', 'wb'), ('wb', 'wb'), ('wb+', 'wb+'),
('w+b', 'wb+'), ('a', 'ab'), ('ab', 'ab'),
('ab+', 'ab+'), ('a+b', 'ab+'), ('r', 'rb'),
('rb', 'rb'), ('rb+', 'rb+'), ('r+b', 'rb+')]:
# read modes are last so that TESTFN will exist first
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ def test_mode(self):
os_helper.unlink(self.filename)
with gzip.GzipFile(self.filename, 'x') as f:
self.assertEqual(f.myfileobj.mode, 'xb')
with gzip.GzipFile(self.filename, 'wb+') as f:
self.assertEqual(f.myfileobj.mode, 'wb+')

def test_1647484(self):
for mode in ('wb', 'rb'):
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4337,8 +4337,8 @@ def test_attributes(self):

f = self.open(os_helper.TESTFN, "w+", encoding="utf-8")
self.assertEqual(f.mode, "w+")
self.assertEqual(f.buffer.mode, "rb+") # Does it really matter?
self.assertEqual(f.buffer.raw.mode, "rb+")
self.assertEqual(f.buffer.mode, "wb+")
self.assertEqual(f.buffer.raw.mode, "wb+")

g = self.open(f.fileno(), "wb", closefd=False)
self.assertEqual(g.mode, "wb")
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,7 @@ def test_properties(self):

f.write(b'x')
self.assertTrue(f._rolled)
self.assertEqual(f.mode, 'rb+')
self.assertEqual(f.mode, 'wb+')
self.assertIsNotNone(f.name)
with self.assertRaises(AttributeError):
f.newlines
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:mod:`io`: Fix a bug where the ``'wb+'`` mode was treated as ``'rb+'``.
16 changes: 13 additions & 3 deletions Modules/_io/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef struct {
unsigned int writable : 1;
unsigned int appending : 1;
signed int seekable : 2; /* -1 means unknown */
unsigned int truncate : 1;
unsigned int closefd : 1;
char finalizing;
/* Stat result which was grabbed at file open, useful for optimizing common
Expand Down Expand Up @@ -209,6 +210,7 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->writable = 0;
self->appending = 0;
self->seekable = -1;
self->truncate = 0;
self->stat_atopen = NULL;
self->closefd = 1;
self->weakreflist = NULL;
Expand Down Expand Up @@ -341,6 +343,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
goto bad_mode;
rwa = 1;
self->writable = 1;
self->truncate = 1;
flags |= O_CREAT | O_TRUNC;
break;
case 'a':
Expand Down Expand Up @@ -1156,10 +1159,17 @@ mode_string(fileio *self)
return "ab";
}
else if (self->readable) {
if (self->writable)
return "rb+";
else
if (self->writable) {
if (self->truncate) {
return "wb+";
}
else {
return "rb+";
}
}
else {
return "rb";
}
}
else
return "wb";
Expand Down
Loading