Utilities for interfacing with the standard library’s atexit module.¶
- class sage.cpython.atexit.restore_atexit[source]¶
Bases:
objectContext manager that restores the state of the atexit module to its previous state when exiting the context.
INPUT:
run– boolean (default:False); ifTrue, when exiting the context (but before restoring the old exit functions), run all atexit functions which were added inside the contextclear– boolean (default: equal torun); ifTrue, clear already registered atexit handlers upon entering the context
Warning
The combination
run=Trueandclear=Falsewill 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 theatexitstate: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
runoption: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})