From ab8a3c66353b8338ceed09a262c4af964eb54fd6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 26 Jan 2022 20:00:55 -0800 Subject: [PATCH 1/8] make it exist --- Doc/library/sys.rst | 20 ++++++++ .../2022-01-26-20-00-45.bpo-46543.oIulvu.rst | 1 + Python/clinic/sysmodule.c.h | 48 ++++++++++++++++++- Python/sysmodule.c | 44 +++++++++++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 5e47201f88eae1..c6fafc15605ef4 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -758,6 +758,26 @@ always available. It is not guaranteed to exist in all implementations of Python. +.. function:: _getfunc(depth=1) + + Return a function object from the call stack. If optional integer *depth* is + positive, return the function object that many calls below the top of the stack. If + that is deeper than the call stack, :exc:`ValueError` is raised. If + *depth* is zero, the function returns the currently executing function. + + Unlike the similar :func:`_getframe`, this does not create a frame object + when called, making it less expensive to call. + + .. versionadded:: 3.11 + + .. audit-event:: sys._getfunc "" sys._getfunc + + .. impl-detail:: + + This function should be used for internal and specialized purposes only. + It is not guaranteed to exist in all implementations of Python. + + .. function:: getprofile() .. index:: diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst new file mode 100644 index 00000000000000..b41c09824d6fbb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst @@ -0,0 +1 @@ +Add :func:`sys._getfunc`. Patch by Jelle Zijlstra. diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index ce5390c8a1e588..127087424bbb93 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -787,6 +787,52 @@ sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +PyDoc_STRVAR(sys__getfunc__doc__, +"_getfunc($module, depth=1, /)\n" +"--\n" +"\n" +"Return a function object from the call stack.\n" +"\n" +"If optional integer depth is 1 or more, return the function object that many\n" +"calls below the top of the stack. If that is deeper than the call\n" +"stack, ValueError is raised. If depth is 0, return the current function\n" +"object.\n" +"\n" +"This is similar to sys._getframe() but cheaper because it does not\n" +"create a full frame object.\n" +"\n" +"This function should be used for internal and specialized purposes\n" +"only."); + +#define SYS__GETFUNC_METHODDEF \ + {"_getfunc", (PyCFunction)(void(*)(void))sys__getfunc, METH_FASTCALL, sys__getfunc__doc__}, + +static PyObject * +sys__getfunc_impl(PyObject *module, int depth); + +static PyObject * +sys__getfunc(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int depth = 1; + + if (!_PyArg_CheckPositional("_getfunc", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + depth = _PyLong_AsInt(args[0]); + if (depth == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional: + return_value = sys__getfunc_impl(module, depth); + +exit: + return return_value; +} + PyDoc_STRVAR(sys__getframe__doc__, "_getframe($module, depth=0, /)\n" "--\n" @@ -1014,4 +1060,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=60756bc6f683e0c8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=357e73ba2ac2bcc7 input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 7597ea2ea9e495..01c0aa1d34e735 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1799,6 +1799,49 @@ sys_getallocatedblocks_impl(PyObject *module) } +/*[clinic input] +sys._getfunc + + depth: int = 1 + / + +Return a function object from the call stack. + +If optional integer depth is 1 or more, return the function object that many +calls below the top of the stack. If that is deeper than the call +stack, ValueError is raised. If depth is 0, return the current function +object. + +This is similar to sys._getframe() but cheaper because it does not +create a full frame object. + +This function should be used for internal and specialized purposes +only. +[clinic start generated code]*/ + +static PyObject * +sys__getfunc_impl(PyObject *module, int depth) +/*[clinic end generated code: output=6a4f9e993f6c96d1 input=3c79a6f4642a5ba5]*/ +{ + PyThreadState *tstate = _PyThreadState_GET(); + InterpreterFrame *frame = tstate->cframe->current_frame; + + if (_PySys_Audit(tstate, "sys._getfunc", NULL) < 0) { + return NULL; + } + + while (depth > 0 && frame != NULL) { + frame = frame->previous; + --depth; + } + if (frame == NULL) { + _PyErr_SetString(tstate, PyExc_ValueError, + "call stack is not deep enough"); + return NULL; + } + return _Py_XNewRef(frame->f_func); +} + /*[clinic input] sys._getframe @@ -2007,6 +2050,7 @@ static PyMethodDef sys_methods[] = { {"getsizeof", (PyCFunction)(void(*)(void))sys_getsizeof, METH_VARARGS | METH_KEYWORDS, getsizeof_doc}, SYS__GETFRAME_METHODDEF + SYS__GETFUNC_METHODDEF SYS_GETWINDOWSVERSION_METHODDEF SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF SYS_INTERN_METHODDEF From adb735f8874ec344c6fbd4bb2925ebe67fffb6f9 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 26 Jan 2022 20:02:58 -0800 Subject: [PATCH 2/8] basic test --- Lib/test/test_sys.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 41c4618ad10d40..a7deb4794ad5be 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -399,6 +399,11 @@ def test_getframe(self): is sys._getframe().f_code ) + def test_getfunc(self): + self.assertRaises(TypeError, sys._getfunc, 42, 42) + self.assertRaises(ValueError, sys._getfunc, 2000000000) + self.assertIs(SysModuleTest.test_getfunc, sys._getfunc(0)) + # sys._current_frames() is a CPython-only gimmick. @threading_helper.reap_threads def test_current_frames(self): From a79fe75f9e57777191d200a48c0d5103649a9ae2 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 26 Jan 2022 20:11:07 -0800 Subject: [PATCH 3/8] more tests --- Lib/test/sys_getfunc.py | 3 +++ Lib/test/test_sys.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 Lib/test/sys_getfunc.py diff --git a/Lib/test/sys_getfunc.py b/Lib/test/sys_getfunc.py new file mode 100644 index 00000000000000..7d4b02b23c4962 --- /dev/null +++ b/Lib/test/sys_getfunc.py @@ -0,0 +1,3 @@ +import sys + +func = sys._getfunc(0) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index a7deb4794ad5be..007c54cfa3907d 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -404,6 +404,22 @@ def test_getfunc(self): self.assertRaises(ValueError, sys._getfunc, 2000000000) self.assertIs(SysModuleTest.test_getfunc, sys._getfunc(0)) + def save_parent(): + return sys._getfunc() + + self.assertIs(SysModuleTest.test_getfunc, save_parent()) + + class X: + func = sys._getfunc(0) + func2 = save_parent() + + self.assertEqual(X.func.__name__, "X") + self.assertIs(X.func, X.func2) + + from test import sys_getfunc + + self.assertEqual(sys_getfunc.func.__name__, "") + # sys._current_frames() is a CPython-only gimmick. @threading_helper.reap_threads def test_current_frames(self): From 1cf14c5c7cb9734b5b6278aa645e6ac8f9926ad9 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 26 Jan 2022 20:16:34 -0800 Subject: [PATCH 4/8] replace some callsites --- Lib/collections/__init__.py | 6 +++--- Lib/doctest.py | 2 +- Lib/enum.py | 2 +- Lib/typing.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index fa8b30985a4350..9408f8edc6f1c3 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -490,12 +490,12 @@ def __getnewargs__(self): # For pickling to work, the __module__ variable needs to be set to the frame # where the named tuple is created. Bypass this step in environments where - # sys._getframe is not defined (Jython for example) or sys._getframe is not - # defined for arguments greater than 0 (IronPython), or where the user has + # sys._getfunc is not defined or sys._getfunc is not + # defined for arguments greater than 0, or where the user has # specified a particular module. if module is None: try: - module = _sys._getframe(1).f_globals.get('__name__', '__main__') + module = _sys._getfunc(1).__globals__.get('__name__', '__main__') except (AttributeError, ValueError): pass if module is not None: diff --git a/Lib/doctest.py b/Lib/doctest.py index 4735b59852685c..02f35be057b3e3 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -207,7 +207,7 @@ def _normalize_module(module, depth=2): elif isinstance(module, str): return __import__(module, globals(), locals(), ["*"]) elif module is None: - return sys.modules[sys._getframe(depth).f_globals['__name__']] + return sys.modules[sys._getfunc(depth).__globals__['__name__']] else: raise TypeError("Expected a module, string, or None") diff --git a/Lib/enum.py b/Lib/enum.py index 85245c95f9a9c7..460d4a86b3c8a2 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -904,7 +904,7 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s # module is ever developed if module is None: try: - module = sys._getframe(2).f_globals['__name__'] + module = sys._getfunc(2).__globals__['__name__'] except (AttributeError, ValueError, KeyError): pass if module is None: diff --git a/Lib/typing.py b/Lib/typing.py index 450cd7b51184ef..441c2ea5e43e4f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1436,8 +1436,8 @@ def _no_init_or_replace_init(self, *args, **kwargs): def _caller(depth=1, default='__main__'): try: - return sys._getframe(depth + 1).f_globals.get('__name__', default) - except (AttributeError, ValueError): # For platforms without _getframe() + return sys._getfunc(depth + 1).__globals__.get('__name__', default) + except (AttributeError, ValueError): # For platforms without _getfunc() return None From b7245ae2d2dfec9febd086dd5b2c904def20c67c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 26 Jan 2022 20:41:33 -0800 Subject: [PATCH 5/8] cast --- Python/sysmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 01c0aa1d34e735..6ccb26df4adaa6 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1839,7 +1839,7 @@ sys__getfunc_impl(PyObject *module, int depth) "call stack is not deep enough"); return NULL; } - return _Py_XNewRef(frame->f_func); + return _Py_XNewRef((PyObject *)frame->f_func); } /*[clinic input] From 0fa97c2006bdd0f3e5bcfb74540078cebfa76674 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 7 Feb 2022 22:23:17 -0800 Subject: [PATCH 6/8] rename it --- Doc/library/sys.rst | 4 ++-- Lib/collections/__init__.py | 4 ++-- Lib/doctest.py | 2 +- Lib/enum.py | 2 +- Lib/test/sys_getcaller.py | 3 +++ Lib/test/sys_getfunc.py | 3 --- Lib/test/test_sys.py | 18 +++++++++--------- Lib/typing.py | 4 ++-- .../2022-01-26-20-00-45.bpo-46543.oIulvu.rst | 2 +- Python/clinic/sysmodule.c.h | 8 ++++---- Python/sysmodule.c | 4 ++-- 11 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 Lib/test/sys_getcaller.py delete mode 100644 Lib/test/sys_getfunc.py diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index c6fafc15605ef4..2ec846b2d8a0ab 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -758,7 +758,7 @@ always available. It is not guaranteed to exist in all implementations of Python. -.. function:: _getfunc(depth=1) +.. function:: _getcaller(depth=1) Return a function object from the call stack. If optional integer *depth* is positive, return the function object that many calls below the top of the stack. If @@ -770,7 +770,7 @@ always available. .. versionadded:: 3.11 - .. audit-event:: sys._getfunc "" sys._getfunc + .. audit-event:: sys._getcaller "" sys._getcaller .. impl-detail:: diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index 9408f8edc6f1c3..2911ac00de0f05 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -490,12 +490,12 @@ def __getnewargs__(self): # For pickling to work, the __module__ variable needs to be set to the frame # where the named tuple is created. Bypass this step in environments where - # sys._getfunc is not defined or sys._getfunc is not + # sys._getcaller is not defined or sys._getcaller is not # defined for arguments greater than 0, or where the user has # specified a particular module. if module is None: try: - module = _sys._getfunc(1).__globals__.get('__name__', '__main__') + module = _sys._getcaller(1).__globals__.get('__name__', '__main__') except (AttributeError, ValueError): pass if module is not None: diff --git a/Lib/doctest.py b/Lib/doctest.py index 02f35be057b3e3..5df59333887d15 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -207,7 +207,7 @@ def _normalize_module(module, depth=2): elif isinstance(module, str): return __import__(module, globals(), locals(), ["*"]) elif module is None: - return sys.modules[sys._getfunc(depth).__globals__['__name__']] + return sys.modules[sys._getcaller(depth).__globals__['__name__']] else: raise TypeError("Expected a module, string, or None") diff --git a/Lib/enum.py b/Lib/enum.py index 460d4a86b3c8a2..94eed268440f12 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -904,7 +904,7 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s # module is ever developed if module is None: try: - module = sys._getfunc(2).__globals__['__name__'] + module = sys._getcaller(2).__globals__['__name__'] except (AttributeError, ValueError, KeyError): pass if module is None: diff --git a/Lib/test/sys_getcaller.py b/Lib/test/sys_getcaller.py new file mode 100644 index 00000000000000..b8962180c2e59e --- /dev/null +++ b/Lib/test/sys_getcaller.py @@ -0,0 +1,3 @@ +import sys + +func = sys._getcaller(0) diff --git a/Lib/test/sys_getfunc.py b/Lib/test/sys_getfunc.py deleted file mode 100644 index 7d4b02b23c4962..00000000000000 --- a/Lib/test/sys_getfunc.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys - -func = sys._getfunc(0) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 007c54cfa3907d..8a143746496f1b 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -399,26 +399,26 @@ def test_getframe(self): is sys._getframe().f_code ) - def test_getfunc(self): - self.assertRaises(TypeError, sys._getfunc, 42, 42) - self.assertRaises(ValueError, sys._getfunc, 2000000000) - self.assertIs(SysModuleTest.test_getfunc, sys._getfunc(0)) + def test_getcaller(self): + self.assertRaises(TypeError, sys._getcaller, 42, 42) + self.assertRaises(ValueError, sys._getcaller, 2000000000) + self.assertIs(SysModuleTest.test_getcaller, sys._getcaller(0)) def save_parent(): - return sys._getfunc() + return sys._getcaller(1) - self.assertIs(SysModuleTest.test_getfunc, save_parent()) + self.assertIs(SysModuleTest.test_getcaller, save_parent()) class X: - func = sys._getfunc(0) + func = sys._getcaller(0) func2 = save_parent() self.assertEqual(X.func.__name__, "X") self.assertIs(X.func, X.func2) - from test import sys_getfunc + from test import sys_getcaller - self.assertEqual(sys_getfunc.func.__name__, "") + self.assertEqual(sys_getcaller.func.__name__, "") # sys._current_frames() is a CPython-only gimmick. @threading_helper.reap_threads diff --git a/Lib/typing.py b/Lib/typing.py index 441c2ea5e43e4f..7022206522933d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1436,8 +1436,8 @@ def _no_init_or_replace_init(self, *args, **kwargs): def _caller(depth=1, default='__main__'): try: - return sys._getfunc(depth + 1).__globals__.get('__name__', default) - except (AttributeError, ValueError): # For platforms without _getfunc() + return sys._getcaller(depth + 1).__globals__.get('__name__', default) + except (AttributeError, ValueError): # For platforms without _getcaller() return None diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst index b41c09824d6fbb..136f2a7ccba342 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-01-26-20-00-45.bpo-46543.oIulvu.rst @@ -1 +1 @@ -Add :func:`sys._getfunc`. Patch by Jelle Zijlstra. +Add :func:`sys._getcaller`. Patch by Jelle Zijlstra. diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 127087424bbb93..5ed900b4b29d80 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -788,7 +788,7 @@ sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(sys__getfunc__doc__, -"_getfunc($module, depth=1, /)\n" +"_getcaller($module, depth=1, /)\n" "--\n" "\n" "Return a function object from the call stack.\n" @@ -805,18 +805,18 @@ PyDoc_STRVAR(sys__getfunc__doc__, "only."); #define SYS__GETFUNC_METHODDEF \ - {"_getfunc", (PyCFunction)(void(*)(void))sys__getfunc, METH_FASTCALL, sys__getfunc__doc__}, + {"_getcaller", (PyCFunction)(void(*)(void))sys__getcaller, METH_FASTCALL, sys__getfunc__doc__}, static PyObject * sys__getfunc_impl(PyObject *module, int depth); static PyObject * -sys__getfunc(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +sys__getcaller(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int depth = 1; - if (!_PyArg_CheckPositional("_getfunc", nargs, 0, 1)) { + if (!_PyArg_CheckPositional("_getcaller", nargs, 0, 1)) { goto exit; } if (nargs < 1) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 6ccb26df4adaa6..b7180960b807f4 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1800,7 +1800,7 @@ sys_getallocatedblocks_impl(PyObject *module) /*[clinic input] -sys._getfunc +sys._getcaller depth: int = 1 / @@ -1826,7 +1826,7 @@ sys__getfunc_impl(PyObject *module, int depth) PyThreadState *tstate = _PyThreadState_GET(); InterpreterFrame *frame = tstate->cframe->current_frame; - if (_PySys_Audit(tstate, "sys._getfunc", NULL) < 0) { + if (_PySys_Audit(tstate, "sys._getcaller", NULL) < 0) { return NULL; } From 6b060f1b4be40ac77901eb1129b26745da391c36 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 8 Feb 2022 06:44:09 -0800 Subject: [PATCH 7/8] adjust docs and default --- Doc/library/sys.rst | 13 +++++++------ Python/sysmodule.c | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 2ec846b2d8a0ab..1c08e5b18ed103 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -750,6 +750,10 @@ always available. that is deeper than the call stack, :exc:`ValueError` is raised. The default for *depth* is zero, returning the frame at the top of the call stack. + Unlike the similar :func:`_getcaller` (new in Python 3.11), this returns a + full frame object, making it more expensive to execute and harder to port + to alternative implementations of Python. + .. audit-event:: sys._getframe "" sys._getframe .. impl-detail:: @@ -758,15 +762,12 @@ always available. It is not guaranteed to exist in all implementations of Python. -.. function:: _getcaller(depth=1) +.. function:: _getcaller([depth]) Return a function object from the call stack. If optional integer *depth* is positive, return the function object that many calls below the top of the stack. If - that is deeper than the call stack, :exc:`ValueError` is raised. If - *depth* is zero, the function returns the currently executing function. - - Unlike the similar :func:`_getframe`, this does not create a frame object - when called, making it less expensive to call. + that is deeper than the call stack, :exc:`ValueError` is raised. The default + for *depth* is zero, returning the currently executing function. .. versionadded:: 3.11 diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b7180960b807f4..77eed729482ee2 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1802,7 +1802,7 @@ sys_getallocatedblocks_impl(PyObject *module) /*[clinic input] sys._getcaller - depth: int = 1 + depth: int = 0 / Return a function object from the call stack. @@ -1812,9 +1812,6 @@ calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. If depth is 0, return the current function object. -This is similar to sys._getframe() but cheaper because it does not -create a full frame object. - This function should be used for internal and specialized purposes only. [clinic start generated code]*/ @@ -1855,6 +1852,10 @@ calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default for depth is zero, returning the frame at the top of the call stack. +Unlike the similar sys._getcaller, this returns a full frame object, +making it more expensive to execute and harder to port to alternative +implementations of Python. + This function should be used for internal and specialized purposes only. [clinic start generated code]*/ From b7985d538e7c697335680c3beb95da611e1c1dd1 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 8 Feb 2022 06:57:08 -0800 Subject: [PATCH 8/8] fix argument clinic --- Python/clinic/sysmodule.c.h | 23 ++++++++++++----------- Python/sysmodule.c | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 5ed900b4b29d80..7f8e2d570b3373 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -787,8 +787,8 @@ sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } -PyDoc_STRVAR(sys__getfunc__doc__, -"_getcaller($module, depth=1, /)\n" +PyDoc_STRVAR(sys__getcaller__doc__, +"_getcaller($module, depth=0, /)\n" "--\n" "\n" "Return a function object from the call stack.\n" @@ -798,23 +798,20 @@ PyDoc_STRVAR(sys__getfunc__doc__, "stack, ValueError is raised. If depth is 0, return the current function\n" "object.\n" "\n" -"This is similar to sys._getframe() but cheaper because it does not\n" -"create a full frame object.\n" -"\n" "This function should be used for internal and specialized purposes\n" "only."); -#define SYS__GETFUNC_METHODDEF \ - {"_getcaller", (PyCFunction)(void(*)(void))sys__getcaller, METH_FASTCALL, sys__getfunc__doc__}, +#define SYS__GETCALLER_METHODDEF \ + {"_getcaller", (PyCFunction)(void(*)(void))sys__getcaller, METH_FASTCALL, sys__getcaller__doc__}, static PyObject * -sys__getfunc_impl(PyObject *module, int depth); +sys__getcaller_impl(PyObject *module, int depth); static PyObject * sys__getcaller(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - int depth = 1; + int depth = 0; if (!_PyArg_CheckPositional("_getcaller", nargs, 0, 1)) { goto exit; @@ -827,7 +824,7 @@ sys__getcaller(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: - return_value = sys__getfunc_impl(module, depth); + return_value = sys__getcaller_impl(module, depth); exit: return return_value; @@ -844,6 +841,10 @@ PyDoc_STRVAR(sys__getframe__doc__, "stack, ValueError is raised. The default for depth is zero, returning\n" "the frame at the top of the call stack.\n" "\n" +"Unlike the similar sys._getcaller, this returns a full frame object,\n" +"making it more expensive to execute and harder to port to alternative\n" +"implementations of Python.\n" +"\n" "This function should be used for internal and specialized purposes\n" "only."); @@ -1060,4 +1061,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=357e73ba2ac2bcc7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32a5bed6e0473b5d input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 917754facb9961..b656369d4710cc 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1817,8 +1817,8 @@ only. [clinic start generated code]*/ static PyObject * -sys__getfunc_impl(PyObject *module, int depth) -/*[clinic end generated code: output=6a4f9e993f6c96d1 input=3c79a6f4642a5ba5]*/ +sys__getcaller_impl(PyObject *module, int depth) +/*[clinic end generated code: output=250f47adb2372e4a input=242cb11f8e6d7a60]*/ { PyThreadState *tstate = _PyThreadState_GET(); InterpreterFrame *frame = tstate->cframe->current_frame; @@ -1862,7 +1862,7 @@ only. static PyObject * sys__getframe_impl(PyObject *module, int depth) -/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/ +/*[clinic end generated code: output=d438776c04d59804 input=a57ecc9db9b721ad]*/ { PyThreadState *tstate = _PyThreadState_GET(); InterpreterFrame *frame = tstate->cframe->current_frame; @@ -2051,7 +2051,7 @@ static PyMethodDef sys_methods[] = { {"getsizeof", (PyCFunction)(void(*)(void))sys_getsizeof, METH_VARARGS | METH_KEYWORDS, getsizeof_doc}, SYS__GETFRAME_METHODDEF - SYS__GETFUNC_METHODDEF + SYS__GETCALLER_METHODDEF SYS_GETWINDOWSVERSION_METHODDEF SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF SYS_INTERN_METHODDEF