diff --git a/src/sage/cpython/atexit.pyx b/src/sage/cpython/atexit.pyx index 5b0c6d1..3ba391b 100644 --- a/src/sage/cpython/atexit.pyx +++ b/src/sage/cpython/atexit.pyx @@ -144,43 +144,63 @@ cdef class restore_atexit: from cpython.ref cimport PyObject -# Internal structures defined in the CPython source in -# Modules/atexitmodule.c and subject to (but unlikely to) change. Watch -# https://bugs.python.org/issue32082 for a request to (eventually) -# re-expose more of the atexit module's internals to Python -ctypedef struct atexit_callback: - PyObject* func - PyObject* args - PyObject* kwargs - - -ctypedef struct atexitmodule_state: - atexit_callback** atexit_callbacks - int ncallbacks - int callback_len - - -cdef extern from "Python.h": - void* PyModule_GetState(object module) - +# Implement "_atexit_callbacks()" for each supported python version +cdef extern from *: + """ + #if PY_VERSION_HEX >= 0x030a0000 + /********** Python 3.10 **********/ + #define Py_BUILD_CORE + #undef _PyGC_FINALIZED + #include "internal/pycore_interp.h" + #include "internal/pycore_pystate.h" + static atexit_callback ** _atexit_callbacks(PyObject *self) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct atexit_state state = interp->atexit; + return state.callbacks; + } + #else + /********** Python < 3.10 **********/ + /* Internal structures defined in the CPython source in + * Modules/atexitmodule.c and subject to (but unlikely to) change. Watch + * https://bugs.python.org/issue32082 for a request to (eventually) + * re-expose more of the atexit module's internals to Python + * typedef struct + */ + typedef struct { + PyObject *func; + PyObject *args; + PyObject *kwargs; + } atexit_callback; + typedef struct { + atexit_callback **atexit_callbacks; + int ncallbacks; + int callback_len; + } atexitmodule_state; + static atexit_callback ** _atexit_callbacks(PyObject *self) { + atexitmodule_state *state = PyModule_GetState(self); + return state->atexit_callbacks; + } + #endif + """ + ctypedef struct atexit_callback: + PyObject* func + PyObject* args + PyObject* kwargs + atexit_callback** _atexit_callbacks(object module) def _get_exithandlers(): """Return list of exit handlers registered with the atexit module.""" - cdef atexitmodule_state* state + cdef atexit_callback ** callbacks cdef atexit_callback callback cdef list exithandlers cdef int idx cdef object kwargs - state = PyModule_GetState(atexit) - - if not state: - raise RuntimeError("atexit module state missing or corrupt") - exithandlers = [] + callbacks = _atexit_callbacks(atexit) - for idx in range(state.ncallbacks): - callback = state.atexit_callbacks[idx][0] + for idx in range(atexit._ncallbacks()): + callback = callbacks[idx][0] if callback.kwargs: kwargs = callback.kwargs else: @@ -207,4 +227,5 @@ def _set_exithandlers(exithandlers): def _clear_exithandlers(): """Clear the atexit module of all registered exit handlers.""" + atexit._clear() diff --git a/src/sage_docbuild/utils.py b/src/sage_docbuild/utils.py index 956d703f..3e4793e 100644 --- a/src/sage_docbuild/utils.py +++ b/src/sage_docbuild/utils.py @@ -79,7 +79,7 @@ def build_many(target, args, processes=None): ....: # Task 4 is a poison pill ....: 1 / 0 ....: else: - ....: time.sleep(0.5) + ....: time.sleep(float(0.5)) ....: print('Processed task %s' % N) ....: @@ -104,7 +104,7 @@ def build_many(target, args, processes=None): ....: # Task 4 is a poison pill ....: os.kill(os.getpid(), signal.SIGKILL) ....: else: - ....: time.sleep(0.5) + ....: time.sleep(float(0.5)) ....: print('Processed task %s' % N) ....: sage: build_many(target, range(8), processes=8) diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index 5c866c8..d2012aa 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -26,7 +26,7 @@ classifiers = Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.7, <3.10 +python_requires = >=3.7, <3.11 install_requires = sage_conf esyscmd(`sage-get-system-packages install-requires \