ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
MethodProxy.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 "structmember.h" // from Python
7 #if PY_VERSION_HEX >= 0x02050000
8 #include "code.h" // from Python
9 #else
10 #include "compile.h" // from Python
11 #endif
12 #ifndef CO_NOFREE
13 // python2.2 does not have CO_NOFREE defined
14 #define CO_NOFREE 0x0040
15 #endif
16 #include "MethodProxy.h"
17 #include "ObjectProxy.h"
18 #include "TCallContext.h"
19 #include "TPyException.h"
20 #include "PyStrings.h"
21 
22 // Standard
23 #include <algorithm>
24 #include <vector>
25 
26 
27 namespace PyROOT {
28 
29 // TODO: only used here, but may be better off integrated with Pythonize.cxx callbacks
30  class TPythonCallback : public PyCallable {
31  public:
32  PyObject* fCallable;
33 
34  TPythonCallback( PyObject* callable ) {
35  if ( !PyCallable_Check( callable ) ) {
36  PyErr_SetString(PyExc_TypeError, "parameter must be callable");
37  return;
38  }
39  fCallable = callable;
40  Py_INCREF( fCallable );
41  }
42 
43  virtual ~TPythonCallback() {
44  Py_DECREF( fCallable );
45  fCallable = 0;
46  }
47 
48  virtual PyObject* GetSignature() { return PyROOT_PyUnicode_FromString( "*args, **kwargs" ); } ;
49  virtual PyObject* GetPrototype() { return PyROOT_PyUnicode_FromString( "<callback>" ); } ;
50  virtual PyObject* GetDocString() {
51  if ( PyObject_HasAttrString( fCallable, "__doc__" )) {
52  return PyObject_GetAttrString( fCallable, "__doc__" );
53  } else {
54  return GetPrototype();
55  }
56  }
57 
58  virtual Int_t GetPriority() { return 100; };
59 
60  virtual Int_t GetMaxArgs() { return 100; };
61  virtual PyObject* GetCoVarNames() { // TODO: pick these up from the callable
62  Py_INCREF( Py_None );
63  return Py_None;
64  }
65  virtual PyObject* GetArgDefault( Int_t /* iarg */ ) { // TODO: pick these up from the callable
66  Py_INCREF( Py_None );
67  return Py_None;
68  }
69 
70  virtual PyObject* GetScopeProxy() { // should this be the module ??
71  Py_INCREF( Py_None );
72  return Py_None;
73  }
74 
75  virtual PyCallable* Clone() { return new TPythonCallback( *this ); }
76 
77  virtual PyObject* Call(
78  ObjectProxy*& self, PyObject* args, PyObject* kwds, TCallContext* /* ctxt = 0 */ ) {
79 
80  PyObject* newArgs = nullptr;
81  if ( self ) {
82  Py_ssize_t nargs = PyTuple_Size( args );
83  newArgs = PyTuple_New( nargs+1 );
84  Py_INCREF( self );
85  PyTuple_SET_ITEM( newArgs, 0, (PyObject*)self );
86  for ( Py_ssize_t iarg = 0; iarg < nargs; ++iarg ) {
87  PyObject* pyarg = PyTuple_GET_ITEM( args, iarg );
88  Py_INCREF( pyarg );
89  PyTuple_SET_ITEM( newArgs, iarg+1, pyarg );
90  }
91  } else {
92  Py_INCREF( args );
93  newArgs = args;
94  }
95  return PyObject_Call( fCallable, newArgs, kwds );
96  }
97  };
98 
99 namespace {
100 
101 // helper to test whether a method is used in a pseudo-function modus
102  Bool_t inline IsPseudoFunc( MethodProxy* pymeth )
103  {
104  return (void*)pymeth == (void*)pymeth->fSelf;
105  }
106 
107 // helper for collecting/maintaining exception data in overload dispatch
108  struct PyError_t {
109  PyError_t() { fType = fValue = fTrace = 0; }
110 
111  static void Clear( PyError_t& e )
112  {
113  // Remove exception information.
114  Py_XDECREF( e.fType ); Py_XDECREF( e.fValue ); Py_XDECREF( e.fTrace );
115  e.fType = e.fValue = e.fTrace = 0;
116  }
117 
119  };
120 
121 // helper to hash tuple (using tuple hash would cause self-tailing loops)
122  inline Long_t HashSignature( PyObject* args )
123  {
124  // Build a hash from the types of the given python function arguments.
125  ULong_t hash = 0;
126 
127  Int_t nargs = PyTuple_GET_SIZE( args );
128  for ( Int_t i = 0; i < nargs; ++i ) {
129  hash += (ULong_t) Py_TYPE( PyTuple_GET_ITEM( args, i ) );
130  hash += (hash << 10); hash ^= (hash >> 6);
131  }
132 
133  hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15);
134 
135  return hash;
136  }
137 
138 // helper to sort on method priority
139  int PriorityCmp( PyCallable* left, PyCallable* right )
140  {
141  return left->GetPriority() > right->GetPriority();
142  }
143 
144 // helper to factor out return logic of mp_call
145  inline PyObject* HandleReturn( MethodProxy* pymeth, ObjectProxy* oldSelf, PyObject* result ) {
146 
147  // special case for python exceptions, propagated through C++ layer
148  if ( result != (PyObject*)TPyExceptionMagic && result != (PyObject*)TPyCPPExceptionMagic ) {
149 
150  // if this method creates new objects, always take ownership
151  if ( IsCreator( pymeth->fMethodInfo->fFlags ) ) {
152 
153  // either be a constructor with a fresh object proxy self ...
154  if ( IsConstructor( pymeth->fMethodInfo->fFlags ) ) {
155  if ( pymeth->fSelf )
156  pymeth->fSelf->HoldOn();
157  }
158 
159  // ... or be a method with an object proxy return value
160  else if ( ObjectProxy_Check( result ) )
161  ((ObjectProxy*)result)->HoldOn();
162  }
163 
164  // if this new object falls inside self, make sure its lifetime is proper
165  if ( ObjectProxy_Check( pymeth->fSelf ) && ObjectProxy_Check( result ) ) {
166  Long_t ptrdiff = (Long_t)((ObjectProxy*)result)->GetObject() - (Long_t)pymeth->fSelf->GetObject();
167  if ( 0 <= ptrdiff && ptrdiff < (Long_t)Cppyy::SizeOf( pymeth->fSelf->ObjectIsA() ) ) {
168  if ( PyObject_SetAttr( result, PyStrings::gLifeLine, (PyObject*)pymeth->fSelf ) == -1 )
169  PyErr_Clear(); // ignored
170  }
171  }
172  } else { // result is TPyExceptionMagic or TPyCPPExceptionMagic
173  result = nullptr; // exception info was already set
174  }
175 
176  // reset self as necessary to allow re-use of the MethodProxy
177  if ( pymeth->fSelf != oldSelf ) {
178  Py_XDECREF( pymeth->fSelf );
179  pymeth->fSelf = oldSelf;
180  }
181 
182  return result;
183  }
184 
185 
186 //= PyROOT method proxy object behaviour =====================================
187  PyObject* mp_name( MethodProxy* pymeth, void* )
188  {
189  return PyROOT_PyUnicode_FromString( pymeth->GetName().c_str() );
190  }
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 
194  PyObject* mp_module( MethodProxy* /* pymeth */, void* )
195  {
196  Py_INCREF( PyStrings::gROOTns );
197  return PyStrings::gROOTns;
198  }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// Build python document string ('__doc__') from all C++-side overloads.
202 
203  PyObject* mp_doc( MethodProxy* pymeth, void* )
204  {
205  MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
206 
207  // collect doc strings
208  Int_t nMethods = methods.size();
209  PyObject* doc = methods[0]->GetDocString();
210 
211  // simple case
212  if ( nMethods == 1 )
213  return doc;
214 
215  // overloaded method
216  PyObject* separator = PyROOT_PyUnicode_FromString( "\n" );
217  for ( Int_t i = 1; i < nMethods; ++i ) {
218  PyROOT_PyUnicode_Append( &doc, separator );
219  PyROOT_PyUnicode_AppendAndDel( &doc, methods[i]->GetDocString() );
220  }
221  Py_DECREF( separator );
222 
223  return doc;
224  }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Create a new method proxy to be returned.
228 
229  PyObject* mp_meth_func( MethodProxy* pymeth, void* )
230  {
231  MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
232 
233  // method info is shared, as it contains the collected overload knowledge
234  *pymeth->fMethodInfo->fRefCount += 1;
235  newPyMeth->fMethodInfo = pymeth->fMethodInfo;
236 
237  // new method is unbound, use of 'meth' is for keeping track whether this
238  // proxy is used in the capacity of a method or a function
239  newPyMeth->fSelf = (ObjectProxy*)newPyMeth;
240 
241  return (PyObject*)newPyMeth;
242  }
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// Return the bound self, if any; in case of pseudo-function role, pretend
246 /// that the data member im_self does not exist.
247 
248  PyObject* mp_meth_self( MethodProxy* pymeth, void* )
249  {
250  if ( IsPseudoFunc( pymeth ) ) {
251  PyErr_Format( PyExc_AttributeError,
252  "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str() );
253  return 0;
254  } else if ( pymeth->fSelf != 0 ) {
255  Py_INCREF( (PyObject*)pymeth->fSelf );
256  return (PyObject*)pymeth->fSelf;
257  }
258 
259  Py_INCREF( Py_None );
260  return Py_None;
261  }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Return scoping class; in case of pseudo-function role, pretend that there
265 /// is no encompassing class (i.e. global scope).
266 
267  PyObject* mp_meth_class( MethodProxy* pymeth, void* )
268  {
269  if ( ! IsPseudoFunc( pymeth ) ) {
270  PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScopeProxy();
271  if ( ! pyclass )
272  PyErr_Format( PyExc_AttributeError,
273  "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str() );
274  return pyclass;
275  }
276 
277  Py_INCREF( Py_None );
278  return Py_None;
279  }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// Stub only, to fill out the python function interface.
283 
284  PyObject* mp_func_closure( MethodProxy* /* pymeth */, void* )
285  {
286  Py_INCREF( Py_None );
287  return Py_None;
288  }
289 
290 ////////////////////////////////////////////////////////////////////////////////
291 /// Code details are used in module inspect to fill out interactive help()
292 
293  PyObject* mp_func_code( MethodProxy* pymeth, void* )
294  {
295 #if PY_VERSION_HEX < 0x03000000
296  MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
297 
298  // collect arguments only if there is just 1 overload, otherwise put in a
299  // fake *args (see below for co_varnames)
300  PyObject* co_varnames = methods.size() == 1 ? methods[0]->GetCoVarNames() : NULL;
301  if ( !co_varnames ) {
302  // TODO: static methods need no 'self' (but is harmless otherwise)
303  co_varnames = PyTuple_New( 1 /* self */ + 1 /* fake */ );
304  PyTuple_SET_ITEM( co_varnames, 0, PyROOT_PyUnicode_FromString( "self" ) );
305  PyTuple_SET_ITEM( co_varnames, 1, PyROOT_PyUnicode_FromString( "*args" ) );
306  }
307 
308  int co_argcount = PyTuple_Size( co_varnames );
309 
310  // for now, code object representing the statement 'pass'
311  PyObject* co_code = PyString_FromStringAndSize( "d\x00\x00S", 4 );
312 
313  // tuples with all the const literals used in the function
314  PyObject* co_consts = PyTuple_New( 0 );
315  PyObject* co_names = PyTuple_New( 0 );
316 
317  // names, freevars, and cellvars go unused
318  PyObject* co_unused = PyTuple_New( 0 );
319 
320  // filename is made-up
321  PyObject* co_filename = PyString_FromString( "ROOT.py" );
322 
323  // name is the function name, also through __name__ on the function itself
324  PyObject* co_name = PyString_FromString( pymeth->GetName().c_str() );
325 
326  // firstlineno is the line number of first function code in the containing scope
327 
328  // lnotab is a packed table that maps instruction count and line number
329  PyObject* co_lnotab = PyString_FromString( "\x00\x01\x0c\x01" );
330 
331  PyObject* code = (PyObject*)PyCode_New(
332  co_argcount, // argcount
333  co_argcount + 1, // nlocals
334  2, // stacksize
335  CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE, // flags
336  co_code, // code
337  co_consts, // consts
338  co_names, // names
339  co_varnames, // varnames
340  co_unused, // freevars
341  co_unused, // cellvars
342  co_filename, // filename
343  co_name, // name
344  1, // firstlineno
345  co_lnotab ); // lnotab
346 
347  Py_DECREF( co_lnotab );
348  Py_DECREF( co_name );
349  Py_DECREF( co_unused );
350  Py_DECREF( co_filename );
351  Py_DECREF( co_varnames );
352  Py_DECREF( co_names );
353  Py_DECREF( co_consts );
354  Py_DECREF( co_code );
355 
356  return code;
357 #else
358 // not important for functioning of most code, so not implemented for p3 for now (TODO)
359  pymeth = 0;
360  if ( pymeth || !pymeth) Py_INCREF( Py_None );
361  return Py_None;
362 #endif
363  }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Create a tuple of default values, if there is only one method (otherwise
367 /// leave undefined: this is only used by inspect for interactive help())
368 
369  PyObject* mp_func_defaults( MethodProxy* pymeth, void* )
370  {
371  MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
372 
373  if ( methods.size() != 1 )
374  return PyTuple_New( 0 );
375 
376  int maxarg = methods[0]->GetMaxArgs();
377 
378  PyObject* defaults = PyTuple_New( maxarg );
379 
380  int itup = 0;
381  for ( int iarg = 0; iarg < maxarg; ++iarg ) {
382  PyObject* defvalue = methods[0]->GetArgDefault( iarg );
383  if ( defvalue )
384  PyTuple_SET_ITEM( defaults, itup++, defvalue );
385  }
386  _PyTuple_Resize( &defaults, itup );
387 
388  return defaults;
389  }
390 
391 ////////////////////////////////////////////////////////////////////////////////
392 /// Return this function's global dict (hard-wired to be the ROOT module); used
393 /// for lookup of names from co_code indexing into co_names.
394 
395  PyObject* mp_func_globals( MethodProxy* /* pymeth */, void* )
396  {
397  PyObject* pyglobal = PyModule_GetDict( PyImport_AddModule( (char*)"ROOT" ) );
398  Py_XINCREF( pyglobal );
399  return pyglobal;
400  }
401 
402 ////////////////////////////////////////////////////////////////////////////////
403 /// Get '_creates' boolean, which determines ownership of return values.
404 
405  PyObject* mp_getcreates( MethodProxy* pymeth, void* )
406  {
407  return PyInt_FromLong( (Bool_t)IsCreator( pymeth->fMethodInfo->fFlags ) );
408  }
409 
410 ////////////////////////////////////////////////////////////////////////////////
411 /// Set '_creates' boolean, which determines ownership of return values.
412 
413  int mp_setcreates( MethodProxy* pymeth, PyObject* value, void* )
414  {
415  if ( ! value ) { // means that _creates is being deleted
416  pymeth->fMethodInfo->fFlags &= ~TCallContext::kIsCreator;
417  return 0;
418  }
419 
420  Long_t iscreator = PyLong_AsLong( value );
421  if ( iscreator == -1 && PyErr_Occurred() ) {
422  PyErr_SetString( PyExc_ValueError, "a boolean 1 or 0 is required for _creates" );
423  return -1;
424  }
425 
426  if ( iscreator )
427  pymeth->fMethodInfo->fFlags |= TCallContext::kIsCreator;
428  else
429  pymeth->fMethodInfo->fFlags &= ~TCallContext::kIsCreator;
430 
431  return 0;
432  }
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Get '_mempolicy' enum, which determines ownership of call arguments.
436 
437  PyObject* mp_getmempolicy( MethodProxy* pymeth, void* )
438  {
439  if ( (Bool_t)(pymeth->fMethodInfo->fFlags & TCallContext::kUseHeuristics ) )
440  return PyInt_FromLong( TCallContext::kUseHeuristics );
441 
442  if ( (Bool_t)(pymeth->fMethodInfo->fFlags & TCallContext::kUseStrict ) )
443  return PyInt_FromLong( TCallContext::kUseStrict );
444 
445  return PyInt_FromLong( -1 );
446  }
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// Set '_mempolicy' enum, which determines ownership of call arguments.
450 
451  int mp_setmempolicy( MethodProxy* pymeth, PyObject* value, void* )
452  {
453  Long_t mempolicy = PyLong_AsLong( value );
454  if ( mempolicy == TCallContext::kUseHeuristics ) {
455  pymeth->fMethodInfo->fFlags |= TCallContext::kUseHeuristics;
456  pymeth->fMethodInfo->fFlags &= ~TCallContext::kUseStrict;
457  } else if ( mempolicy == TCallContext::kUseStrict ) {
458  pymeth->fMethodInfo->fFlags |= TCallContext::kUseStrict;
459  pymeth->fMethodInfo->fFlags &= ~TCallContext::kUseHeuristics;
460  } else {
461  PyErr_SetString( PyExc_ValueError,
462  "expected kMemoryStrict or kMemoryHeuristics as value for _mempolicy" );
463  return -1;
464  }
465 
466  return 0;
467  }
468 
469 ////////////////////////////////////////////////////////////////////////////////
470 /// Get '_manage_smart_ptr' boolean, which determines whether or not to
471 /// manage returned smart pointers intelligently.
472 
473  PyObject* mp_get_manage_smart_ptr( MethodProxy* pymeth, void* )
474  {
475  return PyInt_FromLong(
476  (Bool_t)(pymeth->fMethodInfo->fFlags & TCallContext::kManageSmartPtr) );
477  }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 /// Set '_manage_smart_ptr' boolean, which determines whether or not to
481 /// manage returned smart pointers intelligently.
482 
483  int mp_set_manage_smart_ptr( MethodProxy* pymeth, PyObject* value, void* )
484  {
485  Long_t policy = PyLong_AsLong( value );
486  if ( policy == -1 && PyErr_Occurred() ) {
487  PyErr_SetString( PyExc_ValueError, "a boolean 1 or 0 is required for _manage_smart_ptr" );
488  return -1;
489  }
490 
491  pymeth->fMethodInfo->fFlags |= TCallContext::kManageSmartPtr;
492 
493  return 0;
494  }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// Get '_threaded' boolean, which determines whether the GIL will be released.
498 
499  PyObject* mp_getthreaded( MethodProxy* pymeth, void* )
500  {
501  return PyInt_FromLong(
502  (Bool_t)(pymeth->fMethodInfo->fFlags & TCallContext::kReleaseGIL) );
503  }
504 
505 ////////////////////////////////////////////////////////////////////////////////
506 /// Set '_threaded' boolean, which determines whether the GIL will be released.
507 
508  int mp_setthreaded( MethodProxy* pymeth, PyObject* value, void* )
509  {
510  Long_t isthreaded = PyLong_AsLong( value );
511  if ( isthreaded == -1 && PyErr_Occurred() ) {
512  PyErr_SetString( PyExc_ValueError, "a boolean 1 or 0 is required for _creates" );
513  return -1;
514  }
515 
516  if ( isthreaded )
517  pymeth->fMethodInfo->fFlags |= TCallContext::kReleaseGIL;
518  else
519  pymeth->fMethodInfo->fFlags &= ~TCallContext::kReleaseGIL;
520 
521  return 0;
522  }
523 
524 ////////////////////////////////////////////////////////////////////////////////
525 
526  PyGetSetDef mp_getset[] = {
527  { (char*)"__name__", (getter)mp_name, NULL, NULL, NULL },
528  { (char*)"__module__", (getter)mp_module, NULL, NULL, NULL },
529  { (char*)"__doc__", (getter)mp_doc, NULL, NULL, NULL },
530 
531  // to be more python-like, where these are duplicated as well; to actually
532  // derive from the python method or function type is too memory-expensive,
533  // given that most of the members of those types would not be used
534  { (char*)"im_func", (getter)mp_meth_func, NULL, NULL, NULL },
535  { (char*)"im_self", (getter)mp_meth_self, NULL, NULL, NULL },
536  { (char*)"im_class", (getter)mp_meth_class, NULL, NULL, NULL },
537 
538  { (char*)"func_closure", (getter)mp_func_closure, NULL, NULL, NULL },
539  { (char*)"func_code", (getter)mp_func_code, NULL, NULL, NULL },
540  { (char*)"func_defaults", (getter)mp_func_defaults, NULL, NULL, NULL },
541  { (char*)"func_globals", (getter)mp_func_globals, NULL, NULL, NULL },
542  { (char*)"func_doc", (getter)mp_doc, NULL, NULL, NULL },
543  { (char*)"func_name", (getter)mp_name, NULL, NULL, NULL },
544 
545  { (char*)"_creates", (getter)mp_getcreates, (setter)mp_setcreates,
546  (char*)"For ownership rules of result: if true, objects are python-owned", NULL },
547  { (char*)"_mempolicy", (getter)mp_getmempolicy, (setter)mp_setmempolicy,
548  (char*)"For argument ownership rules: like global, either heuristic or strict", NULL },
549  { (char*)"_manage_smart_ptr", (getter)mp_get_manage_smart_ptr, (setter)mp_set_manage_smart_ptr,
550  (char*)"If a smart pointer is returned, determines management policy.", NULL },
551  { (char*)"_threaded", (getter)mp_getthreaded, (setter)mp_setthreaded,
552  (char*)"If true, releases GIL on call into C++", NULL },
553  { (char*)NULL, NULL, NULL, NULL, NULL }
554  };
555 
556 //= PyROOT method proxy function behavior ====================================
557  PyObject* mp_call( MethodProxy* pymeth, PyObject* args, PyObject* kwds )
558  {
559  // Call the appropriate overload of this method.
560 
561  // if called through im_func pseudo-representation (this can be gamed if the
562  // user really wants to ... )
563  if ( IsPseudoFunc( pymeth ) )
564  pymeth->fSelf = NULL;
565 
566  ObjectProxy* oldSelf = pymeth->fSelf;
567 
568  // get local handles to proxy internals
569  auto& methods = pymeth->fMethodInfo->fMethods;
570  auto& dispatchMap = pymeth->fMethodInfo->fDispatchMap;
571  auto& mflags = pymeth->fMethodInfo->fFlags;
572 
573  Int_t nMethods = methods.size();
574 
575  TCallContext ctxt = { 0 };
576  ctxt.fFlags |= (mflags & TCallContext::kUseHeuristics);
577  ctxt.fFlags |= (mflags & TCallContext::kUseStrict);
578  ctxt.fFlags |= (mflags & TCallContext::kManageSmartPtr);
579  if ( ! ctxt.fFlags ) ctxt.fFlags |= TCallContext::sMemoryPolicy;
580  ctxt.fFlags |= (mflags & TCallContext::kReleaseGIL);
581 
582  // simple case
583  if ( nMethods == 1 ) {
584  PyObject* result = methods[0]->Call( pymeth->fSelf, args, kwds, &ctxt );
585  return HandleReturn( pymeth, oldSelf, result );
586  }
587 
588  // otherwise, handle overloading
589  Long_t sighash = HashSignature( args );
590 
591  // look for known signatures ...
592  MethodProxy::DispatchMap_t::iterator m = dispatchMap.find( sighash );
593  if ( m != dispatchMap.end() ) {
594  Int_t index = m->second;
595  PyObject* result = methods[ index ]->Call( pymeth->fSelf, args, kwds, &ctxt );
596  result = HandleReturn( pymeth, oldSelf, result );
597 
598  if ( result != 0 )
599  return result;
600 
601  // fall through: python is dynamic, and so, the hashing isn't infallible
602  PyErr_Clear();
603  }
604 
605  // ... otherwise loop over all methods and find the one that does not fail
606  if ( ! IsSorted( mflags ) ) {
607  std::stable_sort( methods.begin(), methods.end(), PriorityCmp );
608  mflags |= TCallContext::kIsSorted;
609  }
610 
611  std::vector< PyError_t > errors;
612  for ( Int_t i = 0; i < nMethods; ++i ) {
613  PyObject* result = methods[i]->Call( pymeth->fSelf, args, kwds, &ctxt );
614 
615  if ( result == (PyObject*)TPyCPPExceptionMagic ) {
616  std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
617  return 0; // only interested in this exception!
618  }
619 
620  if ( result == (PyObject*)TPyExceptionMagic ) {
621  std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
622  return 0; // exception info was already set
623  }
624 
625  if ( result != 0 ) {
626  // success: update the dispatch map for subsequent calls
627  dispatchMap[ sighash ] = i;
628  std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
629  return HandleReturn( pymeth, oldSelf, result );
630  }
631 
632  // failure: collect error message/trace (automatically clears exception, too)
633  if ( ! PyErr_Occurred() ) {
634  // this should not happen; set an error to prevent core dump and report
635  PyObject* sig = methods[i]->GetPrototype();
636  PyErr_Format( PyExc_SystemError, "%s =>\n %s",
637  PyROOT_PyUnicode_AsString( sig ), (char*)"NULL result without error in mp_call" );
638  Py_DECREF( sig );
639  }
640  PyError_t e;
641  PyErr_Fetch( &e.fType, &e.fValue, &e.fTrace );
642  errors.push_back( e );
643  }
644 
645  // first summarize, then add details
647  "none of the %d overloaded methods succeeded. Full details:", nMethods );
648  PyObject* separator = PyROOT_PyUnicode_FromString( "\n " );
649 
650  // if this point is reached, none of the overloads succeeded: notify user
651  PyObject* exc_type = NULL;
652  for ( std::vector< PyError_t >::iterator e = errors.begin(); e != errors.end(); ++e ) {
653  if ( e->fType != PyExc_NotImplementedError ) {
654  if ( ! exc_type ) exc_type = e->fType;
655  else if ( exc_type != e->fType ) exc_type = PyExc_TypeError;
656  }
657  PyROOT_PyUnicode_Append( &value, separator );
658  PyROOT_PyUnicode_Append( &value, e->fValue );
659  }
660 
661  Py_DECREF( separator );
662  std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
663 
664  // report failure
665  PyErr_SetObject( exc_type ? exc_type : PyExc_TypeError, value );
666  Py_DECREF( value );
667  return 0;
668  }
669 
670 ////////////////////////////////////////////////////////////////////////////////
671 /// Descriptor; create and return a new bound method proxy (language requirement).
672 
673  MethodProxy* mp_descrget( MethodProxy* pymeth, ObjectProxy* pyobj, PyObject* )
674  {
675  MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
676 
677  // method info is shared, as it contains the collected overload knowledge
678  *pymeth->fMethodInfo->fRefCount += 1;
679  newPyMeth->fMethodInfo = pymeth->fMethodInfo;
680 
681  // new method is to be bound to current object (may be NULL)
682  Py_XINCREF( (PyObject*)pyobj );
683  newPyMeth->fSelf = pyobj;
684 
685  return newPyMeth;
686  }
687 
688 
689 //= PyROOT method proxy construction/destruction =================================
690  MethodProxy* mp_new( PyTypeObject*, PyObject*, PyObject* )
691  {
692  // Create a new method proxy object.
693  MethodProxy* pymeth = PyObject_GC_New( MethodProxy, &MethodProxy_Type );
694  pymeth->fSelf = NULL;
695  pymeth->fMethodInfo = new MethodProxy::MethodInfo_t;
696 
697  PyObject_GC_Track( pymeth );
698  return pymeth;
699  }
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 /// Deallocate memory held by method proxy object.
703 
704  void mp_dealloc( MethodProxy* pymeth )
705  {
706  PyObject_GC_UnTrack( pymeth );
707 
708  if ( ! IsPseudoFunc( pymeth ) )
709  Py_CLEAR( pymeth->fSelf );
710  pymeth->fSelf = NULL;
711 
712  if ( --(*pymeth->fMethodInfo->fRefCount) <= 0 ) {
713  delete pymeth->fMethodInfo;
714  }
715 
716  PyObject_GC_Del( pymeth );
717  }
718 
719 
720 ////////////////////////////////////////////////////////////////////////////////
721 /// Hash of method proxy object for insertion into dictionaries; with actual
722 /// method (fMethodInfo) shared, its address is best suited.
723 
724  Long_t mp_hash( MethodProxy* pymeth )
725  {
726  return _Py_HashPointer( pymeth->fMethodInfo );
727  }
728 
729 ////////////////////////////////////////////////////////////////////////////////
730 /// Garbage collector traverse of held python member objects.
731 
732  int mp_traverse( MethodProxy* pymeth, visitproc visit, void* args )
733  {
734  if ( pymeth->fSelf && ! IsPseudoFunc( pymeth ) )
735  return visit( (PyObject*)pymeth->fSelf, args );
736 
737  return 0;
738  }
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// Garbage collector clear of held python member objects.
742 
743  int mp_clear( MethodProxy* pymeth )
744  {
745  if ( ! IsPseudoFunc( pymeth ) )
746  Py_CLEAR( pymeth->fSelf );
747  pymeth->fSelf = NULL;
748 
749  return 0;
750  }
751 
752 ////////////////////////////////////////////////////////////////////////////////
753 /// Rich set of comparison objects; only equals is defined.
754 
755  PyObject* mp_richcompare( MethodProxy* self, MethodProxy* other, int op )
756  {
757  if ( op != Py_EQ )
758  return PyType_Type.tp_richcompare( (PyObject*)self, (PyObject*)other, op );
759 
760  // defined by type + (shared) MethodInfo + bound self, with special case for fSelf (i.e. pseudo-function)
761  if ( ( Py_TYPE(self) == Py_TYPE(other) && self->fMethodInfo == other->fMethodInfo ) && \
762  ( ( IsPseudoFunc( self ) && IsPseudoFunc( other ) ) || self->fSelf == other->fSelf ) ) {
763  Py_INCREF( Py_True );
764  return Py_True;
765  }
766  Py_INCREF( Py_False );
767  return Py_False;
768  }
769 
770 
771 //= PyROOT method proxy access to internals =================================
772  PyObject* mp_disp( MethodProxy* pymeth, PyObject* sigarg )
773  {
774  // Select and call a specific C++ overload, based on its signature.
775  if ( ! PyROOT_PyUnicode_Check( sigarg ) ) {
776  PyErr_Format( PyExc_TypeError, "disp() argument 1 must be string, not %.50s",
777  sigarg == Py_None ? "None" : Py_TYPE(sigarg)->tp_name );
778  return 0;
779  }
780 
782 
783  MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
784  for ( Int_t i = 0; i < (Int_t)methods.size(); ++i ) {
785 
786  PyObject* sig2 = methods[ i ]->GetSignature();
787  if ( PyObject_RichCompareBool( sig1, sig2, Py_EQ ) ) {
788  Py_DECREF( sig2 );
789 
790  MethodProxy* newmeth = mp_new( NULL, NULL, NULL );
791  MethodProxy::Methods_t vec; vec.push_back( methods[ i ]->Clone() );
792  newmeth->Set( pymeth->fMethodInfo->fName, vec );
793 
794  if ( pymeth->fSelf && ! IsPseudoFunc( pymeth ) ) {
795  Py_INCREF( pymeth->fSelf );
796  newmeth->fSelf = pymeth->fSelf;
797  }
798 
799  Py_DECREF( sig1 );
800  return (PyObject*)newmeth;
801  }
802 
803  Py_DECREF( sig2 );
804  }
805 
806  Py_DECREF( sig1 );
807  PyErr_Format( PyExc_LookupError, "signature \"%s\" not found", PyROOT_PyUnicode_AsString( sigarg ) );
808  return 0;
809  }
810 
811 //= PyROOT method proxy access to internals =================================
812  PyObject* mp_add_overload( MethodProxy* pymeth, PyObject* new_overload )
813  {
814  TPythonCallback* cb = new TPythonCallback(new_overload);
815  pymeth->AddMethod( cb );
816  Py_INCREF( Py_None );
817  return Py_None;
818  }
819 
820  PyMethodDef mp_methods[] = {
821  { (char*)"disp", (PyCFunction)mp_disp, METH_O, (char*)"select overload for dispatch" },
822  { (char*)"__add_overload__", (PyCFunction)mp_add_overload, METH_O, (char*)"add a new overload" },
823  { (char*)NULL, NULL, 0, NULL }
824  };
825 
826 } // unnamed namespace
827 
828 ////////////////////////////////////////////////////////////////////////////////
829 
830 
831 //= PyROOT method proxy type =================================================
832 PyTypeObject MethodProxy_Type = {
833  PyVarObject_HEAD_INIT( &PyType_Type, 0 )
834  (char*)"ROOT.MethodProxy", // tp_name
835  sizeof(MethodProxy), // tp_basicsize
836  0, // tp_itemsize
837  (destructor)mp_dealloc, // tp_dealloc
838  0, // tp_print
839  0, // tp_getattr
840  0, // tp_setattr
841  0, // tp_compare
842  0, // tp_repr
843  0, // tp_as_number
844  0, // tp_as_sequence
845  0, // tp_as_mapping
846  (hashfunc)mp_hash, // tp_hash
847  (ternaryfunc)mp_call, // tp_call
848  0, // tp_str
849  0, // tp_getattro
850  0, // tp_setattro
851  0, // tp_as_buffer
852  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags
853  (char*)"PyROOT method proxy (internal)", // tp_doc
854  (traverseproc)mp_traverse, // tp_traverse
855  (inquiry)mp_clear, // tp_clear
856  (richcmpfunc)mp_richcompare, // tp_richcompare
857  0, // tp_weaklistoffset
858  0, // tp_iter
859  0, // tp_iternext
860  mp_methods, // tp_methods
861  0, // tp_members
862  mp_getset, // tp_getset
863  0, // tp_base
864  0, // tp_dict
865  (descrgetfunc)mp_descrget, // tp_descr_get
866  0, // tp_descr_set
867  0, // tp_dictoffset
868  0, // tp_init
869  0, // tp_alloc
870  (newfunc)mp_new, // tp_new
871  0, // tp_free
872  0, // tp_is_gc
873  0, // tp_bases
874  0, // tp_mro
875  0, // tp_cache
876  0, // tp_subclasses
877  0 // tp_weaklist
878 #if PY_VERSION_HEX >= 0x02030000
879  , 0 // tp_del
880 #endif
881 #if PY_VERSION_HEX >= 0x02060000
882  , 0 // tp_version_tag
883 #endif
884 #if PY_VERSION_HEX >= 0x03040000
885  , 0 // tp_finalize
886 #endif
887 };
888 
889 } // namespace PyROOT
890 
891 
892 //- public members -----------------------------------------------------------
893 void PyROOT::MethodProxy::Set( const std::string& name, std::vector< PyCallable* >& methods )
894 {
895 // Fill in the data of a freshly created method proxy.
896  fMethodInfo->fName = name;
897  fMethodInfo->fMethods.swap( methods );
898  fMethodInfo->fFlags &= ~TCallContext::kIsSorted;
899  fMethodInfo->fFlags |= TCallContext::kManageSmartPtr;
900 
901 // special case: all constructors are considered creators by default
902  if ( name == "__init__" )
903  fMethodInfo->fFlags |= (TCallContext::kIsCreator | TCallContext::kIsConstructor);
904 
905 // special case, in heuristics mode also tag *Clone* methods as creators
907  name.find( "Clone" ) != std::string::npos )
908  fMethodInfo->fFlags |= TCallContext::kIsCreator;
909 }
910 
911 ////////////////////////////////////////////////////////////////////////////////
912 /// Fill in the data of a freshly created method proxy.
913 
915 {
916  fMethodInfo->fMethods.push_back( pc );
917  fMethodInfo->fFlags &= ~TCallContext::kIsSorted;
918 }
919 
920 ////////////////////////////////////////////////////////////////////////////////
921 
923 {
924  fMethodInfo->fMethods.insert( fMethodInfo->fMethods.end(),
925  meth->fMethodInfo->fMethods.begin(), meth->fMethodInfo->fMethods.end() );
926  fMethodInfo->fFlags &= ~TCallContext::kIsSorted;
927 }
928 
929 ////////////////////////////////////////////////////////////////////////////////
930 /// Destructor (this object is reference counted).
931 
933 {
934  for ( Methods_t::iterator it = fMethods.begin(); it != fMethods.end(); ++it ) {
935  delete *it;
936  }
937  fMethods.clear();
938  delete fRefCount;
939 }
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:71
#define CO_NOFREE
Definition: MethodProxy.cxx:14
PyObject * fTrace
void Set(const std::string &name, std::vector< PyCallable * > &methods)
std::vector< PyCallable * > Methods_t
Definition: MethodProxy.h:24
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
#define PyVarObject_HEAD_INIT(type, size)
Definition: PyROOT.h:147
Bool_t IsSorted(UInt_t flags)
Definition: TCallContext.h:61
#define PyROOT_PyUnicode_FromFormat
Definition: PyROOT.h:70
R__EXTERN void * TPyExceptionMagic
Definition: TPyException.h:46
#define PyROOT_PyUnicode_Append
Definition: PyROOT.h:73
MethodProxy::Methods_t fMethods
Definition: MethodProxy.h:32
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:66
Bool_t IsConstructor(UInt_t flags)
Definition: TCallContext.h:69
Bool_t ObjectProxy_Check(T *object)
Definition: ObjectProxy.h:91
R__EXTERN PyObject * gROOTns
Definition: PyStrings.h:55
PyObject * fValue
PyObject * fType
long Long_t
Definition: RtypesCore.h:50
MethodInfo_t * fMethodInfo
Definition: MethodProxy.h:52
#define PyROOT_PyUnicode_AppendAndDel
Definition: PyROOT.h:74
void AddMethod(PyCallable *pc)
Fill in the data of a freshly created method proxy.
R__EXTERN PyObject * gLifeLine
Definition: PyStrings.h:30
unsigned long ULong_t
Definition: RtypesCore.h:51
#define PyROOT_PyUnicode_Check
Definition: PyROOT.h:64
~MethodInfo_t()
Destructor (this object is reference counted).
#define name(a, b)
Definition: linkTestLib0.cpp:5
size_t SizeOf(TCppType_t klass)
Definition: Cppyy.cxx:192
#define Py_TYPE(ob)
Definition: PyROOT.h:149
int Py_ssize_t
Definition: PyROOT.h:154
Bool_t IsCreator(UInt_t flags)
Definition: TCallContext.h:65
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
Retrieve scope proxy from the known ones.
#define NULL
Definition: Rtypes.h:82
R__EXTERN void * TPyCPPExceptionMagic
Definition: TPyException.h:47
void * GetObject() const
std::vector< double > errors
Definition: TwoHistoFit2D.C:33
double result[121]
static ECallFlags sMemoryPolicy
Definition: TCallContext.h:49
_object PyObject
Definition: TPyArg.h:22