7#define PYROOT_INSPECTOR_DBG 0
18#include "TDataMember.h"
20#include "TVirtualCollectionProxy.h"
21#include "TClassEdit.h"
27#ifdef ATLAS_HAVE_CPYCPPYY
28#include "CPyCppyy/API.h"
30#ifdef ATLAS_HAVE_CPYRT
37#define Py_True ( (PyObject*)(void*)&_Py_TrueStruct )
41#define Py_False ( (PyObject*)(void*)&_Py_ZeroStruct )
57to_pyobj(
void* ptr, EDataType mbr_dtype)
64 return Py_BuildValue(
"c", ((
char*)ptr)[0] & 0x7F);
67 return Py_BuildValue(
"i", (*(
bool*)ptr) ? 1 : 0);
70 return Py_BuildValue(
"h", (*(
short*)ptr));
73 return Py_BuildValue(
"H", (*(
unsigned short*)ptr));
77 return Py_BuildValue(
"i", (*(
int*)ptr));
80 return Py_BuildValue(
"I", (*(
unsigned int*)ptr));
84 return Py_BuildValue(
"d", (*(
double*)ptr));
88 return Py_BuildValue(
"f", (*(
float*)ptr));
91 return Py_BuildValue(
"l", (*(
long*)ptr));
94 return Py_BuildValue(
"k", (*(
unsigned long*)ptr));
97 return Py_BuildValue(
"L", (*(Long64_t*)ptr));
100 return Py_BuildValue(
"K", (*(ULong64_t*)ptr));
103 return Py_BuildValue(
"s", (*(
char**)ptr));
109 return PyUnicode_FromString(
"(UNKNOWN)");
118#if PYROOT_INSPECTOR_DBG
122 PyObject *py_str = PyObject_Str(obj);
123 std::string s = py_str && PyUnicode_Check(py_str)
124 ? PyUnicode_AsUTF8(py_str)
135 PyObject *obj = PySequence_List(pylist);
136 PyList_Append(obj, item);
148 if (!TPython::CPPInstance_Check(pyobj)) {
150 PyObject *v0 = pyobj_name; Py_INCREF(v0);
151 PyObject *v1 = pyobj; Py_XINCREF(pyobj);
152 PyTuple_SET_ITEM(val, 0, v0);
153 PyTuple_SET_ITEM(val, 1, v1);
154 PyList_Append(pystack, val);
159 static const std::unordered_set<std::string> vecnames {
161 "std::vector<float>",
163 "std::vector<double>",
166 "vector<unsigned int>",
167 "std::vector<unsigned int>",
169 "std::vector<short>",
170 "vector<unsigned short>",
171 "std::vector<unsigned short>",
174 "vector<unsigned char>",
175 "std::vector<unsigned char>",
178 "vector<unsigned long>",
179 "std::vector<unsigned long>",
181 "std::vector<long long>",
182 "vector<unsigned long long>",
183 "std::vector<unsigned long long>",
186 std::string clsname = tcls ? tcls->GetName() :
"";
188 (tcls->IsTObject() && clsname !=
"TLorentzVector") ||
189 (retvecs && vecnames.count (clsname) > 0))
193 PyObject *v0 = pyobj_name; Py_INCREF(v0);
194 PyObject *v1 = pyobj; Py_XINCREF(pyobj);
195 PyTuple_SET_ITEM(val, 0, v0);
196 PyTuple_SET_ITEM(val, 1, v1);
197 PyList_Append(pystack, val);
201 void *obj = TPython::CPPInstance_AsVoidPtr(pyobj);
203 if (clsname ==
"string") {
204 std::string *
str = (std::string*)obj;
206 PyObject *v0 = pyobj_name; Py_INCREF(v0);
208 PyTuple_SET_ITEM(val, 0, v0);
209 PyTuple_SET_ITEM(val, 1, v1);
210 PyList_Append(pystack, val);
215 if (clsname.starts_with(
"pair<") ||
216 clsname.starts_with(
"std::pair<")) {
218 PyObject *v0 = PyUnicode_FromString(
"first");
219 PyObject *v1 = PyObject_GetAttrString(pyobj,
"first");
220 PyObject *v1_name = ::new_pylist(pyobj_name, v0);
221 recurse_pyinspect(v1, v1_name, pystack, persistentOnly, retvecs);
228 PyObject *v0 = PyUnicode_FromString(
"second");
229 PyObject *v1 = PyObject_GetAttrString(pyobj,
"second");
230 PyObject *v1_name = ::new_pylist(pyobj_name, v0);
231 recurse_pyinspect(v1, v1_name, pystack, persistentOnly, retvecs);
239 if (clsname.starts_with(
"ElementLink<")) {
240 PyObject* key = PyObject_CallMethod (pyobj,
"key",
nullptr);
241 PyObject*
index = PyObject_CallMethod (pyobj,
"index",
nullptr);
243 PyObject *v0 = pyobj_name; Py_INCREF(v0);
244 PyTuple_SET_ITEM(val, 0, v0);
245 PyTuple_SET_ITEM(val, 1, key);
246 PyTuple_SET_ITEM(val, 2,
index);
247 PyList_Append(pystack, val);
252 if (clsname.starts_with(
"DataLink<")) {
253 PyObject* key = PyObject_CallMethod (pyobj,
"key",
nullptr);
255 PyObject *v0 = pyobj_name; Py_INCREF(v0);
256 PyTuple_SET_ITEM(val, 0, v0);
257 PyTuple_SET_ITEM(val, 1, key);
258 PyList_Append(pystack, val);
266 if (clsname.starts_with(
"DataVector<xAOD::")) {
267 TClassEdit::TSplitType
split (clsname.c_str());
268 if (
split.fElements.size() > 1) {
269 TClass* eltcls = TClass::GetClass (
split.fElements[1].c_str());
271 TList *members = eltcls->GetListOfDataMembers();
272 const Int_t nmembers = members ? members->GetEntries() : 0;
274 for (Int_t j = 0; j<nmembers; ++j) {
275 TDataMember *mbr = (TDataMember*)(members->At(j));
276 if (!persistentOnly || mbr->IsPersistent()) {
294#ifdef ATLAS_HAVE_CPYCPPYY
295 if (CPyCppyy::Sequence_Check(pyobj)) {
296 if (clsname ==
"CLHEP::Hep3Vector" ||
297 clsname ==
"TLorentzVector" ||
298 clsname ==
"TVector3")
308#ifdef ATLAS_HAVE_CPYRT
309 if (cppjit::cpyrt::Sequence_Check(pyobj)) {
310 if (clsname ==
"CLHEP::Hep3Vector" ||
311 clsname ==
"TLorentzVector" ||
312 clsname ==
"TVector3")
323 TList *members = tcls->GetListOfDataMembers();
325 const Int_t nmembers = members ? members->GetEntries() : 0;
327#if PYROOT_INSPECTOR_DBG
328 std::println (std::cerr,
"==[{}]== (#mbrs:{} #stl:{})...",
329 clsname, nmembers, hdr);
334#if PYROOT_INSPECTOR_DBG
336 const Py_ssize_t nelems = PySequence_Size(pyobj);
337 std::println (std::cerr,
"== sequence ({})...", nelems);
349 Py_ssize_t nelems = PySequence_Size(pyobj);
352 if (clsname ==
"TileCellVec" ||
353 clsname ==
"vector<char>" ||
354 clsname ==
"vector<signed char>")
356 for (Py_ssize_t i = 0; i < nelems; ++i) {
357 PyObject *pyidx = PyLong_FromLong(i);
358 PyObject *itr = PySequence_GetItem(pyobj, i);
359 PyObject *itr_name = ::new_pylist(pyobj_name, pyidx);
360 recurse_pyinspect(itr, itr_name, pystack, persistentOnly, retvecs);
361 Py_XDECREF(itr_name);
367 PyObject* iter = PyObject_GetIter(pyobj);
374 while (nelems-- && (item = PyIter_Next(iter))) {
375 PyObject *pyidx = PyLong_FromLong(i++);
376 PyObject *itr_name = ::new_pylist(pyobj_name, pyidx);
377 recurse_pyinspect(item, itr_name, pystack, persistentOnly, retvecs);
378 Py_XDECREF(itr_name);
387#if PYROOT_INSPECTOR_DBG
388 std::println (std::cerr,
"== sequence ({})... [done]", nelems);
393 for (Int_t j = 0; j<nmembers; ++j) {
394 TDataMember *mbr = (TDataMember*)(members->At(j));
395 if (mbr->Property() & kIsStatic)
continue;
396 Int_t offset = mbr->GetOffset();
397 char *ptr = (
char*)obj + offset;
399#if PYROOT_INSPECTOR_DBG
400 TClass *mbr_cls = TClass::GetClass(mbr->GetTypeName());
401 std::println (std::cerr,
"==[{}] - [{}] [{}][{}]",
402 j, mbr->GetTypeName(), mbr->GetName(),
403 (mbr_cls ? mbr_cls->GetName() :
"N/A"));
409 if (persistentOnly && !mbr->IsPersistent())
411 if (mbr->IsaPointer() || std::string(mbr->GetTypeName()).starts_with(
"unique_ptr")
412 || std::string(mbr->GetTypeName()).starts_with(
"shared_ptr") )
414 if (mbr->IsBasic()) {
415 TDataType * mbr_type = mbr->GetDataType();
416 EDataType mbr_dtype = (EDataType)mbr_type->GetType();
417 py_mbr_name = PyUnicode_FromString(mbr->GetName());
418 py_mbr = to_pyobj(ptr, mbr_dtype);
419 }
else if (mbr->IsEnum()) {
420#if PYROOT_INSPECTOR_DBG
421 std::println (std::cerr,
"==[{}][{}][val={}][{}] is an enum !!",
422 mbr->GetTypeName(), mbr->GetDataType()->GetType(),
423 *
reinterpret_cast<int*
>(ptr), mbr->GetName());
425 py_mbr_name = PyUnicode_FromString(mbr->GetName());
426 py_mbr = to_pyobj(ptr, kInt_t);
428 py_mbr_name = PyUnicode_FromString(mbr->GetName());
429 py_mbr = TPython::CPPInstance_FromVoidPtr((
void*)ptr,
433 if (!py_mbr || !py_mbr_name) {
434 std::println (std::cerr,
"could not create py-object of type [{}] !",
437 Py_XDECREF(py_mbr_name);
441 PyObject *this_name = ::new_pylist(pyobj_name, py_mbr_name);
442 recurse_pyinspect(py_mbr, this_name, pystack, persistentOnly, retvecs);
443 Py_DECREF(this_name);
444 Py_DECREF(py_mbr_name);
449#if PYROOT_INSPECTOR_DBG
450 std::println (std::cerr,
"==[{}]== (#mbrs:{})... [done]",
451 tcls->GetName(), nmembers);
463 bool persistentOnly )
466 if (!TPython::CPPInstance_Check(pyobj)) {
476 void *obj = TPython::CPPInstance_AsVoidPtr(pyobj);
478 if (!strcmp(tcls->GetName(),
"string")) {
479 std::string *
str = (std::string*)obj;
480 return PyUnicode_FromString(
str->c_str());
483 TString tstring = tcls->GetName();
484 if (tstring.BeginsWith(
"pair<") ||
485 tstring.BeginsWith(
"std::pair<")) {
487 PyObject *v0 = PyObject_GetAttrString(pyobj,
"first");
488 PyObject *v1 = PyObject_GetAttrString(pyobj,
"second");
497#ifdef ATLAS_HAVE_CPYCPPYY
498 if (CPyCppyy::Sequence_Check(pyobj)) {
499 if (!strcmp(tcls->GetName(),
"CLHEP::Hep3Vector")) {
508#ifdef ATLAS_HAVE_CPYCRT
509 if (cppjit::cpyrt::Sequence_Check(pyobj)) {
510 if (!strcmp(tcls->GetName(),
"CLHEP::Hep3Vector")) {
520 TList *members = tcls->GetListOfDataMembers();
521 const Int_t nmembers = members->GetEntries();
523 PyObject *py_members = PyList_New(nmembers+hdr);
524#if PYROOT_INSPECTOR_DBG
525 std::println (std::cerr,
"==[{}]== (#mbrs:{} #stl:{} #py-sz:{})...",
526 tcls->GetName(), nmembers, hdr, PyList_Size(py_members));
531 const Py_ssize_t nelems = PySequence_Size(pyobj);
532#if PYROOT_INSPECTOR_DBG
533 std::println (std::cerr,
"== sequence ({})...", nelems);
535 PyObject *py_elems = PyList_New(nelems);
536 for (Py_ssize_t i = 0; i < nelems; ++i) {
537 PyObject *itr = PySequence_GetItem(pyobj, i);
539 PyList_SET_ITEM(py_elems, i, itr_pyroot);
544 PyList_SET_ITEM(py_members, 0, py_elems);
545#if PYROOT_INSPECTOR_DBG
546 std::println (std::cerr,
"== sequence ({})... content:\n{}",
547 nelems, ::to_str(py_elems));
548 std::println (std::cerr,
"== sequence ({})... [done]", nelems);
553 for (Int_t j = 0; j<nmembers; ++j) {
554 TDataMember *mbr = (TDataMember*)(members->At(j));
555 Int_t offset = mbr->GetOffset();
556 char *ptr = (
char*)obj + offset;
558#if PYROOT_INSPECTOR_DBG
559 TClass *mbr_cls = TClass::GetClass(mbr->GetTypeName());
560 std::println (std::cerr,
"==[{}] - [{}] [{}][{}]",
561 j, mbr->GetTypeName(), mbr->GetName(),
562 (mbr_cls ? mbr_cls->GetName() :
"N/A"));
567 if (persistentOnly && !mbr->IsPersistent())
569 if (mbr->IsaPointer())
571 if (mbr->IsBasic()) {
572 TDataType * mbr_type = mbr->GetDataType();
573 EDataType mbr_dtype = (EDataType)mbr_type->GetType();
574 py_mbr = to_pyobj(ptr, mbr_dtype);
575 }
else if (mbr->IsEnum()) {
576#if PYROOT_INSPECTOR_DBG
577 std::println (std::cerr,
"==[{}][{}][val=][{}] is an enum !!",
578 mbr->GetTypeName(), mbr->GetDataType()->GetType(),
579 *
reinterpret_cast<int*
>(ptr), mbr->GetName());
581 py_mbr = to_pyobj(ptr, kInt_t);
583 PyObject *pyroot_obj = TPython::CPPInstance_FromVoidPtr
589 Py_XDECREF(pyroot_obj);
592 std::println (std::cerr,
"could not create py-object of type [{}] !",
594 Py_DECREF(py_members);
599 PyTuple_SET_ITEM(py_item, 0,
600 PyUnicode_FromString(mbr->GetName()));
601 PyTuple_SET_ITEM(py_item, 1, py_mbr);
602 PyList_SET_ITEM(py_members, j+hdr, py_item);
604#if PYROOT_INSPECTOR_DBG
605 std::println (std::cerr,
"==[{}]== (#mbrs:{})... [done]",
606 tcls->GetName(), nmembers);
614 bool persistentOnly ,
618 ::recurse_pyinspect(pyobj, pyobj_name, pystack, persistentOnly, retvecs);
Utility code originally from pyroot.
Define macros for attributes used to control the static checker.
#define ATLAS_NO_CHECK_FILE_THREAD_SAFETY
static PyObject * pyroot_inspect(PyObject *obj, bool persistentOnly=false)
static PyObject * pyroot_inspect2(PyObject *obj, PyObject *obj_name, bool persistentOnly=false, bool retvecs=false)
std::vector< std::string > split(const std::string &s, const std::string &t=":")
TClass * objectIsA(PyObject *obj)