Skip to content

Commit f6b7759

Browse files
committed
bpo-38971: open file in codecs.open() closes if exception raised
Open issue in the BPO indicated a desire to make the implementation of codecs.open() at parity with io.open(), which implements a try/except to assure file stream gets closed before an exception is raised.
1 parent 791073f commit f6b7759

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

Lib/codecs.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -905,11 +905,16 @@ def open(filename, mode='r', encoding=None, errors='strict', buffering=-1):
905905
file = builtins.open(filename, mode, buffering)
906906
if encoding is None:
907907
return file
908-
info = lookup(encoding)
909-
srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
910-
# Add attributes to simplify introspection
911-
srw.encoding = encoding
912-
return srw
908+
909+
try:
910+
info = lookup(encoding)
911+
srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
912+
# Add attributes to simplify introspection
913+
srw.encoding = encoding
914+
return srw
915+
except:
916+
file.close()
917+
raise
913918

914919
def EncodedFile(file, data_encoding, file_encoding=None, errors='strict'):
915920

Lib/test/test_codecs.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,19 @@ def test_stream_bare(self):
11541154
got = ostream.getvalue()
11551155
self.assertEqual(got, unistring)
11561156

1157+
class FileClosesOnRaiseTest(unittest.TestCase):
1158+
def test_file_closes_if_exception_raised(self):
1159+
mock_open = mock.mock_open()
1160+
mock_lookup = mock.Mock(side_effect=Exception)
1161+
1162+
with mock.patch('codecs.lookup', mock_lookup):
1163+
with mock.patch('builtins.open', mock_open) as file:
1164+
with self.assertRaises(Exception):
1165+
codecs.open(support.TESTFN, mode = 'wt', encoding='utf-8')
1166+
1167+
file().close.assert_called()
1168+
1169+
11571170
class EscapeDecodeTest(unittest.TestCase):
11581171
def test_empty(self):
11591172
self.assertEqual(codecs.escape_decode(b""), (b"", 0))

0 commit comments

Comments
 (0)