ROOT  6.06/09
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 -----------------------------------------------------------
30 TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load, Bool_t silent )
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 // first, check whether the name is of a module
42  PyObject* modules = PySys_GetObject( const_cast<char*>("modules") );
44  PyObject* keys = PyDict_Keys( modules );
45  Bool_t isModule = PySequence_Contains( keys, pyname );
46  Py_DECREF( keys );
47  Py_DECREF( pyname );
48 
49  if ( isModule ) {
50  // the normal TClass::GetClass mechanism doesn't allow direct returns, so
51  // do our own check
52  TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject( name );
53  if ( cl ) return cl;
54 
55  std::ostringstream nsCode;
56  nsCode << "namespace " << name << " {\n";
57 
58  // add all free functions
59  PyObject* mod = PyDict_GetItemString( modules, const_cast<char*>(name) );
60  PyObject* dct = PyModule_GetDict( mod );
61  keys = PyDict_Keys( dct );
62 
63  for ( int i = 0; i < PyList_GET_SIZE( keys ); ++i ) {
64  PyObject* key = PyList_GET_ITEM( keys, i );
65  Py_INCREF( key );
66 
67  PyObject* attr = PyDict_GetItem( dct, key );
68  Py_INCREF( attr );
69 
70  // TODO: refactor the code below with the class method code
71  if ( PyCallable_Check( attr ) && \
72  ! (PyClass_Check( attr ) || PyObject_HasAttr( attr, PyROOT::PyStrings::gBases )) ) {
73  std::string func_name = PyROOT_PyUnicode_AsString( key );
74 
75  // figure out number of variables required
76  PyObject* func_code = PyObject_GetAttrString( attr, (char*)"func_code" );
77  PyObject* var_names =
78  func_code ? PyObject_GetAttrString( func_code, (char*)"co_varnames" ) : NULL;
79  int nVars = var_names ? PyTuple_GET_SIZE( var_names ) : 0 /* TODO: probably large number, all default? */;
80  if ( nVars < 0 ) nVars = 0;
81  Py_XDECREF( var_names );
82  Py_XDECREF( func_code );
83 
84  nsCode << " TPyReturn " << func_name << "(";
85  for ( int ivar = 0; ivar < nVars; ++ivar ) {
86  nsCode << "const TPyArg& a" << ivar;
87  if ( ivar != nVars-1 ) nsCode << ", ";
88  }
89  nsCode << ") {\n";
90  nsCode << " std::vector<TPyArg> v; v.reserve(" << nVars << ");\n";
91 
92  // add the variables
93  for ( int ivar = 0; ivar < nVars; ++ ivar )
94  nsCode << " v.push_back(a" << ivar << ");\n";
95 
96  // call dispatch (method or class pointer hard-wired)
97  nsCode << " return TPyReturn(TPyArg::CallMethod((PyObject*)" << (void*)attr << ", v)); }\n";
98  }
99 
100  Py_DECREF( attr );
101  Py_DECREF( key );
102  }
103 
104  Py_DECREF( keys );
105 
106  nsCode << " }";
107 
108  if ( gInterpreter->LoadText( nsCode.str().c_str() ) ) {
109  TClass* klass = new TClass( name, silent );
110  TClass::AddClass( klass );
111  return klass;
112  }
113 
114  return nullptr;
115  }
116 
117 // determine module and class name part
118  std::string clName = name;
119  std::string::size_type pos = clName.rfind( '.' );
120 
121  if ( pos == std::string::npos )
122  return 0; // this isn't a python style class
123 
124  std::string mdName = clName.substr( 0, pos );
125  clName = clName.substr( pos+1, std::string::npos );
126 
127 // create class in namespace, if it exists (no load, silent)
128  Bool_t useNS = gROOT->GetListOfClasses()->FindObject( mdName.c_str() ) != 0;
129  if ( ! useNS ) {
130  // the class itself may exist if we're using the global scope
131  TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject( clName.c_str() );
132  if ( cl ) return cl;
133  }
134 
135 // locate and get class
136  PyObject* mod = PyImport_AddModule( const_cast< char* >( mdName.c_str() ) );
137  if ( ! mod ) {
138  PyErr_Clear();
139  return 0; // module apparently disappeared
140  }
141 
142  Py_INCREF( mod );
143  PyObject* pyclass =
144  PyDict_GetItemString( PyModule_GetDict( mod ), const_cast< char* >( clName.c_str() ) );
145  Py_XINCREF( pyclass );
146  Py_DECREF( mod );
147 
148  if ( ! pyclass ) {
149  PyErr_Clear(); // the class is no longer available?!
150  return 0;
151  }
152 
153 // get a listing of all python-side members
154  PyObject* attrs = PyObject_Dir( pyclass );
155  if ( ! attrs ) {
156  PyErr_Clear();
157  Py_DECREF( pyclass );
158  return 0;
159  }
160 
161 // pre-amble Cling proxy class
162  std::ostringstream proxyCode;
163  if ( useNS ) proxyCode << "namespace " << mdName << " { ";
164  proxyCode << "class " << clName << " {\nprivate:\n PyObject* fPyObject;\npublic:\n";
165 
166 // loop over and add member functions
167  Bool_t hasConstructor = kFALSE;
168  for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) {
169  PyObject* label = PyList_GET_ITEM( attrs, i );
170  Py_INCREF( label );
171  PyObject* attr = PyObject_GetAttr( pyclass, label );
172 
173  // collect only member functions (i.e. callable elements in __dict__)
174  if ( PyCallable_Check( attr ) ) {
175  std::string mtName = PyROOT_PyUnicode_AsString( label );
176 
177  // figure out number of variables required
178  PyObject* im_func = PyObject_GetAttrString( attr, (char*)"im_func" );
179  PyObject* func_code =
180  im_func ? PyObject_GetAttrString( im_func, (char*)"func_code" ) : NULL;
181  PyObject* var_names =
182  func_code ? PyObject_GetAttrString( func_code, (char*)"co_varnames" ) : NULL;
183  int nVars = var_names ? PyTuple_GET_SIZE( var_names ) - 1 /* self */ : 0 /* TODO: probably large number, all default? */;
184  if ( nVars < 0 ) nVars = 0;
185  Py_XDECREF( var_names );
186  Py_XDECREF( func_code );
187  Py_XDECREF( im_func );
188 
189  Bool_t isConstructor = mtName == "__init__";
190  Bool_t isDestructor = mtName == "__del__";
191 
192  // method declaration as appropriate
193  if ( isConstructor ) {
194  hasConstructor = kTRUE;
195  proxyCode << " " << clName << "(";
196  } else if ( isDestructor )
197  proxyCode << " ~" << clName << "(";
198  else // normal method
199  proxyCode << " TPyReturn " << mtName << "(";
200  for ( int ivar = 0; ivar < nVars; ++ivar ) {
201  proxyCode << "const TPyArg& a" << ivar;
202  if ( ivar != nVars-1 ) proxyCode << ", ";
203  }
204  proxyCode << ") {\n";
205  proxyCode << " std::vector<TPyArg> v; v.reserve(" << nVars+(isConstructor ? 0 : 1) << ");\n";
206 
207  // add the 'self' argument as appropriate
208  if ( ! isConstructor )
209  proxyCode << " v.push_back(fPyObject);\n";
210 
211  // then add the remaining variables
212  for ( int ivar = 0; ivar < nVars; ++ ivar )
213  proxyCode << " v.push_back(a" << ivar << ");\n";
214 
215  // call dispatch (method or class pointer hard-wired)
216  if ( ! isConstructor )
217  proxyCode << " return TPyReturn(TPyArg::CallMethod((PyObject*)" << (void*)attr << ", v))";
218  else
219  proxyCode << " TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << ", v)";
220  proxyCode << ";\n }\n";
221  }
222 
223  // no decref of attr for now (b/c of hard-wired ptr); need cleanup somehow
224  Py_DECREF( label );
225  }
226 
227 // special case if no constructor
228  if ( ! hasConstructor )
229  proxyCode << " " << clName << "() {\n TPyArg::CallConstructor(fPyObject, (PyObject*)" << (void*)pyclass << "); }\n";
230 
231 // closing and building of Cling proxy class
232  proxyCode << "};";
233  if ( useNS ) proxyCode << " }";
234 
235  Py_DECREF( attrs );
236 // done with pyclass, decref here, assuming module is kept
237  Py_DECREF( pyclass );
238 
239 // body compilation
240  if ( ! gInterpreter->LoadText( proxyCode.str().c_str() ) )
241  return nullptr;
242 
243 // done, let ROOT manage the new class
244  TClass* klass = new TClass( useNS ? (mdName+"::"+clName).c_str() : clName.c_str(), silent );
245  TClass::AddClass( klass );
246 
247  return klass;
248 }
249 
250 ////////////////////////////////////////////////////////////////////////////////
251 /// Just forward; based on type name only.
252 
253 TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load, Bool_t silent )
254 {
255  return GetClass( typeinfo.name(), load, silent );
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 /// Just forward; based on type name only
260 
261 TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load )
262 {
263  return GetClass( typeinfo.name(), load );
264 }
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:71
#define pyname
Definition: TMCParticle.cxx:16
#define gROOT
Definition: TROOT.h:340
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
#define gInterpreter
Definition: TInterpreter.h:502
R__EXTERN Bool_t gDictLookupActive
Definition: Utility.h:18
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:66
R__EXTERN PyObject * gBases
Definition: PyStrings.h:16
virtual TClass * GetClass(const char *name, Bool_t load)
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
static void AddClass(TClass *cl)
static: Add a class to the list and map of classes.
Definition: TClass.cxx:450
#define name(a, b)
Definition: linkTestLib0.cpp:5
#define NULL
Definition: Rtypes.h:82
const Bool_t kTRUE
Definition: Rtypes.h:91
_object PyObject
Definition: TPyArg.h:22