Logo ROOT   6.16/01
Reference Guide
TPyClassGenerator.cxx
Go to the documentation of this file.
1// @(#)root/pyroot:$Id$
2// Author: Wim Lavrijsen, May 2004
3
4// Bindings
5#include "PyROOT.h"
6#include "PyStrings.h"
7#include "TPyClassGenerator.h"
8#include "TPyReturn.h"
9#include "Utility.h"
10
11// ROOT
12#include "TClass.h"
13#include "TInterpreter.h"
14#include "TROOT.h"
15
16// Standard
17#include <sstream>
18#include <string>
19#include <typeinfo>
20
21
22//- public members -----------------------------------------------------------
24{
25// Just forward.
26 return GetClass( name, load, kFALSE );
27}
28
29//- public members -----------------------------------------------------------
31{
32// Class generator to make python classes available to Cling
33
34// called if all other class generators failed, attempt to build from python class
36 return 0; // call originated from python
37
38 if ( ! load || ! name )
39 return 0;
40
41 PyROOT::PyGILRAII thePyGILRAII;
42
43// first, check whether the name is of a module
44 PyObject* modules = PySys_GetObject( const_cast<char*>("modules") );
46 PyObject* keys = PyDict_Keys( modules );
47 Bool_t isModule = PySequence_Contains( keys, pyname );
48 Py_DECREF( keys );
49 Py_DECREF( pyname );
50
51 if ( isModule ) {
52 // the normal TClass::GetClass mechanism doesn't allow direct returns, so
53 // do our own check
54 TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject( name );
55 if ( cl ) return cl;
56
57 std::ostringstream nsCode;
58 nsCode << "namespace " << name << " {\n";
59
60 // add all free functions
61 PyObject* mod = PyDict_GetItemString( modules, const_cast<char*>(name) );
62 PyObject* dct = PyModule_GetDict( mod );
63 keys = PyDict_Keys( dct );
64
65 for ( int i = 0; i < PyList_GET_SIZE( keys ); ++i ) {
66 PyObject* key = PyList_GET_ITEM( keys, i );
67 Py_INCREF( key );
68
69 PyObject* attr = PyDict_GetItem( dct, key );
70 Py_INCREF( attr );
71
72 // TODO: refactor the code below with the class method code
73 if ( PyCallable_Check( attr ) && \
74 ! (PyClass_Check( attr ) || PyObject_HasAttr( attr, PyROOT::PyStrings::gBases )) ) {
75 std::string func_name = PyROOT_PyUnicode_AsString( key );
76
77 // figure out number of variables required
78 PyObject* func_code = PyObject_GetAttrString( attr, (char*)"func_code" );
79 PyObject* var_names =
80 func_code ? PyObject_GetAttrString( func_code, (char*)"co_varnames" ) : NULL;
81 int nVars = var_names ? PyTuple_GET_SIZE( var_names ) : 0 /* TODO: probably large number, all default? */;
82 if ( nVars < 0 ) nVars = 0;
83 Py_XDECREF( var_names );
84 Py_XDECREF( func_code );
85
86 nsCode << " TPyReturn " << func_name << "(";
87 for ( int ivar = 0; ivar < nVars; ++ivar ) {
88 nsCode << "const TPyArg& a" << ivar;
89 if ( ivar != nVars-1 ) nsCode << ", ";
90 }
91 nsCode << ") {\n";
92 nsCode << " std::vector<TPyArg> v; v.reserve(" << nVars << ");\n";
93
94 // add the variables
95 for ( int ivar = 0; ivar < nVars; ++ ivar )
96 nsCode << " v.push_back(a" << ivar << ");\n";
97
98 // call dispatch (method or class pointer hard-wired)
99 nsCode << " return TPyReturn(TPyArg::CallMethod((PyObject*)" << (void*)attr << ", v)); }\n";
100 }
101
102 Py_DECREF( attr );
103 Py_DECREF( key );
104 }
105
106 Py_DECREF( keys );
107
108 nsCode << " }";
109
110 if ( gInterpreter->LoadText( nsCode.str().c_str() ) ) {
111 TClass* klass = new TClass( name, silent );
112 TClass::AddClass( klass );
113 return klass;
114 }
115
116 return nullptr;
117 }
118
119// determine module and class name part
120 std::string clName = name;
121 std::string::size_type pos = clName.rfind( '.' );
122
123 if ( pos == std::string::npos )
124 return 0; // this isn't a python style class
125
126 std::string mdName = clName.substr( 0, pos );
127 clName = clName.substr( pos+1, std::string::npos );
128
129// create class in namespace, if it exists (no load, silent)
130 Bool_t useNS = gROOT->GetListOfClasses()->FindObject( mdName.c_str() ) != 0;
131 if ( ! useNS ) {
132 // the class itself may exist if we're using the global scope
133 TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject( clName.c_str() );
134 if ( cl ) return cl;
135 }
136
137// locate and get class
138 PyObject* mod = PyImport_AddModule( const_cast< char* >( mdName.c_str() ) );
139 if ( ! mod ) {
140 PyErr_Clear();
141 return 0; // module apparently disappeared
142 }
143
144 Py_INCREF( mod );
145 PyObject* pyclass =
146 PyDict_GetItemString( PyModule_GetDict( mod ), const_cast< char* >( clName.c_str() ) );
147 Py_XINCREF( pyclass );
148 Py_DECREF( mod );
149
150 if ( ! pyclass ) {
151 PyErr_Clear(); // the class is no longer available?!
152 return 0;
153 }
154
155// get a listing of all python-side members
156 PyObject* attrs = PyObject_Dir( pyclass );
157 if ( ! attrs ) {
158 PyErr_Clear();
159 Py_DECREF( pyclass );
160 return 0;
161 }
162
163// pre-amble Cling proxy class
164 std::ostringstream proxyCode;
165 if ( useNS ) proxyCode << "namespace " << mdName << " { ";
166 proxyCode << "class " << clName << " {\nprivate:\n PyObject* fPyObject;\npublic:\n";
167
168// loop over and add member functions
169 Bool_t hasConstructor = kFALSE, hasDestructor = kFALSE;
170 for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) {
171 PyObject* label = PyList_GET_ITEM( attrs, i );
172 Py_INCREF( label );
173 PyObject* attr = PyObject_GetAttr( pyclass, label );
174
175 // collect only member functions (i.e. callable elements in __dict__)
176 if ( PyCallable_Check( attr ) ) {
177 std::string mtName = PyROOT_PyUnicode_AsString( label );
178
179 if ( mtName == "__del__" ) {
180 hasDestructor = kTRUE;
181 proxyCode << " ~" << clName << "() { TPyArg::CallDestructor(fPyObject); }\n";
182 continue;
183 }
184
185 Bool_t isConstructor = mtName == "__init__";
186 if ( !isConstructor && mtName.find("__", 0, 2) == 0 )
187 continue; // skip all other python special funcs
188
189 // figure out number of variables required
190#if PY_VERSION_HEX < 0x03000000
191 PyObject* im_func = PyObject_GetAttrString( attr, (char*)"im_func" );
192 PyObject* func_code =
193 im_func ? PyObject_GetAttrString( im_func, (char*)"func_code" ) : NULL;
194#else
195 PyObject* func_code = PyObject_GetAttrString( attr, "__code__" );
196#endif
197 PyObject* var_names =
198 func_code ? PyObject_GetAttrString( func_code, (char*)"co_varnames" ) : NULL;
199 if (PyErr_Occurred()) PyErr_Clear(); // happens for slots; default to 0 arguments
200
201 int nVars = var_names ? PyTuple_GET_SIZE( var_names ) - 1 /* self */ : 0 /* TODO: probably large number, all default? */;
202 if ( nVars < 0 ) nVars = 0;
203 Py_XDECREF( var_names );
204 Py_XDECREF( func_code );
205#if PY_VERSION_HEX < 0x03000000
206 Py_XDECREF( im_func );
207#endif
208
209 // method declaration as appropriate
210 if ( isConstructor ) {
211 hasConstructor = kTRUE;
212 proxyCode << " " << clName << "(";
213 } else // normal method
214 proxyCode << " TPyReturn " << mtName << "(";
215 for ( int ivar = 0; ivar < nVars; ++ivar ) {
216 proxyCode << "const TPyArg& a" << ivar;
217 if ( ivar != nVars-1 ) proxyCode << ", ";
218 }
219 proxyCode << ") {\n";
220 proxyCode << " std::vector<TPyArg> v; v.reserve(" << nVars+(isConstructor ? 0 : 1) << ");\n";
221
222 // add the 'self' argument as appropriate
223 if ( ! isConstructor )
224 proxyCode << " v.push_back(fPyObject);\n";
225
226 // then add the remaining variables
227 for ( int ivar = 0; ivar < nVars; ++ ivar )
228 proxyCode << " v.push_back(a" << ivar << ");\n";
229
230 // call dispatch (method or class pointer hard-wired)
231 if ( ! isConstructor )
232 proxyCode << " return TPyReturn(TPyArg::CallMethod((PyObject*)" << (void*)attr << ", v))";
233 else
234 proxyCode << " TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << ", v)";
235 proxyCode << ";\n }\n";
236 }
237
238 // no decref of attr for now (b/c of hard-wired ptr); need cleanup somehow
239 Py_DECREF( label );
240 }
241
242// special case if no constructor or destructor
243 if ( ! hasConstructor )
244 proxyCode << " " << clName << "() {\n TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << "); }\n";
245
246 if ( ! hasDestructor )
247 proxyCode << " ~" << clName << "() { TPyArg::CallDestructor(fPyObject); }\n";
248
249// for now, don't allow copying (ref-counting wouldn't work as expected anyway)
250 proxyCode << " " << clName << "(const " << clName << "&) = delete;\n";
251 proxyCode << " " << clName << "& operator=(const " << clName << "&) = delete;\n";
252
253// closing and building of Cling proxy class
254 proxyCode << "};";
255 if ( useNS ) proxyCode << " }";
256
257 Py_DECREF( attrs );
258// done with pyclass, decref here, assuming module is kept
259 Py_DECREF( pyclass );
260
261// body compilation
262 if ( ! gInterpreter->LoadText( proxyCode.str().c_str() ) )
263 return nullptr;
264
265// done, let ROOT manage the new class
266 TClass* klass = new TClass( useNS ? (mdName+"::"+clName).c_str() : clName.c_str(), silent );
267 TClass::AddClass( klass );
268
269 return klass;
270}
271
272////////////////////////////////////////////////////////////////////////////////
273/// Just forward; based on type name only.
274
275TClass* TPyClassGenerator::GetClass( const std::type_info& typeinfo, Bool_t load, Bool_t silent )
276{
277 return GetClass( typeinfo.name(), load, silent );
278}
279
280////////////////////////////////////////////////////////////////////////////////
281/// Just forward; based on type name only
282
283TClass* TPyClassGenerator::GetClass( const std::type_info& typeinfo, Bool_t load )
284{
285 return GetClass( typeinfo.name(), load );
286}
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:78
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:82
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define gInterpreter
Definition: TInterpreter.h:538
#define pyname
Definition: TMCParticle.cxx:19
_object PyObject
Definition: TPyArg.h:20
#define gROOT
Definition: TROOT.h:410
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
static void AddClass(TClass *cl)
static: Add a class to the list and map of classes.
Definition: TClass.cxx:444
virtual TClass * GetClass(const char *name, Bool_t load)
R__EXTERN PyObject * gBases
Definition: PyStrings.h:16
R__EXTERN Bool_t gDictLookupActive
Definition: Utility.h:18