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