Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit58a2e09

Browse files
authored
gh-62948: IOBase finalizer logs close() errors (#105104)
1 parent85e5d03 commit58a2e09

File tree

5 files changed

+19
-40
lines changed

5 files changed

+19
-40
lines changed

‎Doc/whatsnew/3.13.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ New Modules
8787
Improved Modules
8888
================
8989

90+
io
91+
--
92+
93+
The:class:`io.IOBase` finalizer now logs the ``close()`` method errors with
94+
:data:`sys.unraisablehook`. Previously, errors were ignored silently by default,
95+
and only logged in:ref:`Python Development Mode<devmode>` or on:ref:`Python
96+
built on debug mode <debug-build>`.
97+
(Contributed by Victor Stinner in:gh:`62948`.)
98+
9099
pathlib
91100
-------
92101

‎Lib/_pyio.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,8 @@
3333
# Rebind for compatibility
3434
BlockingIOError=BlockingIOError
3535

36-
# Does io.IOBase finalizer log the exception if the close() method fails?
37-
# The exception is ignored silently by default in release build.
38-
_IOBASE_EMITS_UNRAISABLE= (hasattr(sys,"gettotalrefcount")orsys.flags.dev_mode)
3936
# Does open() check its 'errors' argument?
40-
_CHECK_ERRORS=_IOBASE_EMITS_UNRAISABLE
37+
_CHECK_ERRORS=(hasattr(sys,"gettotalrefcount")orsys.flags.dev_mode)
4138

4239

4340
deftext_encoding(encoding,stacklevel=2):
@@ -416,18 +413,9 @@ def __del__(self):
416413
ifclosed:
417414
return
418415

419-
if_IOBASE_EMITS_UNRAISABLE:
420-
self.close()
421-
else:
422-
# The try/except block is in case this is called at program
423-
# exit time, when it's possible that globals have already been
424-
# deleted, and then the close() call might fail. Since
425-
# there's nothing we can do about such failures and they annoy
426-
# the end users, we suppress the traceback.
427-
try:
428-
self.close()
429-
except:
430-
pass
416+
# If close() fails, the caller logs the exception with
417+
# sys.unraisablehook. close() must be called at the end at __del__().
418+
self.close()
431419

432420
### Inquiries ###
433421

‎Lib/test/test_io.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@ def byteslike(*pos, **kw):
6666
classEmptyStruct(ctypes.Structure):
6767
pass
6868

69-
# Does io.IOBase finalizer log the exception if the close() method fails?
70-
# The exception is ignored silently by default in release build.
71-
IOBASE_EMITS_UNRAISABLE= (support.Py_DEBUGorsys.flags.dev_mode)
72-
7369

7470
def_default_chunk_size():
7571
"""Get the default TextIOWrapper chunk size"""
@@ -1218,10 +1214,7 @@ def test_error_through_destructor(self):
12181214
withself.assertRaises(AttributeError):
12191215
self.tp(rawio).xyzzy
12201216

1221-
ifnotIOBASE_EMITS_UNRAISABLE:
1222-
self.assertIsNone(cm.unraisable)
1223-
elifcm.unraisableisnotNone:
1224-
self.assertEqual(cm.unraisable.exc_type,OSError)
1217+
self.assertEqual(cm.unraisable.exc_type,OSError)
12251218

12261219
deftest_repr(self):
12271220
raw=self.MockRawIO()
@@ -3022,10 +3015,7 @@ def test_error_through_destructor(self):
30223015
withself.assertRaises(AttributeError):
30233016
self.TextIOWrapper(rawio,encoding="utf-8").xyzzy
30243017

3025-
ifnotIOBASE_EMITS_UNRAISABLE:
3026-
self.assertIsNone(cm.unraisable)
3027-
elifcm.unraisableisnotNone:
3028-
self.assertEqual(cm.unraisable.exc_type,OSError)
3018+
self.assertEqual(cm.unraisable.exc_type,OSError)
30293019

30303020
# Systematic tests of the text I/O API
30313021

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The:class:`io.IOBase` finalizer now logs the ``close()`` method errors with
2+
:data:`sys.unraisablehook`. Previously, errors were ignored silently by default,
3+
and only logged in:ref:`Python Development Mode<devmode>` or on
4+
:ref:`Python built on debug mode<debug-build>`. Patch by Victor Stinner.

‎Modules/_io/iobase.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -319,20 +319,8 @@ iobase_finalize(PyObject *self)
319319
if (PyObject_SetAttr(self,&_Py_ID(_finalizing),Py_True))
320320
PyErr_Clear();
321321
res=PyObject_CallMethodNoArgs((PyObject*)self,&_Py_ID(close));
322-
/* Silencing I/O errors is bad, but printing spurious tracebacks is
323-
equally as bad, and potentially more frequent (because of
324-
shutdown issues). */
325322
if (res==NULL) {
326-
#ifndefPy_DEBUG
327-
if (_Py_GetConfig()->dev_mode) {
328-
PyErr_WriteUnraisable(self);
329-
}
330-
else {
331-
PyErr_Clear();
332-
}
333-
#else
334323
PyErr_WriteUnraisable(self);
335-
#endif
336324
}
337325
else {
338326
Py_DECREF(res);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp