diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a87d351b42f..cd5bbe75bf5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -46,6 +46,7 @@ on: "centos-stream-9-python3.9", "gentoo-python3.9", "gentoo-python3.10", + "gentoo-python3.11", "archlinux-latest", "opensuse-15.3-gcc_11-python3.9", "opensuse-15.4-gcc_11-python3.10", diff --git a/build/pkgs/babel/checksums.ini b/build/pkgs/babel/checksums.ini index a98fa598a37..70beeda6613 100644 --- a/build/pkgs/babel/checksums.ini +++ b/build/pkgs/babel/checksums.ini @@ -1,5 +1,5 @@ tarball=Babel-VERSION.tar.gz -sha1=1ce15f82eba5184cabe6ac1491cb58262e27adfd -md5=7166099733d78aa857d74fa50d8ff58c -cksum=1695340328 +sha1=75baeb68d7481a67ba203191aa460c56b0221fda +md5=9ee7784fd452d456206ecd3a12694010 +cksum=227595701 upstream_url=https://pypi.io/packages/source/b/babel/Babel-VERSION.tar.gz diff --git a/build/pkgs/babel/package-version.txt b/build/pkgs/babel/package-version.txt index dedcc7d4335..46b81d815a2 100644 --- a/build/pkgs/babel/package-version.txt +++ b/build/pkgs/babel/package-version.txt @@ -1 +1 @@ -2.9.1 +2.11.0 diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index 6ca43241e34..babe4be9be1 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.29.32.p1 +0.29.32.p2 diff --git a/build/pkgs/cython/patches/trashcan.patch b/build/pkgs/cython/patches/trashcan.patch index 18e1b4a7052..e1e88ebe465 100644 --- a/build/pkgs/cython/patches/trashcan.patch +++ b/build/pkgs/cython/patches/trashcan.patch @@ -1,5 +1,7 @@ See https://github.com/cython/cython/pull/2842 +and https://github.com/cython/cython/pull/4475 + commit c47c4ef735c4b7f1863b21bbe6f112b06c4aad05 Author: Jeroen Demeyer Date: Thu Feb 14 10:02:41 2019 +0100 @@ -128,7 +130,7 @@ diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c index 50d0e21..ca2adbe 100644 --- a/Cython/Utility/ExtensionTypes.c +++ b/Cython/Utility/ExtensionTypes.c -@@ -74,6 +74,49 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) { +@@ -74,6 +74,54 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) { return r; } @@ -140,7 +142,12 @@ index 50d0e21..ca2adbe 100644 + +// This requires CPython version >= 2.7.4 +// (or >= 3.2.4 but we don't support such old Python 3 versions anyway) -+#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070400 ++#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03080000 ++// https://github.com/python/cpython/pull/11841 merged so Cython reimplementation ++// is no longer necessary ++#define __Pyx_TRASHCAN_BEGIN Py_TRASHCAN_BEGIN ++#define __Pyx_TRASHCAN_END Py_TRASHCAN_END ++#elif CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070400 +#define __Pyx_TRASHCAN_BEGIN_CONDITION(op, cond) \ + do { \ + PyThreadState *_tstate = NULL; \ diff --git a/build/pkgs/kiwisolver/checksums.ini b/build/pkgs/kiwisolver/checksums.ini index fc15fadea23..3fc15248198 100644 --- a/build/pkgs/kiwisolver/checksums.ini +++ b/build/pkgs/kiwisolver/checksums.ini @@ -1,5 +1,5 @@ tarball=kiwisolver-VERSION.tar.gz -sha1=61811685031328a8a2a77f45593d8238432ce35e -md5=98d746f558685c6b6658cefc39be14df -cksum=1915059157 +sha1=157556602639eb6cc8546463f56feaa9023e3bcd +md5=73a4e57c33ded99dbe9a5cabca5be04b +cksum=3382585353 upstream_url=https://files.pythonhosted.org/packages/source/k/kiwisolver/kiwisolver-VERSION.tar.gz diff --git a/build/pkgs/kiwisolver/package-version.txt b/build/pkgs/kiwisolver/package-version.txt index 1892b926767..428b770e3e2 100644 --- a/build/pkgs/kiwisolver/package-version.txt +++ b/build/pkgs/kiwisolver/package-version.txt @@ -1 +1 @@ -1.3.2 +1.4.3 diff --git a/build/pkgs/python3/checksums.ini b/build/pkgs/python3/checksums.ini index d76bfeb7a4f..f2727eaf401 100644 --- a/build/pkgs/python3/checksums.ini +++ b/build/pkgs/python3/checksums.ini @@ -1,5 +1,5 @@ tarball=Python-VERSION.tar.xz -sha1=49ca7a5be7f13375e863442fbd9ead893ace3238 -md5=e92356b012ed4d0e09675131d39b1bde -cksum=3450973870 +sha1=89ee31611b73dc0c32c178d15aa208734b462c5a +md5=4efe92adf28875c77d3b9b2e8d3bc44a +cksum=2916176597 upstream_url=https://www.python.org/ftp/python/VERSION/Python-VERSION.tar.xz diff --git a/build/pkgs/python3/package-version.txt b/build/pkgs/python3/package-version.txt index 36435ac696d..371cfe355dd 100644 --- a/build/pkgs/python3/package-version.txt +++ b/build/pkgs/python3/package-version.txt @@ -1 +1 @@ -3.10.8 +3.11.1 diff --git a/build/pkgs/python3/patches/cygwin-socket-tcpnodelay-21649.patch b/build/pkgs/python3/patches/cygwin-socket-tcpnodelay-21649.patch deleted file mode 100644 index 3769318fe74..00000000000 --- a/build/pkgs/python3/patches/cygwin-socket-tcpnodelay-21649.patch +++ /dev/null @@ -1,36 +0,0 @@ -From bf2b131976694d5f4fe182c4a48d2d90edf5f303 Mon Sep 17 00:00:00 2001 -From: Zackery Spytz -Date: Mon, 27 Jul 2020 19:22:14 -0600 -Subject: [PATCH] bpo-41374: Include netinet/tcp.h on Cygwin - -On Cygwin, constants like TCP_NODELAY are no longer provided by -sys/socket.h. ---- - .../next/Library/2020-07-27-19-21-05.bpo-41374.cd-kFL.rst | 2 ++ - Modules/socketmodule.h | 4 +--- - 2 files changed, 3 insertions(+), 3 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2020-07-27-19-21-05.bpo-41374.cd-kFL.rst - -diff --git a/Misc/NEWS.d/next/Library/2020-07-27-19-21-05.bpo-41374.cd-kFL.rst b/Misc/NEWS.d/next/Library/2020-07-27-19-21-05.bpo-41374.cd-kFL.rst -new file mode 100644 -index 0000000000000..a5b2e042a3fae ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2020-07-27-19-21-05.bpo-41374.cd-kFL.rst -@@ -0,0 +1,2 @@ -+Ensure that ``socket.TCP_*`` constants are exposed on Cygwin 3.1.6 and -+greater. -diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h -index ba2c9f5c31c3b..f565b8e1396ff 100644 ---- a/Modules/socketmodule.h -+++ b/Modules/socketmodule.h -@@ -8,9 +8,7 @@ - # include - # endif - # include --# if !defined(__CYGWIN__) --# include --# endif -+# include - - #else /* MS_WINDOWS */ - # include diff --git a/build/pkgs/python3/spkg-configure.m4 b/build/pkgs/python3/spkg-configure.m4 index 65cc548d8f3..19642b59dd9 100644 --- a/build/pkgs/python3/spkg-configure.m4 +++ b/build/pkgs/python3/spkg-configure.m4 @@ -1,8 +1,8 @@ SAGE_SPKG_CONFIGURE([python3], [ m4_pushdef([MIN_VERSION], [3.8.0]) m4_pushdef([MIN_NONDEPRECATED_VERSION], [3.8.0]) - m4_pushdef([LT_STABLE_VERSION], [3.11.0]) - m4_pushdef([LT_VERSION], [3.11.0]) + m4_pushdef([LT_STABLE_VERSION], [3.12.0]) + m4_pushdef([LT_VERSION], [3.12.0]) AC_ARG_WITH([python], [AS_HELP_STRING([--with-python=PYTHON3], [Python 3 executable to use for the Sage venv; default: python3])]) diff --git a/pkgs/sage-docbuild/setup.cfg b/pkgs/sage-docbuild/setup.cfg index abc71ffcd00..337548c6ff3 100644 --- a/pkgs/sage-docbuild/setup.cfg +++ b/pkgs/sage-docbuild/setup.cfg @@ -20,6 +20,7 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics diff --git a/pkgs/sage-setup/setup.cfg b/pkgs/sage-setup/setup.cfg index 05f152ef60b..5d7f440e7c6 100644 --- a/pkgs/sage-setup/setup.cfg +++ b/pkgs/sage-setup/setup.cfg @@ -20,6 +20,7 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics @@ -31,7 +32,7 @@ packages = sage_setup.autogen.interpreters.specs sage_setup.command -python_requires = >=3.8, <3.11 +python_requires = >=3.8, <3.12 install_requires = pkgconfig diff --git a/pkgs/sagemath-categories/setup.cfg.m4 b/pkgs/sagemath-categories/setup.cfg.m4 index 744022da6eb..62aca5af44f 100644 --- a/pkgs/sagemath-categories/setup.cfg.m4 +++ b/pkgs/sagemath-categories/setup.cfg.m4 @@ -21,11 +21,12 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.8, <3.11 +python_requires = >=3.8, <3.12 install_requires = esyscmd(`sage-get-system-packages install-requires \ sagemath_objects \ diff --git a/pkgs/sagemath-environment/setup.cfg.m4 b/pkgs/sagemath-environment/setup.cfg.m4 index c67043cb715..919a5b576cd 100644 --- a/pkgs/sagemath-environment/setup.cfg.m4 +++ b/pkgs/sagemath-environment/setup.cfg.m4 @@ -18,14 +18,15 @@ classifiers = Operating System :: POSIX Operating System :: MacOS :: MacOS X Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.7, <3.11 +python_requires = >=3.8, <3.12 install_requires = esyscmd(`sage-get-system-packages install-requires \ | sed "2,\$s/^/ /;"')dnl diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index cd5d4f72a9e..88246c422f2 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -21,11 +21,12 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.8, <3.11 +python_requires = >=3.8, <3.12 install_requires = esyscmd(`sage-get-system-packages install-requires \ gmpy2 \ diff --git a/pkgs/sagemath-repl/setup.cfg.m4 b/pkgs/sagemath-repl/setup.cfg.m4 index 96515e21499..2367fda7b9a 100644 --- a/pkgs/sagemath-repl/setup.cfg.m4 +++ b/pkgs/sagemath-repl/setup.cfg.m4 @@ -21,11 +21,12 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.8, <3.11 +python_requires = >=3.8, <3.12 install_requires = esyscmd(`sage-get-system-packages install-requires \ sagemath_objects \ diff --git a/src/sage/all.py b/src/sage/all.py index 646b9a0a4e0..93588df1b93 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -104,6 +104,32 @@ message='The distutils(.sysconfig module| package) is deprecated', module='Cython|distutils|numpy|sage.env|sage.features') +# triggered by cython 0.29.32 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message="'cgi' is deprecated and slated for removal in Python 3.13", + module='Cython') + +# triggered by pyparsing 2.4.7 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message="module 'sre_constants' is deprecated", + module='pyparsing') + +# importlib.resources.path and ...read_binary are deprecated in python 3.11, +# but the replacement importlib.resources.files needs python 3.9 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message=r'(path|read_binary) is deprecated\. Use files\(\) instead\.', + module='sage.repl.rich_output.output_(graphics|graphics3d|video)') + +# triggered by sphinx +warnings.filterwarnings('ignore', category=DeprecationWarning, + message="'imghdr' is deprecated and slated for removal in Python 3.13", + module='sphinx.util.images') + +# triggered by docutils 0.19 on Python 3.11 +warnings.filterwarnings('ignore', category=DeprecationWarning, + message=r"Use setlocale\(\), getencoding\(\) and getlocale\(\) instead", + module='docutils.io') + ################ end setup warnings ############################### diff --git a/src/sage/arith/long.pxd b/src/sage/arith/long.pxd index e3a9f1586e5..1c9a53387a0 100644 --- a/src/sage/arith/long.pxd +++ b/src/sage/arith/long.pxd @@ -124,7 +124,7 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: ....: if err == 0: ....: return value ....: elif err == ERR_OVERFLOW: - ....: raise OverflowError("integer_check_long: overflow") + ....: raise OverflowError(f"integer_check_long: overflow ({x})") ....: elif err == ERR_TYPE: ....: raise TypeError("integer_check_long: wrong type") ....: elif err == ERR_INDEX: @@ -136,24 +136,23 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: ....: def long_max(): ....: return smallInteger(LONG_MAX) ....: ''') - sage: types = (ZZ, QQ, int) sage: L = [1, 12345, 10^9, 2^30, long_max()//9, long_max()//3, long_max()] sage: L += [-x for x in L] + [0, long_min()] sage: for v in L: - ....: for t in (Integer, int): + ....: for t in (Integer, int, QQ): ....: assert check_long(t(v)) == v sage: check_long(2^100) Traceback (most recent call last): ... - OverflowError: integer_check_long: overflow + OverflowError: integer_check_long: overflow (...) sage: check_long(long_max() + 1) Traceback (most recent call last): ... - OverflowError: integer_check_long: overflow + OverflowError: integer_check_long: overflow (...) sage: check_long(long_min() - 1) Traceback (most recent call last): ... - OverflowError: integer_check_long: overflow + OverflowError: integer_check_long: overflow (...) sage: check_long("hello") Traceback (most recent call last): ... @@ -162,6 +161,36 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: Traceback (most recent call last): ... TypeError: integer_check_long: bad __index__ + + Repeat the overflow tests with python integers: + + sage: check_long(int(2^100)) + Traceback (most recent call last): + ... + OverflowError: integer_check_long: overflow (...) + sage: check_long(int(long_max() + 1)) + Traceback (most recent call last): + ... + OverflowError: integer_check_long: overflow (...) + sage: check_long(int(long_min() - 1)) + Traceback (most recent call last): + ... + OverflowError: integer_check_long: overflow (...) + + And again with rationals: + + sage: check_long(QQ(2^100)) + Traceback (most recent call last): + ... + OverflowError: integer_check_long: overflow (...) + sage: check_long(QQ(long_max() + 1)) + Traceback (most recent call last): + ... + OverflowError: integer_check_long: overflow (...) + sage: check_long(QQ(long_min() - 1)) + Traceback (most recent call last): + ... + OverflowError: integer_check_long: overflow (...) """ cdef int c = integer_check_long_py(x, value, err) if c: @@ -193,30 +222,93 @@ cdef inline long dig(const digit* D, int n): cdef inline bint integer_check_long_py(x, long* value, int* err): """ - Part of ``integer_check_long`` in ``long.pxd``, checking only for - Python objects of type ``int``. See that function for - documentation and tests. + Return whether ``x`` is a python object of type ``int``. + + If possible, compute the value of this integer as C long and store + it in ``*value``. + + Errors are returned as an error indicator ``*err`` (without raising + any Python exception). + + Possible errors when returning ``True``: + + - ``0``: ``x`` was successfully converted to a C long and its value + is stored in ``*value``. + + - ``ERR_OVERFLOW``: ``x`` is a python object of type ``int`` but + too large to store in a C long. + + Possible errors when returning ``False``: + + - ``ERR_TYPE``: ``x`` is not a python object of type ``int``. + + EXAMPLES: + + We create a pure Python wrapper of this function:: + + sage: cython(''' # optional - sage.misc.cython + ....: from sage.arith.long cimport * + ....: def check_long_py(x): + ....: cdef long value + ....: cdef int err + ....: cdef bint c = integer_check_long_py(x, &value, &err) + ....: if c: + ....: if err == 0: + ....: return value + ....: elif err == ERR_OVERFLOW: + ....: return f"Overflow ({x})" + ....: elif err == ERR_TYPE: + ....: return f"Bad type ({x})" + ....: return f"This should never happen ({x})" + ....: from libc.limits cimport LONG_MIN, LONG_MAX + ....: def long_min(): + ....: return LONG_MIN + ....: def long_max(): + ....: return LONG_MAX + ....: ''') + sage: L = [1, 12345, 10^9, 2^30, long_max()//9, long_max()//3, long_max()] + sage: L += [-x for x in L] + [0, long_min()] + sage: for v in L: + ....: assert check_long_py(int(v)) == v + sage: check_long_py(int(2^100)) + 'Overflow (...)' + sage: check_long_py(int(long_max() + 1)) + 'Overflow (...)' + sage: check_long_py(int(long_min() - 1)) + 'Overflow (...)' + sage: check_long_py(389) + 'Bad type (...)' + sage: check_long_py("hello") + 'Bad type (...)' + sage: check_long_py(2/3) + 'Bad type (...)' """ if not isinstance(x, int): err[0] = ERR_TYPE return 0 - # x is a Python "long" (called "int" on Python 3) + # x is a Python "int" (aka PyLongObject or py_long in cython) cdef const digit* D = (x).ob_digit cdef Py_ssize_t size = Py_SIZE(x) - # We assume that PyLong_SHIFT is 15 on a 32-bit system and 30 on a - # 64-bit system. This is not guaranteed by Python, but it is the - # default configuration. + # We assume PyLong_SHIFT <= BITS_IN_LONG <= 3 * PyLong_SHIFT. + # This is true in all the default configurations: + # - BITS_IN_LONG = 63, PyLong_SHIFT = 30 + # - BITS_IN_LONG = 31, PyLong_SHIFT = 15 (python <= 3.10) + # - BITS_IN_LONG = 31, PyLong_SHIFT = 30 (new in python 3.11) + # cf. https://trac.sagemath.org/ticket/33842#comment:130 # - # This way, we know that 1 and 2 digits certainly fit in a C long - # and 4 or more digits never fit. For 3 digits, we need an explicit - # overflow check. + # This way, we know that 1 digit certainly fits in a C long + # and 4 or more digits never fit. + # For 2 or 3 digits, we need an explicit overflow check. cdef int BITS_IN_LONG = 8 * sizeof(long) - 1 - if not (2 * PyLong_SHIFT <= BITS_IN_LONG < 4 * PyLong_SHIFT): - raise AssertionError + if not (PyLong_SHIFT <= BITS_IN_LONG <= 3 * PyLong_SHIFT): + raise AssertionError( + f"PyLong_SHIFT = {PyLong_SHIFT}, " + f"BITS_IN_LONG = {BITS_IN_LONG}") cdef long lead + cdef long lead_2_overflow = (1) << (BITS_IN_LONG - PyLong_SHIFT) cdef long lead_3_overflow = (1) << (BITS_IN_LONG - 2 * PyLong_SHIFT) if size == 0: value[0] = 0 @@ -228,9 +320,20 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): value[0] = -dig(D, 0) err[0] = 0 elif size == 2: + if BITS_IN_LONG < 2 * PyLong_SHIFT and D[1] >= lead_2_overflow: + err[0] = ERR_OVERFLOW + return 1 value[0] = dig(D, 0) + dig(D, 1) err[0] = 0 elif size == -2: + if BITS_IN_LONG < 2 * PyLong_SHIFT and D[1] >= lead_2_overflow: + if D[0] == 0 and D[1] == lead_2_overflow: + # Special case for LONG_MIN + value[0] = (-1) << BITS_IN_LONG + err[0] = 0 + else: + err[0] = ERR_OVERFLOW + return 1 value[0] = -(dig(D, 0) + dig(D, 1)) err[0] = 0 elif size == 3: diff --git a/src/sage/coding/abstract_code.py b/src/sage/coding/abstract_code.py index ba2ec68a038..238a165c021 100644 --- a/src/sage/coding/abstract_code.py +++ b/src/sage/coding/abstract_code.py @@ -123,7 +123,7 @@ def _explain_constructor(cl): reqs = "The constructor requires the arguments {}.".format(args) else: reqs = "The constructor requires no arguments." - if argspec.varargs or argspec.keywords: + if argspec.varargs or argspec.varkw: var = "It accepts unspecified arguments as well.\n" else: var = "" diff --git a/src/sage/cpython/cython_metaclass.h b/src/sage/cpython/cython_metaclass.h index cc620a4dac7..da06ab75a6b 100644 --- a/src/sage/cpython/cython_metaclass.h +++ b/src/sage/cpython/cython_metaclass.h @@ -8,6 +8,13 @@ * http://www.gnu.org/licenses/ *****************************************************************************/ +/* Compatibility for python 3.8, can be removed later */ +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) +static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) +{ ob->ob_type = type; } +#define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type) +#endif + /* Tuple (None, None, None), initialized as needed */ static PyObject* NoneNoneNone; @@ -66,7 +73,7 @@ static CYTHON_INLINE int Sage_PyType_Ready(PyTypeObject* t) } /* Now, set t.__class__ to metaclass */ - Py_TYPE(t) = metaclass; + Py_SET_TYPE(t, metaclass); PyType_Modified(t); } else diff --git a/src/sage/cpython/dict_del_by_value.pyx b/src/sage/cpython/dict_del_by_value.pyx index 488bf9c84cc..3894554c13d 100644 --- a/src/sage/cpython/dict_del_by_value.pyx +++ b/src/sage/cpython/dict_del_by_value.pyx @@ -19,13 +19,8 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -import weakref -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 cdef extern from "Python.h": ctypedef struct PyDictKeysObject @@ -34,99 +29,47 @@ cdef extern from "Python.h": PyDictKeysObject * ma_keys PyObject ** ma_values - #we need this redefinition because we want to be able to call - #PyWeakref_GetObject with borrowed references. This is the recommended - #strategy according to Cython/Includes/cpython/__init__.pxd - PyObject* PyWeakref_GetObject(PyObject * wr) int PyList_SetItem(object list, Py_ssize_t index, PyObject * item) except -1 - int PyWeakref_Check(PyObject * ob) -#### -#definitions replicated from CPython's Objects/dict-common.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] - int32_t as_4[2] - int64_t as_8[1] - -ctypedef struct MyPyDictKeysObject: - Py_ssize_t dk_refcnt - Py_ssize_t dk_size - dict_lookup_func dk_lookup - Py_ssize_t dk_usable - Py_ssize_t dk_nentries - IndexBlock dk_indices - -ctypedef struct PyDictKeyEntry: - Py_hash_t me_hash - 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 - -##### -#These routines are copied from CPython's Object/dictobject.c -#in order to access PyDictKeysObject fields - -cdef inline int DK_IXSIZE(MyPyDictKeysObject *keys): - cdef Py_ssize_t s = keys.dk_size - if s <= 0xff: - return 1 - elif s <= 0xffff: - return 2 - elif s <= 0xffffffff: - return 4 - else: - return 8 - -cdef inline PyDictKeyEntry * DK_ENTRIES(MyPyDictKeysObject *keys): - return &(keys.dk_indices.as_1[keys.dk_size * DK_IXSIZE(keys)]) - -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: - return keys.dk_indices.as_1[i] - elif s <= 0xffff: - return keys.dk_indices.as_2[i] - elif s <= 0xffffffff: - 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: - keys.dk_indices.as_1[i] = ix - elif s <= 0xffff: - keys.dk_indices.as_2[i] = ix - elif s <= 0xffffffff: - keys.dk_indices.as_4[i] = ix - else: - keys.dk_indices.as_8[i] = ix - -#End of replication of Object/dictobject.c -###### - -cdef dict_lookup_func lookdict - -cdef dict_lookup_func DK_LOOKUP(PyDictObject *mp): - return ((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(D) - -init_lookdict() + +cdef extern from "dict_internal.h": + Py_ssize_t DK_MASK(PyDictKeysObject *) + PyDictKeyEntry * DK_ENTRIES(PyDictKeysObject *keys) + + Py_ssize_t dictkeys_get_index (PyDictKeysObject *keys, Py_ssize_t i) + void dictkeys_set_index (PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) + + Py_ssize_t DKIX_EMPTY, DKIX_DUMMY + int PERTURB_SHIFT + + ctypedef struct PyDictKeyEntry: + Py_hash_t me_hash + PyObject * me_key + PyObject * me_value + + +# dk_lookup was removed in python 3.11 +DEF HAS_DK_LOOKUP = PY_VERSION_HEX < 0x30b0000 + +IF HAS_DK_LOOKUP: + + cdef extern from *: + """ + #define DK_LOOKUP(dk) ((dk)->dk_lookup) + """ + ctypedef void * dict_lookup_func # Precise definition not needed + dict_lookup_func DK_LOOKUP(PyDictKeysObject *mp) + + cdef dict_lookup_func lookdict + + 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((D).ma_keys) + + init_lookdict() cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_t hash) except -1: """ @@ -177,9 +120,9 @@ cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_ sage: for i in range(10^3+10): newA = A(); M[newA] = prev; prev = newA sage: del a """ - keys = (mp.ma_keys) + keys = mp.ma_keys cdef size_t perturb - cdef size_t mask = keys.dk_size-1 + cdef size_t mask = DK_MASK(keys) cdef PyDictKeyEntry *entries = DK_ENTRIES(keys) cdef PyDictKeyEntry *ep @@ -187,7 +130,7 @@ cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_ raise TypeError("del_dictitem_by_exact_value cannot be applied to a shared key dict") cdef size_t i = hash & mask - ix = dk_get_index(keys, i) + ix = dictkeys_get_index(keys, i) if ix == DKIX_EMPTY: # key not found @@ -196,9 +139,9 @@ cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_ 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 + perturb = perturb >> PERTURB_SHIFT i = mask & (i * 5 + perturb + 1) - ix = dk_get_index(keys, i) + ix = dictkeys_get_index(keys, i) if ix == DKIX_EMPTY: # key not found return 0 @@ -206,7 +149,9 @@ cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_ # We need the lookup function to be the generic lookdict, otherwise # deletions may not work correctly - keys.dk_lookup = lookdict + IF HAS_DK_LOOKUP: + # Can this fail? In any case dk_lookup was removed in python 3.11 + assert DK_LOOKUP(keys) is lookdict T = PyList_New(2) PyList_SetItem(T, 0, ep.me_key) @@ -214,7 +159,7 @@ cdef int del_dictitem_by_exact_value(PyDictObject *mp, PyObject *value, Py_hash_ ep.me_key = NULL ep.me_value = NULL mp.ma_used -= 1 - dk_set_index(keys, i, DKIX_DUMMY) + dictkeys_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 diff --git a/src/sage/cpython/dict_internal.h b/src/sage/cpython/dict_internal.h new file mode 100644 index 00000000000..42a57bcb468 --- /dev/null +++ b/src/sage/cpython/dict_internal.h @@ -0,0 +1,242 @@ +/* This contains internal definitions for python dictionaries, + * mostly copied from cpython sourcecode. + * + * Moved here to make it easier to maintain in the face of python + * changes. + * */ + +#if PY_VERSION_HEX < 0x30b0000 + +/************************************************************/ +/* Copied verbatim from cpython 3.8 (Objects/dict-common.h) */ +/************************************************************/ + +#ifndef Py_DICT_COMMON_H +#define Py_DICT_COMMON_H + +typedef struct { + /* Cached hash code of me_key. */ + Py_hash_t me_hash; + PyObject *me_key; + PyObject *me_value; /* This field is only meaningful for combined tables */ +} PyDictKeyEntry; + +/* dict_lookup_func() returns index of entry which can be used like DK_ENTRIES(dk)[index]. + * -1 when no entry found, -3 when compare raises error. + */ +typedef Py_ssize_t (*dict_lookup_func) + (PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr); + +#define DKIX_EMPTY (-1) +#define DKIX_DUMMY (-2) /* Used internally */ +#define DKIX_ERROR (-3) + +/* See dictobject.c for actual layout of DictKeysObject */ +struct _dictkeysobject { + Py_ssize_t dk_refcnt; + + /* Size of the hash table (dk_indices). It must be a power of 2. */ + Py_ssize_t dk_size; + + /* Function to lookup in the hash table (dk_indices): + + - lookdict(): general-purpose, and may return DKIX_ERROR if (and + only if) a comparison raises an exception. + + - lookdict_unicode(): specialized to Unicode string keys, comparison of + which can never raise an exception; that function can never return + DKIX_ERROR. + + - lookdict_unicode_nodummy(): similar to lookdict_unicode() but further + specialized for Unicode string keys that cannot be the value. + + - lookdict_split(): Version of lookdict() for split tables. */ + dict_lookup_func dk_lookup; + + /* Number of usable entries in dk_entries. */ + Py_ssize_t dk_usable; + + /* Number of used entries in dk_entries. */ + Py_ssize_t dk_nentries; + + /* Actual hash table of dk_size entries. It holds indices in dk_entries, + or DKIX_EMPTY(-1) or DKIX_DUMMY(-2). + + Indices must be: 0 <= indice < USABLE_FRACTION(dk_size). + + The size in bytes of an indice depends on dk_size: + + - 1 byte if dk_size <= 0xff (char*) + - 2 bytes if dk_size <= 0xffff (int16_t*) + - 4 bytes if dk_size <= 0xffffffff (int32_t*) + - 8 bytes otherwise (int64_t*) + + Dynamically sized, SIZEOF_VOID_P is minimum. */ + char dk_indices[]; /* char is required to avoid strict aliasing. */ + + /* "PyDictKeyEntry dk_entries[dk_usable];" array follows: + see the DK_ENTRIES() macro */ +}; + +#endif + + +/***********************************************************/ +/* Copied verbatim from cpython 3.8 (Objects/dictobject.c) */ +/***********************************************************/ + +#define PERTURB_SHIFT 5 +#define DK_SIZE(dk) ((dk)->dk_size) +#if SIZEOF_VOID_P > 4 +#define DK_IXSIZE(dk) \ + (DK_SIZE(dk) <= 0xff ? \ + 1 : DK_SIZE(dk) <= 0xffff ? \ + 2 : DK_SIZE(dk) <= 0xffffffff ? \ + 4 : sizeof(int64_t)) +#else +#define DK_IXSIZE(dk) \ + (DK_SIZE(dk) <= 0xff ? \ + 1 : DK_SIZE(dk) <= 0xffff ? \ + 2 : sizeof(int32_t)) +#endif +#define DK_ENTRIES(dk) \ + ((PyDictKeyEntry*)(&((int8_t*)((dk)->dk_indices))[DK_SIZE(dk) * DK_IXSIZE(dk)])) + +#define DK_MASK(dk) (((dk)->dk_size)-1) + +/* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */ +static inline Py_ssize_t +dictkeys_get_index(PyDictKeysObject *keys, Py_ssize_t i) +{ + Py_ssize_t s = DK_SIZE(keys); + Py_ssize_t ix; + + if (s <= 0xff) { + int8_t *indices = (int8_t*)(keys->dk_indices); + ix = indices[i]; + } + else if (s <= 0xffff) { + int16_t *indices = (int16_t*)(keys->dk_indices); + ix = indices[i]; + } +#if SIZEOF_VOID_P > 4 + else if (s > 0xffffffff) { + int64_t *indices = (int64_t*)(keys->dk_indices); + ix = indices[i]; + } +#endif + else { + int32_t *indices = (int32_t*)(keys->dk_indices); + ix = indices[i]; + } + assert(ix >= DKIX_DUMMY); + return ix; +} + +/* write to indices. */ +static inline void +dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) +{ + Py_ssize_t s = DK_SIZE(keys); + + assert(ix >= DKIX_DUMMY); + + if (s <= 0xff) { + int8_t *indices = (int8_t*)(keys->dk_indices); + assert(ix <= 0x7f); + indices[i] = (char)ix; + } + else if (s <= 0xffff) { + int16_t *indices = (int16_t*)(keys->dk_indices); + assert(ix <= 0x7fff); + indices[i] = (int16_t)ix; + } +#if SIZEOF_VOID_P > 4 + else if (s > 0xffffffff) { + int64_t *indices = (int64_t*)(keys->dk_indices); + indices[i] = ix; + } +#endif + else { + int32_t *indices = (int32_t*)(keys->dk_indices); + assert(ix <= 0x7fffffff); + indices[i] = (int32_t)ix; + } +} + +/************************************************************/ + +#else /* Python >= 3.11 */ + +#define Py_BUILD_CORE +#include + +/************************************************************/ +/* Copied verbatim from cpython 3.11 (Objects/dictobject.c) */ +/************************************************************/ + +#define PERTURB_SHIFT 5 +#define DK_MASK(dk) (DK_SIZE(dk)-1) + +/* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */ +static inline Py_ssize_t +dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i) +{ + int log2size = DK_LOG_SIZE(keys); + Py_ssize_t ix; + + if (log2size < 8) { + const int8_t *indices = (const int8_t*)(keys->dk_indices); + ix = indices[i]; + } + else if (log2size < 16) { + const int16_t *indices = (const int16_t*)(keys->dk_indices); + ix = indices[i]; + } +#if SIZEOF_VOID_P > 4 + else if (log2size >= 32) { + const int64_t *indices = (const int64_t*)(keys->dk_indices); + ix = indices[i]; + } +#endif + else { + const int32_t *indices = (const int32_t*)(keys->dk_indices); + ix = indices[i]; + } + assert(ix >= DKIX_DUMMY); + return ix; +} + +/* write to indices. */ +static inline void +dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) +{ + int log2size = DK_LOG_SIZE(keys); + + assert(ix >= DKIX_DUMMY); + assert(keys->dk_version == 0); + + if (log2size < 8) { + int8_t *indices = (int8_t*)(keys->dk_indices); + assert(ix <= 0x7f); + indices[i] = (char)ix; + } + else if (log2size < 16) { + int16_t *indices = (int16_t*)(keys->dk_indices); + assert(ix <= 0x7fff); + indices[i] = (int16_t)ix; + } +#if SIZEOF_VOID_P > 4 + else if (log2size >= 32) { + int64_t *indices = (int64_t*)(keys->dk_indices); + indices[i] = ix; + } +#endif + else { + int32_t *indices = (int32_t*)(keys->dk_indices); + assert(ix <= 0x7fffffff); + indices[i] = (int32_t)ix; + } +} + +#endif diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 1e2db93198d..1fe5d00b669 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -767,8 +767,8 @@ def _is_present(self): from distutils.errors import CCompilerError with open(tmp_filename(ext=".pyx"), 'w') as pyx: pyx.write(self.test_code) - from sage.misc.cython import cython_import try: + from sage.misc.cython import cython_import cython_import(pyx.name, verbose=-1) except CCompilerError: return FeatureTestResult(self, False, reason="Failed to compile test code.") diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 2c377f09efd..a7da61de4bf 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -2781,7 +2781,8 @@ def singular_gb_standard_options(func): sage: P. = QQ[] sage: I = P*[x,y] sage: sage_getargspec(I.interreduced_basis) - ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getsourcelines(I.interreduced_basis) ([' @handle_AA_and_QQbar\n', ' @singular_gb_standard_options\n', diff --git a/src/sage/libs/gmp/pylong.pyx b/src/sage/libs/gmp/pylong.pyx index 388be32c55e..2f7ed35be9d 100644 --- a/src/sage/libs/gmp/pylong.pyx +++ b/src/sage/libs/gmp/pylong.pyx @@ -32,7 +32,15 @@ from cpython.longintrepr cimport _PyLong_New, py_long, digit, PyLong_SHIFT from .mpz cimport * cdef extern from *: - Py_ssize_t* Py_SIZE_PTR "&Py_SIZE"(object) + """ + /* Compatibility for python 3.8, can be removed later */ + #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) + static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) + { ob->ob_size = size; } + #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size) + #endif + """ + void Py_SET_SIZE(object, Py_ssize_t) int hash_bits """ #ifdef _PyHASH_BITS _PyHASH_BITS /* Python 3 */ @@ -57,10 +65,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 + Py_SET_SIZE(L, -pylong_size) return L diff --git a/src/sage/libs/singular/standard_options.py b/src/sage/libs/singular/standard_options.py index 6797cb05001..5d74da3ce3a 100644 --- a/src/sage/libs/singular/standard_options.py +++ b/src/sage/libs/singular/standard_options.py @@ -117,7 +117,8 @@ def libsingular_gb_standard_options(func): sage: P. = QQ[] sage: I = P*[x,y] sage: sage_getargspec(I.interreduced_basis) - ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getsourcelines(I.interreduced_basis) ([' @handle_AA_and_QQbar\n', ' @singular_gb_standard_options\n', diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index 9fa967ce737..cea3071115d 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -931,9 +931,9 @@ cdef class CachedFunction(): sage: I = P*[x,y] sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(I.groebner_basis) # indirect doctest - ArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'], - varargs='args', keywords='kwds', defaults=('', None, None, - False)) + FullArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'], + varargs='args', varkw='kwds', defaults=('', None, None, False), + kwonlyargs=[], kwonlydefaults=None, annotations={}) """ return sage_getargspec(self.f) @@ -2818,7 +2818,7 @@ cdef class CachedMethod(): except Exception: pass if self.nargs == 0: - args, varargs, keywords, defaults = sage_getargspec(f) + args, varargs, keywords, defaults, kwonlyargs, kwonlydefaults, annotations = sage_getargspec(f) if varargs is None and keywords is None and len(args)<=1: self.nargs = 1 else: @@ -2954,7 +2954,7 @@ cdef class CachedSpecialMethod(CachedMethod): # we need to analyse the argspec f = self._cachedfunc.f if self.nargs == 0: - args, varargs, keywords, defaults = sage_getargspec(f) + args, varargs, keywords, defaults, kwonlyargs, kwonlydefaults, annotations = sage_getargspec(f) if varargs is None and keywords is None and len(args)<=1: self.nargs = 1 Caller = CachedMethodCallerNoArgs(inst, f, name=name, do_pickle=self._cachedfunc.do_pickle) diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index 28c52448813..dd9123f5004 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -32,7 +32,8 @@ from sage.misc.sageinspect import (sage_getsource, sage_getsourcelines, sage_getargspec) -from inspect import ArgSpec + +from inspect import FullArgSpec def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): @@ -92,7 +93,8 @@ def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): 5 sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(g) - ArgSpec(args=['x'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['x'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) Demonstrate that it correctly gets the source lines and the source file, which is essential for interactive code edition; note that we @@ -391,7 +393,8 @@ def __call__(self, func): sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(f) - ArgSpec(args=['arrow_size'], varargs='args', keywords='kwds', defaults=(2,)) + FullArgSpec(args=['arrow_size'], varargs='args', varkw='kwds', defaults=(2,), + kwonlyargs=[], kwonlydefaults=None, annotations={}) """ @sage_wraps(func) def wrapper(*args, **kwds): @@ -422,7 +425,8 @@ def listForNone(l): defaults = (argspec.defaults if argspec.defaults is not None else ()) \ + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason - return ArgSpec(args, argspec.varargs, argspec.keywords, defaults) + return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, + kwonlyargs=[], kwonlydefaults=None, annotations={}) wrapper._sage_argspec_ = argspec return wrapper @@ -458,7 +462,8 @@ def __init__(self, **options): sage: f1 = o(f) sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(f1) - ArgSpec(args=['rgbcolor'], varargs='args', keywords='kwds', defaults=((0, 0, 1),)) + FullArgSpec(args=['rgbcolor'], varargs='args', varkw='kwds', defaults=((0, 0, 1),), + kwonlyargs=[], kwonlydefaults=None, annotations={}) """ self.options = options self.original_opts = options.pop('__original_opts', False) @@ -499,7 +504,8 @@ def argspec(): list(self.options)) defaults = (argspec.defaults or ()) + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason - return ArgSpec(args, argspec.varargs, argspec.keywords, defaults) + return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, + kwonlyargs=[], kwonlydefaults=None, annotations={}) wrapper._sage_argspec_ = argspec diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx index 502080e2c10..793041d1422 100644 --- a/src/sage/misc/fpickle.pyx +++ b/src/sage/misc/fpickle.pyx @@ -34,6 +34,12 @@ def reduce_code(co): sage: def foo(N): return N+1 sage: sage.misc.fpickle.reduce_code(foo.__code__) (, ...) + + Test that the constructed code matches the original code:: + + sage: ctor, args = sage.misc.fpickle.reduce_code(foo.__code__) + sage: ctor(*args) == foo.__code__ + True """ if co.co_freevars or co.co_cellvars: raise ValueError("Cannot pickle code objects from closures") @@ -44,7 +50,12 @@ def reduce_code(co): co_args += (co.co_kwonlyargcount, co.co_nlocals, co.co_stacksize, co.co_flags, co.co_code, co.co_consts, co.co_names, co.co_varnames, co.co_filename, - co.co_name, co.co_firstlineno, co.co_lnotab) + co.co_name) + if sys.version_info.minor >= 11: + co_args += (co.co_qualname, co.co_firstlineno, + co.co_linetable, co.co_exceptiontable) + else: + co_args += (co.co_firstlineno, co.co_lnotab) return (code_ctor, co_args) diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index 0ac03cf0715..e1bb7978953 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -116,7 +116,7 @@ cdef class ArgumentFixer: """ def __init__(self, f, classmethod = False): try: - arg_names, varargs, varkw, defaults = sage_getargspec(f) + arg_names, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations = sage_getargspec(f) except AttributeError: # This error occurs if f is defined in a Cython file and the # source file has gone. diff --git a/src/sage/misc/lazy_format.py b/src/sage/misc/lazy_format.py index e3050695b25..b58ea155862 100644 --- a/src/sage/misc/lazy_format.py +++ b/src/sage/misc/lazy_format.py @@ -78,7 +78,7 @@ class LazyFormat(str): ....: LazyFormat("%s is wrong")%IDontLikeBeingPrinted()) Traceback (most recent call last): ... - AssertionError: + AssertionError: ... """ def __mod__(self, args): diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 6bf9365c348..a5bc788d386 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -351,7 +351,9 @@ cdef class LazyImport(): sage: from sage.misc.lazy_import import LazyImport sage: rm = LazyImport('sage.all', 'random_matrix') sage: rm._sage_argspec_() - ArgSpec(args=['ring', 'nrows', 'ncols', 'algorithm', 'implementation'], varargs='args', keywords='kwds', defaults=(None, 'randomize', None)) + FullArgSpec(args=['ring', 'nrows', 'ncols', 'algorithm', 'implementation'], + varargs='args', varkw='kwds', defaults=(None, 'randomize', None), + kwonlyargs=[], kwonlydefaults=None, annotations={}) """ return sageinspect.sage_getargspec(self.get_object()) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 92fc9304807..2c172acdfcf 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -109,7 +109,7 @@ sage: print(sage_getsource(foo)) # optional - sage.misc.cython def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return sage: sage_getargspec(foo) # optional - sage.misc.cython - ArgSpec(args=['x', 'a', 'b'], varargs='args', keywords='kwds', defaults=(1, ')"', {False: 'bar'})) + FullArgSpec(args=['x', 'a', 'b'], varargs='args', varkw='kwds', defaults=(1, ')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={}) """ @@ -343,7 +343,7 @@ def _extract_embedded_signature(docstring, name): File: sage/misc/nested_class.pyx (starting at line ...) ... sage: _extract_embedded_signature(MainClass.NestedClass.NestedSubClass.dummy.__doc__, 'dummy')[1] - ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) + FullArgSpec(args=['self', 'x', 'r'], varargs='args', varkw='kwds', defaults=((1, 2, 3.4),), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: _extract_embedded_signature(range.__call__.__doc__, '__call__') ('Call self as a function.', None) """ @@ -359,7 +359,7 @@ def _extract_embedded_signature(docstring, name): 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, inspect.FullArgSpec(*_sage_getargspec_cython(def_string)) except SyntaxError: docstring = os.linesep.join(L) return docstring, None @@ -1107,22 +1107,18 @@ def _sage_getargspec_from_ast(source): EXAMPLES:: - sage: import warnings - sage: warnings.filterwarnings('ignore', - ....: r'inspect.getargspec\(\) is deprecated', - ....: DeprecationWarning) sage: import inspect, sage.misc.sageinspect as sms sage: from_ast = sms._sage_getargspec_from_ast sage: s = "def f(a, b=2, c={'a': [4, 5.5, False]}, d=(None, True)):\n return" sage: from_ast(s) - ArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, keywords=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True))) + FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True)), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: context = {} sage: exec(compile(s, '', 'single'), context) - sage: inspect.getargspec(context['f']) - ArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, keywords=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True))) - sage: from_ast(s) == inspect.getargspec(context['f']) + sage: inspect.getfullargspec(context['f']) + FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True)), kwonlyargs=[], kwonlydefaults=None, annotations={}) + sage: from_ast(s) == inspect.getfullargspec(context['f']) True - sage: set(from_ast(sms.sage_getsource(x)) == inspect.getargspec(x) for x in [factor, identity_matrix, Graph.__init__]) + sage: set(from_ast(sms.sage_getsource(x)) == inspect.getfullargspec(x) for x in [factor, identity_matrix, Graph.__init__]) {True} """ ast_args = ast.parse(source.lstrip()).body[0].args @@ -1135,8 +1131,9 @@ 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 inspect.FullArgSpec(args, vararg, kwarg, + tuple(defaults) if defaults else None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) def _sage_getargspec_cython(source): @@ -1152,29 +1149,29 @@ def _sage_getargspec_cython(source): OUTPUT: - - an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple + - an instance of :class:`inspect.FullArgSpec`, i.e., a named tuple EXAMPLES:: sage: from sage.misc.sageinspect import _sage_getargspec_cython as sgc sage: sgc("cpdef double abc(self, Element x=None, Parent base=0):") - ArgSpec(args=['self', 'x', 'base'], varargs=None, keywords=None, defaults=(None, 0)) + FullArgSpec(args=['self', 'x', 'base'], varargs=None, varkw=None, defaults=(None, 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc("def __init__(self, x=None, unsigned int base=0):") - ArgSpec(args=['self', 'x', 'base'], varargs=None, keywords=None, defaults=(None, 0)) + FullArgSpec(args=['self', 'x', 'base'], varargs=None, varkw=None, defaults=(None, 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('def o(p, r={}, *q, **s) except? -1:') - ArgSpec(args=['p', 'r'], varargs='q', keywords='s', defaults=({},)) + FullArgSpec(args=['p', 'r'], varargs='q', varkw='s', defaults=({},), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('cpdef how(r=(None, "u:doing?")):') - ArgSpec(args=['r'], varargs=None, keywords=None, defaults=((None, 'u:doing?'),)) + FullArgSpec(args=['r'], varargs=None, varkw=None, defaults=((None, 'u:doing?'),), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('def _(x="):"):') - ArgSpec(args=['x'], varargs=None, keywords=None, defaults=('):',)) + FullArgSpec(args=['x'], varargs=None, varkw=None, defaults=('):',), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('def f(z = {(1, 2, 3): True}):\n return z') - ArgSpec(args=['z'], varargs=None, keywords=None, defaults=({(1, 2, 3): True},)) + FullArgSpec(args=['z'], varargs=None, varkw=None, defaults=({(1, 2, 3): True},), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('def f(double x, z = {(1, 2, 3): True}):\n return z') - ArgSpec(args=['x', 'z'], varargs=None, keywords=None, defaults=({(1, 2, 3): True},)) + FullArgSpec(args=['x', 'z'], varargs=None, varkw=None, defaults=({(1, 2, 3): True},), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('def f(*args): pass') - ArgSpec(args=[], varargs='args', keywords=None, defaults=None) + FullArgSpec(args=[], varargs='args', varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sgc('def f(**args): pass') - ArgSpec(args=[], varargs=None, keywords='args', defaults=None) + FullArgSpec(args=[], varargs=None, varkw='args', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) Some malformed input is detected:: @@ -1206,17 +1203,17 @@ def _sage_getargspec_cython(source): sage: def dummy_python(self, *args, x=1): pass sage: sgc("def dummy_python(self, *args, x=1): pass") - ArgSpec(args=['self', 'x'], varargs='args', keywords=None, defaults=(1,)) + FullArgSpec(args=['self', 'x'], varargs='args', varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: cython("def dummy_cython(self, *args, x=1): pass") sage: sgc("def dummy_cython(self, *args, x=1): pass") - ArgSpec(args=['self', 'x'], varargs='args', keywords=None, defaults=(1,)) + FullArgSpec(args=['self', 'x'], varargs='args', varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) In some examples above, a syntax error was raised when a type definition contains a pointer. An exception is made for ``char*``, since C strings are acceptable input in public Cython functions:: sage: sgc('def f(char *x = "a string", z = {(1,2,3): True}): pass') - ArgSpec(args=['x', 'z'], varargs=None, keywords=None, defaults=('a string', {(1, 2, 3): True})) + FullArgSpec(args=['x', 'z'], varargs=None, varkw=None, defaults=('a string', {(1, 2, 3): True}), kwonlyargs=[], kwonlydefaults=None, annotations={}) AUTHORS: @@ -1502,40 +1499,40 @@ def sage_getargspec(obj): sage: def f(x, y, z=1, t=2, *args, **keywords): ....: pass sage: sage_getargspec(f) - ArgSpec(args=['x', 'y', 'z', 't'], varargs='args', keywords='keywords', defaults=(1, 2)) + FullArgSpec(args=['x', 'y', 'z', 't'], varargs='args', varkw='keywords', defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={}) We now run sage_getargspec on some functions from the Sage library:: sage: sage_getargspec(identity_matrix) - ArgSpec(args=['ring', 'n', 'sparse'], varargs=None, keywords=None, defaults=(0, False)) + FullArgSpec(args=['ring', 'n', 'sparse'], varargs=None, varkw=None, defaults=(0, False), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getargspec(factor) - ArgSpec(args=['n', 'proof', 'int_', 'algorithm', 'verbose'], varargs=None, keywords='kwds', defaults=(None, False, 'pari', 0)) + FullArgSpec(args=['n', 'proof', 'int_', 'algorithm', 'verbose'], varargs=None, varkw='kwds', defaults=(None, False, 'pari', 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) In the case of a class or a class instance, the ``ArgSpec`` of the ``__new__``, ``__init__`` or ``__call__`` method is returned:: sage: P. = QQ[] sage: sage_getargspec(P) - ArgSpec(args=['base_ring', 'n', 'names', 'order'], varargs=None, keywords=None, defaults=('degrevlex',)) + FullArgSpec(args=['base_ring', 'n', 'names', 'order'], varargs=None, varkw=None, defaults=('degrevlex',), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getargspec(P.__class__) - ArgSpec(args=['self', 'x'], varargs='args', keywords='kwds', defaults=(0,)) + FullArgSpec(args=['self', 'x'], varargs='args', varkw='kwds', defaults=(0,), kwonlyargs=[], kwonlydefaults=None, annotations={}) The following tests against various bugs that were fixed in :trac:`9976`:: sage: from sage.rings.polynomial.real_roots import bernstein_polynomial_factory_ratlist sage: sage_getargspec(bernstein_polynomial_factory_ratlist.coeffs_bitsize) - ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid sage: sage_getargspec(BooleanMonomialMonoid.gen) - ArgSpec(args=['self', 'i'], varargs=None, keywords=None, defaults=(0,)) + FullArgSpec(args=['self', 'i'], varargs=None, varkw=None, defaults=(0,), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: I = P*[x,y] sage: sage_getargspec(I.groebner_basis) - ArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'], - varargs='args', keywords='kwds', defaults=('', None, None, False)) + FullArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'], + varargs='args', varkw='kwds', defaults=('', None, None, False), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: cython("cpdef int foo(x,y) except -1: return 1") sage: sage_getargspec(foo) - ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['x', 'y'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) If a ``functools.partial`` instance is involved, we see no other meaningful solution than to return the argspec of the underlying function:: @@ -1545,7 +1542,7 @@ def sage_getargspec(obj): sage: import functools sage: f1 = functools.partial(f, 1,c=2) sage: sage_getargspec(f1) - ArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, keywords=None, defaults=(1,)) + FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) TESTS: @@ -1571,14 +1568,14 @@ def sage_getargspec(obj): sage: print(sage.misc.sageinspect.sage_getsource(O)) def foo(x, a=')"', b={(2+1):'bar', not 1:3, 3<<4:5}): return sage: spec = sage.misc.sageinspect.sage_getargspec(O) - sage: spec.args, spec.varargs, spec.keywords + sage: spec.args, spec.varargs, spec.varkw (['x', 'a', 'b'], None, None) sage: spec.defaults[0] ')"' sage: sorted(spec.defaults[1].items(), key=lambda x: str(x)) [(3, 'bar'), (48, 5), (False, 3)] sage: sage.misc.sageinspect.sage_getargspec(O.__call__) - ArgSpec(args=['self', 'm', 'n'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['self', 'm', 'n'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) :: @@ -1587,13 +1584,13 @@ def foo(x, a=')"', b={(2+1):'bar', not 1:3, 3<<4:5}): return def foo(x, a='\')"', b={not (2+1==3):'bar'}): return sage: sage.misc.sageinspect.sage_getargspec(foo) - ArgSpec(args=['x', 'a', 'b'], varargs=None, keywords=None, defaults=('\')"', {False: 'bar'})) + FullArgSpec(args=['x', 'a', 'b'], varargs=None, varkw=None, defaults=('\')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={}) The following produced a syntax error before the patch at :trac:`11913`, see also :trac:`26906`:: sage: sage.misc.sageinspect.sage_getargspec(r.lm) # optional - rpy2 - ArgSpec(args=['self'], varargs='args', keywords='kwds', defaults=None) + FullArgSpec(args=['self'], varargs='args', varkw='kwds', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) The following was fixed in :trac:`16309`:: @@ -1607,23 +1604,23 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return ....: cpdef meet(categories, bint as_list = False, tuple ignore_axioms=(), tuple axioms=()): pass ....: ''') sage: sage_getargspec(Foo.join) - ArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, keywords=None, defaults=(False, (), ())) + FullArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, varkw=None, defaults=(False, (), ()), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getargspec(Bar.join) - ArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, keywords=None, defaults=(False, (), ())) + FullArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, varkw=None, defaults=(False, (), ()), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getargspec(Bar.meet) - ArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, keywords=None, defaults=(False, (), ())) + FullArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, varkw=None, defaults=(False, (), ()), kwonlyargs=[], kwonlydefaults=None, annotations={}) Test that :trac:`17009` is fixed:: sage: sage_getargspec(gap) - ArgSpec(args=['self', 'x', 'name'], varargs=None, keywords=None, defaults=(None,)) + FullArgSpec(args=['self', 'x', 'name'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={}) By :trac:`17814`, the following gives the correct answer (previously, the defaults would have been found ``None``):: sage: from sage.misc.nested_class import MainClass sage: sage_getargspec(MainClass.NestedClass.NestedSubClass.dummy) - ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) + FullArgSpec(args=['self', 'x', 'r'], varargs='args', varkw='kwds', defaults=((1, 2, 3.4),), kwonlyargs=[], kwonlydefaults=None, annotations={}) In :trac:`18249` was decided to return a generic signature for Python builtin functions, rather than to raise an error (which is what Python's @@ -1631,7 +1628,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return sage: import inspect sage: sage_getargspec(range) - ArgSpec(args=[], varargs='args', keywords='kwds', defaults=None) + FullArgSpec(args=[], varargs='args', varkw='kwds', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) Test that :trac:`28524` is fixed:: @@ -1662,11 +1659,11 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return return sage_getargspec(obj.__call__) if isinstance(obj, (lazy_attribute, AbstractMethod)): source = sage_getsource(obj) - return inspect.ArgSpec(*_sage_getargspec_cython(source)) + return inspect.FullArgSpec(*_sage_getargspec_cython(source)) if not callable(obj): raise TypeError("obj is not a code object") try: - return inspect.ArgSpec(*obj._sage_argspec_()) + return inspect.FullArgSpec(*obj._sage_argspec_()) except (AttributeError, TypeError): pass # If we are lucky, the function signature is embedded in the docstring. @@ -1682,7 +1679,8 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return # 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 inspect.FullArgSpec(args, varargs, varkw, obj.__defaults__, + kwonlyargs=[], kwonlydefaults=None, annotations={}) except (TypeError, AttributeError): pass if isclassinstance(obj): @@ -1717,7 +1715,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return except TypeError: # happens for Python builtins source = '' if source: - return inspect.ArgSpec(*_sage_getargspec_cython(source)) + return inspect.FullArgSpec(*_sage_getargspec_cython(source)) else: func_obj = obj @@ -1730,7 +1728,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return 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 inspect.FullArgSpec(*_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 = [] @@ -1740,7 +1738,8 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return defaults = func_obj.__defaults__ except AttributeError: defaults = None - return inspect.ArgSpec(args, varargs, varkw, defaults) + return inspect.FullArgSpec(args, varargs, varkw, defaults, + kwonlyargs=[], kwonlydefaults=None, annotations={}) def formatannotation(annotation, base_module=None): @@ -1786,7 +1785,7 @@ def formatannotation(annotation, base_module=None): def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, - kwonlyargs=(), kwonlydefaults={}, annotations={}, + kwonlyargs=(), kwonlydefaults=None, annotations={}, formatarg=str, formatvarargs=lambda name: '*' + name, formatvarkw=lambda name: '**' + name, @@ -1811,19 +1810,15 @@ def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, :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``. + ``inspect.FullArgSpec``. 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 """ def formatargandannotation(arg): result = formatarg(arg) @@ -2646,11 +2641,11 @@ def test3(b, # 12 Test _sage_getargspec_cython with multiple default arguments and a type:: sage: _sage_getargspec_cython("def init(self, x=None, base=0):") - ArgSpec(args=['self', 'x', 'base'], varargs=None, keywords=None, defaults=(None, 0)) + FullArgSpec(args=['self', 'x', 'base'], varargs=None, varkw=None, defaults=(None, 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: _sage_getargspec_cython("def __init__(self, x=None, base=0):") - ArgSpec(args=['self', 'x', 'base'], varargs=None, keywords=None, defaults=(None, 0)) + FullArgSpec(args=['self', 'x', 'base'], varargs=None, varkw=None, defaults=(None, 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: _sage_getargspec_cython("def __init__(self, x=None, unsigned int base=0, **keys):") - ArgSpec(args=['self', 'x', 'base'], varargs=None, keywords='keys', defaults=(None, 0)) + FullArgSpec(args=['self', 'x', 'base'], varargs=None, varkw='keys', defaults=(None, 0), kwonlyargs=[], kwonlydefaults=None, annotations={}) Test _extract_embedded_position: diff --git a/src/sage/parallel/decorate.py b/src/sage/parallel/decorate.py index 34cb4860d36..8428b39b4fd 100644 --- a/src/sage/parallel/decorate.py +++ b/src/sage/parallel/decorate.py @@ -241,7 +241,8 @@ def _sage_argspec_(self): ....: return x + y sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(p(f)) - ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['x', 'y'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) """ from sage.misc.sageinspect import sage_getargspec return sage_getargspec(self.func) diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 64b11a0442a..174765980f7 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -329,19 +329,24 @@ def to_cartesian(self, func, params=None): sage: t1,t2,t3=T.to_cartesian(lambda a,b: 2*a+b) sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(t1) - ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getargspec(t2) - ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: sage_getargspec(t3) - ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: def g(a,b): return 2*a+b sage: t1,t2,t3=T.to_cartesian(g) sage: sage_getargspec(t1) - ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: t1,t2,t3=T.to_cartesian(2*a+b) sage: sage_getargspec(t1) - ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) If we cannot guess the right parameter names, then the parameters are named `u` and `v`:: @@ -352,7 +357,8 @@ def to_cartesian(self, func, params=None): sage: T = _ArbitraryCoordinates((x + y, x - y, z), z,[x,y]) sage: t1,t2,t3=T.to_cartesian(operator.add) sage: sage_getargspec(t1) - ArgSpec(args=['u', 'v'], varargs=None, keywords=None, defaults=None) + FullArgSpec(args=['u', 'v'], varargs=None, varkw=None, defaults=None, + kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: [h(1,2) for h in T.to_cartesian(operator.mul)] [3.0, -1.0, 2.0] sage: [h(u=1,v=2) for h in T.to_cartesian(operator.mul)] diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py index 39da6ee4acd..3ae3e7ad0cf 100644 --- a/src/sage/repl/attach.py +++ b/src/sage/repl/attach.py @@ -53,7 +53,7 @@ ... exec(code, globals) File ".../foobar.sage....py", line ..., in - raise ValueError("third") # this should appear in the source snippet + raise ValueError("third") # this should appear in the source snippet... ValueError: third sage: detach(src) """ diff --git a/src/sage/repl/display/formatter.py b/src/sage/repl/display/formatter.py index 488f0bf2791..7e06656d880 100644 --- a/src/sage/repl/display/formatter.py +++ b/src/sage/repl/display/formatter.py @@ -143,6 +143,9 @@ def format(self, obj, include=None, exclude=None): sage: import os sage: import importlib.resources + sage: import warnings + sage: warnings.filterwarnings('ignore', category=DeprecationWarning, + ....: message=r'path is deprecated\. Use files\(\) instead\.') sage: from sage.repl.rich_output.backend_ipython import BackendIPython sage: backend = BackendIPython() sage: shell = get_test_shell() diff --git a/src/sage/rings/polynomial/pbori/gbrefs.py b/src/sage/rings/polynomial/pbori/gbrefs.py index 76e3924715d..70dc795cbab 100644 --- a/src/sage/rings/polynomial/pbori/gbrefs.py +++ b/src/sage/rings/polynomial/pbori/gbrefs.py @@ -1,6 +1,6 @@ import gzip from io import StringIO -import uu +import base64 as uu import re from types import ModuleType from .PyPolyBoRi import Polynomial diff --git a/src/sage/sets/set_from_iterator.py b/src/sage/sets/set_from_iterator.py index 3a2360383ea..74015c4433d 100644 --- a/src/sage/sets/set_from_iterator.py +++ b/src/sage/sets/set_from_iterator.py @@ -526,7 +526,9 @@ def _sage_argspec_(self): sage: d = Decorator() sage: d.f = find_local_minimum sage: sage_getargspec(d) # indirect doctest - ArgSpec(args=['f', 'a', 'b', 'tol', 'maxfun'], varargs=None, keywords=None, defaults=(1.48e-08, 500)) + FullArgSpec(args=['f', 'a', 'b', 'tol', 'maxfun'], + varargs=None, varkw=None, defaults=(1.48e-08, 500), + kwonlyargs=[], kwonlydefaults=None, annotations={}) """ from sage.misc.sageinspect import sage_getargspec return sage_getargspec(self.f) diff --git a/src/sage/symbolic/ginac/numeric.cpp b/src/sage/symbolic/ginac/numeric.cpp index 22060441760..b40ed64edb5 100644 --- a/src/sage/symbolic/ginac/numeric.cpp +++ b/src/sage/symbolic/ginac/numeric.cpp @@ -52,7 +52,6 @@ #define register #define PY_SSIZE_T_CLEAN #include -#include #include "flint/fmpz.h" #include "flint/fmpz_factor.h" diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index ae2a5bfe9a9..9f69af385e9 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -22,11 +22,12 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.8, <3.11 +python_requires = >=3.8, <3.12 install_requires = esyscmd(`sage-get-system-packages install-requires \ sage_conf \ diff --git a/tox.ini b/tox.ini index 744c295dd71..32cffc7a43f 100644 --- a/tox.ini +++ b/tox.ini @@ -302,6 +302,7 @@ setenv = gentoo: BASE_IMAGE=sheerluck/sage-on-gentoo-stage4 gentoo-python3.9: BASE_TAG=latest-py39 gentoo-python3.10: BASE_TAG=latest-py10 + gentoo-python3.11: BASE_TAG=latest-py11 gentoo: IGNORE_MISSING_SYSTEM_PACKAGES=no # # https://hub.docker.com/_/archlinux/