Add patch for python 3.11 compatibility (bz 2099168)

- Add workaround for symlink/directory conflict (bz 2097773)
- Modify the jmol patch to timeout after 5 minutes.  This is a
  workaround for recently observed jmol hangs, but is not a proper fix.
This commit is contained in:
Jerry James 2022-07-06 11:11:16 -06:00
parent 78d0fd60e9
commit 457c650d21
3 changed files with 472 additions and 12 deletions

View file

@ -1,6 +1,6 @@
diff -up src/sage/interfaces/jmoldata.py.orig src/sage/interfaces/jmoldata.py
--- src/sage/interfaces/jmoldata.py.orig 2021-05-09 16:00:11.000000000 -0600
+++ src/sage/interfaces/jmoldata.py 2021-05-28 11:36:18.844565672 -0600
--- src/sage/interfaces/jmoldata.py.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/interfaces/jmoldata.py 2022-07-06 11:03:43.155375965 -0600
@@ -148,8 +148,6 @@ class JmolData(SageObject):
sage: print(os.path.exists(testfile)) # optional -- java
True
@ -10,16 +10,24 @@ diff -up src/sage/interfaces/jmoldata.py.orig src/sage/interfaces/jmoldata.py
target_native = targetfile
if sys.platform == 'cygwin':
@@ -173,10 +171,8 @@ class JmolData(SageObject):
@@ -171,12 +169,14 @@ class JmolData(SageObject):
with open(scratchout, 'w') as jout:
# Now call the java application and write the file.
env = dict(os.environ)
env['LC_ALL'] = 'C'
env['LANG'] = 'C'
- env['LC_ALL'] = 'C'
- env['LANG'] = 'C'
- subprocess.call(["java", "-Xmx512m", "-Djava.awt.headless=true",
- "-jar", jmolpath, "-iox", "-g", size_arg,
- "-J", launchscript, "-j", imagescript],
- stdout=jout, stderr=jout, env=env)
+ subprocess.call(["jmol", "-n", "-g", size_arg,
+ "-J", launchscript, "-j", imagescript], stdout=jout)
+ env['LC_ALL'] = 'C.UTF-8'
+ env['LANG'] = 'C.UTF-8'
+ try:
+ subprocess.call(["jmol", "-n", "-g", size_arg,
+ "-J", launchscript, "-j", imagescript],
+ timeout=300, stdout=jout, stderr=jout, env=env)
+ except:
+ pass
if not os.path.isfile(targetfile):
raise RuntimeError(f"Jmol failed to create file {targetfile}: {Path(scratchout).read_text()}")
os.unlink(scratchout)

427
sagemath-python3.11.patch Normal file
View file

@ -0,0 +1,427 @@
diff -up src/sage/cpython/cython_metaclass.h.orig src/sage/cpython/cython_metaclass.h
--- src/sage/cpython/cython_metaclass.h.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/cpython/cython_metaclass.h 2022-06-29 11:07:37.296150769 -0600
@@ -66,7 +66,7 @@ static CYTHON_INLINE int Sage_PyType_Rea
}
/* Now, set t.__class__ to metaclass */
- Py_TYPE(t) = metaclass;
+ Py_SET_TYPE(t, metaclass);
PyType_Modified(t);
}
else
diff -up src/sage/cpython/dict_del_by_value.pyx.orig src/sage/cpython/dict_del_by_value.pyx
--- src/sage/cpython/dict_del_by_value.pyx.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/cpython/dict_del_by_value.pyx 2022-06-30 12:06:01.148346330 -0600
@@ -25,7 +25,7 @@ from weakref import KeyedRef
from cpython.list cimport PyList_New
from cpython cimport Py_XINCREF, Py_XDECREF
-from libc.stdint cimport int8_t, int16_t, int32_t, int64_t
+from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, uint8_t, uint32_t
cdef extern from "Python.h":
ctypedef struct PyDictKeysObject
@@ -45,8 +45,6 @@ cdef extern from "Python.h":
#(this file is not exported from CPython, so we need to be
#careful the definitions are in step with what happens there.
-ctypedef void* dict_lookup_func # Precise definition not needed
-
ctypedef union IndexBlock:
int8_t as_1[8]
int16_t as_2[4]
@@ -55,8 +53,10 @@ ctypedef union IndexBlock:
ctypedef struct MyPyDictKeysObject:
Py_ssize_t dk_refcnt
- Py_ssize_t dk_size
- dict_lookup_func dk_lookup
+ uint8_t dk_log2_size
+ uint8_t dk_log2_index_bytes
+ uint8_t dk_kind
+ uint32_t dk_version
Py_ssize_t dk_usable
Py_ssize_t dk_nentries
IndexBlock dk_indices
@@ -66,46 +66,65 @@ ctypedef struct PyDictKeyEntry:
PyObject * me_key
PyObject * me_value
+ctypedef struct PyDictUnicodeEntry:
+ PyObject * me_key
+ PyObject * me_value
+
cdef Py_ssize_t DKIX_EMPTY = -1
cdef Py_ssize_t DKIX_DUMMY = -2
cdef Py_ssize_t DKIX_ERROR = -3
+cdef Py_ssize_t DKIX_KEY_CHANGED = -4
+
+ctypedef enum DictKeysKind:
+ DICT_KEYS_GENERAL = 0,
+ DICT_KEYS_UNICODE = 1,
+ DICT_KEYS_SPLIT = 2
#####
#These routines are copied from CPython's Object/dictobject.c
#in order to access PyDictKeysObject fields
+cdef inline Py_ssize_t DK_SIZE(MyPyDictKeysObject *keys):
+ return 1L << keys.dk_log2_size
+
cdef inline int DK_IXSIZE(MyPyDictKeysObject *keys):
- cdef Py_ssize_t s = keys.dk_size
- if s <= 0xff:
+ cdef uint8_t s = keys.dk_log2_size
+ if s <= 7:
return 1
- elif s <= 0xffff:
+ if s <= 15:
return 2
- elif s <= 0xffffffff:
+ if sizeof(void *) <= 4 or s <= 31:
return 4
else:
return 8
cdef inline PyDictKeyEntry * DK_ENTRIES(MyPyDictKeysObject *keys):
- return <PyDictKeyEntry*> &(keys.dk_indices.as_1[keys.dk_size * DK_IXSIZE(keys)])
+ return <PyDictKeyEntry*> &(keys.dk_indices.as_1[1UL << keys.dk_log2_index_bytes])
+
+cdef inline PyDictUnicodeEntry * DK_UNICODE_ENTRIES(MyPyDictKeysObject *keys):
+ return <PyDictUnicodeEntry*> &(keys.dk_indices.as_1[1UL << keys.dk_log2_index_bytes])
+
+cdef inline bint DK_IS_UNICODE(MyPyDictKeysObject *keys):
+ return keys.dk_kind != DICT_KEYS_GENERAL
cdef inline Py_ssize_t dk_get_index(MyPyDictKeysObject *keys, Py_ssize_t i):
- cdef Py_ssize_t s = keys.dk_size
- if s <= 0xff:
+ cdef uint8_t s = keys.dk_log2_size
+ if s < 8:
return keys.dk_indices.as_1[i]
- elif s <= 0xffff:
+ elif s < 16:
return keys.dk_indices.as_2[i]
- elif s <= 0xffffffff:
+ elif sizeof(void *) <= 4 or s < 32:
return keys.dk_indices.as_4[i]
else:
return keys.dk_indices.as_8[i]
cdef inline void dk_set_index(MyPyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix):
- cdef Py_ssize_t s = keys.dk_size
- if s <= 0xff:
+ cdef uint8_t s = keys.dk_log2_size
+ if s < 8:
keys.dk_indices.as_1[i] = ix
- elif s <= 0xffff:
+ elif s < 16:
keys.dk_indices.as_2[i] = ix
- elif s <= 0xffffffff:
+ elif sizeof(void *) <= 4 or s < 32:
keys.dk_indices.as_4[i] = ix
else:
keys.dk_indices.as_8[i] = ix
@@ -113,22 +132,7 @@ cdef inline void dk_set_index(MyPyDictKe
#End of replication of Object/dictobject.c
######
-cdef dict_lookup_func lookdict
-
-cdef dict_lookup_func DK_LOOKUP(PyDictObject *mp):
- return (<MyPyDictKeysObject *>(mp.ma_keys)).dk_lookup
-
-def init_lookdict():
- global lookdict
- # A dict which a non-string key uses the generic "lookdict"
- # as lookup function
- cdef object D = {}
- D[0] = 0
- lookdict = DK_LOOKUP(<PyDictObject *>D)
-
-init_lookdict()
-
-cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_t hash) except -1:
+cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_t hashval) except -1:
"""
This is used in callbacks for the weak values of :class:`WeakValueDictionary`.
@@ -179,47 +183,72 @@ cdef int del_dictitem_by_exact_value(PyD
"""
keys = <MyPyDictKeysObject *>(mp.ma_keys)
cdef size_t perturb
- cdef size_t mask = <size_t> keys.dk_size-1
- cdef PyDictKeyEntry *entries = DK_ENTRIES(keys)
+ cdef size_t mask = <size_t> DK_SIZE(keys)-1
+ cdef PyDictUnicodeEntry *uc_entries
+ cdef PyDictUnicodeEntry *uc_ep
+ cdef PyDictKeyEntry *entries
cdef PyDictKeyEntry *ep
-
+
if mp.ma_values is not NULL:
raise TypeError("del_dictitem_by_exact_value cannot be applied to a shared key dict")
- cdef size_t i = <size_t>hash & mask
+ cdef size_t i = <size_t>hashval & mask
ix = dk_get_index(keys, i)
if ix == DKIX_EMPTY:
# key not found
return 0
- ep = &(entries[ix])
- perturb = hash
- while (ep.me_value != value or ep.me_hash != hash):
- perturb = perturb >> 5 #this is the value of PERTURB_SHIFT
- i = mask & (i * 5 + perturb + 1)
- ix = dk_get_index(keys, i)
- if ix == DKIX_EMPTY:
- # key not found
- return 0
- ep = &(entries[ix])
+ if DK_IS_UNICODE(keys):
+ uc_entries = DK_UNICODE_ENTRIES(keys)
+ uc_ep = &(uc_entries[ix])
+ perturb = hashval
+ while (uc_ep.me_value != value or hash(<object>uc_ep.me_key) != hashval):
+ perturb = perturb >> 5 #this is the value of PERTURB_SHIFT
+ i = mask & (i * 5 + perturb + 1)
+ ix = dk_get_index(keys, i)
+ if ix == DKIX_EMPTY:
+ # key not found
+ return 0
+ uc_ep = &(uc_entries[ix])
- # We need the lookup function to be the generic lookdict, otherwise
- # deletions may not work correctly
- keys.dk_lookup = lookdict
+ T = PyList_New(2)
+ PyList_SetItem(T, 0, uc_ep.me_key)
+ PyList_SetItem(T, 1, uc_ep.me_value)
+ uc_ep.me_key = NULL
+ uc_ep.me_value = NULL
+ mp.ma_used -= 1
+ dk_set_index(keys, i, DKIX_DUMMY)
+ #We have transferred the to-be-deleted references to the list T
+ #we now delete the list so that the actual decref happens through a
+ #deallocation routine that uses the Python Trashcan macros to
+ #avoid stack overflow in deleting deep structures.
+ del T
+ else:
+ entries = DK_ENTRIES(keys)
+ ep = &(entries[ix])
+ perturb = hashval
+ while (ep.me_value != value or ep.me_hash != hashval):
+ perturb = perturb >> 5 #this is the value of PERTURB_SHIFT
+ i = mask & (i * 5 + perturb + 1)
+ ix = dk_get_index(keys, i)
+ if ix == DKIX_EMPTY:
+ # key not found
+ return 0
+ ep = &(entries[ix])
- T = PyList_New(2)
- PyList_SetItem(T, 0, ep.me_key)
- PyList_SetItem(T, 1, ep.me_value)
- ep.me_key = NULL
- ep.me_value = NULL
- mp.ma_used -= 1
- dk_set_index(keys, i, DKIX_DUMMY)
- #We have transferred the to-be-deleted references to the list T
- #we now delete the list so that the actual decref happens through a
- #deallocation routine that uses the Python Trashcan macros to
- #avoid stack overflow in deleting deep structures.
- del T
+ T = PyList_New(2)
+ PyList_SetItem(T, 0, ep.me_key)
+ PyList_SetItem(T, 1, ep.me_value)
+ ep.me_key = NULL
+ ep.me_value = NULL
+ mp.ma_used -= 1
+ dk_set_index(keys, i, DKIX_DUMMY)
+ #We have transferred the to-be-deleted references to the list T
+ #we now delete the list so that the actual decref happens through a
+ #deallocation routine that uses the Python Trashcan macros to
+ #avoid stack overflow in deleting deep structures.
+ del T
def test_del_dictitem_by_exact_value(D, value, h):
"""
diff -up src/sage/libs/gmp/pylong.pyx.orig src/sage/libs/gmp/pylong.pyx
--- src/sage/libs/gmp/pylong.pyx.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/libs/gmp/pylong.pyx 2022-06-29 12:44:27.983218616 -0600
@@ -33,6 +33,7 @@ from .mpz cimport *
cdef extern from *:
Py_ssize_t* Py_SIZE_PTR "&Py_SIZE"(object)
+ void __Pyx_SET_SIZE(object, Py_ssize_t)
int hash_bits """
#ifdef _PyHASH_BITS
_PyHASH_BITS /* Python 3 */
@@ -57,10 +58,8 @@ cdef mpz_get_pylong_large(mpz_srcptr z):
mpz_export(L.ob_digit, NULL,
-1, sizeof(digit), 0, PyLong_nails, z)
if mpz_sgn(z) < 0:
- # Set correct size (use a pointer to hack around Cython's
- # non-support for lvalues).
- sizeptr = Py_SIZE_PTR(L)
- sizeptr[0] = -pylong_size
+ # Set correct size
+ __Pyx_SET_SIZE(L, -pylong_size)
return L
diff -up src/sage/misc/decorators.py.orig src/sage/misc/decorators.py
--- src/sage/misc/decorators.py.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/misc/decorators.py 2022-06-29 14:02:56.995436952 -0600
@@ -31,8 +31,7 @@ from functools import (partial, update_w
from copy import copy
from sage.misc.sageinspect import (sage_getsource, sage_getsourcelines,
- sage_getargspec)
-from inspect import ArgSpec
+ sage_getargspec, ArgSpec)
def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES):
diff -up src/sage/misc/sageinspect.py.orig src/sage/misc/sageinspect.py
--- src/sage/misc/sageinspect.py.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/misc/sageinspect.py 2022-06-29 14:07:56.804147321 -0600
@@ -119,6 +119,7 @@ import functools
import os
import tokenize
import re
+from collections import namedtuple
from sage.env import SAGE_LIB
try:
@@ -126,6 +127,8 @@ try:
except ImportError:
pass
+ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
+
def is_function_or_cython_function(obj):
"""
@@ -348,7 +351,7 @@ def _extract_embedded_signature(docstrin
docstring = L[1] if len(L) > 1 else '' # Remove first line, keep the rest
def_string = "def " + name + signature + ": pass"
try:
- return docstring, inspect.ArgSpec(*_sage_getargspec_cython(def_string))
+ return docstring, ArgSpec(*_sage_getargspec_cython(def_string))
except SyntaxError:
docstring = os.linesep.join(L)
return docstring, None
@@ -1092,7 +1095,7 @@ def _sage_getargspec_from_ast(source):
OUTPUT:
- - an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple
+ - an instance of :obj:`ArgSpec`, i.e., a named tuple
EXAMPLES::
@@ -1124,8 +1127,7 @@ def _sage_getargspec_from_ast(source):
vararg = getattr(ast_args.vararg, 'arg', None)
kwarg = getattr(ast_args.kwarg, 'arg', None)
- return inspect.ArgSpec(args, vararg, kwarg,
- tuple(defaults) if defaults else None)
+ return ArgSpec(args, vararg, kwarg, tuple(defaults) if defaults else None)
def _sage_getargspec_cython(source):
@@ -1141,7 +1143,7 @@ def _sage_getargspec_cython(source):
OUTPUT:
- - an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple
+ - an instance of :obj:`ArgSpec`, i.e., a named tuple
EXAMPLES::
@@ -1605,11 +1607,11 @@ def sage_getargspec(obj):
return sage_getargspec(obj.__call__)
if isinstance(obj, (lazy_attribute, AbstractMethod)):
source = sage_getsource(obj)
- return inspect.ArgSpec(*_sage_getargspec_cython(source))
+ return ArgSpec(*_sage_getargspec_cython(source))
if not callable(obj):
raise TypeError("obj is not a code object")
try:
- return inspect.ArgSpec(*obj._sage_argspec_())
+ return ArgSpec(*obj._sage_argspec_())
except (AttributeError, TypeError):
pass
# If we are lucky, the function signature is embedded in the docstring.
@@ -1625,7 +1627,7 @@ def sage_getargspec(obj):
# Note that this may give a wrong result for the constants!
try:
args, varargs, varkw = inspect.getargs(obj.__code__)
- return inspect.ArgSpec(args, varargs, varkw, obj.__defaults__)
+ return ArgSpec(args, varargs, varkw, obj.__defaults__)
except (TypeError, AttributeError):
pass
if isclassinstance(obj):
@@ -1660,7 +1662,7 @@ def sage_getargspec(obj):
except TypeError: # happens for Python builtins
source = ''
if source:
- return inspect.ArgSpec(*_sage_getargspec_cython(source))
+ return ArgSpec(*_sage_getargspec_cython(source))
else:
func_obj = obj
@@ -1673,7 +1675,7 @@ def sage_getargspec(obj):
except TypeError: # arg is not a code object
# The above "hopefully" was wishful thinking:
try:
- return inspect.ArgSpec(*_sage_getargspec_cython(sage_getsource(obj)))
+ return ArgSpec(*_sage_getargspec_cython(sage_getsource(obj)))
except TypeError: # This happens for Python builtins
# The best we can do is to return a generic argspec
args = []
@@ -1683,7 +1685,7 @@ def sage_getargspec(obj):
defaults = func_obj.__defaults__
except AttributeError:
defaults = None
- return inspect.ArgSpec(args, varargs, varkw, defaults)
+ return ArgSpec(args, varargs, varkw, defaults)
def formatannotation(annotation, base_module=None):
@@ -1754,19 +1756,7 @@ def sage_formatargspec(args, varargs=Non
:func:`sage_getargspec`. Since :func:`sage_getargspec` works for
Cython functions while Python's inspect module does not, it makes
sense to keep this function for formatting instances of
- ``inspect.ArgSpec``.
-
- EXAMPLES::
-
- sage: from sage.misc.sageinspect import sage_formatargspec
- sage: from inspect import formatargspec # deprecated in Python 3
- sage: args = ['a', 'b', 'c']
- sage: defaults = [3]
- sage: sage_formatargspec(args, defaults=defaults)
- '(a, b, c=3)'
- sage: import warnings; warnings.simplefilter('ignore') # ignore DeprecationWarning
- sage: formatargspec(args, defaults=defaults) == sage_formatargspec(args, defaults=defaults)
- True
+ ``ArgSpec``.
"""
def formatargandannotation(arg):
result = formatarg(arg)
diff -up src/sage/symbolic/ginac/numeric.cpp.orig src/sage/symbolic/ginac/numeric.cpp
--- src/sage/symbolic/ginac/numeric.cpp.orig 2022-05-15 16:11:11.000000000 -0600
+++ src/sage/symbolic/ginac/numeric.cpp 2022-06-24 14:58:32.506790725 -0600
@@ -52,7 +52,6 @@
#define register
#define PY_SSIZE_T_CLEAN
#include <Python.h>
-#include <longintrepr.h>
#include "flint/fmpz.h"
#include "flint/fmpz_factor.h"

