ROOT  6.06/09
Reference Guide
PyRootType.cxx
Go to the documentation of this file.
1 // @(#)root/pyroot:$Id$
2 // Author: Wim Lavrijsen, Jan 2005
3 
4 // Bindings
5 #include "PyROOT.h"
6 #include "PyRootType.h"
7 #include "MethodProxy.h"
8 #include "PropertyProxy.h"
9 #include "RootWrapper.h"
10 #include "TFunctionHolder.h"
11 #include "TemplateProxy.h"
12 
13 // ROOT
14 #include "TClass.h" // for method and enum finding
15 #include "TList.h" // id.
16 
17 // Standard
18 #include <string.h>
19 #include <string>
20 #include <vector>
21 
22 
23 namespace PyROOT {
24 
25 namespace {
26 
27 //= PyROOT type proxy construction/destruction ===============================
28  PyObject* meta_alloc( PyTypeObject* metatype, Py_ssize_t nitems )
29  {
30  // specialized allocator, fitting in a few extra bytes for a TClassRef
31  PyObject* pyclass = PyType_Type.tp_alloc( metatype, nitems );
32 
33  return pyclass;
34  }
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 
38  void meta_dealloc( PyRootClass* pytype )
39  {
40  return PyType_Type.tp_dealloc( (PyObject*)pytype );
41  }
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Called when PyRootType acts as a metaclass; since type_new always resets
45 /// tp_alloc, and since it does not call tp_init on types, the metaclass is
46 /// being fixed up here, and the class is initialized here as well.
47 
48  PyObject* pt_new( PyTypeObject* subtype, PyObject* args, PyObject* kwds )
49  {
50  // fixup of metaclass (left permanent, and in principle only called once b/c
51  // PyROOT caches python classes)
52  subtype->tp_alloc = (allocfunc)meta_alloc;
53  subtype->tp_dealloc = (destructor)meta_dealloc;
54 
55  // creation of the python-side class
56  PyRootClass* result = (PyRootClass*)PyType_Type.tp_new( subtype, args, kwds );
57 
58  // initialization of class (based on name only, initially, which is lazy)
59 
60  // there's a snag here: if a python class is derived from the bound class,
61  // the name will not be known by TClassRef, hence we'll use the meta class
62  // name from the subtype, rather than given class name
63 
64  const char* mp = strstr( subtype->tp_name, "_meta" );
65  if ( ! mp ) {
66  // there has been a user meta class override in a derived class, so do
67  // the consistent thing, thus allowing user control over naming
68  result->fCppType = Cppyy::GetScope(
69  PyROOT_PyUnicode_AsString( PyTuple_GET_ITEM( args, 0 ) ) );
70  } else {
71  // coming here from PyROOT, use meta class name instead of given name,
72  // so that it is safe to inherit python classes from the bound class
73  result->fCppType = Cppyy::GetScope(
74  std::string( subtype->tp_name ).substr( 0, mp-subtype->tp_name ).c_str() );
75  }
76 
77  return (PyObject*)result;
78  }
79 
80 
81 //= PyROOT type metaclass behavior ===========================================
82  PyObject* pt_getattro( PyObject* pyclass, PyObject* pyname )
83  {
84  // normal type lookup
85  PyObject* attr = PyType_Type.tp_getattro( pyclass, pyname );
86 
87  // extra ROOT lookup in case of failure (e.g. for inner classes on demand)
88  if ( ! attr && PyROOT_PyUnicode_CheckExact( pyname ) ) {
89  PyObject *etype, *value, *trace;
90  PyErr_Fetch( &etype, &value, &trace ); // clears current exception
91 
92  // filter for python specials and lookup qualified class or function
93  std::string name = PyROOT_PyUnicode_AsString( pyname );
94  if ( name.size() <= 2 || name.substr( 0, 2 ) != "__" ) {
95  attr = CreateScopeProxy( name, pyclass );
96 
97  // namespaces may have seen updates in their list of global functions, which
98  // are available as "methods" even though they're not really that
99  if ( ! attr && ! PyRootType_CheckExact( pyclass ) && PyType_Check( pyclass ) ) {
100  PyErr_Clear();
101 
102  Cppyy::TCppScope_t scope = Cppyy::GetScope( ((PyTypeObject*)pyclass)->tp_name );
103  TClass* klass = TClass::GetClass( ((PyTypeObject*)pyclass)->tp_name );
104  if ( Cppyy::IsNamespace( scope ) ) {
105 
106  // tickle lazy lookup of functions
107  if ( ! attr ) {
108  if ( klass->GetListOfMethods()->FindObject( name.c_str() ) ) {
109  // function exists, now collect overloads
110  std::vector< PyCallable* > overloads;
111  const size_t nmeth = Cppyy::GetNumMethods( scope );
112  for ( size_t imeth = 0; imeth < nmeth; ++imeth ) {
113  Cppyy::TCppMethod_t method = Cppyy::GetMethod( scope, imeth );
114  if ( Cppyy::GetMethodName( method ) == name )
115  overloads.push_back( new TFunctionHolder( scope, method ) );
116  }
117 
118  // Note: can't re-use Utility::AddClass here, as there's the risk of
119  // a recursive call. Simply add method directly, as we're guaranteed
120  // that it doesn't exist yet.
121  attr = (PyObject*)MethodProxy_New( name.c_str(), overloads );
122  }
123  }
124 
125  // tickle lazy lookup of data members
126  if ( ! attr ) {
127  Cppyy::TCppIndex_t dmi = Cppyy::GetDatamemberIndex( scope, name );
128  if ( 0 <= dmi ) attr = (PyObject*)PropertyProxy_New( scope, dmi );
129  }
130  }
131 
132  // function templates that have not been instantiated
133  if ( ! attr && klass ) {
134  TFunctionTemplate* tmpl = klass->GetFunctionTemplate( name.c_str() );
135  if ( tmpl )
136  attr = (PyObject*)TemplateProxy_New( name, pyclass );
137  }
138 
139  // enums types requested as type (rather than the constants)
140  if ( ! attr && klass && klass->GetListOfEnums()->FindObject( name.c_str() ) ) {
141  // special case; enum types; for now, pretend int
142  // TODO: although fine for C++98, this isn't correct in C++11
143  Py_INCREF( &PyInt_Type );
144  attr = (PyObject*)&PyInt_Type;
145  }
146 
147  if ( attr ) {
148  PyObject_SetAttr( pyclass, pyname, attr );
149  Py_DECREF( attr );
150  attr = PyType_Type.tp_getattro( pyclass, pyname );
151  }
152  }
153 
154  if ( ! attr && ! PyRootType_Check( pyclass ) /* at global or module-level only */ ) {
155  PyErr_Clear();
156  // get class name to look up CINT tag info ...
157  attr = GetCppGlobal( name /*, tag */ );
158  if ( PropertyProxy_Check( attr ) ) {
159  PyObject_SetAttr( (PyObject*)Py_TYPE(pyclass), pyname, attr );
160  Py_DECREF( attr );
161  attr = PyType_Type.tp_getattro( pyclass, pyname );
162  } else if ( attr )
163  PyObject_SetAttr( pyclass, pyname, attr );
164  }
165 
166  }
167 
168  // if failed, then the original error is likely to be more instructive
169  if ( ! attr && etype )
170  PyErr_Restore( etype, value, trace );
171  else if ( ! attr ) {
172  PyObject* sklass = PyObject_Str( pyclass );
173  PyErr_Format( PyExc_AttributeError, "%s has no attribute \'%s\'",
175  Py_DECREF( sklass );
176  }
177 
178  // attribute is cached, if found
179  }
180 
181  return attr;
182  }
183 
184 } // unnamed namespace
185 
186 
187 //= PyROOT object proxy type type ============================================
188 PyTypeObject PyRootType_Type = {
189  PyVarObject_HEAD_INIT( &PyType_Type, 0 )
190  (char*)"ROOT.PyRootType", // tp_name
191  sizeof(PyROOT::PyRootClass),// tp_basicsize
192  0, // tp_itemsize
193  0, // tp_dealloc
194  0, // tp_print
195  0, // tp_getattr
196  0, // tp_setattr
197  0, // tp_compare
198  0, // tp_repr
199  0, // tp_as_number
200  0, // tp_as_sequence
201  0, // tp_as_mapping
202  0, // tp_hash
203  0, // tp_call
204  0, // tp_str
205  (getattrofunc)pt_getattro, // tp_getattro
206  0, // tp_setattro
207  0, // tp_as_buffer
208  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
209  (char*)"PyROOT metatype (internal)", // tp_doc
210  0, // tp_traverse
211  0, // tp_clear
212  0, // tp_richcompare
213  0, // tp_weaklistoffset
214  0, // tp_iter
215  0, // tp_iternext
216  0, // tp_methods
217  0, // tp_members
218  0, // tp_getset
219  &PyType_Type, // tp_base
220  0, // tp_dict
221  0, // tp_descr_get
222  0, // tp_descr_set
223  0, // tp_dictoffset
224  0, // tp_init
225  0, // tp_alloc
226  (newfunc)pt_new, // tp_new
227  0, // tp_free
228  0, // tp_is_gc
229  0, // tp_bases
230  0, // tp_mro
231  0, // tp_cache
232  0, // tp_subclasses
233  0 // tp_weaklist
234 #if PY_VERSION_HEX >= 0x02030000
235  , 0 // tp_del
236 #endif
237 #if PY_VERSION_HEX >= 0x02060000
238  , 0 // tp_version_tag
239 #endif
240 #if PY_VERSION_HEX >= 0x03040000
241  , 0 // tp_finalize
242 #endif
243 };
244 
245 } // namespace PyROOT
Bool_t IsNamespace(TCppScope_t scope)
Definition: Cppyy.cxx:513
Dictionary for function template This class describes one single function template.
TList * GetListOfEnums(Bool_t load=kTRUE)
Return list containing the TEnums of a class.
Definition: TClass.cxx:3488
Bool_t PyRootType_CheckExact(T *object)
Definition: PyRootType.h:56
MethodProxy * MethodProxy_New(const std::string &name, std::vector< PyCallable * > &methods)
Definition: MethodProxy.h:75
Bool_t PyRootType_Check(T *object)
Definition: PyRootType.h:50
TemplateProxy * TemplateProxy_New(const std::string &name, PyObject *pyclass)
Definition: TemplateProxy.h:62
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:496
#define PyVarObject_HEAD_INIT(type, size)
Definition: PyROOT.h:147
PyObject * GetCppGlobal(const std::string &name)
try named global variable/enum (first ROOT, then Cling: sync is too slow)
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:66
Bool_t PropertyProxy_Check(T *object)
Definition: PropertyProxy.h:50
TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
Definition: Cppyy.cxx:701
ptrdiff_t TCppMethod_t
Definition: Cppyy.h:15
std::string GetMethodName(TCppMethod_t)
Definition: Cppyy.cxx:707
TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
Definition: Cppyy.cxx:936
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
Type object to hold TClassRef instance (this is only semantically a presentation of PyRootType instan...
Definition: PyRootType.h:37
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Convenience function with a lookup first through the known existing proxies.
TCppScope_t GetScope(const std::string &scope_name)
Definition: Cppyy.cxx:150
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:2881
#define PyROOT_PyUnicode_CheckExact
Definition: PyROOT.h:65
TFunctionTemplate * GetFunctionTemplate(const char *name)
Definition: TClass.cxx:3419
#define Py_TYPE(ob)
Definition: PyROOT.h:149
Long_t TCppIndex_t
Definition: Cppyy.h:17
int Py_ssize_t
Definition: PyROOT.h:154
TCppIndex_t GetNumMethods(TCppScope_t scope)
Definition: Cppyy.cxx:633
PropertyProxy * PropertyProxy_New(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
Definition: PropertyProxy.h:62
double result[121]
TList * GetListOfMethods(Bool_t load=kTRUE)
Return list containing the TMethods of a class.
Definition: TClass.cxx:3588
float value
Definition: math.cpp:443
ptrdiff_t TCppScope_t
Definition: Cppyy.h:12
_object PyObject
Definition: TPyArg.h:22