33#include " pathUtils.hpp"
44#include " pythoncapi_compat.h"
55
6+ #include < string>
67#include < sstream>
78#include < stdlib.h>
9+ #include < cstdio>
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+ 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+
1137std::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
4876std::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