ATLAS Offline Software
SgPyDataModel.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 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 
13 const CLID PyCLID = 72785480;
14 
15 namespace {
16 
17 
18 TClass* 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 
41 namespace 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 
54  void* PyDataBucket::cast( CLID clid,
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) ) {
97  }
98  Py_XDECREF(value);
99  throw CPyCppyy::PyException();
100  return 0;
101  }
102 
103  void* PyDataBucket::cast( const std::type_info& tinfo,
104  IRegisterTransient* /*itr*/,
105  bool /*isConst*/)
106  {
108  // if regular PyObject, meaningless
109  if ( m_clid == PyCLID ) {
110  return 0;
111  }
112 
113  // if requested type is same than myself ==> no conversion needed
114  TClass* tcls = objectIsA (m_pyObj);
115  if ( tcls && (tinfo == *(tcls->GetTypeInfo())) ) {
117  }
119 
120  // try SG-based conversion functions
121  {
122  void* o = m_bib ? m_bib->cast(address, tinfo) : 0;
123  if ( o ) { return o; }
124  }
125 
126  // this will be a conversion for a class instance only (see below:
127  // verified that only a CPPInstance is expected), so bind with cast
128  TClass* clsnew = TClass::GetClass (tinfo);
129  if (!clsnew) {
130  PyErr_SetString
131  ( PyExc_RuntimeError,
132  "SG::PyDataBucket::cast() can't find TClass" );
133  return 0;
134  }
135  TClass* act_class = clsnew->GetActualClass (address);
136  PyObject* value = TPython::CPPInstance_FromVoidPtr (address, act_class->GetName());
137  PyErr_Clear();
138 
139  if ( value && TPython::CPPInstance_Check(value) ) {
141  }
142  Py_XDECREF(value);
143  //throw PyROOT::TPyException();
144  return 0;
145  }
146 
148  {
150  if (!m_pyObj) return;
151  if (!PyObject_HasAttrString (m_pyObj, "lock"))
152  return;
153  PyObject* lock = PyObject_GetAttrString (m_pyObj, "lock");
154  if (!lock) return;
155  if (PyCallable_Check (lock)) {
156  PyObject* ret = PyObject_CallObject (lock, NULL);
157  Py_DECREF (ret);
158  }
159  Py_DECREF (lock);
160  }
161 
163  // PyProxyMgr
164 
166  {
168  m_clids = PyDict_New();
169  m_clidSvc = 0;
170  {
171  ServiceHandle<IClassIDSvc> svc("ClassIDSvc", "SgPyDataModel");
172  if ( !svc.retrieve().isSuccess()) {
173  throw std::runtime_error
174  ("SG::PyProxyMgr: Could not retrieve ClassIDSvc");
175  }
176  m_clidSvc = svc.operator->();
177  }
178  m_dictSvc = 0;
179  {
180  ServiceHandle<IDictLoaderSvc> svc("AthDictLoaderSvc", "SgPyDataModel");
181  if ( !svc.retrieve().isSuccess()) {
182  throw std::runtime_error
183  ("SG::PyProxyMgr: Could not retrieve AthDictLoaderSvc");
184  }
185  m_dictSvc = svc.operator->();
186  }
187  }
188 
190  {
191  // Don't do this if don't have a valid thread state.
192  // (With py3, the interpreter gets shut down before global dtors run...)
193  if (_PyThreadState_UncheckedGet())
194  {
195  Py_DECREF(m_aliases);
196  Py_DECREF(m_clids);
197  }
198  // delete the proxy dicts...
200  i = m_proxyMap.begin(),
201  iEnd = m_proxyMap.end();
202  i != iEnd;
203  ++i ) {
204  delete i->second; i->second = 0;
205  }
206  }
207 
208 } //< end namespace SG
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
RootUtils::PyException
CPyCppyy::PyException PyException
Definition: Utility.h:24
SG::IRegisterTransient
Interface for registering a transient object in t2p map.
Definition: IRegisterTransient.h:28
SG::PyDataBucket::tinfo
virtual const std::type_info & tinfo() const override
Return the type_info for the stored object.
Definition: SgPyDataModel.h:158
SG::PyDataBucket::lock
virtual void lock() override
If the held object derives from ILockable, call lock() on it.
Definition: SgPyDataModel.cxx:147
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
SG::PyDataBucket::m_bib
const SG::BaseInfoBase * m_bib
pointer to the SG::BaseInfoBase structure holding the converter functions for objects held by StoreGa...
Definition: SgPyDataModel.h:185
SG
Forward declaration.
Definition: CaloCellPacker_400_500.h:32
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
SG::PyDataBucket::m_clid
CLID m_clid
The class ID of the wrapped object.
Definition: SgPyDataModel.h:181
DataBucketBase
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
Definition: DataBucketBase.h:24
SG::PyProxyMgr::m_dictSvc
IDictLoaderSvc * m_dictSvc
Definition: SgPyDataModel.h:193
CaloClusterListBadChannel.cls
cls
Definition: CaloClusterListBadChannel.py:8
athena.value
value
Definition: athena.py:122
SG::PyProxyMgr::m_aliases
PyObject * m_aliases
a dictionary of "typedef'ed typename" -> "typename"
Definition: SgPyDataModel.h:196
SG::PyDataBucket::m_pyObj
PyObject * m_pyObj
Pointer to the held pyroot object (or 'regular' PyObject)
Definition: SgPyDataModel.h:178
SG::BaseInfoBase::cast
void * cast(void *p, CLID clid) const
Cast to a base pointer.
Definition: BaseInfo.cxx:166
SgPyDataModel.h
RootUtils::PyGILStateEnsure
Definition: PyAthenaGILStateEnsure.h:20
CPPInstance_ASVOIDPTR
#define CPPInstance_ASVOIDPTR(o)
Definition: AthenaPyRoot.h:20
SG::PyDataBucket::cast
virtual void * cast(CLID clid, IRegisterTransient *itr=0, bool isConst=true) override
Return the contents of the DataBucket, converted to type given by clid.
Definition: SgPyDataModel.cxx:54
lumiFormat.i
int i
Definition: lumiFormat.py:92
RootUtils::objectIsA
TClass * objectIsA(PyObject *obj)
Definition: Utility.cxx:103
ret
T ret(T t)
Definition: rootspy.cxx:260
PyCLID
const CLID PyCLID
Definition: SgPyDataModel.cxx:13
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
CLID
uint32_t CLID
The Class ID type.
Definition: Event/xAOD/xAODCore/xAODCore/ClassID_traits.h:47
SG::PyProxyMgr::importDictAliases
PyObject * importDictAliases()
import the dictionary of aliases from a well known location
Definition: SgPyDataModel.h:369
SG::PyProxyMgr::m_proxyMap
PyProxyMap_t m_proxyMap
Definition: SgPyDataModel.h:202
SG::PyProxyMgr::m_clidSvc
IClassIDSvc * m_clidSvc
Definition: SgPyDataModel.h:194
SG::PyProxyMgr::m_clids
PyObject * m_clids
a dictionary of 'typename' -> CLID (and reverse CLID->'typename')
Definition: SgPyDataModel.h:199
SG::PyProxyMgr::PyProxyMgr
PyProxyMgr()
Definition: SgPyDataModel.cxx:165
RTTAlgmain.address
address
Definition: RTTAlgmain.py:55
RootUtils::PyGetString
std::pair< std::string, bool > PyGetString(PyObject *s)
Convert python string -> C++ string for py2 and py3.
Definition: PyGetString.h:40
ATLAS_NO_CHECK_FILE_THREAD_SAFETY
ATLAS_NO_CHECK_FILE_THREAD_SAFETY
Definition: SgPyDataModel.cxx:11
SG::PyProxyMgr::pytp
PyObject * pytp(PyObject *clid)
returns a borrowed reference
Definition: SgPyDataModel.h:238
SG::BaseInfoBase
The non-template portion of the BaseInfo implementation.
Definition: Control/AthenaKernel/AthenaKernel/BaseInfo.h:451
SG::PyProxyMgr::instance
static PyProxyMgr & instance()
Definition: SgPyDataModel.h:209
checker_macros.h
Define macros for attributes used to control the static checker.
python.PyAthena.obj
obj
Definition: PyAthena.py:135
SG::PyProxyMgr::~PyProxyMgr
~PyProxyMgr()
Definition: SgPyDataModel.cxx:189
PyObject
_object PyObject
Definition: IPyComponent.h:26
SG::PyDataBucket::PyDataBucket
PyDataBucket(PyObject *obj, CLID clid)
Constructor.
Definition: SgPyDataModel.cxx:43
ServiceHandle< IClassIDSvc >