Skip to content

Commit 9144356

Browse files
author
Release Manager
committed
gh-36407: Support python 3.12 This PR adds support for running with python 3.12 from system. This has been tested on the python 3.12 branch of void linux (x86_64, x86_64-musl and i686). The first two commits correspond to #36403. The rest is split is small pieces and I tried to add reasonable explanations in the commit messages. Reviewing by commit may be easier (ignoring the first two, already reviewed). See also: #36181 ### ⌛ Dependencies #36403 URL: #36407 Reported by: Gonzalo Tornaría Reviewer(s): Matthias Köppe
2 parents 77df29e + 1cf3634 commit 9144356

File tree

19 files changed

+176
-46
lines changed

19 files changed

+176
-46
lines changed

build/sage_bootstrap/package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def _init_checksum(self):
326326
# Name of the directory containing the checksums.ini file
327327
self.__tarball_package_name = os.path.realpath(checksums_ini).split(os.sep)[-2]
328328

329-
VERSION_PATCHLEVEL = re.compile('(?P<version>.*)\.p(?P<patchlevel>[0-9]+)')
329+
VERSION_PATCHLEVEL = re.compile(r'(?P<version>.*)\.p(?P<patchlevel>[0-9]+)')
330330

331331
def _init_version(self):
332332
try:

src/sage/all__sagemath_repl.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,23 @@
7979
message=r"Use setlocale\(\), getencoding\(\) and getlocale\(\) instead",
8080
module='docutils.io')
8181

82+
# triggered by dateutil 2.8.2 and sphinx 7.0.1 on Python 3.12
83+
# see: https://github.com/dateutil/dateutil/pull/1285
84+
# see: https://github.com/sphinx-doc/sphinx/pull/11468
85+
warnings.filterwarnings('ignore', category=DeprecationWarning,
86+
message=r"datetime.datetime.utcfromtimestamp\(\) is deprecated",
87+
module='dateutil.tz.tz|sphinx.(builders.gettext|util.i18n)')
88+
89+
# triggered on Python 3.12
90+
warnings.filterwarnings('ignore', category=DeprecationWarning,
91+
message=r"This process.* is multi-threaded, "
92+
r"use of .*\(\) may lead to deadlocks in the child.")
93+
94+
# pickling of itertools is deprecated in Python 3.12
95+
warnings.filterwarnings('ignore', category=DeprecationWarning,
96+
message=r"Pickle, copy, and deepcopy support will be "
97+
r"removed from itertools in Python 3.14.")
98+
8299

83100
from .all__sagemath_objects import *
84101
from .all__sagemath_environment import *

src/sage/arith/long.pxd

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ from libc.limits cimport LONG_MIN, LONG_MAX
1919
from cpython.object cimport Py_SIZE
2020
from cpython.number cimport PyNumber_Index, PyIndex_Check
2121
from cpython.longintrepr cimport py_long, PyLong_SHIFT, digit
22+
from sage.cpython.pycore_long cimport (
23+
ob_digit, _PyLong_IsNegative, _PyLong_DigitCount)
2224

2325
from sage.libs.gmp.mpz cimport mpz_fits_slong_p, mpz_get_si
2426
from sage.rings.integer_fake cimport is_Integer, Integer_AS_MPZ
@@ -299,8 +301,11 @@ cdef inline bint integer_check_long_py(x, long* value, int* err):
299301
return 0
300302

301303
# x is a Python "int" (aka PyLongObject or py_long in cython)
302-
cdef const digit* D = (<py_long>x).ob_digit
303-
cdef Py_ssize_t size = Py_SIZE(x)
304+
cdef const digit* D = ob_digit(x)
305+
cdef Py_ssize_t size = _PyLong_DigitCount(x)
306+
307+
if _PyLong_IsNegative(x):
308+
size = -size
304309

305310
# We assume PyLong_SHIFT <= BITS_IN_LONG <= 3 * PyLong_SHIFT.
306311
# This is true in all the default configurations:

