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