Utilities for interfacing with the standard library’s atexit module.#
- class sage.cpython.atexit.restore_atexit[source]#
Bases:
object
Context manager that restores the state of the atexit module to its previous state when exiting the context.
INPUT:
run
(bool, default:False
) – if True, when exiting the context (but before restoring the old exit functions), run all atexit functions which were added inside the context.clear
(bool, default: equal torun
) – if True, clear already registered atexit handlers upon entering the context.
Warning
The combination
run=True
andclear=False
will cause already-registered exit functions to be run twice: once when exiting the context and again when exiting Python.EXAMPLES:
For this example we will wrap the entire example with
restore_atexit(clear=True)
so as to start with a fresh atexit module state for the sake of the example.Note that the function
atexit._run_exitfuncs()
runs all registered handlers, and then clears the list of handlers, so we can use it to test manipulation of theatexit
state:sage: import atexit sage: from sage.cpython.atexit import restore_atexit sage: def handler(*args, **kwargs): ....: import sys ....: # see https://github.com/sagemath/sage/issues/25270#comment:56 ....: sys.stdout.write(str((args, kwargs))) ....: sys.stdout.write('\n') sage: atexit.register(handler, 1, 2, c=3) <function handler at 0x...> sage: atexit.register(handler, 4, 5, d=6) <function handler at 0x...> sage: with restore_atexit(clear=True): ....: atexit._run_exitfuncs() # Should be none registered ....: atexit.register(handler, 1, 2, c=3) ....: with restore_atexit(): ....: atexit._run_exitfuncs() # Run just registered handler ....: atexit._run_exitfuncs() # Handler should be run again <function handler at 0x...> ((1, 2), {'c': 3}) ((1, 2), {'c': 3})
>>> from sage.all import * >>> import atexit >>> from sage.cpython.atexit import restore_atexit >>> def handler(*args, **kwargs): ... import sys ... # see https://github.com/sagemath/sage/issues/25270#comment:56 ... sys.stdout.write(str((args, kwargs))) ... sys.stdout.write('\n') >>> atexit.register(handler, Integer(1), Integer(2), c=Integer(3)) <function handler at 0x...> >>> atexit.register(handler, Integer(4), Integer(5), d=Integer(6)) <function handler at 0x...> >>> with restore_atexit(clear=True): ... atexit._run_exitfuncs() # Should be none registered ... atexit.register(handler, Integer(1), Integer(2), c=Integer(3)) ... with restore_atexit(): ... atexit._run_exitfuncs() # Run just registered handler ... atexit._run_exitfuncs() # Handler should be run again <function handler at 0x...> ((1, 2), {'c': 3}) ((1, 2), {'c': 3})
We test the
run
option:sage: with restore_atexit(run=True): ....: # this handler is run when exiting the context ....: _ = atexit.register(handler, 7, 8, e=9) ((7, 8), {'e': 9}) sage: with restore_atexit(clear=False, run=True): ....: # original handlers are run when exiting the context ....: pass ((4, 5), {'d': 6}) ((1, 2), {'c': 3})
>>> from sage.all import * >>> with restore_atexit(run=True): ... # this handler is run when exiting the context ... _ = atexit.register(handler, Integer(7), Integer(8), e=Integer(9)) ((7, 8), {'e': 9}) >>> with restore_atexit(clear=False, run=True): ... # original handlers are run when exiting the context ... pass ((4, 5), {'d': 6}) ((1, 2), {'c': 3})
The original handlers are still in place:
sage: atexit._run_exitfuncs() ((4, 5), {'d': 6}) ((1, 2), {'c': 3})
>>> from sage.all import * >>> atexit._run_exitfuncs() ((4, 5), {'d': 6}) ((1, 2), {'c': 3})