ATLAS Offline Software
Loading...
Searching...
No Matches
SgPyDataModel.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5
6#include "SgPyDataModel.h"
7#include "GaudiKernel/ServiceHandle.h"
8
9// Called from python, so only excuted single-threaded (GIL).
12
13const CLID PyCLID = 72785480;
14
15namespace {
16
17
18TClass* objectIsA (PyObject* obj)
19{
20 TClass* cls = nullptr;
21 PyObject* attr = PyObject_GetAttrString ((PyObject*)Py_TYPE(obj), "__cpp_name__");
22 if (attr) {
23 const char* s = PyUnicode_AsUTF8AndSize (attr, nullptr);
24 if (s) {
25 if (*s == '<') ++s;
26 if (strncmp (s, "ROOT.", 5) == 0)
27 s += 5;
28 if (strncmp (s, "cppyy.gbl.", 10) == 0)
29 s += 10;
30 cls = TClass::GetClass (s);
31 }
32 Py_XDECREF (attr);
33 }
34 PyErr_Clear();
35 return cls;
36}
37
38
39}
40
41namespace SG {
42
44 CLID clid ) :
46 m_pyObj( pyObj ),
47 m_clid ( clid ),
48 m_bib ( SG::BaseInfoBase::find(clid) )
49 {
50 // prevent Python from sweeping the rug under our feet
51 Py_INCREF( pyObj );
52 }
53
55 IRegisterTransient* /*itr*/,
56 bool /*isConst*/ )
57 {
59 // if requested type is same than myself ==> no conversion needed
60 if ( clid == m_clid ) {
61 return clid == PyCLID
62 ? m_pyObj
64 }
65 void* address = (m_clid == PyCLID)
66 ? (void*)m_pyObj
68
69 // try SG-based conversion functions
70 {
71 void* o = m_bib ? m_bib->cast(address, clid) : 0;
72 if ( o ) { return o; }
73 }
74
75 // try PyRoot based ones
76 PyObject* pytp = PyProxyMgr::instance().pytp(clid);
77 if ( !pytp ) {
78 PyErr_Format( PyExc_TypeError, "actual type of CLID %lu unknown",
79 (long unsigned int)clid );
80 return 0;
81 }
82
83 // this will be a conversion for a class instance only (see below:
84 // verified that only a CPPInstance is expected), so bind with cast
85 std::string pytpstr = RootUtils::PyGetString(pytp).first;
86 TClass* cls = TClass::GetClass (pytpstr.c_str());
87 if (!cls) {
88 PyErr_Format( PyExc_TypeError, "Can't find TClass for `%s'",
89 pytpstr.c_str() );
90 return 0;
91 }
92 TClass* act_class = cls->GetActualClass (address);
93 PyObject* value = TPython::CPPInstance_FromVoidPtr (address, act_class->GetName());
94
95 if ( value && TPython::CPPInstance_Check(value) ) {
96 return CPPInstance_ASVOIDPTR(value);
97 }
98 Py_XDECREF(value);
99#ifdef ATLAS_HAVE_CPYCPPYY
100 throw CPyCppyy::PyException();
101#else
102 throw std::runtime_error ("Python exception");
103#endif // ATLAS_HAVE_CPYCPPYY
104 return 0;
105 }
106
107 void* PyDataBucket::cast( const std::type_info& tinfo,
108 IRegisterTransient* /*itr*/,
109 bool /*isConst*/)
110 {
112 // if regular PyObject, meaningless
113 if ( m_clid == PyCLID ) {
114 return 0;
115 }
116
117 // if requested type is same than myself ==> no conversion needed
118 TClass* tcls = objectIsA (m_pyObj);
119 if ( tcls && (tinfo == *(tcls->GetTypeInfo())) ) {
121 }
122 void* address = CPPInstance_ASVOIDPTR(m_pyObj);
123
124 // try SG-based conversion functions
125 {
126 void* o = m_bib ? m_bib->cast(address, tinfo) : 0;
127 if ( o ) { return o; }
128 }
129
130 // this will be a conversion for a class instance only (see below:
131 // verified that only a CPPInstance is expected), so bind with cast
132 TClass* clsnew = TClass::GetClass (tinfo);
133 if (!clsnew) {
134 PyErr_SetString
135 ( PyExc_RuntimeError,
136 "SG::PyDataBucket::cast() can't find TClass" );
137 return 0;
138 }
139 TClass* act_class = clsnew->GetActualClass (address);
140 PyObject* value = TPython::CPPInstance_FromVoidPtr (address, act_class->GetName());
141 PyErr_Clear();
142
143 if ( value && TPython::CPPInstance_Check(value) ) {
144 return CPPInstance_ASVOIDPTR(value);
145 }
146 Py_XDECREF(value);
147 //throw PyROOT::TPyException();
148 return 0;
149 }
150
152 {
154 if (!m_pyObj) return;
155 if (!PyObject_HasAttrString (m_pyObj, "lock"))
156 return;
157 PyObject* lock = PyObject_GetAttrString (m_pyObj, "lock");
158 if (!lock) return;
159 if (PyCallable_Check (lock)) {
160 PyObject* ret = PyObject_CallObject (lock, NULL);
161 Py_DECREF (ret);
162 }
163 Py_DECREF (lock);
164 }
165
167 // PyProxyMgr
168
170 {
172 m_clids = PyDict_New();
173 m_clidSvc = 0;
174 {
175 ServiceHandle<IClassIDSvc> svc("ClassIDSvc", "SgPyDataModel");
176 if ( !svc.retrieve().isSuccess()) {
177 throw std::runtime_error
178 ("SG::PyProxyMgr: Could not retrieve ClassIDSvc");
179 }
180 m_clidSvc = svc.operator->();
181 }
182 m_dictSvc = 0;
183 {
184 ServiceHandle<IDictLoaderSvc> svc("AthDictLoaderSvc", "SgPyDataModel");
185 if ( !svc.retrieve().isSuccess()) {
186 throw std::runtime_error
187 ("SG::PyProxyMgr: Could not retrieve AthDictLoaderSvc");
188 }
189 m_dictSvc = svc.operator->();
190 }
191 }
192
194 {
195 // Don't do this if don't have a valid thread state.
196 // (With py3, the interpreter gets shut down before global dtors run...)
197 if (PyThreadState_GetUnchecked())
198 {
199 Py_DECREF(m_aliases);
200 Py_DECREF(m_clids);
201 }
202 // delete the proxy dicts...
203 for ( PyProxyMap_t::iterator
204 i = m_proxyMap.begin(),
205 iEnd = m_proxyMap.end();
206 i != iEnd;
207 ++i ) {
208 delete i->second; i->second = 0;
209 }
210 }
211
212} //< end namespace SG
#define CPPInstance_ASVOIDPTR(o)
uint32_t CLID
The Class ID type.
_object PyObject
const CLID PyCLID
Define macros for attributes used to control the static checker.
#define ATLAS_NO_CHECK_FILE_THREAD_SAFETY
The non-template portion of the BaseInfo implementation.
Interface for registering a transient object in t2p map.
PyDataBucket(PyObject *obj, CLID clid)
Constructor.
PyObject * m_pyObj
Pointer to the held pyroot object (or 'regular' PyObject).
virtual void * cast(CLID clid, IRegisterTransient *itr=0, bool isConst=true) override
Return the contents of the DataBucket, converted to type given by clid.
virtual void lock() override
If the held object derives from ILockable, call lock() on it.
CLID m_clid
The class ID of the wrapped object.
virtual const std::type_info & tinfo() const override
Return the type_info for the stored object.
const SG::BaseInfoBase * m_bib
pointer to the SG::BaseInfoBase structure holding the converter functions for objects held by StoreGa...
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:140
std::pair< std::string, bool > PyGetString(PyObject *s)
Convert python string -> C++ string for py2 and py3.
Definition PyGetString.h:40
Forward declaration.
PyObject * importDictAliases()
import the dictionary of aliases from a well known location
static PyProxyMgr & instance()
PyObject * m_aliases
a dictionary of "typedef'ed typename" -> "typename"
PyProxyMap_t m_proxyMap
IDictLoaderSvc * m_dictSvc
IClassIDSvc * m_clidSvc
PyObject * pytp(PyObject *clid)
returns a borrowed reference
PyObject * m_clids
a dictionary of 'typename' -> CLID (and reverse CLID->'typename')