Skip to content

Commit

Permalink
Trac #30766: Experimental support for Python 3.10 in Sage 9.5
Browse files Browse the repository at this point in the history
This is to support Python 3.10, which was released on 2021-10-04.
https://docs.python.org/3.10/whatsnew/changelog.html#changelog

Thanks to the following tickets, Sage is mostly ready for
Python 3.10 in addition to 3.9, 3.8, 3.7.

 - needs Cython 0.29.23 (#31445)
 - #31855 Patch/upgrade `gmpy2` to add python 3.10 support
 - #31856 Upgrade `pyzmq`, `babel` - to fix `error: implicit declaration
of function 'PyObject_AsWriteBuffer' is invalid in C99` with
pyzmq-19.0.2
 - #32815 `numpy`
 - #32837 `cffi`: Update to 1.15.0
 - #32852 Update `traitlets` to 5.1.1 (for python 3.9.8, 3.10)
 - #32671 Update `pip` to 21.3.1, `distlib` to 0.3.3
 - #31295 Meta-ticket: Replace imports from deprecated `distutils`
 - #32930 IPython/Jupyter upgrade for python 3.10 support
 - #33013 Fix tests with Python 3.10

In this ticket, we enable use of system Python 3.10 but issue a warning
regarding its experimental status for Sage.

The ticket does not include the upgrade of the `python3` SPKG to Python
3.10.  Many systems already ship Python 3.10.  To test, thanks to https:
//wiki.sagemath.org/ReleaseTours/sage-9.5#Separate_virtual_environment_f
or_Python_packages, a full rebuild of the Sage distribution is not
necessary - only the Python packages will be  built from scratch in a
separate venv.

Related:

- [https://www.python.org/dev/peps/pep-0619/ PEP 619 -- Python 3.10
Release Schedule]
- [https://docs.python.org/3.10/whatsnew/3.10.html What's new in Python
3.10]
- #30767: Upgrade to Python 3.10
- #30184: Support Python 3.9
- #30384: Adopt the “time window-based” policy for support of Python
versions from NEP 29

URL: https://trac.sagemath.org/30766
Reported by: slelievre
Ticket author(s): Matthias Koeppe, Gonzalo Tornaría
Reviewer(s): Antonio Rojas, Matthias Koeppe
  • Loading branch information
Release Manager committed Dec 28, 2021
2 parents a34b980 + df9f1d4 commit 935315f
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 32 deletions.
7 changes: 6 additions & 1 deletion build/pkgs/python3/spkg-configure.m4
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
SAGE_SPKG_CONFIGURE([python3], [
m4_pushdef([MIN_VERSION], [3.7.0])
m4_pushdef([MIN_NONDEPRECATED_VERSION], [3.7.0])
m4_pushdef([LT_VERSION], [3.10.0])
m4_pushdef([LT_STABLE_VERSION], [3.10.0])
m4_pushdef([LT_VERSION], [3.11.0])
AC_ARG_WITH([python],
[AS_HELP_STRING([--with-python=PYTHON3],
[Python 3 executable to use for the Sage venv; default: python3])])
Expand Down Expand Up @@ -114,6 +115,10 @@ SAGE_SPKG_CONFIGURE([python3], [
AC_MSG_NOTICE([deprecation notice: Support for system python < MIN_NONDEPRECATED_VERSION is deprecated
and will be removed in the next development cycle. Consider using a newer version of Python
that may be available on your system or can be installed using the system package manager.
To build Sage with a different system python, use ./configure --with-python=/path/to/python])
])
AX_COMPARE_VERSION([$python3_version], [ge], LT_STABLE_VERSION, [
AC_MSG_WARN([Support for system python >= LT_STABLE_VERSION is experimental.
To build Sage with a different system python, use ./configure --with-python=/path/to/python])
])
])
Expand Down
2 changes: 1 addition & 1 deletion pkgs/sage-setup/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ packages =
sage_setup.autogen.interpreters.specs
sage_setup.command

python_requires = >=3.7, <3.10
python_requires = >=3.7, <3.11

install_requires =
pkgconfig
75 changes: 48 additions & 27 deletions src/sage/cpython/atexit.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <atexitmodule_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 = <object>callback.kwargs
else:
Expand All @@ -207,4 +227,5 @@ def _set_exithandlers(exithandlers):

def _clear_exithandlers():
"""Clear the atexit module of all registered exit handlers."""

atexit._clear()
4 changes: 2 additions & 2 deletions src/sage_docbuild/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
....:
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/setup.cfg.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down

0 comments on commit 935315f

Please sign in to comment.