https://github.com/python/cpython/commit/1d28836e43efba08ac71d91d135d721e1f4ada69
commit: 1d28836e43efba08ac71d91d135d721e1f4ada69
branch: main
author: Petr Viktorin <[email protected]>
committer: encukou <[email protected]>
date: 2026-09-03T10:20:52+02:00
summary:
Reword `atexit` docs (#156086)
For the `atexit` module:
- Move common info from `register` to the module level (a lot of this
was duplicated -- less maintainable and harder to read)
- Use *interpreter shutdown* consistently, introducing it as a more
general term for the old docs' *program termination*.
- Use the term *exit handler* consistently
- Move warning for a mitigated footgun to a change entry
- Add a new warning about keeping things usable
Similarly clarify docs for the `atexit` attribute in `weakref`.
files:
M Doc/library/atexit.rst
M Doc/library/weakref.rst
diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst
index b5caf5502d0e1c..417611307577fd 100644
--- a/Doc/library/atexit.rst
+++ b/Doc/library/atexit.rst
@@ -6,59 +6,69 @@
--------------
-The :mod:`!atexit` module defines functions to register and unregister cleanup
-functions. Functions thus registered are automatically executed upon normal
-interpreter termination. :mod:`!atexit` runs these functions in the *reverse*
-order in which they were registered; if you register ``A``, ``B``, and ``C``,
-at interpreter termination time they will be run in the order ``C``, ``B``,
-``A``.
-
-**Note:** The functions registered via this module are not called when the
+The :mod:`!atexit` module defines functions to register and unregister
+:dfn:`exit handlers`: functions that are automatically executed
+"at exit", that is, upon normal program termination (for instance,
+if :func:`sys.exit` is called or the main module's execution completes)
+or, more generally, upon :term:`interpreter shutdown`.
+
+At exit, all registered exit handlers are called
+in the *reverse* order in which they were registered.
+If you register ``A``, ``B``, and ``C``, at interpreter shutdown time they
+will be run in the order ``C``, ``B``, ``A``.
+The assumption is that lower level modules will normally be imported before
+higher level modules and thus must be cleaned up later.
+
+If an exception is raised during execution of an exit handler, a traceback is
+printed (unless :exc:`SystemExit` is raised) and the exception information is
+saved. After all exit handlers have had a chance to run, the last exception to
+be raised is re-raised.
+
+In programs that use multiple interpreters, each interpreter has its own stack
+of exit handlers, which are executed when the interpreter shuts down
+(for example, with :meth:`concurrent.interpreters.Interpreter.close` or the
+C API :c:func:`Py_EndInterpreter`).
+Registration functions in this module only affect the interpreter they are
+called from.
+
+**Note:** Exit handlers are not called when the
program is killed by a signal not handled by Python, when a Python fatal
internal error is detected, or when :func:`os._exit` is called.
**Note:** The effect of registering or unregistering functions from within
a cleanup function is undefined.
-.. versionchanged:: 3.7
- When used with C-API subinterpreters, registered functions
- are local to the interpreter they were registered in.
+.. warning::
+ When writing exit handlers, especially in C API extensions, keep in mind
+ that other exit handlers may still run arbitrary Python code after you
+ clean up.
+ Such code should succeed or fail with an exception, rather than crash.
-.. function:: register(func, *args, **kwargs)
+.. versionchanged:: 3.12
+ Attempts to start a new thread or :func:`os.fork` a new process
+ in an exit handler now leads to :exc:`RuntimeError`.
+ Previously, this could cause race conditions between the main Python
+ runtime thread freeing thread states while internal :mod:`threading`
+ routines or the new process try to use that state, which could lead to
+ crashes rather than clean shutdown.
- Register *func* as a function to be executed at termination. Any optional
- arguments that are to be passed to *func* must be passed as arguments to
- :func:`register`. It is possible to register the same function and
arguments
- more than once.
+.. versionchanged:: 3.7
+ When used with subinterpreters, registered functions
+ are local to the interpreter they were registered in.
- At normal program termination (for instance, if :func:`sys.exit` is called
or
- the main module's execution completes), all functions registered are called
in
- last in, first out order. The assumption is that lower level modules will
- normally be imported before higher level modules and thus must be cleaned up
- later.
+.. function:: register(func, *args, **kwargs)
- If an exception is raised during execution of the exit handlers, a
traceback is
- printed (unless :exc:`SystemExit` is raised) and the exception information
is
- saved. After all exit handlers have had a chance to run, the last
exception to
- be raised is re-raised.
+ Register *func* as an exit handler.
+ Any optional arguments that are to be passed to *func* must be passed as
+ arguments to :func:`register`.
+ It is possible to register the same function and arguments more than once.
This function returns *func*, which makes it possible to use it as a
decorator.
- .. warning::
- Starting new threads or calling :func:`os.fork` from a registered
- function can lead to race condition between the main Python
- runtime thread freeing thread states while internal :mod:`threading`
- routines or the new process try to use that state. This can lead to
- crashes rather than clean shutdown.
-
- .. versionchanged:: 3.12
- Attempts to start a new thread or :func:`os.fork` a new process
- in a registered function now leads to :exc:`RuntimeError`.
-
.. function:: unregister(func)
- Remove *func* from the list of functions to be run at interpreter shutdown.
+ Remove *func* from the list of exit handlers.
:func:`unregister` silently does nothing if *func* was not previously
registered. If *func* has been registered more than once, every occurrence
of that function in the :mod:`!atexit` call stack will be removed. Equality
diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst
index 7cc0c33fda353c..52fedb00a940c9 100644
--- a/Doc/library/weakref.rst
+++ b/Doc/library/weakref.rst
@@ -290,9 +290,10 @@ same issues as the :meth:`WeakKeyDictionary.keyrefs`
method.
from an object's :meth:`~object.__del__` method or a weak reference's
callback.
- When the program exits, each remaining live finalizer is called
- unless its :attr:`atexit` attribute has been set to false. They
- are called in reverse order of creation.
+ When the program exits (or more generally, at :term:`interpreter shutdown`),
+ each remaining live finalizer is called unless its :attr:`atexit` attribute
+ has been set to false.
+ They are called in reverse order of creation.
A finalizer will never invoke its callback during the later part of
the :term:`interpreter shutdown` when module globals are liable to have
@@ -321,9 +322,9 @@ same issues as the :meth:`WeakKeyDictionary.keyrefs` method.
.. attribute:: atexit
- A writable boolean property which by default is true. When the
- program exits, it calls all remaining live finalizers for which
- :attr:`.atexit` is true. They are called in reverse order of
+ A writable boolean property which by default is true. At
+ :term:`interpreter shutdown`, all remaining live finalizers for which
+ :attr:`.atexit` is true are called in reverse order of
creation.
.. note::
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]