Logo ROOT   6.16/01
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 _______________________________________________________________________
47namespace 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
55namespace {
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 AddConstantPropertyToClass( PyObject* pyclass,
123 Cppyy::TCppScope_t scope, const std::string& name, void* address, TEnum* en )
124 {
125 PyROOT::PropertyProxy* property =
126 PyROOT::PropertyProxy_NewConstant( scope, name, address, en );
127 AddPropertyToClass1( pyclass, property, kTRUE );
128 Py_DECREF( property );
129 }
130
131
132} // unnamed namespace
133
134
135//- helpers --------------------------------------------------------------------
136namespace {
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
196static 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(
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 auto isScoped = e->Property() & kIsScopedEnum;
349 if (isScoped) continue; // scoped enum: do not add constants as properties of the enum's scope
350 for ( Int_t i = 0; i < seq->GetSize(); i++ ) {
351 TEnumConstant* ec = (TEnumConstant*)seq->At( i );
352 AddConstantPropertyToClass( pyclass, scope, ec->GetName(), ec->GetAddress(), e );
353 }
354 }
355
356// collect data members
357 const Cppyy::TCppIndex_t nDataMembers = Cppyy::GetNumDatamembers( scope );
358 for ( Cppyy::TCppIndex_t idata = 0; idata < nDataMembers; ++idata ) {
359 // allow only public members
360 if ( ! Cppyy::IsPublicData( scope, idata ) )
361 continue;
362
363 // enum datamembers (this in conjunction with previously collected enums above)
364 if ( Cppyy::IsEnumData( scope, idata ) && Cppyy::IsStaticData( scope, idata ) ) {
365 // some implementation-specific data members have no address: ignore them
366 if ( ! Cppyy::GetDatamemberOffset( scope, idata ) )
367 continue;
368
369 // two options: this is a static variable, or it is the enum value, the latter
370 // already exists, so check for it and move on if set
371 PyObject* eset = PyObject_GetAttrString( pyclass,
372 const_cast<char*>( Cppyy::GetDatamemberName( scope, idata ).c_str()) );
373 if ( eset ) {
374 Py_DECREF( eset );
375 continue;
376 }
377
378 PyErr_Clear();
379
380 // it could still be that this is an anonymous enum, which is not in the list
381 // provided by the class
382 if ( strstr( Cppyy::GetDatamemberType( scope, idata ).c_str(), "(anonymous)" ) != 0 ) {
383 AddPropertyToClass( pyclass, scope, idata );
384 continue;
385 }
386 }
387
388 // properties (aka public (static) data members)
389 AddPropertyToClass( pyclass, scope, idata );
390 }
391
392// restore custom __getattr__
393 Py_TYPE(pyclass)->tp_getattro = oldgetattro;
394
395// all ok, done
396 return 0;
397}
398
399////////////////////////////////////////////////////////////////////////////////
400/// Build a tuple of python shadow classes of all the bases of the given 'klass'.
401
403{
404 size_t nbases = Cppyy::GetNumBases( klass );
405
406// collect bases while removing duplicates
407 std::vector< std::string > uqb;
408 uqb.reserve( nbases );
409
410 for ( size_t ibase = 0; ibase < nbases; ++ibase ) {
411 const std::string& name = Cppyy::GetBaseName( klass, ibase );
412 if ( std::find( uqb.begin(), uqb.end(), name ) == uqb.end() ) {
413 uqb.push_back( name );
414 }
415 }
416
417// allocate a tuple for the base classes, special case for first base
418 nbases = uqb.size();
419
420 PyObject* pybases = PyTuple_New( nbases ? nbases : 1 );
421 if ( ! pybases )
422 return 0;
423
424// build all the bases
425 if ( nbases == 0 ) {
426 Py_INCREF( (PyObject*)(void*)&ObjectProxy_Type );
427 PyTuple_SET_ITEM( pybases, 0, (PyObject*)(void*)&ObjectProxy_Type );
428 } else {
429 for ( std::vector< std::string >::size_type ibase = 0; ibase < nbases; ++ibase ) {
430 PyObject* pyclass = CreateScopeProxy( uqb[ ibase ] );
431 if ( ! pyclass ) {
432 Py_DECREF( pybases );
433 return 0;
434 }
435
436 PyTuple_SET_ITEM( pybases, ibase, pyclass );
437 }
438
439 // special case, if true python types enter the hierarchy, make sure that
440 // the first base seen is still the ObjectProxy_Type
441 if ( ! PyObject_IsSubclass( PyTuple_GET_ITEM( pybases, 0 ), (PyObject*)&ObjectProxy_Type ) ) {
442 PyObject* newpybases = PyTuple_New( nbases + 1 );
443 Py_INCREF( (PyObject*)(void*)&ObjectProxy_Type );
444 PyTuple_SET_ITEM( newpybases, 0, (PyObject*)(void*)&ObjectProxy_Type );
445 for ( int ibase = 0; ibase < (int)nbases; ++ibase ) {
446 PyObject* pyclass = PyTuple_GET_ITEM( pybases, ibase );
447 Py_INCREF( pyclass );
448 PyTuple_SET_ITEM( newpybases, ibase + 1, pyclass );
449 }
450 Py_DECREF( pybases );
451 pybases = newpybases;
452 }
453 }
454
455 return pybases;
456}
457
458////////////////////////////////////////////////////////////////////////////////
459/// Retrieve scope proxy from the known ones.
460
462{
463 PyClassMap_t::iterator pci = gPyClasses.find( scope );
464 if ( pci != gPyClasses.end() ) {
465 PyObject* pyclass = PyWeakref_GetObject( pci->second );
466 if ( pyclass ) {
467 Py_INCREF( pyclass );
468 return pyclass;
469 }
470 }
471
472 return nullptr;
473}
474
475////////////////////////////////////////////////////////////////////////////////
476/// Convenience function with a lookup first through the known existing proxies.
477
479{
480 PyObject* pyclass = GetScopeProxy( scope );
481 if ( pyclass )
482 return pyclass;
483
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// Build a python shadow class for the named C++ class.
489
491{
492 std::string cname = PyROOT_PyUnicode_AsString( PyTuple_GetItem( args, 0 ) );
493 if ( PyErr_Occurred() )
494 return nullptr;
495
496 return CreateScopeProxy( cname );
497}
498
499////////////////////////////////////////////////////////////////////////////////
500/// Build a python shadow class for the named C++ class.
501
502PyObject* PyROOT::CreateScopeProxy( const std::string& scope_name, PyObject* parent )
503{
504 if ( scope_name.empty() || scope_name == "std" ) {
505 // special cases, as gbl and gbl.std are defined in cppyy.py
506 PyObject* mods = PyImport_GetModuleDict();
507 PyObject* gbl = PyDict_GetItemString( mods, "cppyy.gbl" );
508 if ( gbl ) {
509 if ( scope_name.empty() ) {
510 Py_INCREF( gbl );
511 return gbl;
512 } else
513 return PyObject_GetAttrString( gbl, "std" );
514 }
515 PyErr_SetString( PyExc_SystemError, "could not locate global namespace" );
516 return nullptr;
517 }
518
519// force building of the class if a parent is specified (prevents loops)
520 Bool_t force = parent != 0;
521
522// working copy
523 std::string name = scope_name;
524
525// determine complete scope name, if a python parent has been given
526 std::string scName = "";
527 if ( parent ) {
528 PyObject* pyparent = PyObject_GetAttr( parent, PyStrings::gCppName );
529 if ( ! pyparent ) {
530 PyErr_Clear();
531 pyparent = PyObject_GetAttr( parent, PyStrings::gName );
532 }
533 if ( ! pyparent ) {
534 PyErr_Format( PyExc_SystemError, "given scope has no name for %s", name.c_str() );
535 return 0;
536 }
537
538 // should be a string
539 scName = PyROOT_PyUnicode_AsString( pyparent );
540 Py_DECREF( pyparent );
541 if ( PyErr_Occurred() )
542 return 0;
543
544 // accept this parent scope and use it's name for prefixing
545 Py_INCREF( parent );
546 }
547
548// retrieve ROOT class (this verifies name, and is therefore done first)
549 const std::string& lookup = parent ? (scName+"::"+name) : name;
550 Cppyy::TCppScope_t klass = Cppyy::GetScope( lookup );
551
552 if ( ! (Bool_t)klass && gInterpreter->CheckClassTemplate( lookup.c_str() ) ) {
553 // a "naked" templated class is requested: return callable proxy for instantiations
554 PyObject* pytcl = PyObject_GetAttr( gRootModule, PyStrings::gTemplate );
555 PyObject* pytemplate = PyObject_CallFunction(
556 pytcl, const_cast< char* >( "s" ), const_cast< char* >( lookup.c_str() ) );
557 Py_DECREF( pytcl );
558
559 // cache the result
560 PyObject_SetAttrString( parent ? parent : gRootModule, (char*)name.c_str(), pytemplate );
561
562 // done, next step should be a call into this template
563 Py_XDECREF( parent );
564 return pytemplate;
565 }
566
567 if ( ! (Bool_t)klass ) { // if so, all options have been exhausted: it doesn't exist as such
568 if ( ! parent && scope_name.find( "ROOT::" ) == std::string::npos ) { // not already in ROOT::
569 // final attempt, for convenience, the "ROOT" namespace isn't required, try again ...
570 klass = Cppyy::GetScope( "ROOT::"+scope_name );
571 if ( (Bool_t)klass ) {
572 PyObject* rtns = PyObject_GetAttr( gRootModule, PyStrings::gROOTns );
573 PyObject* pyclass = CreateScopeProxy( scope_name, rtns );
574 Py_DECREF( rtns );
575 return pyclass;
576 }
577 }
578
579 PyErr_Format( PyExc_TypeError, "requested class \'%s\' does not exist", lookup.c_str() );
580 Py_XDECREF( parent );
581 return 0;
582 }
583
584// locate class by ID, if possible, to prevent parsing scopes/templates anew
585 PyObject* pyscope = GetScopeProxy( klass );
586 if ( pyscope ) {
587 if ( parent ) PyObject_SetAttrString( parent, (char*)scope_name.c_str(), pyscope );
588 return pyscope;
589 }
590
591// locate the parent, if necessary, for building the class if not specified
592 std::string::size_type last = 0;
593 if ( ! parent ) {
594 // need to deal with template paremeters that can have scopes themselves
595 Int_t tpl_open = 0;
596 for ( std::string::size_type pos = 0; pos < name.size(); ++pos ) {
597 std::string::value_type c = name[ pos ];
598
599 // count '<' and '>' to be able to skip template contents
600 if ( c == '<' )
601 ++tpl_open;
602 else if ( c == '>' )
603 --tpl_open;
604
605 // by only checking for "::" the last part (class name) is dropped
606 else if ( tpl_open == 0 &&\
607 c == ':' && pos+1 < name.size() && name[ pos+1 ] == ':' ) {
608 // found a new scope part
609 const std::string& part = name.substr( last, pos-last );
610
611 PyObject* next = PyObject_GetAttrString(
612 parent ? parent : gRootModule, const_cast< char* >( part.c_str() ) );
613
614 if ( ! next ) { // lookup failed, try to create it
615 PyErr_Clear();
616 next = CreateScopeProxy( part, parent );
617 }
618 Py_XDECREF( parent );
619
620 if ( ! next ) // create failed, give up
621 return 0;
622
623 // found scope part
624 parent = next;
625
626 // done with part (note that pos is moved one ahead here)
627 last = pos+2; ++pos;
628 }
629
630 }
631
632 if ( parent && !PyRootType_Check( parent ) ) {
633 // Special case: parent found is not one of ours (it's e.g. a pure Python module), so
634 // continuing would fail badly. One final lookup, then out of here ...
635 std::string unscoped = scope_name.substr( last, std::string::npos );
636 return PyObject_GetAttrString( parent, unscoped.c_str() );
637 }
638 }
639
640// use global scope if no inner scope found
641 if ( ! parent ) {
642 parent = gRootModule;
643 Py_INCREF( parent );
644 }
645
646// use actual class name for binding
647 const std::string& actual = Cppyy::GetFinalName( klass );
648
649// first try to retrieve an existing class representation
650 PyObject* pyactual = PyROOT_PyUnicode_FromString( Cppyy::GetName(actual).c_str() );
651 PyObject* pyclass = force ? 0 : PyObject_GetAttr( parent, pyactual );
652
653 Bool_t bClassFound = pyclass ? kTRUE : kFALSE;
654
655// build if the class does not yet exist
656 if ( ! pyclass ) {
657 // ignore error generated from the failed lookup
658 PyErr_Clear();
659
660 // construct the base classes
661 PyObject* pybases = BuildCppClassBases( klass );
662 if ( pybases != 0 ) {
663 // create a fresh Python class, given bases, name, and empty dictionary
664 pyclass = CreateNewROOTPythonClass( actual, pybases );
665 Py_DECREF( pybases );
666 }
667
668 // fill the dictionary, if successful
669 if ( pyclass != 0 ) {
670 if ( BuildScopeProxyDict( klass, pyclass ) != 0 ) {
671 // something failed in building the dictionary
672 Py_DECREF( pyclass );
673 pyclass = 0;
674 } else {
675 PyObject_SetAttr( parent, pyactual, pyclass );
676 }
677 }
678
679 }
680
681 if ( pyclass && name != actual ) // class exists, but is typedef-ed: simply map reference
682 PyObject_SetAttrString( parent, const_cast< char* >( name.c_str() ), pyclass );
683
684 if ( pyclass && ! bClassFound ) {
685 // store a ref from ROOT TClass to new python class
686 gPyClasses[ klass ] = PyWeakref_NewRef( pyclass, NULL );
687
688 // add a ref in the class to its scope
689 PyObject_SetAttrString( pyclass, "__scope__", PyROOT_PyUnicode_FromString( scName.c_str() ) );
690 }
691
692 // add __cppname__ to keep the C++ name of the class/scope
693 PyObject_SetAttr( pyclass, PyStrings::gCppName, PyROOT_PyUnicode_FromString( actual.c_str() ) );
694
695 // add __module__ (see https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_name)
696 std::string module;
697 if( parent == gRootModule) {
698 module = "ROOT";
699 } else {
700 PyObject* _name_ = PyObject_GetAttr(parent, PyStrings::gName);
701 PyObject* _module_ = PyObject_GetAttr(parent, PyStrings::gModule);
702 if(_module_) {
703 module = PyROOT_PyUnicode_AsString(_module_);
704 module += ".";
705 Py_DECREF(_module_);
706 }
707 if(_name_) {
708 module += PyROOT_PyUnicode_AsString(_name_);
709 Py_DECREF(_name_);
710 }
711 }
712 PyObject_SetAttr( pyclass, PyStrings::gModule, PyROOT_PyUnicode_FromString( module.c_str()) );
713
714 Py_DECREF( pyactual );
715 Py_DECREF( parent );
716
717
718 if ( ! bClassFound ) { // add python-style features to newly minted classes
719 if ( ! Pythonize( pyclass, actual ) ) {
720 Py_XDECREF( pyclass );
721 pyclass = 0;
722 }
723 }
724
725
726 if ( pyclass && actual != "ROOT" ) {
727 // add to sys.modules to allow importing from this module
728 std::string pyfullname = lookup;
729 std::string::size_type pos = pyfullname.find( "::" );
730 while ( pos != std::string::npos ) {
731 pyfullname = pyfullname.replace( pos, 2, "." );
732 pos = pyfullname.find( "::", pos );
733 }
734 PyObject* modules = PySys_GetObject( const_cast<char*>("modules") );
735 if ( modules && PyDict_Check( modules) ) {
736 PyDict_SetItemString( modules,
737 const_cast<char*>(("ROOT."+pyfullname).c_str()), pyclass );
738 }
739 }
740
741// all done
742 return pyclass;
743}
744
745////////////////////////////////////////////////////////////////////////////////
746/// get the requested name
747
749{
750 std::string ename = PyROOT_PyUnicode_AsString( PyTuple_GetItem( args, 0 ) );
751
752 if ( PyErr_Occurred() )
753 return 0;
754
755 return GetCppGlobal( ename );
756}
757
758////////////////////////////////////////////////////////////////////////////////
759/// try named global variable/enum (first ROOT, then Cling: sync is too slow)
760
761PyObject* PyROOT::GetCppGlobal( const std::string& name )
762{
764 if ( 0 <= idata )
766
767// still here ... try functions (sync has been fixed, so is okay)
768 const std::vector< Cppyy::TCppMethod_t >& methods =
770 if ( ! methods.empty() ) {
771 std::vector< PyCallable* > overloads;
772 for ( auto method : methods )
773 overloads.push_back( new TFunctionHolder( Cppyy::gGlobalScope, method ) );
774 return (PyObject*)MethodProxy_New( name, overloads );
775 }
776
777// allow lookup into std as if global (historic)
778 TDataMember* dm = TClass::GetClass( "std" )->GetDataMember( name.c_str() );
779 if ( dm ) {
781 return BindCppObjectNoCast( (void*)dm->GetOffset(), klass, kFALSE );
782 }
783
784// nothing found
785 PyErr_Format( PyExc_LookupError, "no such global: %s", name.c_str() );
786 return 0;
787}
788
789////////////////////////////////////////////////////////////////////////////////
790/// only known or knowable objects will be bound (null object is ok)
791
793 Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Bool_t isRef, Bool_t isValue ) {
794 if ( ! klass ) {
795 PyErr_SetString( PyExc_TypeError, "attempt to bind ROOT object w/o class" );
796 return 0;
797 }
798
799// retrieve python class
800 PyObject* pyclass = CreateScopeProxy( klass );
801 if ( ! pyclass )
802 return 0; // error has been set in CreateScopeProxy
803
804// instantiate an object of this class
805 PyObject* args = PyTuple_New(0);
806 ObjectProxy* pyobj =
807 (ObjectProxy*)((PyTypeObject*)pyclass)->tp_new( (PyTypeObject*)pyclass, args, NULL );
808 Py_DECREF( args );
809 Py_DECREF( pyclass );
810
811// bind, register and return if successful
812 if ( pyobj != 0 ) { // fill proxy value?
813 // TODO: take flags directly instead of separate Bool_t args
814 unsigned flags = (isRef ? ObjectProxy::kIsReference : 0) | (isValue ? ObjectProxy::kIsValue : 0);
815 pyobj->Set( address, (ObjectProxy::EFlags)flags );
816 }
817
818// successful completion
819 return (PyObject*)pyobj;
820}
821
822////////////////////////////////////////////////////////////////////////////////
823/// if the object is a null pointer, return a typed one (as needed for overloading)
824
826{
827 if ( ! address )
828 return BindCppObjectNoCast( address, klass, kFALSE );
829
830// only known or knowable objects will be bound
831 if ( ! klass ) {
832 PyErr_SetString( PyExc_TypeError, "attempt to bind ROOT object w/o class" );
833 return 0;
834 }
835
836// get actual class for recycling checking and/or downcasting
837// CLING WORKAROUND -- silence:
838// Error in <TStreamerInfo::Build>: __gnu_cxx::__normal_iterator<int*,vector<int> >, discarding: int* _M_current, no [dimension]
839 Int_t oldval = gErrorIgnoreLevel;
840 gErrorIgnoreLevel = 5000;
841 Cppyy::TCppType_t clActual = isRef ? 0 : Cppyy::GetActualClass( klass, address );
842 gErrorIgnoreLevel = oldval;
843
844// obtain pointer to TObject base class (if possible) for memory mgmt; this is
845// done before downcasting, as upcasting from the current class may be easier and
846// downcasting is unnecessary if the python side object gets recycled by the
847// memory regulator
848 TObject* object = 0;
849 static Cppyy::TCppScope_t sTObjectScope = Cppyy::GetScope( "TObject" );
850 if ( ! isRef && Cppyy::IsSubtype( klass, sTObjectScope) ) {
851 object = (TObject*)((Long_t)address + \
852 Cppyy::GetBaseOffset( klass, sTObjectScope, address, 1 /* up-cast */ ) );
853
854 // use the old reference if the object already exists
855 PyObject* oldPyObject = TMemoryRegulator::RetrieveObject( object, clActual ? clActual : klass );
856 if ( oldPyObject )
857 return oldPyObject;
858 }
859
860// downcast to real class for object returns
861 if ( clActual && klass != clActual ) {
862 ptrdiff_t offset = Cppyy::GetBaseOffset(
863 clActual, klass, address, -1 /* down-cast */, true /* report errors */ );
864 if ( offset != -1 ) { // may fail if clActual not fully defined
865 address = (void*)((Long_t)address + offset);
866 klass = clActual;
867 }
868 }
869
870
871// check if type is pinned
872 Bool_t ignore_pin = std::find(
873 gIgnorePinnings.begin(), gIgnorePinnings.end(), klass ) != gIgnorePinnings.end();
874
875 if ( ! ignore_pin ) {
876 for ( auto it = gPinnedTypes.cbegin(); it != gPinnedTypes.cend(); ++it ) {
877 if ( klass == std::get<0>(*it) || Cppyy::IsSubtype( klass, std::get<0>(*it) ) )
878 klass = std::get<1>(*it);
879 }
880 }
881
882// actual binding
883 ObjectProxy* pyobj = (ObjectProxy*)BindCppObjectNoCast( address, klass, isRef );
884
885// memory management, for TObject's only (for referenced objects, it is assumed
886// that the (typically global) reference itself is zeroed out (or replaced) on
887// destruction; it can't thus be reliably zeroed out from the python side)
888 if ( object && !(pyobj->fFlags & ObjectProxy::kIsReference) ) {
889 TMemoryRegulator::RegisterObject( pyobj, object );
890 }
891
892// completion (returned object may be zero w/ a python exception set)
893 return (PyObject*)pyobj;
894}
895
896////////////////////////////////////////////////////////////////////////////////
897/// TODO: this function exists for symmetry; need to figure out if it's useful
898
900 Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Int_t size ) {
901 return TTupleOfInstances_New( address, klass, size );
902}
903
904
905////////////////////////////////////////////////////////////////////////////////
906/// gbl == 0 means global does not exist (rather than gbl is NULL pointer)
907
909{
910 if ( ! gbl || strcmp(gbl->GetName(), "") == 0 ) {
911 Py_INCREF( Py_None );
912 return Py_None;
913 }
914
915// determine type and cast as appropriate
917 if ( klass != 0 ) {
918 // handle array of objects
919 if ( gbl->GetArrayDim() == 1 ) {
920 return BindCppObjectArray( (void*)gbl->GetAddress(), klass, gbl->GetMaxIndex(0) );
921 } else if ( gbl->GetArrayDim() ) {
922 PyErr_SetString( PyExc_NotImplementedError,
923 "larger than 1D arrays of objects not supported" );
924 return 0;
925 }
926
927 // special case where there should be no casting:
928 // TODO: WORK HERE ... restore cast
929 //if ( klass->InheritsFrom( "ios_base" ) )
930 //return BindCppObjectNoCast( (void*)gbl->GetAddress(), klass );
931
932 // pointer types are bound "by-reference"
933 if ( Utility::Compound( gbl->GetFullTypeName() ) != "" )
934 return BindCppObject( (void*)gbl->GetAddress(), klass, kTRUE );
935 }
936
937 if ( gbl->GetAddress() && // check for enums and consts
938 (unsigned long)gbl->GetAddress() != (unsigned long)-1 && // Cling (??)
939 ( gInterpreter->ClassInfo_IsEnum( gbl->GetTypeName() ) ) ) {
940 return PyInt_FromLong( (long)*((int*)gbl->GetAddress()) );
941 }
942
943// no class and no enum: for built-in types, to ensure setability
946 return result;
947}
#define R__EXTERN
Definition: DllImport.h:27
#define Py_TYPE(ob)
Definition: PyROOT.h:161
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:78
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:82
#define c(i)
Definition: RSha256.hxx:101
#define e(i)
Definition: RSha256.hxx:103
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.
static PyObject * BuildCppClassBases(Cppyy::TCppType_t klass)
Build a tuple of python shadow classes of all the bases of the given 'klass'.
int Int_t
Definition: RtypesCore.h:41
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
@ kIsScopedEnum
Definition: TDictionary.h:89
@ kIsReference
Definition: TDictionary.h:81
R__EXTERN Int_t gErrorIgnoreLevel
Definition: TError.h:105
#define gInterpreter
Definition: TInterpreter.h:538
_object PyObject
Definition: TPyArg.h:20
#define gROOT
Definition: TROOT.h:410
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
const std::string & GetName() const
Definition: MethodProxy.h:45
void Set(void *address, EFlags flags=kNone)
Definition: ObjectProxy.h:33
std::string GetName()
Definition: PropertyProxy.h:30
virtual PyCallable * Clone()=0
Template proxy object to return functions and methods.
Definition: TemplateProxy.h:24
void AddOverload(MethodProxy *mp)
Store overloads of this templated method.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3278
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition: TClass.cxx:3559
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:2885
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
Long_t GetOffset() const
Get offset from "this".
The TEnumConstant class implements the constants of the enum type.
Definition: TEnumConstant.h:29
void * GetAddress() const override
Return address of global.
Definition: TEnumConstant.h:39
The TEnum class implements the enum type.
Definition: TEnum.h:33
Global variables class (global variables are obtained from CINT).
Definition: TGlobal.h:28
virtual Int_t GetArrayDim() const
Return number of array dimensions.
Definition: TGlobal.cxx:85
virtual const char * GetTypeName() const
Get type of global variable, e,g.
Definition: TGlobal.cxx:111
virtual Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
Definition: TGlobal.cxx:101
virtual void * GetAddress() const
Return address of global.
Definition: TGlobal.cxx:77
virtual const char * GetFullTypeName() const
Get full type description of global variable, e,g.: "class TDirectory*".
Definition: TGlobal.cxx:120
TObject * Next()
Definition: TCollection.h:249
A doubly linked list.
Definition: TList.h:44
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
Sequenceable collection abstract base class.
virtual TObject * At(Int_t idx) const =0
ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
Definition: Cppyy.cxx:637
Bool_t IsConstructor(TCppMethod_t method)
Definition: Cppyy.cxx:865
Bool_t IsPublicMethod(TCppMethod_t method)
Definition: Cppyy.cxx:874
ptrdiff_t TCppScope_t
Definition: Cppyy.h:15
Bool_t IsNamespace(TCppScope_t scope)
Definition: Cppyy.cxx:556
std::string GetMethodName(TCppMethod_t)
Definition: Cppyy.cxx:750
TCppIndex_t GetNumMethods(TCppScope_t scope)
Definition: Cppyy.cxx:676
TCppIndex_t GetNumDatamembers(TCppScope_t scope)
Definition: Cppyy.cxx:893
Bool_t IsPublicData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1003
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:146
TCppScope_t gGlobalScope
Definition: Cppyy.cxx:64
std::vector< TCppMethod_t > GetMethodsFromName(TCppScope_t scope, const std::string &name)
Definition: Cppyy.cxx:707
std::string ResolveName(const std::string &cppitem_name)
Definition: Cppyy.cxx:167
TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj)
Definition: Cppyy.cxx:224
TCppScope_t TCppType_t
Definition: Cppyy.h:16
std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
Definition: Cppyy.cxx:609
std::string GetScopedFinalName(TCppType_t type)
Definition: Cppyy.cxx:587
Bool_t IsEnumData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1039
Bool_t IsStaticData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1014
TCppIndex_t GetMethodNumArgs(TCppMethod_t)
Definition: Cppyy.cxx:772
TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
Definition: Cppyy.cxx:979
Long_t TCppIndex_t
Definition: Cppyy.h:21
std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:928
TCppScope_t GetScope(const std::string &scope_name)
Definition: Cppyy.cxx:193
Bool_t IsStaticMethod(TCppMethod_t method)
Definition: Cppyy.cxx:883
ptrdiff_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:963
ptrdiff_t TCppMethod_t
Definition: Cppyy.h:18
std::string GetMethodResultType(TCppMethod_t)
Definition: Cppyy.cxx:761
std::string GetFinalName(TCppType_t type)
Definition: Cppyy.cxx:578
TCppIndex_t GetNumBases(TCppType_t type)
Definition: Cppyy.cxx:600
TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
Definition: Cppyy.cxx:744
std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:916
void * TCppObject_t
Definition: Cppyy.h:17
Bool_t IsSubtype(TCppType_t derived, TCppType_t base)
Definition: Cppyy.cxx:615
R__EXTERN PyObject * gName
Definition: PyStrings.h:33
R__EXTERN PyObject * gROOTns
Definition: PyStrings.h:56
R__EXTERN PyObject * gTemplate
Definition: PyStrings.h:51
R__EXTERN PyObject * gModule
Definition: PyStrings.h:31
R__EXTERN PyObject * gCppName
Definition: PyStrings.h:34
std::string MapOperatorName(const std::string &name, Bool_t bTakesParames)
Map the given C++ operator name on the python equivalent.
Definition: Utility.cxx:612
const std::string Compound(const std::string &name)
Break down the compound of a fully qualified type name.
Definition: Utility.cxx:658
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)
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
Retrieve scope proxy from the known ones.
PyTypeObject PyRootType_Type
Definition: PyRootType.cxx:227
PropertyProxy * PropertyProxy_NewConstant(Cppyy::TCppScope_t scope, const std::string &name, void *address, TEnum *en)
Definition: PropertyProxy.h:72
PyObject * BindCppGlobal(TGlobal *)
gbl == 0 means global does not exist (rather than gbl is NULL pointer)
Bool_t PyRootType_Check(T *object)
Definition: PyRootType.h:50
void InitRoot()
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's useful.
PyObject * TTupleOfInstances_New(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t nelems)
Bool_t TemplateProxy_Check(T *object)
Definition: TemplateProxy.h:50
PyTypeObject ObjectProxy_Type
TemplateProxy * TemplateProxy_New(const std::string &name, PyObject *pyclass)
Definition: TemplateProxy.h:62
MethodProxy * MethodProxy_New(const std::string &name, std::vector< PyCallable * > &methods)
Definition: MethodProxy.h:75
Bool_t MethodProxy_Check(T *object)
Definition: MethodProxy.h:63
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Convenience function with a lookup first through the known existing proxies.
PropertyProxy * PropertyProxy_New(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
Definition: PropertyProxy.h:62
std::vector< Cppyy::TCppType_t > gIgnorePinnings
Definition: RootModule.cxx:148
std::vector< std::pair< Cppyy::TCppType_t, Cppyy::TCppType_t > > gPinnedTypes
Definition: RootModule.cxx:147
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)
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)
Bool_t Pythonize(PyObject *pyclass, const std::string &name)
Definition: Pythonize.cxx:2348
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
auto * m
Definition: textangle.C:8