Logo ROOT  
Reference Guide
TPython.cxx
Go to the documentation of this file.
1// Author: Enric Tejedor CERN 08/2019
2// Original PyROOT code by Wim Lavrijsen, LBL
3//
4// /*************************************************************************
5// * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6// * All rights reserved. *
7// * *
8// * For the licensing terms see $ROOTSYS/LICENSE. *
9// * For the list of contributors see $ROOTSYS/README/CREDITS. *
10// *************************************************************************/
11
12// Bindings
13// CPyCppyy.h must be go first, since it includes Python.h, which must be
14// included before any standard header
15#include "CPyCppyy.h"
16#include "TPython.h"
17#include "CPPInstance.h"
18#include "CPPOverload.h"
19#include "ProxyWrappers.h"
20#include "TPyClassGenerator.h"
21
22// ROOT
23#include "TROOT.h"
24#include "TClassRef.h"
25#include "TObject.h"
26
27// Standard
28#include <stdio.h>
29#include <Riostream.h>
30#include <string>
31
32/// \class TPython
33/// Accessing the Python interpreter from C++.
34///
35/// The TPython class allows for access to python objects from Cling. The current
36/// functionality is only basic: ROOT objects and builtin types can freely cross
37/// the boundary between the two interpreters, python objects can be instantiated
38/// and their methods can be called. All other cross-coding is based on strings
39/// that are run on the python interpreter.
40///
41/// Examples:
42///
43/// ~~~{.cpp}
44/// $ root -l
45/// // Execute a string of python code.
46/// root [0] TPython::Exec( "print(\'Hello World!\')" );
47/// Hello World!
48///
49/// // Create a TBrowser on the python side, and transfer it back and forth.
50/// // Note the required explicit (void*) cast!
51/// root [1] TBrowser* b = (void*)TPython::Eval( "ROOT.TBrowser()" );
52/// root [2] TPython::Bind( b, "b" );
53/// root [3] b == (void*) TPython::Eval( "b" )
54/// (int)1
55///
56/// // Builtin variables can cross-over by using implicit casts.
57/// root [4] int i = TPython::Eval( "1 + 1" );
58/// root [5] i
59/// (int)2
60/// ~~~
61///
62/// And with a python file `MyPyClass.py` like this:
63/// ~~~{.py}
64/// print 'creating class MyPyClass ... '
65///
66/// class MyPyClass:
67/// def __init__( self ):
68/// print 'in MyPyClass.__init__'
69///
70/// def gime( self, what ):
71/// return what
72/// ~~~
73/// one can load a python module, and use the class. Casts are
74/// necessary as the type information can not be otherwise derived.
75/// ~~~{.cpp}
76/// root [6] TPython::LoadMacro( "MyPyClass.py" );
77/// creating class MyPyClass ...
78/// root [7] MyPyClass m;
79/// in MyPyClass.__init__
80/// root [8] std::string s = (char*)m.gime( "aap" );
81/// root [9] s
82/// (class TString)"aap"
83/// ~~~
84/// It is possible to switch between interpreters by calling `TPython::Prompt()`
85/// on the Cling side, while returning with `^D` (EOF). State is preserved between
86/// successive switches.
87///
88/// The API part provides (direct) C++ access to the bindings functionality of
89/// PyROOT. It allows verifying that you deal with a PyROOT python object in the
90/// first place (CPPInstance_Check for CPPInstance and any derived types, as well
91/// as CPPInstance_CheckExact for CPPInstance's only); and it allows conversions
92/// of `void*` to an CPPInstance and vice versa.
93
94//- data ---------------------------------------------------------------------
96static PyObject *gMainDict = 0;
97
98// needed to properly resolve (dllimport) symbols on Windows
99namespace CPyCppyy {
101 namespace PyStrings {
106 }
107}
108
109//- static public members ----------------------------------------------------
110/// Initialization method: setup the python interpreter and load the
111/// ROOT module.
113{
114 static Bool_t isInitialized = kFALSE;
115 if (isInitialized)
116 return kTRUE;
117
118 if (!Py_IsInitialized()) {
119// this happens if Cling comes in first
120#if PY_VERSION_HEX < 0x03020000
121 PyEval_InitThreads();
122#endif
123 Py_Initialize();
124#if PY_VERSION_HEX >= 0x03020000
125#if PY_VERSION_HEX < 0x03090000
126 PyEval_InitThreads();
127#endif
128#endif
129
130 // try again to see if the interpreter is initialized
131 if (!Py_IsInitialized()) {
132 // give up ...
133 std::cerr << "Error: python has not been intialized; returning." << std::endl;
134 return kFALSE;
135 }
136
137// set the command line arguments on python's sys.argv
138#if PY_VERSION_HEX < 0x03000000
139 char *argv[] = {const_cast<char *>("root")};
140#else
141 wchar_t *argv[] = {const_cast<wchar_t *>(L"root")};
142#endif
143 PySys_SetArgv(sizeof(argv) / sizeof(argv[0]), argv);
144
145 // force loading of the ROOT module
146 const int ret = PyRun_SimpleString(const_cast<char *>("import ROOT"));
147 if( ret != 0 )
148 {
149 std::cerr << "Error: import ROOT failed, check your PYTHONPATH environmental variable." << std::endl;
150 return kFALSE;
151 }
152 }
153
154 if (!gMainDict) {
155 // retrieve the main dictionary
156 gMainDict = PyModule_GetDict(PyImport_AddModule(const_cast<char *>("__main__")));
157 Py_INCREF(gMainDict);
158 }
159
160 // python side class construction, managed by ROOT
161 gROOT->AddClassGenerator(new TPyClassGenerator);
162
163 // declare success ...
164 isInitialized = kTRUE;
165 return kTRUE;
166}
167
168////////////////////////////////////////////////////////////////////////////////
169/// Import the named python module and create Cling equivalents for its classes
170/// and methods.
171
172Bool_t TPython::Import(const char *mod_name)
173{
174 // setup
175 if (!Initialize())
176 return kFALSE;
177
178 PyObject *mod = PyImport_ImportModule(mod_name);
179 if (!mod) {
180 PyErr_Print();
181 return kFALSE;
182 }
183
184 // allow finding to prevent creation of a python proxy for the C++ proxy
185 Py_INCREF(mod);
186 PyModule_AddObject(CPyCppyy::gThisModule, mod_name, mod);
187
188 // force creation of the module as a namespace
189 TClass::GetClass(mod_name, kTRUE);
190
191 PyObject *dct = PyModule_GetDict(mod);
192
193 // create Cling classes for all new python classes
194 PyObject *values = PyDict_Values(dct);
195 for (int i = 0; i < PyList_GET_SIZE(values); ++i) {
196 PyObject *value = PyList_GET_ITEM(values, i);
197 Py_INCREF(value);
198
199 // collect classes
200 if (PyClass_Check(value) || PyObject_HasAttr(value, CPyCppyy::PyStrings::gBases)) {
201 // get full class name (including module)
202 PyObject *pyClName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gCppName);
203 if (!pyClName) {
204 pyClName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gName);
205 }
206
207 if (PyErr_Occurred())
208 PyErr_Clear();
209
210 // build full, qualified name
211 std::string fullname = mod_name;
212 fullname += ".";
213 fullname += CPyCppyy_PyText_AsString(pyClName);
214
215 // force class creation (this will eventually call TPyClassGenerator)
216 TClass::GetClass(fullname.c_str(), kTRUE);
217
218 Py_XDECREF(pyClName);
219 }
220
221 Py_DECREF(value);
222 }
223
224 Py_DECREF(values);
225
226 // TODO: mod "leaks" here
227 if (PyErr_Occurred())
228 return kFALSE;
229 return kTRUE;
230}
231
232////////////////////////////////////////////////////////////////////////////////
233/// Execute the give python script as if it were a macro (effectively an
234/// execfile in __main__), and create Cling equivalents for any newly available
235/// python classes.
236
237void TPython::LoadMacro(const char *name)
238{
239 // setup
240 if (!Initialize())
241 return;
242
243 // obtain a reference to look for new classes later
244 PyObject *old = PyDict_Values(gMainDict);
245
246// actual execution
247#if PY_VERSION_HEX < 0x03000000
248 Exec((std::string("execfile(\"") + name + "\")").c_str());
249#else
250 Exec((std::string("__pyroot_f = open(\"") + name + "\"); "
251 "exec(__pyroot_f.read()); "
252 "__pyroot_f.close(); del __pyroot_f")
253 .c_str());
254#endif
255
256 // obtain new __main__ contents
257 PyObject *current = PyDict_Values(gMainDict);
258
259 // create Cling classes for all new python classes
260 for (int i = 0; i < PyList_GET_SIZE(current); ++i) {
261 PyObject *value = PyList_GET_ITEM(current, i);
262 Py_INCREF(value);
263
264 if (!PySequence_Contains(old, value)) {
265 // collect classes
266 if (PyClass_Check(value) || PyObject_HasAttr(value, CPyCppyy::PyStrings::gBases)) {
267 // get full class name (including module)
268 PyObject *pyModName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gModule);
269 PyObject *pyClName = PyObject_GetAttr(value, CPyCppyy::PyStrings::gName);
270
271 if (PyErr_Occurred())
272 PyErr_Clear();
273
274 // need to check for both exact and derived (differences exist between older and newer
275 // versions of python ... bug?)
276 if ((pyModName && pyClName) &&
277 ((CPyCppyy_PyText_CheckExact(pyModName) && CPyCppyy_PyText_CheckExact(pyClName)) ||
278 (CPyCppyy_PyText_Check(pyModName) && CPyCppyy_PyText_Check(pyClName)))) {
279 // build full, qualified name
280 std::string fullname = CPyCppyy_PyText_AsString(pyModName);
281 fullname += '.';
282 fullname += CPyCppyy_PyText_AsString(pyClName);
283
284 // force class creation (this will eventually call TPyClassGenerator)
285 TClass::GetClass(fullname.c_str(), kTRUE);
286 }
287
288 Py_XDECREF(pyClName);
289 Py_XDECREF(pyModName);
290 }
291 }
292
293 Py_DECREF(value);
294 }
295
296 Py_DECREF(current);
297 Py_DECREF(old);
298}
299
300////////////////////////////////////////////////////////////////////////////////
301/// Execute a python stand-alone script, with argv CLI arguments.
302///
303/// example of use:
304/// const char* argv[] = { "1", "2", "3" };
305/// TPython::ExecScript( "test.py", sizeof(argv)/sizeof(argv[0]), argv );
306
307void TPython::ExecScript(const char *name, int argc, const char **
308#if PY_VERSION_HEX < 0x03000000
309 argv
310#endif
311 )
312{
313
314 // setup
315 if (!Initialize())
316 return;
317
318 // verify arguments
319 if (!name) {
320 std::cerr << "Error: no file name specified." << std::endl;
321 return;
322 }
323
324 FILE *fp = fopen(name, "r");
325 if (!fp) {
326 std::cerr << "Error: could not open file \"" << name << "\"." << std::endl;
327 return;
328 }
329
330 // store a copy of the old cli for restoration
331 PyObject *oldargv = PySys_GetObject(const_cast<char *>("argv")); // borrowed
332 if (!oldargv) // e.g. apache
333 PyErr_Clear();
334 else {
335 PyObject *l = PyList_New(PyList_GET_SIZE(oldargv));
336 for (int i = 0; i < PyList_GET_SIZE(oldargv); ++i) {
337 PyObject *item = PyList_GET_ITEM(oldargv, i);
338 Py_INCREF(item);
339 PyList_SET_ITEM(l, i, item); // steals ref
340 }
341 oldargv = l;
342 }
343
344 // create and set (add progam name) the new command line
345 argc += 1;
346#if PY_VERSION_HEX < 0x03000000
347 const char **argv2 = new const char *[argc];
348 for (int i = 1; i < argc; ++i)
349 argv2[i] = argv[i - 1];
350 argv2[0] = Py_GetProgramName();
351 PySys_SetArgv(argc, const_cast<char **>(argv2));
352 delete[] argv2;
353#else
354// TODO: fix this to work like above ...
355#endif
356
357 // actual script execution
358 PyObject *gbl = PyDict_Copy(gMainDict);
359 PyObject *result = // PyRun_FileEx closes fp (b/c of last argument "1")
360 PyRun_FileEx(fp, const_cast<char *>(name), Py_file_input, gbl, gbl, 1);
361 if (!result)
362 PyErr_Print();
363 Py_XDECREF(result);
364 Py_DECREF(gbl);
365
366 // restore original command line
367 if (oldargv) {
368 PySys_SetObject(const_cast<char *>("argv"), oldargv);
369 Py_DECREF(oldargv);
370 }
371}
372
373////////////////////////////////////////////////////////////////////////////////
374/// Execute a python statement (e.g. "import ROOT").
375
376Bool_t TPython::Exec(const char *cmd)
377{
378 // setup
379 if (!Initialize())
380 return kFALSE;
381
382 // execute the command
383 PyObject *result = PyRun_String(const_cast<char *>(cmd), Py_file_input, gMainDict, gMainDict);
384
385 // test for error
386 if (result) {
387 Py_DECREF(result);
388 return kTRUE;
389 }
390
391 PyErr_Print();
392 return kFALSE;
393}
394
395////////////////////////////////////////////////////////////////////////////////
396/// Evaluate a python expression (e.g. "ROOT.TBrowser()").
397///
398/// Caution: do not hold on to the return value: either store it in a builtin
399/// type (implicit casting will work), or in a pointer to a ROOT object (explicit
400/// casting to a void* is required).
401
402const TPyReturn TPython::Eval(const char *expr)
403{
404 // setup
405 if (!Initialize())
406 return TPyReturn();
407
408 // evaluate the expression
409 PyObject *result = PyRun_String(const_cast<char *>(expr), Py_eval_input, gMainDict, gMainDict);
410
411 // report errors as appropriate; return void
412 if (!result) {
413 PyErr_Print();
414 return TPyReturn();
415 }
416
417 // results that require no conversion
418 if (result == Py_None || CPyCppyy::CPPInstance_Check(result) || PyBytes_Check(result) || PyFloat_Check(result) ||
419 PyLong_Check(result) || PyInt_Check(result))
420 return TPyReturn(result);
421
422 // explicit conversion for python type required
423 PyObject *pyclass = PyObject_GetAttrString(result, const_cast<char*>("__class__"));
424 if (pyclass != 0) {
425 // retrieve class name and the module in which it resides
426 PyObject *name = PyObject_GetAttr(pyclass, CPyCppyy::PyStrings::gName);
427 PyObject *module = PyObject_GetAttr(pyclass, CPyCppyy::PyStrings::gModule);
428
429 // concat name
430 std::string qname = std::string(CPyCppyy_PyText_AsString(module)) + '.' + CPyCppyy_PyText_AsString(name);
431 Py_DECREF(module);
432 Py_DECREF(name);
433 Py_DECREF(pyclass);
434
435 // locate ROOT style class with this name
436 TClass *klass = TClass::GetClass(qname.c_str());
437
438 // construct general ROOT python object that pretends to be of class 'klass'
439 if (klass != 0)
440 return TPyReturn(result);
441 } else
442 PyErr_Clear();
443
444 // no conversion, return null pointer object
445 Py_DECREF(result);
446 return TPyReturn();
447}
448
449////////////////////////////////////////////////////////////////////////////////
450/// Bind a ROOT object with, at the python side, the name "label".
451
452Bool_t TPython::Bind(TObject *object, const char *label)
453{
454 // check given address and setup
455 if (!(object && Initialize()))
456 return kFALSE;
457
458 // bind object in the main namespace
459 TClass *klass = object->IsA();
460 if (klass != 0) {
461 PyObject *bound = CPyCppyy::BindCppObject((void *)object, Cppyy::GetScope(klass->GetName()));
462
463 if (bound) {
464 Bool_t bOk = PyDict_SetItemString(gMainDict, const_cast<char *>(label), bound) == 0;
465 Py_DECREF(bound);
466
467 return bOk;
468 }
469 }
470
471 return kFALSE;
472}
473
474////////////////////////////////////////////////////////////////////////////////
475/// Enter an interactive python session (exit with ^D). State is preserved
476/// between successive calls.
477
479{
480 // setup
481 if (!Initialize()) {
482 return;
483 }
484
485 // enter i/o interactive mode
486 PyRun_InteractiveLoop(stdin, const_cast<char *>("\0"));
487}
488
489////////////////////////////////////////////////////////////////////////////////
490/// Test whether the type of the given pyobject is of CPPInstance type or any
491/// derived type.
492
494{
495 // setup
496 if (!Initialize())
497 return kFALSE;
498
499 // detailed walk through inheritance hierarchy
500 return CPyCppyy::CPPInstance_Check(pyobject);
501}
502
503////////////////////////////////////////////////////////////////////////////////
504/// Test whether the type of the given pyobject is CPPinstance type.
505
507{
508 // setup
509 if (!Initialize())
510 return kFALSE;
511
512 // direct pointer comparison of type member
513 return CPyCppyy::CPPInstance_CheckExact(pyobject);
514}
515
516////////////////////////////////////////////////////////////////////////////////
517/// Test whether the type of the given pyobject is of CPPOverload type or any
518/// derived type.
519
521{
522 // setup
523 if (!Initialize())
524 return kFALSE;
525
526 // detailed walk through inheritance hierarchy
527 return CPyCppyy::CPPOverload_Check(pyobject);
528}
529
530////////////////////////////////////////////////////////////////////////////////
531/// Test whether the type of the given pyobject is CPPOverload type.
532
534{
535 // setup
536 if (!Initialize())
537 return kFALSE;
538
539 // direct pointer comparison of type member
540 return CPyCppyy::CPPOverload_CheckExact(pyobject);
541}
542
543////////////////////////////////////////////////////////////////////////////////
544/// Extract the object pointer held by the CPPInstance pyobject.
545
547{
548 // setup
549 if (!Initialize())
550 return 0;
551
552 // check validity of cast
553 if (!CPyCppyy::CPPInstance_Check(pyobject))
554 return 0;
555
556 // get held object (may be null)
557 return ((CPyCppyy::CPPInstance *)pyobject)->GetObject();
558}
559
560////////////////////////////////////////////////////////////////////////////////
561/// Bind the addr to a python object of class defined by classname.
562
563PyObject *TPython::CPPInstance_FromVoidPtr(void *addr, const char *classname, Bool_t python_owns)
564{
565 // setup
566 if (!Initialize())
567 return 0;
568
569 // perform cast (the call will check TClass and addr, and set python errors)
570 PyObject *pyobject = CPyCppyy::BindCppObjectNoCast(addr, Cppyy::GetScope(classname), false);
571
572 // give ownership, for ref-counting, to the python side, if so requested
573 if (python_owns && CPyCppyy::CPPInstance_Check(pyobject))
574 ((CPyCppyy::CPPInstance *)pyobject)->PythonOwns();
575
576 return pyobject;
577}
#define PyBytes_Check
Definition: CPyCppyy.h:83
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
#define CPyCppyy_PyText_CheckExact
Definition: CPyCppyy.h:96
#define CPyCppyy_PyText_Check
Definition: CPyCppyy.h:95
#define R__EXTERN
Definition: DllImport.h:27
_object PyObject
Definition: PyMethodBase.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define ClassImp(name)
Definition: Rtypes.h:364
char name[80]
Definition: TGX11.cxx:110
static PyObject * gMainDict
Definition: TPython.cxx:96
#define gROOT
Definition: TROOT.h:404
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2955
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
Accessing the Python interpreter from C++.
Definition: TPython.h:29
static void Prompt()
Enter an interactive python session (exit with ^D).
Definition: TPython.cxx:478
static Bool_t CPPOverload_Check(PyObject *pyobject)
Test whether the type of the given pyobject is of CPPOverload type or any derived type.
Definition: TPython.cxx:520
static void * CPPInstance_AsVoidPtr(PyObject *pyobject)
Extract the object pointer held by the CPPInstance pyobject.
Definition: TPython.cxx:546
static Bool_t Import(const char *name)
Import the named python module and create Cling equivalents for its classes and methods.
Definition: TPython.cxx:172
static Bool_t CPPInstance_CheckExact(PyObject *pyobject)
Test whether the type of the given pyobject is CPPinstance type.
Definition: TPython.cxx:506
static Bool_t Bind(TObject *object, const char *label)
Bind a ROOT object with, at the python side, the name "label".
Definition: TPython.cxx:452
static void LoadMacro(const char *name)
Execute the give python script as if it were a macro (effectively an execfile in main),...
Definition: TPython.cxx:237
static Bool_t CPPOverload_CheckExact(PyObject *pyobject)
Test whether the type of the given pyobject is CPPOverload type.
Definition: TPython.cxx:533
static Bool_t Initialize()
Initialization method: setup the python interpreter and load the ROOT module.
Definition: TPython.cxx:112
static Bool_t Exec(const char *cmd)
Execute a python statement (e.g. "import ROOT").
Definition: TPython.cxx:376
static void ExecScript(const char *name, int argc=0, const char **argv=0)
Execute a python stand-alone script, with argv CLI arguments.
Definition: TPython.cxx:307
static Bool_t CPPInstance_Check(PyObject *pyobject)
Test whether the type of the given pyobject is of CPPInstance type or any derived type.
Definition: TPython.cxx:493
static const TPyReturn Eval(const char *expr)
Evaluate a python expression (e.g.
Definition: TPython.cxx:402
static PyObject * CPPInstance_FromVoidPtr(void *addr, const char *classname, Bool_t python_owns=kFALSE)
Bind the addr to a python object of class defined by classname.
Definition: TPython.cxx:563
R__EXTERN PyObject * gName
Definition: TPython.cxx:105
R__EXTERN PyObject * gCppName
Definition: TPython.cxx:103
R__EXTERN PyObject * gBases
R__EXTERN PyObject * gModule
Definition: TPython.cxx:104
Set of helper functions that are invoked from the pythonizors, on the Python side.
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
bool CPPOverload_Check(T *object)
Definition: CPPOverload.h:79
bool CPPInstance_Check(T *object)
Definition: CPPInstance.h:118
bool CPPInstance_CheckExact(T *object)
Definition: CPPInstance.h:128
R__EXTERN PyObject * gThisModule
Definition: TPython.cxx:100
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
bool CPPOverload_CheckExact(T *object)
Definition: CPPOverload.h:85
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
static constexpr double L
auto * l
Definition: textangle.C:4