src/sage/cpython/atexit.pyx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ cdef extern from *:
154154
#undef _PyGC_FINALIZED
155155
#include "internal/pycore_interp.h"
156156
#include "internal/pycore_pystate.h"
157+
#if PY_VERSION_HEX >= 0x030c0000
158+
// struct atexit_callback was renamed in 3.12 to atexit_py_callback
159+
#define atexit_callback atexit_py_callback
160+
#endif
157161
static atexit_callback ** _atexit_callbacks(PyObject *self) {
158162
PyInterpreterState *interp = _PyInterpreterState_GET();
159163
struct atexit_state state = interp->atexit;

src/sage/cpython/debug.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def getattr_debug(obj, name, default=_no_default):
7878
7979
EXAMPLES::
8080
81-
sage: _ = getattr_debug(list, "reverse")
81+
sage: _ = getattr_debug(list, "reverse") # not tested - broken in python 3.12
8282
getattr_debug(obj=<class 'list'>, name='reverse'):
8383
type(obj) = <class 'type'>
8484
object has __dict__ slot (<class 'dict'>)

src/sage/cpython/dict_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
169169
#else /* Python >= 3.11 */
170170

171171
#define Py_BUILD_CORE
172+
#undef _PyGC_FINALIZED
172173
#include <internal/pycore_dict.h>
173174

174175
/************************************************************/

src/sage/cpython/pycore_long.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "Python.h"
2+
#include <stdbool.h>
3+
4+
#if PY_VERSION_HEX >= 0x030C00A5
5+
#define ob_digit(o) (((PyLongObject*)o)->long_value.ob_digit)
6+
#else
7+
#define ob_digit(o) (((PyLongObject*)o)->ob_digit)
8+
#endif
9+
10+
#if PY_VERSION_HEX >= 0x030C00A7
11+
// taken from cpython:Include/internal/pycore_long.h @ 3.12
12+
13+
/* Long value tag bits:
14+
* 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1.
15+
* 2: Reserved for immortality bit
16+
* 3+ Unsigned digit count
17+
*/
18+
#define SIGN_MASK 3
19+
#define SIGN_ZERO 1
20+
#define SIGN_NEGATIVE 2
21+
#define NON_SIZE_BITS 3
22+
23+
static inline bool
24+
_PyLong_IsZero(const PyLongObject *op)
25+
{
26+
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO;
27+
}
28+
29+
static inline bool
30+
_PyLong_IsNegative(const PyLongObject *op)
31+
{
32+
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE;
33+
}
34+
35+
static inline bool
36+
_PyLong_IsPositive(const PyLongObject *op)
37+
{
38+
return (op->long_value.lv_tag & SIGN_MASK) == 0;
39+
}
40+
41+
static inline Py_ssize_t
42+
_PyLong_DigitCount(const PyLongObject *op)
43+
{
44+
assert(PyLong_Check(op));
45+
return op->long_value.lv_tag >> NON_SIZE_BITS;
46+
}
47+
48+
#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS))
49+
50+
static inline void
51+
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
52+
{
53+
assert(size >= 0);
54+
assert(-1 <= sign && sign <= 1);
55+
assert(sign != 0 || size == 0);
56+
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size);
57+
}
58+
59+
#else
60+
// fallback for < 3.12
61+
62+
static inline bool
63+
_PyLong_IsZero(const PyLongObject *op)
64+
{
65+
return Py_SIZE(op) == 0;
66+
}
67+
68+
static inline bool
69+
_PyLong_IsNegative(const PyLongObject *op)
70+
{
71+
return Py_SIZE(op) < 0;
72+
}
73+
74+
static inline bool
75+
_PyLong_IsPositive(const PyLongObject *op)
76+
{
77+
return Py_SIZE(op) > 0;
78+
}
79+
80+
static inline Py_ssize_t
81+
_PyLong_DigitCount(const PyLongObject *op)
82+
{
83+
Py_ssize_t size = Py_SIZE(op);
84+
return size < 0 ? -size : size;
85+
}
86+
87+
static inline void
88+
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
89+
{
90+
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION < 9)
91+
// The function Py_SET_SIZE is defined starting with python 3.9.
92+
Py_SIZE(o) = size;
93+
#else
94+
Py_SET_SIZE(op, sign < 0 ? -size : size);
95+
#endif
96+
}
97+
98+
#endif

src/sage/cpython/pycore_long.pxd

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from cpython.longintrepr cimport py_long, digit
2+
3+
cdef extern from "pycore_long.h":
4+
digit* ob_digit(py_long o)
5+
bint _PyLong_IsZero(py_long o)
6+
bint _PyLong_IsNegative(py_long o)
7+
bint _PyLong_IsPositive(py_long o)
8+
Py_ssize_t _PyLong_DigitCount(py_long o)
9+
void _PyLong_SetSignAndDigitCount(py_long o, int sign, Py_ssize_t size)

src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1945,7 +1945,8 @@ cdef inline int next_face_loop(iter_t structure) nogil except -1:
19451945
# The function is not supposed to be called,
19461946
# just prevent it from crashing.
19471947
# Actually raising an error here results in a bad branch prediction.
1948-
return -1
1948+
# But return -1 results in a crash with python 3.12
1949+
raise StopIteration
19491950

19501951
# Getting ``[faces, n_faces, n_visited_all]`` according to dimension.
19511952
cdef face_list_t* faces = &structure.new_faces[structure.current_dimension]

src/sage/lfunctions/dokchitser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,8 @@ def init_coeffs(self, v, cutoff=1,
418418
sage: L(14)
419419
0.998583063162746
420420
sage: a = delta_qexp(1000)
421-
sage: sum(a[n]/float(n)^14 for n in range(1,1000))
422-
0.9985830631627459
421+
sage: sum(a[n]/float(n)^14 for n in reversed(range(1,1000)))
422+
0.9985830631627461
423423
424424
Illustrate that one can give a list of complex numbers for v
425425
(see :trac:`10937`)::

0 commit comments

Comments
 (0)