Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
API.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#define CPYCPPYY_INTERNAL 1
4#include "CPyCppyy/API.h"
5#undef CPYCPPYY_INTERNAL
6
7#include "CPPInstance.h"
8#include "CPPOverload.h"
9#include "CPPScope.h"
10#include "ProxyWrappers.h"
11#include "PyStrings.h"
12
13// Standard
14#include <stdio.h>
15#include <iostream>
16#include <string>
17
18//______________________________________________________________________________
19// CPyCppyy API: Interpreter and Proxy Access
20// ==========================================
21//
22// Access to cppyy Python objects from Cling and C++: allows conversion for
23// instances and type checking for scopes, instances, etc.
24// Adds a few convenience functions to call Python from Cling and expose Python
25// classes to Cling for use in inheritance etc.
26
27
28//- data ---------------------------------------------------------------------
29static PyObject* gMainDict = nullptr;
30
31namespace CPyCppyy {
32 extern PyObject* gThisModule;
33}
34
35
36//- private helpers ----------------------------------------------------------
37namespace {
38
39static bool Initialize()
40{
41// Private initialization method: setup the python interpreter and load the
42// cppyy module.
43 static bool isInitialized = false;
44 if (isInitialized)
45 return true;
46
47 if (!Py_IsInitialized()) {
48 // this happens if Cling comes in first
49#if PY_VERSION_HEX < 0x03020000
50 PyEval_InitThreads();
51#endif
52#if PY_VERSION_HEX < 0x03080000
53 Py_Initialize();
54#else
55 PyConfig config;
56 PyConfig_InitPythonConfig(&config);
57 PyConfig_SetString(&config, &config.program_name, L"cppyy");
58 Py_InitializeFromConfig(&config);
59#endif
60#if PY_VERSION_HEX >= 0x03020000
61#if PY_VERSION_HEX < 0x03090000
62 PyEval_InitThreads();
63#endif
64#endif
65
66 // try again to see if the interpreter is initialized
67 if (!Py_IsInitialized()) {
68 // give up ...
69 std::cerr << "Error: python has not been intialized; returning." << std::endl;
70 return false;
71 }
72
73 // set the command line arguments on python's sys.argv
74#if PY_VERSION_HEX < 0x03000000
75 char* argv[] = {const_cast<char*>("cppyy")};
76#elif PY_VERSION_HEX < 0x03080000
77 wchar_t* argv[] = {const_cast<wchar_t*>(L"cppyy")};
78#endif
79#if PY_VERSION_HEX < 0x03080000
80 PySys_SetArgv(sizeof(argv)/sizeof(argv[0]), argv);
81#endif
82 // force loading of the cppyy module
83 PyRun_SimpleString(const_cast<char*>("import cppyy"));
84 }
85
86 if (!gMainDict) {
87 // retrieve the main dictionary
88 gMainDict = PyModule_GetDict(
89 PyImport_AddModule(const_cast<char*>("__main__")));
90 Py_INCREF(gMainDict);
91 }
92
93// declare success ...
94 isInitialized = true;
95 return true;
96}
97
98} // unnamed namespace
99
100
101//- C++ access to cppyy objects ---------------------------------------------
103{
104// Extract the object pointer held by the CPPInstance pyobject.
105 if (!Initialize())
106 return nullptr;
107
108// check validity of cast
109 if (!CPPInstance_Check(pyobject))
110 return nullptr;
111
112// get held object (may be null)
113 return ((CPPInstance*)pyobject)->GetObject();
114}
115
116//-----------------------------------------------------------------------------
118 void* addr, const std::string& classname, bool python_owns)
119{
120// Bind the addr to a python object of class defined by classname.
121 if (!Initialize())
122 return nullptr;
123
124// perform cast (the call will check TClass and addr, and set python errors)
125 PyObject* pyobject = BindCppObjectNoCast(addr, Cppyy::GetScope(classname), false);
126
127// give ownership, for ref-counting, to the python side, if so requested
128 if (python_owns && CPPInstance_Check(pyobject))
129 ((CPPInstance*)pyobject)->PythonOwns();
130
131 return pyobject;
132}
133
134
135//-----------------------------------------------------------------------------
137{
138// Test if the given object is of a CPPScope derived type.
139 if (!Initialize())
140 return false;
141
142 return CPPScope_Check(pyobject);
143}
144
145//-----------------------------------------------------------------------------
147{
148// Test if the given object is of a CPPScope type.
149 if (!Initialize())
150 return false;
151
152 return CPPScope_CheckExact(pyobject);
153}
154
155//-----------------------------------------------------------------------------
157{
158// Test if the given pyobject is of CPPInstance derived type.
159 if (!Initialize())
160 return false;
161
162// detailed walk through inheritance hierarchy
163 return CPPInstance_Check(pyobject);
164}
165
166//-----------------------------------------------------------------------------
168{
169// Test if the given pyobject is of CPPInstance type.
170 if (!Initialize())
171 return false;
172
173// direct pointer comparison of type member
174 return CPPInstance_CheckExact(pyobject);
175}
176
177//-----------------------------------------------------------------------------
179{
180// Test whether the given instance can safely return to C++, or whether
181 if (!CPPInstance_Check(pyobject))
182 return true; // simply don't know
183
184// the instance fails the lively test if it owns the C++ object while having a
185// reference count of 1 (meaning: it could delete the C++ instance any moment)
186 if (pyobject->ob_refcnt <= 1 && (((CPPInstance*)pyobject)->fFlags & CPPInstance::kIsOwner))
187 return false;
188
189 return true;
190}
191
192//-----------------------------------------------------------------------------
194{
195// Test if the given pyobject is of CPPOverload derived type.
196 if (!Initialize())
197 return false;
198
199// detailed walk through inheritance hierarchy
200 return CPPOverload_Check(pyobject);
201}
202
203//-----------------------------------------------------------------------------
205{
206// Test if the given pyobject is of CPPOverload type.
207 if (!Initialize())
208 return false;
209
210// direct pointer comparison of type member
211 return CPPOverload_CheckExact(pyobject);
212}
213
214
215//- access to the python interpreter ----------------------------------------
216bool CPyCppyy::Import(const std::string& mod_name)
217{
218// Import the named python module and create Cling equivalents for its classes.
219 if (!Initialize())
220 return false;
221
222 PyObject* mod = PyImport_ImportModule(mod_name.c_str());
223 if (!mod) {
224 PyErr_Print();
225 return false;
226 }
227
228// allow finding to prevent creation of a python proxy for the C++ proxy
229 Py_INCREF(mod);
230 PyModule_AddObject(gThisModule, mod_name.c_str(), mod);
231
232// force creation of the module as a namespace
233// TODO: the following is broken (and should live in Cppyy.cxx)
234// TClass::GetClass(mod_name, true);
235
236 PyObject* dct = PyModule_GetDict(mod);
237
238// create Cling classes for all new python classes
239 PyObject* values = PyDict_Values(dct);
240 for (int i = 0; i < PyList_GET_SIZE(values); ++i) {
241 PyObject* value = PyList_GET_ITEM(values, i);
242 Py_INCREF(value);
243
244 // collect classes
245 if (PyClass_Check(value) || PyObject_HasAttr(value, PyStrings::gBases)) {
246 // get full class name (including module)
247 PyObject* pyClName = PyObject_GetAttr(value, PyStrings::gName);
248 if (PyErr_Occurred())
249 PyErr_Clear();
250
251 // build full, qualified name
252 std::string fullname = mod_name;
253 fullname += ".";
254 fullname += CPyCppyy_PyText_AsString(pyClName);
255
256 // force class creation (this will eventually call TPyClassGenerator)
257 // TODO: the following is broken (and should live in Cppyy.cxx) to
258 // TClass::GetClass(fullname.c_str(), true);
259
260 Py_XDECREF(pyClName);
261 }
262
263 Py_DECREF(value);
264 }
265
266 Py_DECREF(values);
267
268// TODO: mod "leaks" here
269 if (PyErr_Occurred())
270 return false;
271 return true;
272}
273
274//-----------------------------------------------------------------------------
275void CPyCppyy::ExecScript(const std::string& name, const std::vector<std::string>& args)
276{
277// Execute a python stand-alone script, with argv CLI arguments.
278//
279// example of use:
280// CPyCppyy::ExecScript("test.py", {"1", "2", "3"});
281
282 if (!Initialize())
283 return;
284
285// verify arguments
286 if (name.empty()) {
287 std::cerr << "Error: no file name specified." << std::endl;
288 return;
289 }
290
291 FILE* fp = fopen(name.c_str(), "r");
292 if (!fp) {
293 std::cerr << "Error: could not open file \"" << name << "\"." << std::endl;
294 return;
295 }
296
297// store a copy of the old cli for restoration
298 PyObject* oldargv = PySys_GetObject(const_cast<char*>("argv")); // borrowed
299 if (!oldargv) // e.g. apache
300 PyErr_Clear();
301 else {
302 PyObject* l = PyList_New(PyList_GET_SIZE(oldargv));
303 for (int i = 0; i < PyList_GET_SIZE(oldargv); ++i) {
304 PyObject* item = PyList_GET_ITEM(oldargv, i);
305 Py_INCREF(item);
306 PyList_SET_ITEM(l, i, item); // steals ref
307 }
308 oldargv = l;
309 }
310
311// create and set (add progam name) the new command line
312#if PY_VERSION_HEX < 0x03000000
313 int argc = args.size() + 1;
314 const char** argv = new const char*[argc];
315 for (int i = 1; i < argc; ++i) argv[i] = args[i-1].c_str();
316 argv[0] = Py_GetProgramName();
317 PySys_SetArgv(argc, const_cast<char**>(argv));
318 delete [] argv;
319#else
320// TODO: fix this to work like above ...
321 (void)args;
322#endif
323
324// actual script execution
325 PyObject* gbl = PyDict_Copy(gMainDict);
326 PyObject* result = // PyRun_FileEx closes fp (b/c of last argument "1")
327 PyRun_FileEx(fp, const_cast<char*>(name.c_str()), Py_file_input, gbl, gbl, 1);
328 if (!result)
329 PyErr_Print();
330 Py_XDECREF(result);
331 Py_DECREF(gbl);
332
333// restore original command line
334 if (oldargv) {
335 PySys_SetObject(const_cast<char*>("argv"), oldargv);
336 Py_DECREF(oldargv);
337 }
338}
339
340//-----------------------------------------------------------------------------
341bool CPyCppyy::Exec(const std::string& cmd)
342{
343// Execute a python statement (e.g. "import noddy").
344 if (!Initialize())
345 return false;
346
347// execute the command
349 PyRun_String(const_cast<char*>(cmd.c_str()), Py_file_input, gMainDict, gMainDict);
350
351// test for error
352 if (result) {
353 Py_DECREF(result);
354 return true;
355 }
356
357 PyErr_Print();
358 return false;
359}
360
361//-----------------------------------------------------------------------------
362const CPyCppyy::PyResult CPyCppyy::Eval(const std::string& expr)
363{
364// Evaluate a python expression.
365//
366// Caution: do not hold on to the return value: either store it in a builtin
367// type (implicit casting will work), or in a pointer to a cppyy object (explicit
368// casting to a void* is required).
369 if (!Initialize())
370 return PyResult();
371
372// evaluate the expression
374 PyRun_String(const_cast<char*>(expr.c_str()), Py_eval_input, gMainDict, gMainDict);
375
376// report errors as appropriate; return void
377 if (!result) {
378 PyErr_Print();
379 return PyResult();
380 }
381
382// results that require no convserion
383 if (result == Py_None || CPPInstance_Check(result) ||
385 PyFloat_Check(result) || PyLong_Check(result) || PyInt_Check(result))
386 return PyResult(result);
387
388// explicit conversion for python type required
389 PyObject* pyclass = (PyObject*)Py_TYPE(result);
390
391// retrieve class name and the module in which it resides
392 PyObject* name = PyObject_GetAttr(pyclass, PyStrings::gName);
393 PyObject* module = PyObject_GetAttr(pyclass, PyStrings::gModule);
394
395 // concat name
396 std::string qname =
397 std::string(CPyCppyy_PyText_AsString(module)) + \
399 Py_DECREF(module);
400 Py_DECREF(name);
401
402// locate cppyy style class with this name
403 // TODO: use Cppyy.cxx ...
404 //TClass* klass = TClass::GetClass(qname.c_str());
405 void* klass = nullptr;
406
407// construct general cppyy python object that pretends to be of class 'klass'
408 if (klass)
409 return PyResult(result);
410
411// no conversion, return null pointer object
412 Py_DECREF(result);
413 return PyResult();
414}
415
416//-----------------------------------------------------------------------------
418// Enter an interactive python session (exit with ^D). State is preserved
419// between successive calls.
420 if (!Initialize())
421 return;
422
423// enter i/o interactive mode
424 PyRun_InteractiveLoop(stdin, const_cast<char*>("\0"));
425}
static PyObject * gMainDict
Definition API.cxx:29
#define Py_TYPE(ob)
Definition CPyCppyy.h:217
#define PyBytes_Check
Definition CPyCppyy.h:83
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:97
_object PyObject
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
Set of helper functions that are invoked from the pythonizors, on the Python side.
CPYCPPYY_EXTERN bool Instance_CheckExact(PyObject *pyobject)
Definition API.cxx:167
CPYCPPYY_EXTERN void Prompt()
Definition API.cxx:417
CPYCPPYY_EXTERN bool Overload_Check(PyObject *pyobject)
Definition API.cxx:193
CPYCPPYY_EXTERN bool Overload_CheckExact(PyObject *pyobject)
Definition API.cxx:204
CPYCPPYY_EXTERN bool Import(const std::string &name)
Definition API.cxx:216
CPYCPPYY_EXTERN void ExecScript(const std::string &name, const std::vector< std::string > &args)
Definition API.cxx:275
CPYCPPYY_EXTERN bool Instance_IsLively(PyObject *pyobject)
Definition API.cxx:178
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
bool CPPOverload_Check(T *object)
Definition CPPOverload.h:79
bool CPPScope_Check(T *object)
Definition CPPScope.h:76
CPYCPPYY_EXTERN bool Instance_Check(PyObject *pyobject)
Definition API.cxx:156
CPYCPPYY_EXTERN PyObject * Instance_FromVoidPtr(void *addr, const std::string &classname, bool python_owns=false)
Definition API.cxx:117
CPYCPPYY_EXTERN bool Scope_CheckExact(PyObject *pyobject)
Definition API.cxx:146
bool CPPInstance_Check(T *object)
bool CPPInstance_CheckExact(T *object)
R__EXTERN PyObject * gThisModule
Definition TPython.cxx:100
bool CPPScope_CheckExact(T *object)
Definition CPPScope.h:82
CPYCPPYY_EXTERN void * Instance_AsVoidPtr(PyObject *pyobject)
Definition API.cxx:102
CPYCPPYY_EXTERN bool Scope_Check(PyObject *pyobject)
Definition API.cxx:136
CPYCPPYY_EXTERN bool Exec(const std::string &cmd)
Definition API.cxx:341
bool CPPOverload_CheckExact(T *object)
Definition CPPOverload.h:85
CPYCPPYY_EXTERN const PyResult Eval(const std::string &expr)
Definition API.cxx:362
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RooArgList L(Args_t &&... args)
Definition RooArgList.h:156
void Initialize(Bool_t useTMVAStyle=kTRUE)
Definition tmvaglob.cxx:176
TLine l
Definition textangle.C:4