Logo ROOT   6.14/05
Reference Guide
RootWrapper.cxx
Go to the documentation of this file.
1 // @(#)root/pyroot:$Id$
2 // Author: Wim Lavrijsen, Apr 2004
3 
4 // Bindings
5 #include "PyROOT.h"
6 #include "PyStrings.h"
7 #include "RootWrapper.h"
8 #include "PyRootType.h"
9 #include "ObjectProxy.h"
10 #include "MethodProxy.h"
11 #include "TemplateProxy.h"
12 #include "PropertyProxy.h"
13 #include "Pythonize.h"
14 #include "TMethodHolder.h"
15 #include "TConstructorHolder.h"
16 #include "TClassMethodHolder.h"
17 #include "TFunctionHolder.h"
18 #include "TSetItemHolder.h"
19 #include "TMemoryRegulator.h"
20 #include "TTupleOfInstances.h"
21 #include "Utility.h"
22 
23 // ROOT
24 #include "TROOT.h"
25 #include "TSystem.h"
26 #include "TDataMember.h"
27 #include "TClassEdit.h"
28 #include "TEnum.h"
29 #include "TEnumConstant.h"
30 #include "TInterpreter.h"
31 #include "TGlobal.h"
32 #include "DllImport.h"
33 
34 // Standard
35 #include <map>
36 #include <set>
37 #include <string>
38 #include <algorithm>
39 #include <vector>
40 
41 //- FOR CLING WORKAROUND
42 #include "TError.h"
43 //
44 
45 
46 //- data _______________________________________________________________________
47 namespace PyROOT {
49 
50 // TODO: move this to Cppyy.cxx (if possible) (and gPinnedTypes should be a hashmap)
51  R__EXTERN std::vector<std::pair<Cppyy::TCppType_t, Cppyy::TCppType_t> > gPinnedTypes;
52  R__EXTERN std::vector<Cppyy::TCppType_t> gIgnorePinnings;
53 }
54 
55 namespace {
56 
57 // to prevent having to walk scopes, track python classes by ROOT class
58  typedef std::map< Cppyy::TCppScope_t, PyObject* > PyClassMap_t;
59  PyClassMap_t gPyClasses;
60 
61 // helper for creating new ROOT python types
62  PyObject* CreateNewROOTPythonClass( const std::string& name, PyObject* pybases )
63  {
64  // Create a new python shadow class with the required hierarchy and meta-classes.
65  Py_XINCREF( pybases );
66  if ( ! pybases ) {
67  pybases = PyTuple_New( 1 );
68  Py_INCREF( (PyObject*)(void*)&PyROOT::ObjectProxy_Type );
69  PyTuple_SET_ITEM( pybases, 0, (PyObject*)(void*)&PyROOT::ObjectProxy_Type );
70  }
71 
72  PyObject* pymetabases = PyTuple_New( PyTuple_GET_SIZE( pybases ) );
73  for ( int i = 0; i < PyTuple_GET_SIZE( pybases ); ++i ) {
74  PyObject* btype = (PyObject*)Py_TYPE( PyTuple_GetItem( pybases, i ) );
75  Py_INCREF( btype );
76  PyTuple_SET_ITEM( pymetabases, i, btype );
77  }
78 
79  PyObject* args = Py_BuildValue( (char*)"sO{}", (name+"_meta").c_str(), pymetabases );
80  Py_DECREF( pymetabases );
81 
82  PyObject* pymeta = PyType_Type.tp_new( &PyROOT::PyRootType_Type, args, NULL );
83  Py_DECREF( args );
84  if ( ! pymeta ) {
85  PyErr_Print();
86  Py_DECREF( pybases );
87  return 0;
88  }
89 
90  args = Py_BuildValue( (char*)"sO{}", Cppyy::GetName(name).c_str(), pybases );
91  PyObject* pyclass = ((PyTypeObject*)pymeta)->tp_new( (PyTypeObject*)pymeta, args, NULL );
92  Py_DECREF( args );
93  Py_DECREF( pymeta );
94 
95  Py_DECREF( pybases );
96 
97  return pyclass;
98  }
99 
100  inline void AddPropertyToClass1(
101  PyObject* pyclass, PyROOT::PropertyProxy* property, Bool_t isStatic )
102  {
103  // allow access at the instance level
104  PyObject_SetAttrString( pyclass,
105  const_cast< char* >( property->GetName().c_str() ), (PyObject*)property );
106 
107  // allow access at the class level (always add after setting instance level)
108  if ( isStatic ) {
109  PyObject_SetAttrString( (PyObject*)Py_TYPE(pyclass),
110  const_cast< char* >( property->GetName().c_str() ), (PyObject*)property );
111  }
112  }
113 
114  void AddPropertyToClass( PyObject* pyclass,
116  {
117  PyROOT::PropertyProxy* property = PyROOT::PropertyProxy_New( scope, idata );
118  AddPropertyToClass1( pyclass, property, Cppyy::IsStaticData( scope, idata ) );
119  Py_DECREF( property );
120  }
121 
122  void AddPropertyToClass( PyObject* pyclass,
123  Cppyy::TCppScope_t scope, const std::string& name, void* address )
124  {
125  PyROOT::PropertyProxy* property =
126  PyROOT::PropertyProxy_NewConstant( scope, name, address );
127  AddPropertyToClass1( pyclass, property, kTRUE );
128  Py_DECREF( property );
129  }
130 
131 
132 } // unnamed namespace
133 
134 
135 //- helpers --------------------------------------------------------------------
136 namespace {
137 
138  using namespace PyROOT;
139 
140  inline void AddToGlobalScope(
141  const char* label, const char* /* hdr */, TObject* obj, Cppyy::TCppType_t klass )
142  {
143  // Bind the given object with the given class in the global scope with the
144  // given label for its reference.
145  PyModule_AddObject( gRootModule, const_cast< char* >( label ),
146  PyROOT::BindCppObjectNoCast( obj, klass ) );
147  }
148 
149  std::set< std::string > gSTLTypes, gSTLExceptions;
150  struct InitSTLTypes_t {
151  InitSTLTypes_t()
152  {
153  // Initialize the sets of known STL (container) types.
154  const std::string nss = "std::";
155 
156  const char* stlTypes[] = { "complex", "exception",
157  "deque", "list", "queue", "stack", "vector",
158  "map", "multimap", "set", "multiset" };
159  for ( int i = 0; i < int(sizeof(stlTypes)/sizeof(stlTypes[0])); ++i ) {
160  gSTLTypes.insert( stlTypes[ i ] );
161  gSTLTypes.insert( nss + stlTypes[ i ] );
162  }
163 
164  const char* stlExceptions[] = { "logic_error", "domain_error",
165  "invalid_argument", "length_error", "out_of_range", "runtime_error",
166  "range_error", "overflow_error", "underflow_error" };
167  for ( int i = 0; i < int(sizeof(stlExceptions)/sizeof(stlExceptions[0])); ++i ) {
168  gSTLExceptions.insert( stlExceptions[ i ] );
169  gSTLExceptions.insert( nss + stlExceptions[ i ] );
170  }
171  }
172  } initSTLTypes_;
173 } // unnamed namespace
174 
175 
176 //- public functions ---------------------------------------------------------
178 {
179 // setup interpreter locks to allow for threading in ROOT
180  PyEval_InitThreads();
181 
182 // memory management
183  static TMemoryRegulator m;
184  gROOT->GetListOfCleanups()->Add( &m );
185 
186 // bind ROOT globals that are needed in ROOT.py
187  AddToGlobalScope( "gROOT", "TROOT.h", gROOT, Cppyy::GetScope( gROOT->IsA()->GetName() ) );
188  AddToGlobalScope( "gSystem", "TSystem.h", gSystem, Cppyy::GetScope( gSystem->IsA()->GetName() ) );
189  AddToGlobalScope( "gInterpreter", "TInterpreter.h", gInterpreter, Cppyy::GetScope( gInterpreter->IsA()->GetName() ) );
190 }
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// Collect methods and data for the given scope, and add them to the given python
194 /// proxy object.
195 
196 static int BuildScopeProxyDict( Cppyy::TCppScope_t scope, PyObject* pyclass ) {
197 // some properties that'll affect building the dictionary
198  Bool_t isNamespace = Cppyy::IsNamespace( scope );
199  Bool_t hasConstructor = kFALSE;
200 
201 // load all public methods and data members
202  typedef std::vector< PyCallable* > Callables_t;
203  typedef std::map< std::string, Callables_t > CallableCache_t;
204  CallableCache_t cache;
205 
206 // bypass custom __getattr__ for efficiency
207  getattrofunc oldgetattro = Py_TYPE(pyclass)->tp_getattro;
208  Py_TYPE(pyclass)->tp_getattro = PyType_Type.tp_getattro;
209 
210 // functions in namespaces are properly found through lazy lookup, so do not
211 // create them until needed (the same is not true for data members)
212  const Cppyy::TCppIndex_t nMethods =
213  Cppyy::IsNamespace( scope ) ? 0 : Cppyy::GetNumMethods( scope );
214  for ( Cppyy::TCppIndex_t imeth = 0; imeth < nMethods; ++imeth ) {
215  Cppyy::TCppMethod_t method = Cppyy::GetMethod( scope, imeth );
216 
217  // process the method based on its name
218  std::string mtName = Cppyy::GetMethodName( method );
219 
220  // special case trackers
221  Bool_t setupSetItem = kFALSE;
222  Bool_t isConstructor = Cppyy::IsConstructor( method );
223 
224  // filter empty names (happens for namespaces, is bug?)
225  if ( mtName == "" )
226  continue;
227 
228  // filter C++ destructors
229  if ( mtName[0] == '~' )
230  continue;
231 
232  // translate operators
233  mtName = Utility::MapOperatorName( mtName, Cppyy::GetMethodNumArgs( method ) );
234 
235  // operator[]/() returning a reference type will be used for __setitem__
236  if ( mtName == "__call__" || mtName == "__getitem__" ) {
237  const std::string& qual_return = Cppyy::ResolveName( Cppyy::GetMethodResultType( method ) );
238  if ( qual_return.find( "const", 0, 5 ) == std::string::npos ) {
239  const std::string& cpd = Utility::Compound( qual_return );
240  if ( ! cpd.empty() && cpd[ cpd.size() - 1 ] == '&' ) {
241  setupSetItem = kTRUE;
242  }
243  }
244  }
245 
246  // decide on method type: member or static (which includes globals)
247  Bool_t isStatic = Cppyy::IsStaticMethod( method );
248 
249  // template members; handled by adding a dispatcher to the class
250  std::string tmplName = "";
251  if ( ! (isNamespace || isStatic || isConstructor) && mtName[mtName.size()-1] == '>' ) {
252  tmplName = mtName.substr( 0, mtName.find('<') );
253  // TODO: the following is incorrect if both base and derived have the same
254  // templated method (but that is an unlikely scenario anyway)
255  PyObject* attr = PyObject_GetAttrString( pyclass, const_cast< char* >( tmplName.c_str() ) );
256  if ( ! TemplateProxy_Check( attr ) ) {
257  PyErr_Clear();
258  TemplateProxy* pytmpl = TemplateProxy_New( tmplName, pyclass );
259  if ( MethodProxy_Check( attr ) ) pytmpl->AddOverload( (MethodProxy*)attr );
260  PyObject_SetAttrString(
261  pyclass, const_cast< char* >( tmplName.c_str() ), (PyObject*)pytmpl );
262  Py_DECREF( pytmpl );
263  }
264  Py_XDECREF( attr );
265  // continue processing to actually add the method so that the proxy can find
266  // it on the class when called explicitly
267  }
268 
269  // public methods are normally visible, private methods are mangled python-wise
270  // note the overload implications which are name based, and note that rootcint
271  // does not create the interface methods for private/protected methods ...
272  if ( ! Cppyy::IsPublicMethod( method ) ) {
273  if ( isConstructor ) // don't expose private ctors
274  continue;
275  else { // mangle private methods
276  const std::string& clName = TClassEdit::ShortType(
277  Cppyy::GetFinalName( scope ).c_str(), TClassEdit::kDropAlloc );
278  mtName = "_" + clName + "__" + mtName;
279  }
280  }
281 
282  // construct the holder
283  PyCallable* pycall = 0;
284  if ( isStatic ) // class method
285  pycall = new TClassMethodHolder( scope, method );
286  else if ( isNamespace ) // free function
287  pycall = new TFunctionHolder( scope, method );
288  else if ( isConstructor ) { // constructor
289  pycall = new TConstructorHolder( scope, method );
290  mtName = "__init__";
291  hasConstructor = kTRUE;
292  } else // member function
293  pycall = new TMethodHolder( scope, method );
294 
295  // lookup method dispatcher and store method
296  Callables_t& md = (*(cache.insert(
297  std::make_pair( mtName, Callables_t() ) ).first)).second;
298  md.push_back( pycall );
299 
300  // special case for operator[]/() that returns by ref, use for getitem/call and setitem
301  if ( setupSetItem ) {
302  Callables_t& setitem = (*(cache.insert(
303  std::make_pair( std::string( "__setitem__" ), Callables_t() ) ).first)).second;
304  setitem.push_back( new TSetItemHolder( scope, method ) );
305  }
306 
307  // special case for templates, add another call for the template name
308  if ( ! tmplName.empty() ) {
309  PyObject* attr = PyObject_GetAttrString( pyclass, const_cast< char* >( tmplName.c_str() ) );
310  ((TemplateProxy*)attr)->AddTemplate( pycall->Clone() );
311  Py_DECREF( attr );
312  }
313  }
314 
315 // add a pseudo-default ctor, if none defined
316  if ( ! isNamespace && ! hasConstructor )
317  cache[ "__init__" ].push_back( new TConstructorHolder( scope, (Cppyy::TCppMethod_t)0 ) );
318 
319 // add the methods to the class dictionary
320  for ( CallableCache_t::iterator imd = cache.begin(); imd != cache.end(); ++imd ) {
321  // in order to prevent removing templated editions of this method (which were set earlier,
322  // above, as a different proxy object), we'll check and add this method flagged as a generic
323  // one (to be picked up by the templated one as appropriate) if a template exists
324  PyObject* attr = PyObject_GetAttrString( pyclass, const_cast< char* >( imd->first.c_str() ) );
325  if ( TemplateProxy_Check( attr ) ) {
326  // template exists, supply it with the non-templated method overloads
327  for ( Callables_t::iterator cit = imd->second.begin(); cit != imd->second.end(); ++cit )
328  ((TemplateProxy*)attr)->AddOverload( *cit );
329  } else {
330  if ( ! attr ) PyErr_Clear();
331  // normal case, add a new method
332  MethodProxy* method = MethodProxy_New( imd->first, imd->second );
333  PyObject_SetAttrString(
334  pyclass, const_cast< char* >( method->GetName().c_str() ), (PyObject*)method );
335  Py_DECREF( method );
336  }
337 
338  Py_XDECREF( attr ); // could have be found in base class or non-existent
339  }
340 
341 // collect enums; this must happen before data members, so that we can check on their existence
342  TClass* klass = TClass::GetClass( Cppyy::GetFinalName( scope ).c_str() );
343  TList* enums = klass->GetListOfEnums();
344  TIter ienum( enums );
345  TEnum* e = 0;
346  while ( (e = (TEnum*)ienum.Next()) ) {
347  const TSeqCollection* seq = e->GetConstants();
348  for ( Int_t i = 0; i < seq->GetSize(); i++ ) {
349  TEnumConstant* ec = (TEnumConstant*)seq->At( i );
350  AddPropertyToClass( pyclass, scope, ec->GetName(), ec->GetAddress() );
351  }
352  }
353 
354 // collect data members
355  const Cppyy::TCppIndex_t nDataMembers = Cppyy::GetNumDatamembers( scope );
356  for ( Cppyy::TCppIndex_t idata = 0; idata < nDataMembers; ++idata ) {
357  // allow only public members
358  if ( ! Cppyy::IsPublicData( scope, idata ) )
359  continue;
360 
361  // enum datamembers (this in conjunction with previously collected enums above)
362  if ( Cppyy::IsEnumData( scope, idata ) && Cppyy::IsStaticData( scope, idata ) ) {
363  // some implementation-specific data members have no address: ignore them
364  if ( ! Cppyy::GetDatamemberOffset( scope, idata ) )
365  continue;
366 
367  // two options: this is a static variable, or it is the enum value, the latter
368  // already exists, so check for it and move on if set
369  PyObject* eset = PyObject_GetAttrString( pyclass,
370  const_cast<char*>( Cppyy::GetDatamemberName( scope, idata ).c_str()) );
371  if ( eset ) {
372  Py_DECREF( eset );
373  continue;
374  }
375 
376  PyErr_Clear();
377 
378  // it could still be that this is an anonymous enum, which is not in the list
379  // provided by the class
380  if ( strstr( Cppyy::GetDatamemberType( scope, idata ).c_str(), "(anonymous)" ) != 0 ) {
381  AddPropertyToClass( pyclass, scope, idata );
382  continue;
383  }
384  }
385 
386  // properties (aka public (static) data members)
387  AddPropertyToClass( pyclass, scope, idata );
388  }
389 
390 // restore custom __getattr__
391  Py_TYPE(pyclass)->tp_getattro = oldgetattro;
392 
393 // all ok, done
394  return 0;
395 }
396 
397 ////////////////////////////////////////////////////////////////////////////////
398 /// Build a tuple of python shadow classes of all the bases of the given 'klass'.
399 
401 {
402  size_t nbases = Cppyy::GetNumBases( klass );
403 
404 // collect bases while removing duplicates
405  std::vector< std::string > uqb;
406  uqb.reserve( nbases );
407 
408  for ( size_t ibase = 0; ibase < nbases; ++ibase ) {
409  const std::string& name = Cppyy::GetBaseName( klass, ibase );
410  if ( std::find( uqb.begin(), uqb.end(), name ) == uqb.end() ) {
411  uqb.push_back( name );
412  }
413  }
414 
415 // allocate a tuple for the base classes, special case for first base
416  nbases = uqb.size();
417 
418  PyObject* pybases = PyTuple_New( nbases ? nbases : 1 );
419  if ( ! pybases )
420  return 0;
421 
422 // build all the bases
423  if ( nbases == 0 ) {
424  Py_INCREF( (PyObject*)(void*)&ObjectProxy_Type );
425  PyTuple_SET_ITEM( pybases, 0, (PyObject*)(void*)&ObjectProxy_Type );
426  } else {
427  for ( std::vector< std::string >::size_type ibase = 0; ibase < nbases; ++ibase ) {
428  PyObject* pyclass = CreateScopeProxy( uqb[ ibase ] );
429  if ( ! pyclass ) {
430  Py_DECREF( pybases );
431  return 0;
432  }
433 
434  PyTuple_SET_ITEM( pybases, ibase, pyclass );
435  }
436 
437  // special case, if true python types enter the hierarchy, make sure that
438  // the first base seen is still the ObjectProxy_Type
439  if ( ! PyObject_IsSubclass( PyTuple_GET_ITEM( pybases, 0 ), (PyObject*)&ObjectProxy_Type ) ) {
440  PyObject* newpybases = PyTuple_New( nbases + 1 );
441  Py_INCREF( (PyObject*)(void*)&ObjectProxy_Type );
442  PyTuple_SET_ITEM( newpybases, 0, (PyObject*)(void*)&ObjectProxy_Type );
443  for ( int ibase = 0; ibase < (int)nbases; ++ibase ) {
444  PyObject* pyclass = PyTuple_GET_ITEM( pybases, ibase );
445  Py_INCREF( pyclass );
446  PyTuple_SET_ITEM( newpybases, ibase + 1, pyclass );
447  }
448  Py_DECREF( pybases );
449  pybases = newpybases;
450  }
451  }
452 
453  return pybases;
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// Retrieve scope proxy from the known ones.
458 
460 {
461  PyClassMap_t::iterator pci = gPyClasses.find( scope );
462  if ( pci != gPyClasses.end() ) {
463  PyObject* pyclass = PyWeakref_GetObject( pci->second );
464  if ( pyclass ) {
465  Py_INCREF( pyclass );
466  return pyclass;
467  }
468  }
469 
470  return nullptr;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// Convenience function with a lookup first through the known existing proxies.
475 
477 {
478  PyObject* pyclass = GetScopeProxy( scope );
479  if ( pyclass )
480  return pyclass;
481 
482  return CreateScopeProxy( Cppyy::GetScopedFinalName( scope ) );
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// Build a python shadow class for the named C++ class.
487 
489 {
490  std::string cname = PyROOT_PyUnicode_AsString( PyTuple_GetItem( args, 0 ) );
491  if ( PyErr_Occurred() )
492  return nullptr;
493 
494  return CreateScopeProxy( cname );
495 }
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Build a python shadow class for the named C++ class.
499 
500 PyObject* PyROOT::CreateScopeProxy( const std::string& scope_name, PyObject* parent )
501 {
502  if ( scope_name.empty() || scope_name == "std" ) {
503  // special cases, as gbl and gbl.std are defined in cppyy.py
504  PyObject* mods = PyImport_GetModuleDict();
505  PyObject* gbl = PyDict_GetItemString( mods, "cppyy.gbl" );
506  if ( gbl ) {
507  if ( scope_name.empty() ) {
508  Py_INCREF( gbl );
509  return gbl;
510  } else
511  return PyObject_GetAttrString( gbl, "std" );
512  }
513  PyErr_SetString( PyExc_SystemError, "could not locate global namespace" );
514  return nullptr;
515  }
516 
517 // force building of the class if a parent is specified (prevents loops)
518  Bool_t force = parent != 0;
519 
520 // working copy
521  std::string name = scope_name;
522 
523 // determine complete scope name, if a python parent has been given
524  std::string scName = "";
525  if ( parent ) {
526  PyObject* pyparent = PyObject_GetAttr( parent, PyStrings::gCppName );
527  if ( ! pyparent ) pyparent = PyObject_GetAttr( parent, PyStrings::gName );
528  if ( ! pyparent ) {
529  PyErr_Format( PyExc_SystemError, "given scope has no name for %s", name.c_str() );
530  return 0;
531  }
532 
533  // should be a string
534  scName = PyROOT_PyUnicode_AsString( pyparent );
535  Py_DECREF( pyparent );
536  if ( PyErr_Occurred() )
537  return 0;
538 
539  // accept this parent scope and use it's name for prefixing
540  Py_INCREF( parent );
541  }
542 
543 // retrieve ROOT class (this verifies name, and is therefore done first)
544  const std::string& lookup = parent ? (scName+"::"+name) : name;
545  Cppyy::TCppScope_t klass = Cppyy::GetScope( lookup );
546 
547  if ( ! (Bool_t)klass && gInterpreter->CheckClassTemplate( lookup.c_str() ) ) {
548  // a "naked" templated class is requested: return callable proxy for instantiations
549  PyObject* pytcl = PyObject_GetAttr( gRootModule, PyStrings::gTemplate );
550  PyObject* pytemplate = PyObject_CallFunction(
551  pytcl, const_cast< char* >( "s" ), const_cast< char* >( lookup.c_str() ) );
552  Py_DECREF( pytcl );
553 
554  // cache the result
555  PyObject_SetAttrString( parent ? parent : gRootModule, (char*)name.c_str(), pytemplate );
556 
557  // done, next step should be a call into this template
558  Py_XDECREF( parent );
559  return pytemplate;
560  }
561 
562  if ( ! (Bool_t)klass ) { // if so, all options have been exhausted: it doesn't exist as such
563  if ( ! parent && scope_name.find( "ROOT::" ) == std::string::npos ) { // not already in ROOT::
564  // final attempt, for convenience, the "ROOT" namespace isn't required, try again ...
565  klass = Cppyy::GetScope( "ROOT::"+scope_name );
566  if ( (Bool_t)klass ) {
567  PyObject* rtns = PyObject_GetAttr( gRootModule, PyStrings::gROOTns );
568  PyObject* pyclass = CreateScopeProxy( scope_name, rtns );
569  Py_DECREF( rtns );
570  return pyclass;
571  }
572  }
573 
574  PyErr_Format( PyExc_TypeError, "requested class \'%s\' does not exist", lookup.c_str() );
575  Py_XDECREF( parent );
576  return 0;
577  }
578 
579 // locate class by ID, if possible, to prevent parsing scopes/templates anew
580  PyObject* pyscope = GetScopeProxy( klass );
581  if ( pyscope ) {
582  if ( parent ) PyObject_SetAttrString( parent, (char*)scope_name.c_str(), pyscope );
583  return pyscope;
584  }
585 
586 // locate the parent, if necessary, for building the class if not specified
587  std::string::size_type last = 0;
588  if ( ! parent ) {
589  // need to deal with template paremeters that can have scopes themselves
590  Int_t tpl_open = 0;
591  for ( std::string::size_type pos = 0; pos < name.size(); ++pos ) {
592  std::string::value_type c = name[ pos ];
593 
594  // count '<' and '>' to be able to skip template contents
595  if ( c == '<' )
596  ++tpl_open;
597  else if ( c == '>' )
598  --tpl_open;
599 
600  // by only checking for "::" the last part (class name) is dropped
601  else if ( tpl_open == 0 &&\
602  c == ':' && pos+1 < name.size() && name[ pos+1 ] == ':' ) {
603  // found a new scope part
604  const std::string& part = name.substr( last, pos-last );
605 
606  PyObject* next = PyObject_GetAttrString(
607  parent ? parent : gRootModule, const_cast< char* >( part.c_str() ) );
608 
609  if ( ! next ) { // lookup failed, try to create it
610  PyErr_Clear();
611  next = CreateScopeProxy( part, parent );
612  }
613  Py_XDECREF( parent );
614 
615  if ( ! next ) // create failed, give up
616  return 0;
617 
618  // found scope part
619  parent = next;
620 
621  // done with part (note that pos is moved one ahead here)
622  last = pos+2; ++pos;
623  }
624 
625  }
626 
627  if ( parent && !PyRootType_Check( parent ) ) {
628  // Special case: parent found is not one of ours (it's e.g. a pure Python module), so
629  // continuing would fail badly. One final lookup, then out of here ...
630  std::string unscoped = scope_name.substr( last, std::string::npos );
631  return PyObject_GetAttrString( parent, unscoped.c_str() );
632  }
633  }
634 
635 // use global scope if no inner scope found
636  if ( ! parent ) {
637  parent = gRootModule;
638  Py_INCREF( parent );
639  }
640 
641 // use actual class name for binding
642  const std::string& actual = Cppyy::GetFinalName( klass );
643 
644 // first try to retrieve an existing class representation
645  PyObject* pyactual = PyROOT_PyUnicode_FromString( Cppyy::GetName(actual).c_str() );
646  PyObject* pyclass = force ? 0 : PyObject_GetAttr( parent, pyactual );
647 
648  Bool_t bClassFound = pyclass ? kTRUE : kFALSE;
649 
650 // build if the class does not yet exist
651  if ( ! pyclass ) {
652  // ignore error generated from the failed lookup
653  PyErr_Clear();
654 
655  // construct the base classes
656  PyObject* pybases = BuildCppClassBases( klass );
657  if ( pybases != 0 ) {
658  // create a fresh Python class, given bases, name, and empty dictionary
659  pyclass = CreateNewROOTPythonClass( actual, pybases );
660  Py_DECREF( pybases );
661  }
662 
663  // fill the dictionary, if successful
664  if ( pyclass != 0 ) {
665  if ( BuildScopeProxyDict( klass, pyclass ) != 0 ) {
666  // something failed in building the dictionary
667  Py_DECREF( pyclass );
668  pyclass = 0;
669  } else {
670  PyObject_SetAttr( parent, pyactual, pyclass );
671  }
672  }
673 
674  }
675 
676  if ( pyclass && name != actual ) // class exists, but is typedef-ed: simply map reference
677  PyObject_SetAttrString( parent, const_cast< char* >( name.c_str() ), pyclass );
678 
679  if ( pyclass && ! bClassFound ) {
680  // store a ref from ROOT TClass to new python class
681  gPyClasses[ klass ] = PyWeakref_NewRef( pyclass, NULL );
682 
683  // add a ref in the class to its scope
684  PyObject_SetAttrString( pyclass, "__scope__", PyROOT_PyUnicode_FromString( scName.c_str() ) );
685  }
686 
687  // add __cppname__ to keep the C++ name of the class/scope
688  PyObject_SetAttr( pyclass, PyStrings::gCppName, PyROOT_PyUnicode_FromString( actual.c_str() ) );
689 
690  // add __module__ (see https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_name)
691  std::string module;
692  if( parent == gRootModule) {
693  module = "ROOT";
694  } else {
695  PyObject* _name_ = PyObject_GetAttr(parent, PyStrings::gName);
696  PyObject* _module_ = PyObject_GetAttr(parent, PyStrings::gModule);
697  if(_module_) {
698  module = PyROOT_PyUnicode_AsString(_module_);
699  module += ".";
700  Py_DECREF(_module_);
701  }
702  if(_name_) {
703  module += PyROOT_PyUnicode_AsString(_name_);
704  Py_DECREF(_name_);
705  }
706  }
707  PyObject_SetAttr( pyclass, PyStrings::gModule, PyROOT_PyUnicode_FromString( module.c_str()) );
708 
709  Py_DECREF( pyactual );
710  Py_DECREF( parent );
711 
712 
713  if ( ! bClassFound ) { // add python-style features to newly minted classes
714  if ( ! Pythonize( pyclass, actual ) ) {
715  Py_XDECREF( pyclass );
716  pyclass = 0;
717  }
718  }
719 
720 
721  if ( pyclass && actual != "ROOT" ) {
722  // add to sys.modules to allow importing from this module
723  std::string pyfullname = lookup;
724  std::string::size_type pos = pyfullname.find( "::" );
725  while ( pos != std::string::npos ) {
726  pyfullname = pyfullname.replace( pos, 2, "." );
727  pos = pyfullname.find( "::", pos );
728  }
729  PyObject* modules = PySys_GetObject( const_cast<char*>("modules") );
730  if ( modules && PyDict_Check( modules) ) {
731  PyDict_SetItemString( modules,
732  const_cast<char*>(("ROOT."+pyfullname).c_str()), pyclass );
733  }
734  }
735 
736 // all done
737  return pyclass;
738 }
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// get the requested name
742 
744 {
745  std::string ename = PyROOT_PyUnicode_AsString( PyTuple_GetItem( args, 0 ) );
746 
747  if ( PyErr_Occurred() )
748  return 0;
749 
750  return GetCppGlobal( ename );
751 }
752 
753 ////////////////////////////////////////////////////////////////////////////////
754 /// try named global variable/enum (first ROOT, then Cling: sync is too slow)
755 
756 PyObject* PyROOT::GetCppGlobal( const std::string& name )
757 {
759  if ( 0 <= idata )
761 
762 // still here ... try functions (sync has been fixed, so is okay)
763  const std::vector< Cppyy::TCppMethod_t >& methods =
765  if ( ! methods.empty() ) {
766  std::vector< PyCallable* > overloads;
767  for ( auto method : methods )
768  overloads.push_back( new TFunctionHolder( Cppyy::gGlobalScope, method ) );
769  return (PyObject*)MethodProxy_New( name, overloads );
770  }
771 
772 // allow lookup into std as if global (historic)
773  TDataMember* dm = TClass::GetClass( "std" )->GetDataMember( name.c_str() );
774  if ( dm ) {
776  return BindCppObjectNoCast( (void*)dm->GetOffset(), klass, kFALSE );
777  }
778 
779 // nothing found
780  PyErr_Format( PyExc_LookupError, "no such global: %s", name.c_str() );
781  return 0;
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 /// only known or knowable objects will be bound (null object is ok)
786 
788  Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Bool_t isRef, Bool_t isValue ) {
789  if ( ! klass ) {
790  PyErr_SetString( PyExc_TypeError, "attempt to bind ROOT object w/o class" );
791  return 0;
792  }
793 
794 // retrieve python class
795  PyObject* pyclass = CreateScopeProxy( klass );
796  if ( ! pyclass )
797  return 0; // error has been set in CreateScopeProxy
798 
799 // instantiate an object of this class
800  PyObject* args = PyTuple_New(0);
801  ObjectProxy* pyobj =
802  (ObjectProxy*)((PyTypeObject*)pyclass)->tp_new( (PyTypeObject*)pyclass, args, NULL );
803  Py_DECREF( args );
804  Py_DECREF( pyclass );
805 
806 // bind, register and return if successful
807  if ( pyobj != 0 ) { // fill proxy value?
808  // TODO: take flags directly instead of separate Bool_t args
809  unsigned flags = (isRef ? ObjectProxy::kIsReference : 0) | (isValue ? ObjectProxy::kIsValue : 0);
810  pyobj->Set( address, (ObjectProxy::EFlags)flags );
811  }
812 
813 // successful completion
814  return (PyObject*)pyobj;
815 }
816 
817 ////////////////////////////////////////////////////////////////////////////////
818 /// if the object is a null pointer, return a typed one (as needed for overloading)
819 
821 {
822  if ( ! address )
823  return BindCppObjectNoCast( address, klass, kFALSE );
824 
825 // only known or knowable objects will be bound
826  if ( ! klass ) {
827  PyErr_SetString( PyExc_TypeError, "attempt to bind ROOT object w/o class" );
828  return 0;
829  }
830 
831 // get actual class for recycling checking and/or downcasting
832 // CLING WORKAROUND -- silence:
833 // Error in <TStreamerInfo::Build>: __gnu_cxx::__normal_iterator<int*,vector<int> >, discarding: int* _M_current, no [dimension]
834  Int_t oldval = gErrorIgnoreLevel;
835  gErrorIgnoreLevel = 5000;
836  Cppyy::TCppType_t clActual = isRef ? 0 : Cppyy::GetActualClass( klass, address );
837  gErrorIgnoreLevel = oldval;
838 
839 // obtain pointer to TObject base class (if possible) for memory mgmt; this is
840 // done before downcasting, as upcasting from the current class may be easier and
841 // downcasting is unnecessary if the python side object gets recycled by the
842 // memory regulator
843  TObject* object = 0;
844  static Cppyy::TCppScope_t sTObjectScope = Cppyy::GetScope( "TObject" );
845  if ( ! isRef && Cppyy::IsSubtype( klass, sTObjectScope) ) {
846  object = (TObject*)((Long_t)address + \
847  Cppyy::GetBaseOffset( klass, sTObjectScope, address, 1 /* up-cast */ ) );
848 
849  // use the old reference if the object already exists
850  PyObject* oldPyObject = TMemoryRegulator::RetrieveObject( object, clActual ? clActual : klass );
851  if ( oldPyObject )
852  return oldPyObject;
853  }
854 
855 // downcast to real class for object returns
856  if ( clActual && klass != clActual ) {
857  ptrdiff_t offset = Cppyy::GetBaseOffset(
858  clActual, klass, address, -1 /* down-cast */, true /* report errors */ );
859  if ( offset != -1 ) { // may fail if clActual not fully defined
860  address = (void*)((Long_t)address + offset);
861  klass = clActual;
862  }
863  }
864 
865 
866 // check if type is pinned
867  Bool_t ignore_pin = std::find(
868  gIgnorePinnings.begin(), gIgnorePinnings.end(), klass ) != gIgnorePinnings.end();
869 
870  if ( ! ignore_pin ) {
871  for ( auto it = gPinnedTypes.cbegin(); it != gPinnedTypes.cend(); ++it ) {
872  if ( klass == std::get<0>(*it) || Cppyy::IsSubtype( klass, std::get<0>(*it) ) )
873  klass = std::get<1>(*it);
874  }
875  }
876 
877 // actual binding
878  ObjectProxy* pyobj = (ObjectProxy*)BindCppObjectNoCast( address, klass, isRef );
879 
880 // memory management, for TObject's only (for referenced objects, it is assumed
881 // that the (typically global) reference itself is zeroed out (or replaced) on
882 // destruction; it can't thus be reliably zeroed out from the python side)
883  if ( object && !(pyobj->fFlags & ObjectProxy::kIsReference) ) {
884  TMemoryRegulator::RegisterObject( pyobj, object );
885  }
886 
887 // completion (returned object may be zero w/ a python exception set)
888  return (PyObject*)pyobj;
889 }
890 
891 ////////////////////////////////////////////////////////////////////////////////
892 /// TODO: this function exists for symmetry; need to figure out if it's useful
893 
895  Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Int_t size ) {
896  return TTupleOfInstances_New( address, klass, size );
897 }
898 
899 
900 ////////////////////////////////////////////////////////////////////////////////
901 /// gbl == 0 means global does not exist (rather than gbl is NULL pointer)
902 
904 {
905  if ( ! gbl || strcmp(gbl->GetName(), "") == 0 ) {
906  Py_INCREF( Py_None );
907  return Py_None;
908  }
909 
910 // determine type and cast as appropriate
912  if ( klass != 0 ) {
913  // handle array of objects
914  if ( gbl->GetArrayDim() == 1 ) {
915  return BindCppObjectArray( (void*)gbl->GetAddress(), klass, gbl->GetMaxIndex(0) );
916  } else if ( gbl->GetArrayDim() ) {
917  PyErr_SetString( PyExc_NotImplementedError,
918  "larger than 1D arrays of objects not supported" );
919  return 0;
920  }
921 
922  // special case where there should be no casting:
923  // TODO: WORK HERE ... restore cast
924  //if ( klass->InheritsFrom( "ios_base" ) )
925  //return BindCppObjectNoCast( (void*)gbl->GetAddress(), klass );
926 
927  // pointer types are bound "by-reference"
928  if ( Utility::Compound( gbl->GetFullTypeName() ) != "" )
929  return BindCppObject( (void*)gbl->GetAddress(), klass, kTRUE );
930  }
931 
932  if ( gbl->GetAddress() && // check for enums and consts
933  (unsigned long)gbl->GetAddress() != (unsigned long)-1 && // Cling (??)
934  ( gInterpreter->ClassInfo_IsEnum( gbl->GetTypeName() ) ) ) {
935  return PyInt_FromLong( (long)*((int*)gbl->GetAddress()) );
936  }
937 
938 // no class and no enum: for built-in types, to ensure setability
939  PyObject* result = (PyObject*)PropertyProxy_New(
941  return result;
942 }
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:145
TCppScope_t TCppType_t
Definition: Cppyy.h:13
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:71
static PyObject * RetrieveObject(TObject *object, Cppyy::TCppType_t klass)
lookup <object>, return old proxy if tracked
The TEnum class implements the enum type.
Definition: TEnum.h:31
std::string GetScopedFinalName(TCppType_t type)
Definition: Cppyy.cxx:570
auto * m
Definition: textangle.C:8
virtual Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
Definition: TGlobal.cxx:101
R__EXTERN Int_t gErrorIgnoreLevel
Definition: TError.h:105
virtual const char * GetFullTypeName() const
Get full type description of global variable, e,g.: "class TDirectory*".
Definition: TGlobal.cxx:120
void AddOverload(MethodProxy *mp)
Store overloads of this templated method.
Bool_t IsNamespace(TCppScope_t scope)
Definition: Cppyy.cxx:539
virtual PyCallable * Clone()=0
static Bool_t RegisterObject(ObjectProxy *pyobj, TObject *object)
start tracking <object> proxied by <pyobj>
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition: TClass.cxx:3561
ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
Definition: Cppyy.cxx:620
Bool_t IsPublicMethod(TCppMethod_t method)
Definition: Cppyy.cxx:857
TCppIndex_t GetNumBases(TCppType_t type)
Definition: Cppyy.cxx:583
std::vector< TCppMethod_t > GetMethodsFromName(TCppScope_t scope, const std::string &name)
Definition: Cppyy.cxx:690
MethodProxy * MethodProxy_New(const std::string &name, std::vector< PyCallable * > &methods)
Definition: MethodProxy.h:75
R__EXTERN PyObject * gTemplate
Definition: PyStrings.h:51
#define gROOT
Definition: TROOT.h:410
std::string GetFinalName(TCppType_t type)
Definition: Cppyy.cxx:561
virtual void * GetAddress() const
Return address of global.
Definition: TGlobal.cxx:77
Bool_t PyRootType_Check(T *object)
Definition: PyRootType.h:50
ptrdiff_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:946
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
TemplateProxy * TemplateProxy_New(const std::string &name, PyObject *pyclass)
Definition: TemplateProxy.h:62
#define gInterpreter
Definition: TInterpreter.h:527
Bool_t IsEnumData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1022
std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:911
PyObject * BindCppObjectArray(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Int_t size)
TODO: this function exists for symmetry; need to figure out if it&#39;s useful.
const TSeqCollection * GetConstants() const
Definition: TEnum.h:55
std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
Definition: Cppyy.cxx:592
Sequenceable collection abstract base class.
std::string ResolveName(const std::string &cppitem_name)
Definition: Cppyy.cxx:166
std::vector< Cppyy::TCppType_t > gIgnorePinnings
Definition: RootModule.cxx:148
std::string MapOperatorName(const std::string &name, Bool_t bTakesParames)
Map the given C++ operator name on the python equivalent.
Definition: Utility.cxx:612
R__EXTERN PyObject * gRootModule
Definition: ObjectProxy.cxx:39
PyObject * GetCppGlobal(const std::string &name)
try named global variable/enum (first ROOT, then Cling: sync is too slow)
R__EXTERN PyObject * gModule
Definition: PyStrings.h:31
TCppIndex_t GetNumDatamembers(TCppScope_t scope)
Definition: Cppyy.cxx:876
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:66
PropertyProxy * PropertyProxy_NewConstant(Cppyy::TCppScope_t scope, const std::string &name, void *address)
Definition: PropertyProxy.h:72
TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
Definition: Cppyy.cxx:727
A doubly linked list.
Definition: TList.h:44
Bool_t IsConstructor(TCppMethod_t method)
Definition: Cppyy.cxx:848
TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj)
Definition: Cppyy.cxx:207
PyTypeObject PyRootType_Type
Definition: PyRootType.cxx:191
PyTypeObject ObjectProxy_Type
ptrdiff_t TCppMethod_t
Definition: Cppyy.h:15
TCppScope_t gGlobalScope
Definition: Cppyy.cxx:63
Bool_t IsPublicData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:986
std::string GetMethodName(TCppMethod_t)
Definition: Cppyy.cxx:733
R__EXTERN PyObject * gROOTns
Definition: PyStrings.h:56
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
void * GetAddress() const override
Return address of global.
Definition: TEnumConstant.h:39
TObject * Next()
Definition: TCollection.h:249
std::vector< std::pair< Cppyy::TCppType_t, Cppyy::TCppType_t > > gPinnedTypes
Definition: RootModule.cxx:147
PyObject * BindCppGlobal(TGlobal *)
gbl == 0 means global does not exist (rather than gbl is NULL pointer)
void InitRoot()
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, Bool_t isRef=kFALSE, Bool_t isValue=kFALSE)
only known or knowable objects will be bound (null object is ok)
The TEnumConstant class implements the constants of the enum type.
Definition: TEnumConstant.h:29
TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
Definition: Cppyy.cxx:962
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject *pyclass)
Collect methods and data for the given scope, and add them to the given python proxy object...
Global variables class (global variables are obtained from CINT).
Definition: TGlobal.h:27
PyObject * TTupleOfInstances_New(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t nelems)
void * TCppObject_t
Definition: Cppyy.h:14
virtual Int_t GetArrayDim() const
Return number of array dimensions.
Definition: TGlobal.cxx:85
Long_t GetOffset() const
Get offset from "this".
const Bool_t kFALSE
Definition: RtypesCore.h:88
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
long Long_t
Definition: RtypesCore.h:50
Bool_t IsSubtype(TCppType_t derived, TCppType_t base)
Definition: Cppyy.cxx:598
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Convenience function with a lookup first through the known existing proxies.
virtual const char * GetTypeName() const
Get type of global variable, e,g.
Definition: TGlobal.cxx:111
TCppScope_t GetScope(const std::string &scope_name)
Definition: Cppyy.cxx:176
const std::string & GetName() const
Definition: MethodProxy.h:45
std::string GetMethodResultType(TCppMethod_t)
Definition: Cppyy.cxx:744
R__EXTERN PyObject * gName
Definition: PyStrings.h:33
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
TCppIndex_t GetMethodNumArgs(TCppMethod_t)
Definition: Cppyy.cxx:755
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:2887
R__EXTERN PyObject * gCppName
Definition: PyStrings.h:34
virtual TObject * At(Int_t idx) const =0
Bool_t IsStaticMethod(TCppMethod_t method)
Definition: Cppyy.cxx:866
Mother of all ROOT objects.
Definition: TObject.h:37
std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:899
#define R__EXTERN
Definition: DllImport.h:27
Bool_t IsStaticData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:997
#define Py_TYPE(ob)
Definition: PyROOT.h:151
Long_t TCppIndex_t
Definition: Cppyy.h:17
TCppIndex_t GetNumMethods(TCppScope_t scope)
Definition: Cppyy.cxx:659
static PyObject * BuildCppClassBases(Cppyy::TCppType_t klass)
Build a tuple of python shadow classes of all the bases of the given &#39;klass&#39;.
PropertyProxy * PropertyProxy_New(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
Definition: PropertyProxy.h:62
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
Retrieve scope proxy from the known ones.
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
Bool_t MethodProxy_Check(T *object)
Definition: MethodProxy.h:63
#define c(i)
Definition: RSha256.hxx:101
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3280
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
ptrdiff_t TCppScope_t
Definition: Cppyy.h:12
const Bool_t kTRUE
Definition: RtypesCore.h:87
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, Bool_t isRef=kFALSE)
if the object is a null pointer, return a typed one (as needed for overloading)
Template proxy object to return functions and methods.
Definition: TemplateProxy.h:24
void Set(void *address, EFlags flags=kNone)
Definition: ObjectProxy.h:33
std::string GetName()
Definition: PropertyProxy.h:30
char name[80]
Definition: TGX11.cxx:109
Bool_t TemplateProxy_Check(T *object)
Definition: TemplateProxy.h:50
_object PyObject
Definition: TPyArg.h:20
Bool_t Pythonize(PyObject *pyclass, const std::string &name)
Definition: Pythonize.cxx:2325
const std::string Compound(const std::string &name)
Break down the compound of a fully qualified type name.
Definition: Utility.cxx:658