View file

@ -84,7 +84,7 @@
Name: sagemath
Summary: A free open-source mathematics software system
Version: 9.6
Release: 2%{?dist}
Release: 3%{?dist}
# The file ${SAGE_ROOT}/COPYING.txt is the upstream license breakdown file
# Additionally, every $files section has a comment with the license name
# before files with that license
@ -178,6 +178,9 @@ Patch21: %{name}-infinite-recursion.patch
# Fix a use-after-free bug
Patch22: %{name}-use-after-free.patch
# Adapt to changes in python 3.11
Patch23: %{name}-python3.11.patch
BuildRequires: 4ti2
BuildRequires: 4ti2-devel
BuildRequires: appstream
@ -981,6 +984,7 @@ popd
%patch20
%patch21
%patch22
%patch23
sed -i 's|@@SAGE_LOCAL@@|%{SAGE_LOCAL}|' src/sage/env.py
@ -1030,6 +1034,9 @@ sed -i 's/3\.11\.0/3.12.0/g' configure
# Allow use of libfplll 5.4.2
sed -i 's/5\.4\.1/5.4.2/g' configure
# Allow use of eclib 20220621
sed -i 's/20210625/20220621/g' configure
# Do not build with -march=native
sed -i 's/CFLAGS_MARCH="-march=native"/CFLAGS_MARCH=""/' configure
@ -1037,7 +1044,6 @@ sed -i 's/CFLAGS_MARCH="-march=native"/CFLAGS_MARCH=""/' configure
########################################################################
%build
export LC_ALL=C.UTF-8
export CC=%{__cc}
export CPPFLAGS="-I%{_includedir}/4ti2 -I%{_includedir}/arb -I%{_includedir}/cddlib"
export ECMBIN=%{_bindir}/gmp-ecm
export SAGE_ROOT=%{buildroot}%{SAGE_ROOT}
@ -1678,10 +1684,9 @@ mkdir -p %{SAGE_LOCAL}/var/lib/sage/installed/database_cremona_ellcurve-%{cremon
rm -fr %{SAGE_LOCAL}/var/lib/sage/installed/database_cremona_ellcurve-%{cremona_ver}
%if %{with docs}
########################################################################
# Fix directory/symlink conflicts introduced by fix for bz 1875606.
# This can be removed when Fedora 36 reaches EOL.
%pretrans -n sagemath-doc-en -p <lua>
-- Fix directory/symlink conflicts introduced by fix for bz 1875606.
-- This can be removed when Fedora 36 reaches EOL.
paths = {
"%{SAGE_DOC}/html/en/_static/config",
"%{SAGE_DOC}/html/en/_static/extensions",
@ -1765,6 +1770,20 @@ for _, path in ipairs(paths) do
end
end
end
-- Fix directory/symlink conflicts introduced by sagemath 3.5 -> 3.6 upgrade.
-- This can be removed when Fedora 40 reaches EOL.
paths2 = {
"%{SAGE_DOC}/html/en/reference/plot3d/_static",
"%{SAGE_DOC}/html/en/reference/repl/_static"
}
for _, path in ipairs(paths2) do
st = posix.stat(path)
if st and st.type == "link" then
os.remove(path)
end
end
%endif
@ -2021,6 +2040,12 @@ end
########################################################################
%changelog
* Tue Jul 5 2022 Jerry James <loganjerry@gmail.com> - 9.6-3
- Add patch for python 3.11 compatibility (bz 2099168)
- Add workaround for symlink/directory conflict (bz 2097773)
- Modify the jmol patch to timeout after 5 minutes. This is a workaround for
recently observed jmol hangs, but is not a proper fix.
* Tue Jun 21 2022 Python Maint <python-maint@redhat.com> - 9.6-2
- Rebuilt for Python 3.11