From 8955607c71cb94e4a810b89f113b7b220a351417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Sun, 6 Nov 2022 11:26:10 -0300 Subject: [PATCH 01/11] dict_del_by_value: move python internal definitions to a separate file --- src/sage/cpython/dict_del_by_value.pyx | 153 ++++++++--------------- src/sage/cpython/dict_internal.h | 165 +++++++++++++++++++++++++ 2 files changed, 214 insertions(+), 104 deletions(-) create mode 100644 src/sage/cpython/dict_internal.h 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..06c7a16b275 --- /dev/null +++ b/src/sage/cpython/dict_internal.h @@ -0,0 +1,165 @@ +/* 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. + * */ + +/************************************************************/ +/* 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; + } +} + +/************************************************************/ -- 2.38.1 From 76040803c8ae150baef449edce67ebdafb2ee896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Sun, 6 Nov 2022 11:53:24 -0300 Subject: [PATCH 02/11] dict_del_by_value: add internal definitions for python 3.11 --- src/sage/cpython/dict_internal.h | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/sage/cpython/dict_internal.h b/src/sage/cpython/dict_internal.h index 06c7a16b275..42a57bcb468 100644 --- a/src/sage/cpython/dict_internal.h +++ b/src/sage/cpython/dict_internal.h @@ -5,6 +5,8 @@ * changes. * */ +#if PY_VERSION_HEX < 0x30b0000 + /************************************************************/ /* Copied verbatim from cpython 3.8 (Objects/dict-common.h) */ /************************************************************/ @@ -163,3 +165,78 @@ dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_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 -- 2.38.1 From 014c2ac9a6f6de25d4e31fe0bdaf819e9c67d24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 06:47:18 -0300 Subject: [PATCH 03/11] deprecated uu -> base64 --- src/sage/rings/polynomial/pbori/gbrefs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 -- 2.38.1 From dc8e155994a870a5e0b01a690a3fec8975197973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 06:47:34 -0300 Subject: [PATCH 04/11] sage.misc.fpickle: fix for python 3.11 --- src/sage/misc/fpickle.pyx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx index 502080e2c10..c5d544765bb 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) -- 2.38.1 From 8b0dac2322d4a888c607c56d3b5a72ff71df4147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 08:15:43 -0300 Subject: [PATCH 05/11] Fix FullArgSpec usage after 9eb08f3afde3266bbd667e196513240a0fe245f4 - `kwonlydefaults` default is `[]` rather than `{}` - `argspec.keywords` changed to `argspec.varkw` - `ArgSpec` changed to `FullArgSpec` --- src/sage/coding/abstract_code.py | 2 +- src/sage/misc/decorators.py | 7 ++++--- src/sage/misc/sageinspect.py | 9 +++++---- 3 files changed, 10 insertions(+), 8 deletions(-) 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/misc/decorators.py b/src/sage/misc/decorators.py index 311a5105739..271e243050f 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -423,7 +423,8 @@ class suboptions(): 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 @@ -500,8 +501,8 @@ class options(): list(self.options)) defaults = (argspec.defaults or ()) + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason - return FullArgSpec(args, argspec.varargs, argspec.keywords, defaults, - kwonlyargs=[], kwonlydefaults={}, annotations={}) + return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, + kwonlyargs=[], kwonlydefaults=None, annotations={}) wrapper._sage_argspec_ = argspec diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index a3821cb56b9..ce9a74f931d 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1137,7 +1137,7 @@ def _sage_getargspec_from_ast(source): return inspect.FullArgSpec(args, vararg, kwarg, tuple(defaults) if defaults else None, - kwonlyargs=[], kwonlydefaults={}, annotations={}) + kwonlyargs=[], kwonlydefaults=None, annotations={}) def _sage_getargspec_cython(source): @@ -1683,7 +1683,8 @@ 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.FullArgSpec(args, varargs, varkw, obj.__defaults__) + return inspect.FullArgSpec(args, varargs, varkw, obj.__defaults__, + kwonlyargs=[], kwonlydefaults=None, annotations={}) except (TypeError, AttributeError): pass if isclassinstance(obj): @@ -1742,7 +1743,7 @@ def sage_getargspec(obj): except AttributeError: defaults = None return inspect.FullArgSpec(args, varargs, varkw, defaults, - kwonlyargs=[], kwonlydefaults={}, annotations={}) + kwonlyargs=[], kwonlydefaults=None, annotations={}) def formatannotation(annotation, base_module=None): @@ -1788,7 +1789,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, -- 2.38.1 From db45aebfd6bd8413bec0fda218410d72deacd398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 07:13:38 -0300 Subject: [PATCH 06/11] warnings: ignore deprecation for 'import cgi' in cython --- src/sage/all.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/all.py b/src/sage/all.py index 6aef26c42a9..92d36d1fd26 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -104,6 +104,11 @@ warnings.filterwarnings('ignore', category=DeprecationWarning, 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') + ################ end setup warnings ############################### -- 2.38.1 From 664fc008ed50c2f61fb3df3020c0d81b41170628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 20:39:12 -0300 Subject: [PATCH 07/11] warnings: ignore deprecation for 'import sre_constants' in pyparsing --- src/sage/all.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/all.py b/src/sage/all.py index 92d36d1fd26..ea0712308b4 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -109,6 +109,11 @@ 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') + ################ end setup warnings ############################### -- 2.38.1 From 08e1161c23caeeed5ad0e0237df8172eb8806ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 22:40:17 -0300 Subject: [PATCH 08/11] warnings: ignore deprecation of importlib.resources.path/read_binary --- src/sage/all.py | 6 ++++++ src/sage/repl/display/formatter.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/sage/all.py b/src/sage/all.py index ea0712308b4..fedf2a17aab 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -114,6 +114,12 @@ 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)') + ################ end setup warnings ############################### 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 @@ class SageDisplayFormatter(DisplayFormatter): 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() -- 2.38.1 From 44480f4827e2bc1ed8daf6f4504a22ae6e8be4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 07:14:01 -0300 Subject: [PATCH 09/11] doctests: fixes due to ArgSpec -> FullArgSpec change --- src/sage/interfaces/singular.py | 3 +- src/sage/libs/singular/standard_options.py | 3 +- src/sage/misc/cachefunc.pyx | 6 +- src/sage/misc/decorators.py | 9 ++- src/sage/misc/lazy_import.pyx | 4 +- src/sage/misc/sageinspect.py | 94 ++++++++++------------ src/sage/parallel/decorate.py | 3 +- src/sage/plot/plot3d/plot3d.py | 18 +++-- src/sage/sets/set_from_iterator.py | 4 +- 9 files changed, 76 insertions(+), 68 deletions(-) diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 9c9586d8bc7..1dea77cdff0 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -2734,7 +2734,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/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 72042ef13d6..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) diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index 271e243050f..dd9123f5004 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -93,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 @@ -392,7 +393,8 @@ class suboptions(): 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): @@ -460,7 +462,8 @@ class 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) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 2d4413cd1a3..018078b0cf2 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 ce9a74f931d..619ff6da661 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -109,7 +109,7 @@ defined Cython code, and with rather tricky argument lines:: 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) """ @@ -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 @@ -1159,23 +1155,23 @@ def _sage_getargspec_cython(source): 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:: @@ -1207,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: @@ -1503,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:: @@ -1546,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: @@ -1572,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={}) :: @@ -1588,13 +1584,13 @@ def sage_getargspec(obj): 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`:: @@ -1608,23 +1604,23 @@ def sage_getargspec(obj): ....: 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 @@ -1632,7 +1628,7 @@ def sage_getargspec(obj): 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:: @@ -1819,14 +1815,10 @@ def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, 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) @@ -2649,11 +2641,11 @@ def __internal_tests(): 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 c14518af570..3a7152d5ac9 100644 --- a/src/sage/parallel/decorate.py +++ b/src/sage/parallel/decorate.py @@ -243,7 +243,8 @@ for a in args[0])) ....: 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 @@ class _Coordinates(): 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 @@ class _Coordinates(): 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/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 @@ class Decorator(): 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) -- 2.38.1 From 482dd1ac3d2bcaa94dd935e3add1a5165674b146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 22:12:38 -0300 Subject: [PATCH 10/11] doctests: AssertionError message changed in python 3.11 --- src/sage/misc/lazy_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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): -- 2.38.1 From 7b6fa565f426e28e14be3b22c202301f9d530e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Mon, 31 Oct 2022 22:13:13 -0300 Subject: [PATCH 11/11] doctests: message added more info in python 3.11 --- src/sage/repl/attach.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py index 39da6ee4acd..20b848e4f04 100644 --- a/src/sage/repl/attach.py +++ b/src/sage/repl/attach.py @@ -54,6 +54,7 @@ character-by-character:: exec(code, globals) File ".../foobar.sage....py", line ..., in raise ValueError("third") # this should appear in the source snippet + ... ValueError: third sage: detach(src) """ -- 2.38.1