ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
Control
AthenaPython
src
PyAthenaUtils.cxx
Go to the documentation of this file.
1
2
3
/*
4
Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5
*/
6
7
// PyAthenaUtils.cxx
8
// Implementation file for various PyAthena helpers
9
// Author: S.Binet<binet@cern.ch>
10
// Modified: Wim Lavrijsen <WLavrijsen@lbl.gov>
12
13
// Python includes
14
#include "Python.h"
15
16
// AthenaPython includes
17
#include "
AthenaPython/PyAthenaUtils.h
"
18
#include "
RootUtils/PyAthenaGILStateEnsure.h
"
19
#include "
RootUtils/PyGetString.h
"
20
21
// Framework includes
22
#include "GaudiKernel/IInterface.h"
23
#include "GaudiKernel/INamedInterface.h"
24
#include "GaudiKernel/StatusCode.h"
25
26
// PyROOT includes
27
#include "TPython.h"
28
#ifdef ATLAS_HAVE_CPYCPPYY
29
# include "CPyCppyy/PyException.h"
30
#endif
// ATLAS_HAVE_CPYCPPYY
31
32
// Reflex includes
33
#include "
DataModelRoot/RootType.h
"
34
35
// ROOT includes
36
#include "TClassRef.h"
37
38
// STL includes
39
#include <string>
40
#include <iostream>
41
#include <sstream>
42
#include <stdexcept>
43
44
namespace
{
45
46
struct
MyObjProxy {
47
PyObject_HEAD
48
void
* m_object;
49
TClassRef m_class;
50
};
51
52
StatusCode
53
fetchInterfaceId(
PyObject
* klass,
54
unsigned
long
&
id
,
55
unsigned
long
& major,
56
unsigned
long
& minor )
57
{
58
Py_INCREF( klass );
59
60
RootUtils::PyGILStateEnsure
ensure;
61
PyObject
* idObj = PyObject_CallMethod( klass,
62
const_cast<
char
*
>
(
"interfaceID"
),
63
const_cast<
char
*
>
(
""
) );
64
Py_DECREF (klass);
65
if
( 0 == idObj ) {
66
PyErr_Clear();
67
return
StatusCode::FAILURE;
68
}
69
70
PyObject
* pyId = PyObject_CallMethod( idObj,
71
const_cast<
char
*
>
(
"id"
),
72
const_cast<
char
*
>
(
""
) );
73
if
( 0 == pyId ) {
74
PyErr_Clear();
75
Py_DECREF (idObj);
76
return
StatusCode::FAILURE;
77
}
78
id
= PyLong_AsUnsignedLong(pyId);
79
Py_DECREF(pyId);
80
81
PyObject
* pyMajor = PyObject_CallMethod( idObj,
82
const_cast<
char
*
>
(
"majorVersion"
),
83
const_cast<
char
*
>
(
""
) );
84
if
( 0 == pyMajor ) {
85
PyErr_Clear();
86
Py_DECREF (idObj);
87
return
StatusCode::FAILURE;
88
}
89
major = PyLong_AsUnsignedLong(pyMajor);
90
Py_DECREF(pyMajor);
91
92
PyObject
* pyMinor = PyObject_CallMethod( idObj,
93
const_cast<
char
*
>
(
"minorVersion"
),
94
const_cast<
char
*
>
(
""
) );
95
if
( 0 == pyMinor ) {
96
PyErr_Clear();
97
Py_DECREF (idObj);
98
return
StatusCode::FAILURE;
99
}
100
minor = PyLong_AsUnsignedLong(pyMinor);
101
Py_DECREF(pyMajor);
102
103
Py_DECREF (idObj);
104
return
StatusCode::SUCCESS;
105
}
106
}
//> anonymous namespace
107
108
std::string
109
PyAthena::repr
(
PyObject
* o )
110
{
111
// PyObject_Repr returns a new ref.
112
RootUtils::PyGILStateEnsure
ensure;
113
PyObject
* py_repr = PyObject_Repr( o );
114
115
auto
[cpp_repr, flag] =
RootUtils::PyGetString
(py_repr);
116
Py_DECREF( py_repr );
117
if
(!flag) {
118
PyAthena::throw_py_exception
();
119
}
120
return
cpp_repr;
121
}
122
123
std::string
124
PyAthena::str
(
PyObject
* o )
125
{
126
// PyObject_Str returns a new ref.
127
RootUtils::PyGILStateEnsure
ensure;
128
PyObject
* py_str = PyObject_Str( o );
129
auto
[cpp_str, flag] =
RootUtils::PyGetString
(py_str);
130
Py_DECREF( py_str );
131
if
( !flag ) {
132
PyAthena::throw_py_exception
();
133
}
134
return
cpp_str;
135
}
136
137
[[noreturn]]
138
void
PyAthena::throw_py_exception
(
bool
display)
139
{
140
if
(display) {
141
RootUtils::PyGILStateEnsure
ensure;
142
// fetch error
143
PyObject
* pytype = 0, *pyvalue = 0, *pytrace = 0;
144
PyErr_Fetch (&pytype, &pyvalue, &pytrace);
145
Py_XINCREF (pytype);
146
Py_XINCREF (pyvalue);
147
Py_XINCREF (pytrace);
148
// restore...
149
PyErr_Restore (pytype, pyvalue, pytrace);
150
// and print
151
PyErr_Print();
152
{
153
// With py3, need to explicitly flush the python stderr
154
// for the error to be visible.
155
PyObject
* f = PySys_GetObject (
const_cast<
char
*
>
(
"stderr"
));
156
PyObject
* fstr = PyUnicode_FromString (
"flush"
);
157
PyObject
*
x
= PyObject_CallMethodObjArgs (f, fstr, NULL);
158
Py_XDECREF (
x
);
159
Py_XDECREF (fstr);
160
Py_XDECREF (f);
161
}
162
}
163
#ifdef ATLAS_HAVE_CPYCPPYY
164
throw
CPyCppyy::PyException();
165
#else
166
throw
std::runtime_error (
"Python exception"
);
167
#endif
// ATLAS_HAVE_CPYCPPYY
168
}
169
170
StatusCode
171
PyAthena::callPyMethod
ATLAS_NOT_THREAD_SAFE
(
PyObject
* self,
172
const
char
* methodName,
173
PyObject
* arg
/*= nullptr*/
)
174
{
175
// that's a bit ugly...
176
char
* method =
const_cast<
char
*
>
(methodName);
177
178
// check arguments
179
if
( 0 == self || 0 == method ) {
return
StatusCode::FAILURE; }
180
181
// call Python
182
RootUtils::PyGILStateEnsure
ensure;
183
PyObject
*
r
;
184
if
(arg)
185
r
= PyObject_CallMethod( self, method,
const_cast<
char
*
>
(
"O"
), arg );
186
else
187
r
= PyObject_CallMethod( self, method,
const_cast<
char
*
>
(
""
) );
188
189
if
( 0 ==
r
) {
190
throw_py_exception();
191
}
192
193
if
( PyLong_Check(
r
) ) {
194
StatusCode
sc
(PyLong_AS_LONG(
r
));
195
Py_DECREF(
r
);
196
return
sc
;
197
}
198
199
// look for the method getCode with the signature:
200
// ' int getCode() '
201
PyObject
* c = 0;
202
if
( PyObject_HasAttrString (
r
, (
char
*)
"getCode"
) ) {
203
c = PyObject_CallMethod(
r
,
204
const_cast<
char
*
>
(
"getCode"
),
205
const_cast<
char
*
>
(
""
) );
206
Py_DECREF (
r
);
207
}
208
209
else
{
210
std::ostringstream
msg
;
211
msg
<<
"unexpected returned type from (python) function '"
212
<< method <<
"()' [got "
213
<<
PyAthena::repr
((
PyObject
*)
r
->ob_type)
214
<<
"]"
;
215
PyErr_SetString (PyExc_TypeError,
msg
.str().c_str());
216
Py_XDECREF (c);
217
throw_py_exception();
218
}
219
220
if
( !c ) {
221
// error on python side...
222
throw_py_exception();
223
}
224
225
if
( PyLong_Check (c) ) {
226
StatusCode
sc
(PyLong_AsLong (c));
227
Py_DECREF (c);
228
return
sc
;
229
}
230
231
else
{
232
std::ostringstream
msg
;
233
msg
<<
"unexpected returned type from (python) function '"
234
<< method <<
"().getCode()' [got "
235
<<
PyAthena::repr
((
PyObject
*)c->ob_type)
236
<<
"]"
;
237
PyErr_SetString (PyExc_TypeError,
msg
.str().c_str());
238
Py_DECREF (c);
239
throw_py_exception();
240
}
241
return
StatusCode::FAILURE;
242
}
243
244
StatusCode PyAthena::queryInterface
ATLAS_NOT_THREAD_SAFE
245
(
PyObject
* self,
246
const
InterfaceID& riid,
247
void
** ppvInterface )
248
{
249
StatusCode
sc
= StatusCode::FAILURE;
250
251
{
252
std::cout
253
<<
"==============[ "
<<
PyAthena::repr
(self) <<
" ]=============="
254
<< std::endl;
255
}
256
257
RootUtils::PyGILStateEnsure
ensure;
258
PyObject
*
type
= PyObject_GetAttrString( self,
259
const_cast<
char
*
>
(
"__class__"
) );
260
if
( !
type
) {
261
Py_XDECREF(
type
);
262
return
sc
;
263
}
264
265
PyObject
* bases;
266
bases = PyObject_CallMethod(
type
,
267
const_cast<
char
*
>
(
"mro"
),
268
const_cast<
char
*
>
(
""
) );
269
if
( !bases || !PySequence_Check( bases ) ) {
270
Py_XDECREF(
type
);
271
Py_XDECREF(bases);
272
return
sc
;
273
}
274
275
const
int
nBases = PySequence_Size( bases );
276
if
( -1 == nBases ) {
277
Py_XDECREF(
type
);
278
Py_XDECREF(bases);
279
return
sc
;
280
}
281
282
for
(
int
i = 0; i < nBases; ++i ) {
283
PyObject
*
base
= PySequence_GetItem( bases, i );
284
if
( !
base
) {
285
Py_XDECREF(
base
);
286
continue
;
287
}
288
unsigned
long
id
= 0;
289
unsigned
long
major = 0;
290
unsigned
long
minor = 0;
291
if
( !fetchInterfaceId(
base
,
id
, major, minor ).isSuccess() ) {
292
Py_DECREF(
base
);
293
continue
;
294
}
295
296
InterfaceID pyID(
id
, major, minor );
297
if
( !pyID.versionMatch( riid ) ) {
298
Py_DECREF(
base
);
299
continue
;
300
}
301
302
PyObject
* pyname = 0;
303
pyname = PyObject_GetAttrString(
base
,
304
const_cast<
char
*
>
(
"__name__"
) );
305
auto
[cppBaseName, flag] =
RootUtils::PyGetString
(pyname);
306
Py_DECREF(pyname);
307
if
( !flag ) {
308
Py_DECREF (
base
);
309
continue
;
310
}
311
312
const
std::string cppName =
reinterpret_cast<
MyObjProxy*
>
(self)->m_class->GetName();
313
314
std::cout <<
"::: would like to do: *ppvInterface = static_cast<"
315
<< cppBaseName <<
"*>( "
316
<< cppName <<
"|m_self );"
317
<< std::endl;
318
319
const
RootType
fromType( cppName );
320
const
RootType
toType( cppBaseName );
321
void
* objProxy = TPython::CPPInstance_AsVoidPtr(self);
322
*ppvInterface = objProxy;
323
if
(fromType.
Class
() && toType.
Class
())
324
*ppvInterface = fromType.
Class
()->DynamicCast (toType.
Class
(), objProxy);
325
std::cout <<
"::: ["
<< cppName <<
"]: "
326
<< ( (bool)fromType ?
" OK"
:
"ERR"
)
327
<<
" "
<< objProxy
328
<<
"\n"
329
<<
"::: ["
<< cppBaseName <<
"]: "
330
<< ( (
bool
)toType ?
" OK"
:
"ERR"
)
331
<<
" "
<< *ppvInterface
332
<<
"\n"
;
333
std::cout <<
"::: *ppvInterface: "
<< *ppvInterface << std::endl;
334
if
( *ppvInterface ) {
335
PyObject
* c = PyObject_CallMethod( self,
336
const_cast<
char
*
>
(
"addRef"
),
337
const_cast<
char
*
>
(
""
) );
338
if
( c && PyLong_Check(c) ) {
339
sc
= StatusCode::SUCCESS;
340
}
341
Py_DECREF(c);
342
}
343
Py_DECREF(
base
);
344
if
(
sc
.isSuccess() ) {
345
break
;
346
}
347
}
348
349
Py_DECREF(
type
);
350
Py_DECREF(bases);
351
return
sc
;
352
}
353
355
void
PyAthena::pyAudit
ATLAS_NOT_THREAD_SAFE
356
(
PyObject
* self,
357
const
char
* method,
358
const
char
* evt,
359
const
char
* component )
360
{
361
RootUtils::PyGILStateEnsure
ensure;
362
PyObject
* call = PyObject_CallMethod(self,
363
(
char
*)method,
364
(
char
*)
"ss"
, evt, component);
365
if
( !call ) {
366
Py_XDECREF(call);
367
throw_py_exception();
368
}
369
Py_DECREF(call);
370
return
;
371
}
372
374
void
PyAthena::pyAudit
ATLAS_NOT_THREAD_SAFE
375
(
PyObject
* self,
376
const
char
* method,
377
const
char
* evt,
378
const
char
* component,
379
const
StatusCode&
sc
)
380
{
381
RootUtils::PyGILStateEnsure
ensure;
382
PyObject
* pySc = TPython::CPPInstance_FromVoidPtr((
void
*)&
sc
,
383
"StatusCode"
);
384
if
( !pySc ) {
385
#ifdef ATLAS_HAVE_CPYCPPYY
386
throw
CPyCppyy::PyException();
387
#else
388
throw
std::runtime_error (
"Python exception"
);
389
#endif
// ATLAS_HAVE_CPYCPPYY
390
}
391
392
PyObject
* call = PyObject_CallMethod(self,
393
(
char
*)method,
394
(
char
*)
"ssO"
, evt, component, pySc);
395
Py_DECREF(pySc);
396
397
if
( !call ) {
398
Py_XDECREF(call);
399
throw_py_exception();
400
}
401
Py_DECREF(call);
402
return
;
403
}
PyObject
_object PyObject
Definition
IPyComponent.h:27
sc
static Double_t sc
Definition
LArPhysWaveHECTool.cxx:37
PyAthenaGILStateEnsure.h
PyAthenaUtils.h
PyGetString.h
Convert python string -> C++ string for py2 and py3.
RootType.h
RootType
TTypeAdapter RootType
Definition
RootType.h:211
x
#define x
ATLAS_NOT_THREAD_SAFE
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
Definition
checker_macros.h:212
RootUtils::PyGILStateEnsure
Definition
PyAthenaGILStateEnsure.h:20
TScopeAdapter::Class
TClass * Class() const
Definition
RootType.h:183
r
int r
Definition
globals.cxx:22
base
std::string base
Definition
hcg.cxx:83
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition
PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
PyAthena::repr
std::string repr(PyObject *o)
returns the string representation of a python object equivalent of calling repr(o) in python
Definition
PyAthenaUtils.cxx:109
PyAthena::throw_py_exception
void throw_py_exception(bool display=true)
helper function to capture the boilerplate code for user friendly stack trace display
Definition
PyAthenaUtils.cxx:138
PyAthena::str
std::string str(PyObject *o)
returns the string representation of a python object equivalent of calling str(o) in python
Definition
PyAthenaUtils.cxx:124
RootUtils::PyGetString
std::pair< std::string, bool > PyGetString(PyObject *s)
Convert python string -> C++ string for py2 and py3.
Definition
PyGetString.h:40
type
msg
MsgStream & msg
Definition
testRead.cxx:32
Generated on
for ATLAS Offline Software by
1.17.0