From d87a60c54453763476845138133ad7da54c159a7 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 24 Mar 2025 10:38:12 +0700 Subject: [PATCH 1/2] Safeguard _sage_getargspec_cython --- This patch was taken from: https://github.com/sagemath/sage/pull/39776 It will be released in version 10.7 and can be removed after the upgrade. src/sage/misc/sageinspect.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 6fc0e29551f..d25f1f81820 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1139,6 +1139,11 @@ def _sage_getargspec_cython(source): defaults=('a string', {(1, 2, 3): True}), kwonlyargs=[], kwonlydefaults=None, annotations={}) """ + if not isinstance(source, str): + # the caller ought to ensure this, but if it forgets (e.g. passing None), + # we raise the correct exception type to avoid confusing error message + # and possible further hard-to-debug errors, see :issue:`39735` + raise TypeError defpos = source.find('def ') assert defpos > -1, "The given source does not contain 'def'" s = source[defpos:].strip() From 21dd8224fca8a70490c754309350d08f56178809 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 27 Mar 2025 22:58:22 +0700 Subject: [PATCH 2/2] Change to AssertionError and handle issue upstream --- src/sage/misc/sageinspect.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index b617e288b97..bb704d74075 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1140,11 +1140,10 @@ def _sage_getargspec_cython(source): defaults=('a string', {(1, 2, 3): True}), kwonlyargs=[], kwonlydefaults=None, annotations={}) """ - if not isinstance(source, str): - # the caller ought to ensure this, but if it forgets (e.g. passing None), - # we raise the correct exception type to avoid confusing error message - # and possible further hard-to-debug errors, see :issue:`39735` - raise TypeError + assert isinstance(source, str) + # the caller ought to ensure this, but if it forgets (e.g. passing None), + # we avoid raising AttributeError to avoid confusing error message + # and possible further hard-to-debug errors, see :issue:`39735` defpos = source.find('def ') assert defpos > -1, "The given source does not contain 'def'" s = source[defpos:].strip() @@ -1682,12 +1681,15 @@ 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.FullArgSpec(*_sage_getargspec_cython(sage_getsource(obj))) + source = sage_getsource(obj) except TypeError: # This happens for Python builtins - # The best we can do is to return a generic argspec - args = [] - varargs = 'args' - varkw = 'kwds' + source = None + if source is not None: + return inspect.FullArgSpec(*_sage_getargspec_cython(source)) + # The best we can do is to return a generic argspec + args = [] + varargs = 'args' + varkw = 'kwds' try: defaults = func_obj.__defaults__ except AttributeError: