From b56b94655281fa7dce62fd7cb4cdbbeb18ad6b90 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Thu, 8 Aug 2024 15:24:27 -0600 Subject: [PATCH 1/3] Get the correct computed tb lineno Fix for https://github.com/python/cpython/issues/109181 introduced lazily computed lineno for traceback object in 3.11.7 and 3.12.1. Tested in a number of Python versions, the change seems to be safe. --- src/main/c/jni/org_jpy_PyLib.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/c/jni/org_jpy_PyLib.c b/src/main/c/jni/org_jpy_PyLib.c index 83c68970..a7f0b923 100644 --- a/src/main/c/jni/org_jpy_PyLib.c +++ b/src/main/c/jni/org_jpy_PyLib.c @@ -2667,7 +2667,7 @@ void PyLib_RedirectStdOut(void) static const int PYLIB_RECURSIVE_CUTOFF = 3; -#define PyLib_TraceBack_LIMIT 1024 +#define PyLib_TraceBack_LIMIT 1024 static PyObject *format_displayline(PyObject *filename, int lineno, PyObject *name) { @@ -2730,6 +2730,13 @@ static int append_to_java_message(PyObject * pyObjUtf8, char **buf, int *bufLen return 0; } +static int get_traceback_lineno(PyTracebackObject *tb) { + PyObject* po_lineno = PyObject_GetAttrString((PyObject*)tb, "tb_lineno"); + int lineno = (int)PyLong_AsLong(po_lineno); + JPy_DECREF(po_lineno); + return lineno; +} + static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLen) { int err = 0; @@ -2754,7 +2761,7 @@ static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLe PyCodeObject* co = PyFrame_GetCode(tb->tb_frame); if (last_file == NULL || co->co_filename != last_file || - last_line == -1 || tb->tb_lineno != last_line || + last_line == -1 || get_traceback_lineno(tb) != last_line || last_name == NULL || co->co_name != last_name) { if (cnt > PYLIB_RECURSIVE_CUTOFF) { pyObjUtf8 = format_line_repeated(cnt); @@ -2765,7 +2772,7 @@ static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLe } } last_file = co->co_filename; - last_line = tb->tb_lineno; + last_line = get_traceback_lineno(tb); last_name = co->co_name; cnt = 0; } @@ -2773,7 +2780,7 @@ static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLe if (err == 0 && cnt <= PYLIB_RECURSIVE_CUTOFF) { pyObjUtf8 = format_displayline( co->co_filename, - tb->tb_lineno, + get_traceback_lineno(tb), co->co_name); err = append_to_java_message(pyObjUtf8, buf, bufLen); if (err != 0) { From d5271077680cab1559b2ad321b0c384b5dd6143c Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Thu, 8 Aug 2024 16:19:42 -0600 Subject: [PATCH 2/3] Work around the breaking change in setuptools --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8d1164f3..a5846175 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -25,7 +25,7 @@ jobs: distribution: 'temurin' java-version: ${{ matrix.java }} - - run: pip install setuptools + - run: pip install "setuptools < 72" - name: Run Test run: python setup.py test From 657f5b9541348175787255fe5f34189aa191a249 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Fri, 9 Aug 2024 13:21:40 -0600 Subject: [PATCH 3/3] Minimize the number of calls to get_tb_lineno() --- src/main/c/jni/org_jpy_PyLib.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/c/jni/org_jpy_PyLib.c b/src/main/c/jni/org_jpy_PyLib.c index a7f0b923..7200c12b 100644 --- a/src/main/c/jni/org_jpy_PyLib.c +++ b/src/main/c/jni/org_jpy_PyLib.c @@ -2759,9 +2759,10 @@ static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLe } while (tb != NULL && err == 0) { PyCodeObject* co = PyFrame_GetCode(tb->tb_frame); + int tb_lineno = get_traceback_lineno(tb); if (last_file == NULL || co->co_filename != last_file || - last_line == -1 || get_traceback_lineno(tb) != last_line || + last_line == -1 || tb_lineno != last_line || last_name == NULL || co->co_name != last_name) { if (cnt > PYLIB_RECURSIVE_CUTOFF) { pyObjUtf8 = format_line_repeated(cnt); @@ -2772,7 +2773,7 @@ static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLe } } last_file = co->co_filename; - last_line = get_traceback_lineno(tb); + last_line = tb_lineno; last_name = co->co_name; cnt = 0; } @@ -2780,7 +2781,7 @@ static int format_python_traceback(PyTracebackObject *tb, char **buf, int *bufLe if (err == 0 && cnt <= PYLIB_RECURSIVE_CUTOFF) { pyObjUtf8 = format_displayline( co->co_filename, - get_traceback_lineno(tb), + tb_lineno, co->co_name); err = append_to_java_message(pyObjUtf8, buf, bufLen); if (err != 0) {