33#include " pathUtils.hpp"
44#include " pythoncapi_compat.h"
55
6+ #include < cstdio>
67#include < sstream>
78#include < stdlib.h>
9+ #include < string>
810
911namespace 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+ {
27+ PyObject* tmp = PyDict_GetItemString (locals, " self" ); // Borrowed
28+ if (tmp)
29+ {
30+ Py_INCREF (tmp);
31+ self = tmp;
32+ }
33+ Py_DECREF (locals);
34+ }
35+ #endif
36+ return self;
37+ }
38+
1139std::string get_module_name (PyFrameObject& frame)
1240{
1341 const char * self_name = nullptr ;
14- PyObject* locals = PyFrame_GetLocals (&frame);
15- PyObject* self = PyDict_GetItemString (locals, " self " );
42+
43+ PyObject* self = get_self_from_frame (&frame );
1644 if (self)
1745 {
18- Py_INCREF (self);
1946 PyTypeObject* type = Py_TYPE (self);
2047 self_name = _PyType_Name (type);
2148 Py_DECREF (self);
2249 }
23- Py_DECREF (locals);
2450
25- PyObject* globals = PyFrame_GetGlobals (&frame);
26- PyObject* module_name = PyDict_GetItemString (globals, " __name__" );
27- Py_DECREF (globals);
51+ // --- get module name from globals ---------------------------------------
52+ PyObject* globals = PyFrame_GetGlobals (&frame); // New reference
53+ PyObject* module_name = globals ? PyDict_GetItemString (globals, " __name__" ) // Borrowed
54+ :
55+ nullptr ;
56+ if (globals)
57+ Py_DECREF (globals);
58+
2859 if (module_name)
2960 {
3061 std::stringstream result;
62+ // compat::get_string_as_utf_8() is assumed to convert PyObject* → UTF-8 std::string
3163 result << compat::get_string_as_utf_8 (module_name);
3264 if (self_name)
3365 result << ' .' << self_name;
34- return std::move ( result) .str ();
66+ return result.str ();
3567 }
3668
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
69+ // --- special-case NumPy internal frames ---------------------------------
3970 PyCodeObject* code = PyFrame_GetCode (&frame);
4071 std::string_view filename = compat::get_string_as_utf_8 (code->co_filename );
4172 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" ));
73+
74+ if (filename == " <__array_function__ internals>" )
75+ return " numpy.__array_function__" ;
76+
77+ return " unknown" ;
4678}
4779
4880std::string get_file_name (PyFrameObject& frame)
@@ -57,4 +89,5 @@ std::string get_file_name(PyFrameObject& frame)
5789 const auto full_file_name = abspath (compat::get_string_as_utf_8 (filename));
5890 return !full_file_name.empty () ? std::move (full_file_name) : " ErrorPath" ;
5991}
92+
6093} // namespace scorepy
0 commit comments