Skip to content

Commit dd70f8a

Browse files
committed
Fixes #174
1 parent 40959ab commit dd70f8a

3 files changed

Lines changed: 2405 additions & 348 deletions

File tree

.github/workflows/static_analysis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
uses: Flamefire/clang-format-lint-action@master
1111
with:
1212
source: src
13+
exclude: "src/scorepy/pythoncapi_compat.h"
1314
clangFormatVersion: 9
1415

1516
Python:

src/scorepy/pythonHelpers.cpp

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,74 @@
33
#include "pathUtils.hpp"
44
#include "pythoncapi_compat.h"
55

6+
#include <string>
67
#include <sstream>
78
#include <stdlib.h>
9+
#include <cstdio>
810

911
namespace scorepy
1012
{
13+
14+
static PyObject* get_self_from_frame(PyFrameObject* frame)
15+
{
16+
PyObject* self = nullptr;
17+
18+
#if PY_VERSION_HEX >= 0x030C0000 // Python 3.12+
19+
// Added in 3.12: directly fetch a local variable by name.
20+
self = PyFrame_GetVarString(frame, "self");
21+
if (!self && PyErr_Occurred())
22+
PyErr_Clear();
23+
#else
24+
PyObject* locals = PyFrame_GetLocals(frame); // New reference
25+
if (locals) {
26+
PyObject* tmp = PyDict_GetItemString(locals, "self"); // Borrowed
27+
if (tmp) {
28+
Py_INCREF(tmp);
29+
self = tmp;
30+
}
31+
Py_DECREF(locals);
32+
}
33+
#endif
34+
return self;
35+
}
36+
1137
std::string get_module_name(PyFrameObject& frame)
1238
{
1339
const char* self_name = nullptr;
14-
PyObject* locals = PyFrame_GetLocals(&frame);
15-
PyObject* self = PyDict_GetItemString(locals, "self");
16-
if (self)
17-
{
18-
Py_INCREF(self);
40+
41+
PyObject* self = get_self_from_frame(&frame);
42+
if (self) {
1943
PyTypeObject* type = Py_TYPE(self);
2044
self_name = _PyType_Name(type);
2145
Py_DECREF(self);
2246
}
23-
Py_DECREF(locals);
2447

25-
PyObject* globals = PyFrame_GetGlobals(&frame);
26-
PyObject* module_name = PyDict_GetItemString(globals, "__name__");
27-
Py_DECREF(globals);
28-
if (module_name)
29-
{
48+
// --- get module name from globals ---------------------------------------
49+
PyObject* globals = PyFrame_GetGlobals(&frame); // New reference
50+
PyObject* module_name = globals
51+
? PyDict_GetItemString(globals, "__name__") // Borrowed
52+
: nullptr;
53+
if (globals)
54+
Py_DECREF(globals);
55+
56+
if (module_name) {
3057
std::stringstream result;
58+
// compat::get_string_as_utf_8() is assumed to convert PyObject* → UTF-8 std::string
3159
result << compat::get_string_as_utf_8(module_name);
3260
if (self_name)
3361
result << '.' << self_name;
34-
return std::move(result).str();
62+
return result.str();
3563
}
3664

37-
// this is a NUMPY special situation, see NEP-18, and Score-P issue #63
38-
// TODO: Use string_view/C-String to avoid creating 2 std::strings
65+
// --- special-case NumPy internal frames ---------------------------------
3966
PyCodeObject* code = PyFrame_GetCode(&frame);
4067
std::string_view filename = compat::get_string_as_utf_8(code->co_filename);
4168
Py_DECREF(code);
42-
if ((filename.size() > 0) && (filename == "<__array_function__ internals>"))
43-
return std::move(std::string("numpy.__array_function__"));
44-
else
45-
return std::move(std::string("unkown"));
69+
70+
if (filename == "<__array_function__ internals>")
71+
return "numpy.__array_function__";
72+
73+
return "unknown";
4674
}
4775

4876
std::string get_file_name(PyFrameObject& frame)
@@ -57,4 +85,5 @@ std::string get_file_name(PyFrameObject& frame)
5785
const auto full_file_name = abspath(compat::get_string_as_utf_8(filename));
5886
return !full_file_name.empty() ? std::move(full_file_name) : "ErrorPath";
5987
}
88+
6089
} // namespace scorepy

0 commit comments

Comments
 (0)