ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
Control
AthenaPython
src
PyComponentMgr.cxx
Go to the documentation of this file.
1
2
3
/*
4
Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
5
*/
6
7
// PyComponentMgr.cxx
8
// Implementation file for class PyComponentMgr
9
// Author: S.Binet<binet@cern.ch>
10
// Modified: Wim Lavrijsen <WLavrijsen@lbl.gov>
12
13
// Python includes
14
#include "Python.h"
15
16
#include "
AthenaKernel/CLASS_DEF.h
"
17
CLASS_DEF
(
PyObject
, 72785480, 1)
18
19
// AthenaPython includes
20
#include "PyComponentMgr.h"
21
#include "
RootUtils/PyAthenaGILStateEnsure.h
"
22
23
// STL includes
24
25
// FrameWork includes
26
#include "Gaudi/Property.h"
27
#include "
AthenaPython/IPyComponent.h
"
28
29
// PyROOT includes
30
#include "CPyCppyy/PyException.h"
31
#include "TPython.h"
32
#include "TROOT.h"
33
#include "TClassGenerator.h"
34
35
using namespace
PyAthena
;
36
37
namespace
{
38
39
// Remove the TPyClassGenerator from the list of class generators.
40
// TPyClassGenerator makes classes defined in Python accessible to ROOT.
41
// We don't rely on this at all in Athena. Further, in MT jobs,
42
// we can get deadlocks. TClass::GetClass holds the ROOT internal
43
// mutexes, and if it ends up calling TPyClassGenerator, then the
44
// generator will end up acquiring the Python GIL.
45
// On the other hand, Python-based algorithms will hold the GIL.
46
// If they then use PyROOT (or do anything which could trigger I/O),
47
// then they can try to acquire the ROOT internal locks.
48
// Since we have the same locks being acquired in different orders
49
// in different threads, we can deadlock.
50
//
51
// Ideally, TClass::GetClass should probably drop the ROOT locks
52
// before calling a class generator. But since we don't actually
53
// use this functionality on Athena, just suppress it.
54
void
removePyGen ()
55
{
56
TCollection* gens = gROOT->GetListOfClassGenerators();
57
TIter
next
(gens);
58
TClassGenerator *
gen
;
59
while
( (gen = (TClassGenerator*)
next
()) ) {
60
if
(System::typeinfoName (
typeid
(*gen)) ==
"TPyClassGenerator"
) {
61
gens->Remove (gen);
62
break
;
63
}
64
}
65
}
66
}
// anonymous namespace
67
68
69
70
// Constructors
72
PyComponentMgr::PyComponentMgr
(
const
std::string& name,
73
ISvcLocator* pSvcLocator ) :
74
base_class ( name, pSvcLocator ),
75
m_dict
( nullptr ),
76
m_components
( )
77
{
78
//
79
// Property declaration
80
//
81
//declareProperty( "Property", m_nProperty, "descr" );
82
83
}
84
85
// Destructor
87
PyComponentMgr::~PyComponentMgr
()
88
{
89
ATH_MSG_DEBUG
(
"Calling destructor"
);
90
91
// we own the repository of instances' description
92
if
(
m_dict
) {
93
RootUtils::PyGILStateEnsure
ensure;
94
Py_DECREF(
m_dict
);
95
m_dict
=
nullptr
;
96
}
97
98
// as well as the one of corresponding instances
99
if
(
m_components
.size() ) {
100
RootUtils::PyGILStateEnsure
ensure;
101
for
( PyComponents_t::iterator
102
i =
m_components
.begin(),
103
iEnd =
m_components
.end();
104
i != iEnd;
105
++i ) {
106
ATH_MSG_VERBOSE
(
"__del__("
<< i->first <<
")..."
);
107
Py_XDECREF( i->second );
108
}
109
}
110
111
}
112
113
// Athena Algorithm's Hooks
115
StatusCode
116
PyComponentMgr::initialize
()
117
{
118
ATH_MSG_INFO
(
"Initializing "
<< name() <<
"..."
);
119
120
const
std::string pyModuleName =
"AthenaPython.Configurables"
;
121
122
// import the module holding the dictionary of component instances
123
RootUtils::PyGILStateEnsure
ensure;
124
ATH_MSG_DEBUG
(
"Importing module ["
<< pyModuleName <<
"]..."
);
125
PyObject
* module = PyImport_ImportModule(
const_cast<
char
*
>
(pyModuleName.c_str()) );
126
if
( !module || !PyModule_Check( module ) ) {
127
ATH_MSG_ERROR
(
"Could not import ["
<< pyModuleName <<
"] !!"
);
128
Py_XDECREF (module);
129
throw
CPyCppyy::PyException();
130
}
131
132
const
std::string pyClassName =
"PyComponents"
;
133
PyObject
* pyClass = 0;
134
pyClass = PyDict_GetItemString( PyModule_GetDict( module ),
135
const_cast<
char
*
>
( pyClassName.c_str() ) );
136
137
// borrowed ref. so ->increment
138
Py_XINCREF( pyClass );
139
140
if
( !pyClass ) {
141
ATH_MSG_ERROR
(
"Could not retrieve class ["
<< pyClassName
142
<<
"] from module ["
<< pyModuleName <<
"] !!"
);
143
Py_XDECREF(pyClass);
144
Py_DECREF (module);
145
return
StatusCode::FAILURE;
146
}
147
148
m_dict
= PyObject_GetAttrString( pyClass,
149
const_cast<
char
*
>
(
"instances"
) );
150
if
( !
m_dict
|| !PyDict_Check(
m_dict
) ) {
151
ATH_MSG_ERROR
(
"Could not retrieve attribute [instances] from class ["
152
<< pyClassName <<
"] !!"
);
153
Py_DECREF (pyClass);
154
Py_DECREF (module);
155
return
StatusCode::FAILURE;
156
}
157
Py_DECREF(pyClass);
158
159
// install the fancy attribute getter for PyComponents to automatically
160
// retrieve an initialized component.
161
// see bug #46668
162
{
163
PyObject
* fancy_attr = 0;
164
fancy_attr = PyDict_GetItemString(PyModule_GetDict(module),
165
(
char
*)
"_install_fancy_attrs"
);
166
// borrowed ref => increment
167
Py_XINCREF(fancy_attr);
168
if
(!fancy_attr) {
169
PyErr_Clear();
170
ATH_MSG_INFO
171
(
"could not retrieve function [_install_fancy_attrs] from module ["
172
<< pyModuleName <<
"]"
);
173
}
else
{
174
PyObject
* ret = PyObject_CallFunction(fancy_attr, NULL);
175
Py_XDECREF(ret);
176
}
177
Py_XDECREF(fancy_attr);
178
}
179
Py_DECREF (module);
180
181
// make sure the PyROOT fixes are installed
182
const
std::string pyRootFixes =
"RootUtils.PyROOTFixes"
;
183
ATH_MSG_DEBUG
(
"Importing module ["
<< pyRootFixes <<
"]..."
);
184
PyObject
*rootFixes = 0;
185
rootFixes = PyImport_ImportModule(
const_cast<
char
*
>
(pyRootFixes.c_str()));
186
if
( !rootFixes || !PyModule_Check( rootFixes ) ) {
187
PyErr_Print();
188
PyErr_Clear();
189
ATH_MSG_WARNING
(
"Could not import ["
<< pyRootFixes <<
"] !!"
190
<<
endmsg
191
<<
"Some problem may appear with some C++->python binded classes (YMMV)"
);
192
}
193
Py_XDECREF(rootFixes);
194
return
StatusCode::SUCCESS;
195
}
196
197
StatusCode
198
PyComponentMgr::finalize
()
199
{
200
ATH_MSG_INFO
(
"Finalizing "
<< name() <<
"..."
);
201
return
StatusCode::SUCCESS;
202
}
203
204
205
PyObject
*
206
PyComponentMgr::pyObject
(
IPyComponent
* cppComp )
207
{
208
const
std::string& name = cppComp->name();
209
210
// Check if we already have instantiated that component
211
RootUtils::PyGILStateEnsure
ensure;
212
PyComponents_t::iterator comp =
m_components
.find( name );
213
if
( comp !=
m_components
.end() && comp->second ) {
214
Py_INCREF (comp->second);
215
return
comp->second;
216
}
217
m_components
[name] =
static_cast<
PyObject
*
>
( NULL );
218
219
// Check we have a valid dict.
220
if
( !
m_dict
|| !PyDict_Check(
m_dict
) ) {
221
ATH_MSG_ERROR
(
"Invalid repository of Python components !!"
);
222
Py_INCREF( Py_None );
223
return
Py_None;
224
}
225
226
PyObject
* o = PyDict_GetItemString(
m_dict
,
227
const_cast<
char
*
>
(name.c_str()) );
228
// borrowed ref -> incr
229
Py_XINCREF( o );
230
231
// Check we have a valid dict.
232
if
( !o ) {
233
ATH_MSG_ERROR
(
"No such python component ["
<< name
234
<<
"] or invalid item !!"
);
235
Py_XDECREF( o );
236
throw
CPyCppyy::PyException();
237
}
238
m_components
[name] = o;
239
243
// // remove the object from the python dict
244
// if ( PyDict_DelItemString( m_dict, const_cast<char*>(name.c_str()) ) ) {
245
// ATH_MSG_ERROR("Could not remove [" << name << "] from PyComponents.instances !!");
246
// throw PyROOT::TPyException();
247
// }
248
249
// now we tell the PyObject which C++ object it is the cousin of.
250
if
( !cppComp->
setPyAttr
(o) ) {
251
ATH_MSG_WARNING
(
"Could not connect the C++ object ["
252
<< cppComp->
typeName
() <<
"/"
<< cppComp->name()
253
<<
"] with its python cousin !"
);
254
}
255
256
removePyGen();
257
258
Py_INCREF(o);
259
return
o;
260
}
endmsg
#define endmsg
Definition
AnalysisConfig_Ntuple.cxx:54
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition
AthMsgStreamMacros.h:32
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition
AthMsgStreamMacros.h:30
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition
AthMsgStreamMacros.h:27
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition
AthMsgStreamMacros.h:31
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition
AthMsgStreamMacros.h:28
CLASS_DEF.h
macros to associate a CLID to a type
CLASS_DEF
#define CLASS_DEF(NAME, CID, VERSION)
associate a clid and a version to a type eg
Definition
Control/AthenaKernel/AthenaKernel/CLASS_DEF.h:67
IPyComponent.h
PyObject
_object PyObject
Definition
IPyComponent.h:27
PyAthenaGILStateEnsure.h
IPyComponent
Definition
IPyComponent.h:31
IPyComponent::typeName
virtual const char * typeName() const =0
return the std::type_info name of the underlying py-component This is used by concrete implementation...
IPyComponent::setPyAttr
virtual bool setPyAttr(PyObject *pyobj)=0
attach the C++ component to its python cousin
PyAthena::PyComponentMgr::m_components
PyComponents_t m_components
A fast look-up hash-map for python components { 'name' : PyObject* } PyObject* is NULL if not yet ins...
Definition
PyComponentMgr.h:90
PyAthena::PyComponentMgr::finalize
virtual StatusCode finalize() override
Definition
PyComponentMgr.cxx:198
PyAthena::PyComponentMgr::PyComponentMgr
PyComponentMgr()=delete
PyAthena::PyComponentMgr::initialize
virtual StatusCode initialize() override
Gaudi Service Implementation.
Definition
PyComponentMgr.cxx:116
PyAthena::PyComponentMgr::pyObject
virtual PyObject * pyObject(IPyComponent *component) override
Retrieve a python object from the python world.
Definition
PyComponentMgr.cxx:206
PyAthena::PyComponentMgr::~PyComponentMgr
virtual ~PyComponentMgr()
Destructor:
Definition
PyComponentMgr.cxx:87
PyAthena::PyComponentMgr::m_dict
PyObject * m_dict
The dictionary of python components' description It should be of the form: { 'name' : { 'package' : "...
Definition
PyComponentMgr.h:82
RootUtils::PyGILStateEnsure
Definition
PyAthenaGILStateEnsure.h:20
PyAthena
Definition
IPyComponent.h:28
fillPileUpNoiseLumi.next
next
Definition
fillPileUpNoiseLumi.py:52
master.gen
gen
Definition
master.py:32
Generated on
for ATLAS Offline Software by
1.17.0