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-2025 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
#include "CPyCppyy/PyException.h"
29
30
// Reflex includes
31
#include "
DataModelRoot/RootType.h
"
32
33
// ROOT includes
34
#include "TClassRef.h"
35
36
// STL includes
37
#include <string>
38
#include <iostream>
39
#include <sstream>
40
41
namespace
{
42
43
struct
MyObjProxy {
44
PyObject_HEAD
45
void
* m_object;
46
TClassRef m_class;
47
};
48
49
StatusCode
50
fetchInterfaceId(
PyObject
* klass,
51
unsigned
long
&
id
,
52
unsigned
long
& major,
53
unsigned
long
& minor )
54
{
55
Py_INCREF( klass );
56
57
RootUtils::PyGILStateEnsure
ensure;
58
PyObject
* idObj = PyObject_CallMethod( klass,
59
const_cast<
char
*
>
(
"interfaceID"
),
60
const_cast<
char
*
>
(
""
) );
61
Py_DECREF (klass);
62
if
( 0 == idObj ) {
63
PyErr_Clear();
64
return
StatusCode::FAILURE;
65
}
66
67
PyObject
* pyId = PyObject_CallMethod( idObj,
68
const_cast<
char
*
>
(
"id"
),
69
const_cast<
char
*
>
(
""
) );
70
if
( 0 == pyId ) {
71
PyErr_Clear();
72
Py_DECREF (idObj);
73
return
StatusCode::FAILURE;
74
}
75
id
= PyLong_AsUnsignedLong(pyId);
76
Py_DECREF(pyId);
77
78
PyObject
* pyMajor = PyObject_CallMethod( idObj,
79
const_cast<
char
*
>
(
"majorVersion"
),
80
const_cast<
char
*
>
(
""
) );
81
if
( 0 == pyMajor ) {
82
PyErr_Clear();
83
Py_DECREF (idObj);
84
return
StatusCode::FAILURE;
85
}
86
major = PyLong_AsUnsignedLong(pyMajor);
87
Py_DECREF(pyMajor);
88
89
PyObject
* pyMinor = PyObject_CallMethod( idObj,
90
const_cast<
char
*
>
(
"minorVersion"
),
91
const_cast<
char
*
>
(
""
) );
92
if
( 0 == pyMinor ) {
93
PyErr_Clear();
94
Py_DECREF (idObj);
95
return
StatusCode::FAILURE;
96
}
97
minor = PyLong_AsUnsignedLong(pyMinor);
98
Py_DECREF(pyMajor);
99
100
Py_DECREF (idObj);
101
return
StatusCode::SUCCESS;
102
}
103
}
//> anonymous namespace
104
105
std::string
106
PyAthena::repr
(
PyObject
* o )
107
{
108
// PyObject_Repr returns a new ref.
109
RootUtils::PyGILStateEnsure
ensure;
110
PyObject
* py_repr = PyObject_Repr( o );
111
112
auto
[cpp_repr, flag] =
RootUtils::PyGetString
(py_repr);
113
Py_DECREF( py_repr );
114
if
(!flag) {
115
PyAthena::throw_py_exception
();
116
}
117
return
cpp_repr;
118
}
119
120
std::string
121
PyAthena::str
(
PyObject
* o )
122
{
123
// PyObject_Str returns a new ref.
124
RootUtils::PyGILStateEnsure
ensure;
125
PyObject
* py_str = PyObject_Str( o );
126
auto
[cpp_str, flag] =
RootUtils::PyGetString
(py_str);
127
Py_DECREF( py_str );
128
if
( !flag ) {
129
PyAthena::throw_py_exception
();
130
}
131
return
cpp_str;
132
}
133
134
[[noreturn]]
135
void
PyAthena::throw_py_exception
(
bool
display)
136
{
137
if
(display) {
138
RootUtils::PyGILStateEnsure
ensure;
139
// fetch error
140
PyObject
* pytype = 0, *pyvalue = 0, *pytrace = 0;
141
PyErr_Fetch (&pytype, &pyvalue, &pytrace);
142
Py_XINCREF (pytype);
143
Py_XINCREF (pyvalue);
144
Py_XINCREF (pytrace);
145
// restore...
146
PyErr_Restore (pytype, pyvalue, pytrace);
147
// and print
148
PyErr_Print();
149
{
150
// With py3, need to explicitly flush the python stderr
151
// for the error to be visible.
152
PyObject
* f = PySys_GetObject (
const_cast<
char
*
>
(
"stderr"
));
153
PyObject
* fstr = PyUnicode_FromString (
"flush"
);
154
PyObject
*
x
= PyObject_CallMethodObjArgs (f, fstr, NULL);
155
Py_XDECREF (
x
);
156
Py_XDECREF (fstr);
157
Py_XDECREF (f);
158
}
159
}
160
throw
CPyCppyy::PyException();
161
}
162
163
StatusCode
164
PyAthena::callPyMethod
ATLAS_NOT_THREAD_SAFE
(
PyObject
* self,
165
const
char
* methodName,
166
PyObject
* arg
/*= nullptr*/
)
167
{
168
// that's a bit ugly...
169
char
* method =
const_cast<
char
*
>
(methodName);
170
171
// check arguments
172
if
( 0 == self || 0 == method ) {
return
StatusCode::FAILURE; }
173
174
// call Python
175
RootUtils::PyGILStateEnsure
ensure;
176
PyObject
*
r
;
177
if
(arg)
178
r
= PyObject_CallMethod( self, method,
const_cast<
char
*
>
(
"O"
), arg );
179
else
180
r
= PyObject_CallMethod( self, method,
const_cast<
char
*
>
(
""
) );
181
182
if
( 0 ==
r
) {
183
throw_py_exception();
184
}
185
186
if
( PyLong_Check(
r
) ) {
187
StatusCode
sc
(PyLong_AS_LONG(
r
));
188
Py_DECREF(
r
);
189
return
sc
;
190
}
191
192
// look for the method getCode with the signature:
193
// ' int getCode() '
194
PyObject
* c = 0;
195
if
( PyObject_HasAttrString (
r
, (
char
*)
"getCode"
) ) {
196
c = PyObject_CallMethod(
r
,
197
const_cast<
char
*
>
(
"getCode"
),
198
const_cast<
char
*
>
(
""
) );
199
Py_DECREF (
r
);
200
}
201
202
else
{
203
std::ostringstream
msg
;
204
msg
<<
"unexpected returned type from (python) function '"
205
<< method <<
"()' [got "
206
<<
PyAthena::repr
((
PyObject
*)
r
->ob_type)
207
<<
"]"
;
208
PyErr_SetString (PyExc_TypeError,
msg
.str().c_str());
209
Py_XDECREF (c);
210
throw_py_exception();
211
}
212
213
if
( !c ) {
214
// error on python side...
215
throw_py_exception();
216
}
217
218
if
( PyLong_Check (c) ) {
219
StatusCode
sc
(PyLong_AsLong (c));
220
Py_DECREF (c);
221
return
sc
;
222
}
223
224
else
{
225
std::ostringstream
msg
;
226
msg
<<
"unexpected returned type from (python) function '"
227
<< method <<
"().getCode()' [got "
228
<<
PyAthena::repr
((
PyObject
*)c->ob_type)
229
<<
"]"
;
230
PyErr_SetString (PyExc_TypeError,
msg
.str().c_str());
231
Py_DECREF (c);
232
throw_py_exception();
233
}
234
return
StatusCode::FAILURE;
235
}
236
237
StatusCode PyAthena::queryInterface
ATLAS_NOT_THREAD_SAFE
238
(
PyObject
* self,
239
const
InterfaceID& riid,
240
void
** ppvInterface )
241
{
242
StatusCode
sc
= StatusCode::FAILURE;
243
244
{
245
std::cout
246
<<
"==============[ "
<<
PyAthena::repr
(self) <<
" ]=============="
247
<< std::endl;
248
}
249
250
RootUtils::PyGILStateEnsure
ensure;
251
PyObject
*
type
= PyObject_GetAttrString( self,
252
const_cast<
char
*
>
(
"__class__"
) );
253
if
( !
type
) {
254
Py_XDECREF(
type
);
255
return
sc
;
256
}
257
258
PyObject
* bases;
259
bases = PyObject_CallMethod(
type
,
260
const_cast<
char
*
>
(
"mro"
),
261
const_cast<
char
*
>
(
""
) );
262
if
( !bases || !PySequence_Check( bases ) ) {
263
Py_XDECREF(
type
);
264
Py_XDECREF(bases);
265
return
sc
;
266
}
267
268
const
int
nBases = PySequence_Size( bases );
269
if
( -1 == nBases ) {
270
Py_XDECREF(
type
);
271
Py_XDECREF(bases);
272
return
sc
;
273
}
274
275
for
(
int
i = 0; i < nBases; ++i ) {
276
PyObject
*
base
= PySequence_GetItem( bases, i );
277
if
( !
base
) {
278
Py_XDECREF(
base
);
279
continue
;
280
}
281
unsigned
long
id
= 0;
282
unsigned
long
major = 0;
283
unsigned
long
minor = 0;
284
if
( !fetchInterfaceId(
base
,
id
, major, minor ).isSuccess() ) {
285
Py_DECREF(
base
);
286
continue
;
287
}
288
289
InterfaceID pyID(
id
, major, minor );
290
if
( !pyID.versionMatch( riid ) ) {
291
Py_DECREF(
base
);
292
continue
;
293
}
294
295
PyObject
* pyname = 0;
296
pyname = PyObject_GetAttrString(
base
,
297
const_cast<
char
*
>
(
"__name__"
) );
298
auto
[cppBaseName, flag] =
RootUtils::PyGetString
(pyname);
299
Py_DECREF(pyname);
300
if
( !flag ) {
301
Py_DECREF (
base
);
302
continue
;
303
}
304
305
const
std::string cppName =
reinterpret_cast<
MyObjProxy*
>
(self)->m_class->GetName();
306
307
std::cout <<
"::: would like to do: *ppvInterface = static_cast<"
308
<< cppBaseName <<
"*>( "
309
<< cppName <<
"|m_self );"
310
<< std::endl;
311
312
const
RootType
fromType( cppName );
313
const
RootType
toType( cppBaseName );
314
void
* objProxy = TPython::CPPInstance_AsVoidPtr(self);
315
*ppvInterface = objProxy;
316
if
(fromType.
Class
() && toType.
Class
())
317
*ppvInterface = fromType.
Class
()->DynamicCast (toType.
Class
(), objProxy);
318
std::cout <<
"::: ["
<< cppName <<
"]: "
319
<< ( (bool)fromType ?
" OK"
:
"ERR"
)
320
<<
" "
<< objProxy
321
<<
"\n"
322
<<
"::: ["
<< cppBaseName <<
"]: "
323
<< ( (
bool
)toType ?
" OK"
:
"ERR"
)
324
<<
" "
<< *ppvInterface
325
<<
"\n"
;
326
std::cout <<
"::: *ppvInterface: "
<< *ppvInterface << std::endl;
327
if
( *ppvInterface ) {
328
PyObject
* c = PyObject_CallMethod( self,
329
const_cast<
char
*
>
(
"addRef"
),
330
const_cast<
char
*
>
(
""
) );
331
if
( c && PyLong_Check(c) ) {
332
sc
= StatusCode::SUCCESS;
333
}
334
Py_DECREF(c);
335
}
336
Py_DECREF(
base
);
337
if
(
sc
.isSuccess() ) {
338
break
;
339
}
340
}
341
342
Py_DECREF(
type
);
343
Py_DECREF(bases);
344
return
sc
;
345
}
346
348
void
PyAthena::pyAudit
ATLAS_NOT_THREAD_SAFE
349
(
PyObject
* self,
350
const
char
* method,
351
const
char
* evt,
352
const
char
* component )
353
{
354
RootUtils::PyGILStateEnsure
ensure;
355
PyObject
* call = PyObject_CallMethod(self,
356
(
char
*)method,
357
(
char
*)
"ss"
, evt, component);
358
if
( !call ) {
359
Py_XDECREF(call);
360
throw_py_exception();
361
}
362
Py_DECREF(call);
363
return
;
364
}
365
367
void
PyAthena::pyAudit
ATLAS_NOT_THREAD_SAFE
368
(
PyObject
* self,
369
const
char
* method,
370
const
char
* evt,
371
const
char
* component,
372
const
StatusCode&
sc
)
373
{
374
RootUtils::PyGILStateEnsure
ensure;
375
PyObject
* pySc = TPython::CPPInstance_FromVoidPtr((
void
*)&
sc
,
376
"StatusCode"
);
377
if
( !pySc ) {
378
throw
CPyCppyy::PyException();
379
}
380
381
PyObject
* call = PyObject_CallMethod(self,
382
(
char
*)method,
383
(
char
*)
"ssO"
, evt, component, pySc);
384
Py_DECREF(pySc);
385
386
if
( !call ) {
387
Py_XDECREF(call);
388
throw_py_exception();
389
}
390
Py_DECREF(call);
391
return
;
392
}
393
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:106
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:135
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:121
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