-
-
Notifications
You must be signed in to change notification settings - Fork 35.3k
Reword atexit docs
#156086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reword atexit docs
#156086
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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` | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Link to the term here?
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarifying which internals exactly cause your crash isn't too useful. |
||||||
| 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 | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is defined starting in 3.15; Python will run any handlers that have been added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, really?
In any case, should we guarantee that? What about unregistering?
Sounds like material for a follow-up that's not backported to 3.14.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, you may have found a bug.
atexitcallbacks are supposed to be ran in a loop:cpython/Python/pylifecycle.c
Line 2262 in f54fd2a
cpython/Python/pylifecycle.c
Line 2280 in f54fd2a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it works as documented -- and better than an infinite loop with a function registering itself...