6 #include "structmember.h"
7 #if PY_VERSION_HEX >= 0x02050000
14 #define CO_NOFREE 0x0040
30 class TPythonCallback :
public PyCallable {
34 TPythonCallback(
PyObject* callable ) {
35 if ( !PyCallable_Check( callable ) ) {
36 PyErr_SetString(PyExc_TypeError,
"parameter must be callable");
40 Py_INCREF( fCallable );
43 virtual ~TPythonCallback() {
44 Py_DECREF( fCallable );
51 if ( PyObject_HasAttrString( fCallable,
"__doc__" )) {
52 return PyObject_GetAttrString( fCallable,
"__doc__" );
54 return GetPrototype();
58 virtual Int_t GetPriority() {
return 100; };
60 virtual Int_t GetMaxArgs() {
return 100; };
75 virtual PyCallable* Clone() {
return new TPythonCallback( *
this ); }
83 newArgs = PyTuple_New( nargs+1 );
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 );
89 PyTuple_SET_ITEM( newArgs, iarg+1, pyarg );
95 return PyObject_Call( fCallable, newArgs, kwds );
102 Bool_t inline IsPseudoFunc( MethodProxy* pymeth )
104 return (
void*)pymeth == (
void*)pymeth->fSelf;
111 static void Clear( PyError_t& e )
114 Py_XDECREF( e.fType ); Py_XDECREF( e.fValue ); Py_XDECREF( e.fTrace );
115 e.fType = e.fValue = e.fTrace = 0;
127 Int_t nargs = PyTuple_GET_SIZE( args );
128 for (
Int_t i = 0; i < nargs; ++i ) {
130 hash += (hash << 10); hash ^= (hash >> 6);
133 hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15);
139 int PriorityCmp( PyCallable* left, PyCallable* right )
141 return left->GetPriority() > right->GetPriority();
145 inline void ResetCallState( ObjectProxy*& selfnew, ObjectProxy* selfold,
Bool_t clear ) {
146 if ( selfnew != selfold ) {
147 Py_XDECREF( selfnew );
156 inline PyObject* HandleReturn( MethodProxy* pymeth, ObjectProxy* oldSelf,
PyObject* result ) {
162 if (
IsCreator( pymeth->fMethodInfo->fFlags ) ) {
167 pymeth->fSelf->HoldOn();
172 ((ObjectProxy*)result)->HoldOn();
186 ResetCallState( pymeth->fSelf, oldSelf,
kFALSE );
193 PyObject* mp_name( MethodProxy* pymeth,
void* )
200 PyObject* mp_module( MethodProxy* ,
void* )
209 PyObject* mp_doc( MethodProxy* pymeth,
void* )
214 Int_t nMethods = methods.size();
215 PyObject* doc = methods[0]->GetDocString();
223 for (
Int_t i = 1; i < nMethods; ++i ) {
227 Py_DECREF( separator );
235 PyObject* mp_meth_func( MethodProxy* pymeth,
void* )
237 MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
240 *pymeth->fMethodInfo->fRefCount += 1;
241 newPyMeth->fMethodInfo = pymeth->fMethodInfo;
245 newPyMeth->fSelf = (ObjectProxy*)newPyMeth;
254 PyObject* mp_meth_self( MethodProxy* pymeth,
void* )
256 if ( IsPseudoFunc( pymeth ) ) {
257 PyErr_Format( PyExc_AttributeError,
258 "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str() );
260 }
else if ( pymeth->fSelf != 0 ) {
261 Py_INCREF( (
PyObject*)pymeth->fSelf );
265 Py_INCREF( Py_None );
273 PyObject* mp_meth_class( MethodProxy* pymeth,
void* )
275 if ( ! IsPseudoFunc( pymeth ) ) {
276 PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScopeProxy();
278 PyErr_Format( PyExc_AttributeError,
279 "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str() );
283 Py_INCREF( Py_None );
290 PyObject* mp_func_closure( MethodProxy* ,
void* )
292 Py_INCREF( Py_None );
299 PyObject* mp_func_code( MethodProxy* pymeth,
void* )
301 #if PY_VERSION_HEX < 0x03000000
306 PyObject* co_varnames = methods.size() == 1 ? methods[0]->GetCoVarNames() :
NULL;
307 if ( !co_varnames ) {
309 co_varnames = PyTuple_New( 1 + 1 );
314 int co_argcount = PyTuple_Size( co_varnames );
317 PyObject* co_code = PyString_FromStringAndSize(
"d\x00\x00S", 4 );
320 PyObject* co_consts = PyTuple_New( 0 );
321 PyObject* co_names = PyTuple_New( 0 );
324 PyObject* co_unused = PyTuple_New( 0 );
327 PyObject* co_filename = PyString_FromString(
"ROOT.py" );
330 PyObject* co_name = PyString_FromString( pymeth->GetName().c_str() );
335 PyObject* co_lnotab = PyString_FromString(
"\x00\x01\x0c\x01" );
353 Py_DECREF( co_lnotab );
354 Py_DECREF( co_name );
355 Py_DECREF( co_unused );
356 Py_DECREF( co_filename );
357 Py_DECREF( co_varnames );
358 Py_DECREF( co_names );
359 Py_DECREF( co_consts );
360 Py_DECREF( co_code );
366 if ( pymeth || !pymeth) Py_INCREF( Py_None );
375 PyObject* mp_func_defaults( MethodProxy* pymeth,
void* )
379 if ( methods.size() != 1 )
380 return PyTuple_New( 0 );
382 int maxarg = methods[0]->GetMaxArgs();
384 PyObject* defaults = PyTuple_New( maxarg );
387 for (
int iarg = 0; iarg < maxarg; ++iarg ) {
388 PyObject* defvalue = methods[0]->GetArgDefault( iarg );
390 PyTuple_SET_ITEM( defaults, itup++, defvalue );
392 _PyTuple_Resize( &defaults, itup );
401 PyObject* mp_func_globals( MethodProxy* ,
void* )
403 PyObject* pyglobal = PyModule_GetDict( PyImport_AddModule( (
char*)
"ROOT" ) );
404 Py_XINCREF( pyglobal );
411 PyObject* mp_getcreates( MethodProxy* pymeth,
void* )
413 return PyInt_FromLong( (
Bool_t)
IsCreator( pymeth->fMethodInfo->fFlags ) );
419 int mp_setcreates( MethodProxy* pymeth,
PyObject* value,
void* )
422 pymeth->fMethodInfo->fFlags &= ~TCallContext::kIsCreator;
426 Long_t iscreator = PyLong_AsLong( value );
427 if ( iscreator == -1 && PyErr_Occurred() ) {
428 PyErr_SetString( PyExc_ValueError,
"a boolean 1 or 0 is required for _creates" );
435 pymeth->fMethodInfo->fFlags &= ~TCallContext::kIsCreator;
443 PyObject* mp_getmempolicy( MethodProxy* pymeth,
void* )
451 return PyInt_FromLong( -1 );
457 int mp_setmempolicy( MethodProxy* pymeth,
PyObject* value,
void* )
459 Long_t mempolicy = PyLong_AsLong( value );
462 pymeth->fMethodInfo->fFlags &= ~TCallContext::kUseStrict;
465 pymeth->fMethodInfo->fFlags &= ~TCallContext::kUseHeuristics;
467 PyErr_SetString( PyExc_ValueError,
468 "expected kMemoryStrict or kMemoryHeuristics as value for _mempolicy" );
479 PyObject* mp_get_manage_smart_ptr( MethodProxy* pymeth,
void* )
481 return PyInt_FromLong(
489 int mp_set_manage_smart_ptr( MethodProxy* pymeth,
PyObject* value,
void* )
491 Long_t policy = PyLong_AsLong( value );
492 if ( policy == -1 && PyErr_Occurred() ) {
493 PyErr_SetString( PyExc_ValueError,
"a boolean 1 or 0 is required for _manage_smart_ptr" );
505 PyObject* mp_getthreaded( MethodProxy* pymeth,
void* )
507 return PyInt_FromLong(
514 int mp_setthreaded( MethodProxy* pymeth,
PyObject* value,
void* )
516 Long_t isthreaded = PyLong_AsLong( value );
517 if ( isthreaded == -1 && PyErr_Occurred() ) {
518 PyErr_SetString( PyExc_ValueError,
"a boolean 1 or 0 is required for _creates" );
525 pymeth->fMethodInfo->fFlags &= ~TCallContext::kReleaseGIL;
532 PyGetSetDef mp_getset[] = {
544 { (
char*)
"func_closure", (
getter)mp_func_closure,
NULL,
NULL, NULL },
546 { (
char*)
"func_defaults", (
getter)mp_func_defaults,
NULL,
NULL, NULL },
547 { (
char*)
"func_globals", (
getter)mp_func_globals,
NULL,
NULL, NULL },
551 { (
char*)
"_creates", (
getter)mp_getcreates, (
setter)mp_setcreates,
552 (
char*)
"For ownership rules of result: if true, objects are python-owned",
NULL },
553 { (
char*)
"_mempolicy", (
getter)mp_getmempolicy, (
setter)mp_setmempolicy,
554 (
char*)
"For argument ownership rules: like global, either heuristic or strict",
NULL },
555 { (
char*)
"_manage_smart_ptr", (
getter)mp_get_manage_smart_ptr, (
setter)mp_set_manage_smart_ptr,
556 (
char*)
"If a smart pointer is returned, determines management policy.",
NULL },
557 { (
char*)
"_threaded", (
getter)mp_getthreaded, (
setter)mp_setthreaded,
558 (
char*)
"If true, releases GIL on call into C++",
NULL },
569 if ( IsPseudoFunc( pymeth ) )
570 pymeth->fSelf =
NULL;
572 ObjectProxy* oldSelf = pymeth->fSelf;
575 auto& methods = pymeth->fMethodInfo->fMethods;
576 auto& dispatchMap = pymeth->fMethodInfo->fDispatchMap;
577 auto& mflags = pymeth->fMethodInfo->fFlags;
579 Int_t nMethods = methods.size();
581 TCallContext ctxt = { 0 };
589 if ( nMethods == 1 ) {
590 PyObject* result = methods[0]->Call( pymeth->fSelf, args, kwds, &ctxt );
591 return HandleReturn( pymeth, oldSelf, result );
595 Long_t sighash = HashSignature( args );
598 MethodProxy::DispatchMap_t::iterator m = dispatchMap.find( sighash );
599 if ( m != dispatchMap.end() ) {
600 Int_t index = m->second;
601 PyObject* result = methods[ index ]->Call( pymeth->fSelf, args, kwds, &ctxt );
602 result = HandleReturn( pymeth, oldSelf, result );
608 ResetCallState( pymeth->fSelf, oldSelf,
kTRUE );
613 std::stable_sort( methods.begin(), methods.end(), PriorityCmp );
617 std::vector< PyError_t > errors;
618 for (
Int_t i = 0; i < nMethods; ++i ) {
619 PyObject* result = methods[i]->Call( pymeth->fSelf, args, kwds, &ctxt );
623 dispatchMap[ sighash ] = i;
624 std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
625 return HandleReturn( pymeth, oldSelf, result );
629 if ( ! PyErr_Occurred() ) {
631 PyObject* sig = methods[i]->GetPrototype();
632 PyErr_Format( PyExc_SystemError,
"%s =>\n %s",
637 PyErr_Fetch( &e.fType, &e.fValue, &e.fTrace );
638 errors.push_back( e );
639 ResetCallState( pymeth->fSelf, oldSelf,
kFALSE );
644 "none of the %d overloaded methods succeeded. Full details:", nMethods );
649 for ( std::vector< PyError_t >::iterator e = errors.begin(); e != errors.end(); ++e ) {
650 if ( e->fType != PyExc_NotImplementedError ) {
651 if ( ! exc_type ) exc_type = e->fType;
652 else if ( exc_type != e->fType ) exc_type = PyExc_TypeError;
658 Py_DECREF( separator );
659 std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
662 PyErr_SetObject( exc_type ? exc_type : PyExc_TypeError, value );
670 MethodProxy* mp_descrget( MethodProxy* pymeth, ObjectProxy* pyobj,
PyObject* )
672 MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
675 *pymeth->fMethodInfo->fRefCount += 1;
676 newPyMeth->fMethodInfo = pymeth->fMethodInfo;
680 newPyMeth->fSelf = pyobj;
690 MethodProxy* pymeth = PyObject_GC_New( MethodProxy, &MethodProxy_Type );
691 pymeth->fSelf =
NULL;
692 pymeth->fMethodInfo =
new MethodProxy::MethodInfo_t;
694 PyObject_GC_Track( pymeth );
701 void mp_dealloc( MethodProxy* pymeth )
703 PyObject_GC_UnTrack( pymeth );
705 if ( ! IsPseudoFunc( pymeth ) )
706 Py_CLEAR( pymeth->fSelf );
707 pymeth->fSelf =
NULL;
709 if ( --(*pymeth->fMethodInfo->fRefCount) <= 0 ) {
710 delete pymeth->fMethodInfo;
713 PyObject_GC_Del( pymeth );
721 Long_t mp_hash( MethodProxy* pymeth )
723 return _Py_HashPointer( pymeth->fMethodInfo );
729 int mp_traverse( MethodProxy* pymeth, visitproc visit,
void* args )
731 if ( pymeth->fSelf && ! IsPseudoFunc( pymeth ) )
732 return visit( (
PyObject*)pymeth->fSelf, args );
740 int mp_clear( MethodProxy* pymeth )
742 if ( ! IsPseudoFunc( pymeth ) )
743 Py_CLEAR( pymeth->fSelf );
744 pymeth->fSelf =
NULL;
752 PyObject* mp_richcompare( MethodProxy*
self, MethodProxy* other,
int op )
758 if ( (
Py_TYPE(
self) ==
Py_TYPE(other) && self->fMethodInfo == other->fMethodInfo ) && \
759 ( ( IsPseudoFunc(
self ) && IsPseudoFunc( other ) ) || self->fSelf == other->fSelf ) ) {
760 Py_INCREF( Py_True );
763 Py_INCREF( Py_False );
773 PyErr_Format( PyExc_TypeError,
"disp() argument 1 must be string, not %.50s",
774 sigarg == Py_None ?
"None" :
Py_TYPE(sigarg)->tp_name );
781 for (
Int_t i = 0; i < (
Int_t)methods.size(); ++i ) {
783 PyObject* sig2 = methods[ i ]->GetSignature();
784 if ( PyObject_RichCompareBool( sig1, sig2, Py_EQ ) ) {
789 newmeth->Set( pymeth->fMethodInfo->fName, vec );
791 if ( pymeth->fSelf && ! IsPseudoFunc( pymeth ) ) {
792 Py_INCREF( pymeth->fSelf );
793 newmeth->fSelf = pymeth->fSelf;
811 TPythonCallback* cb =
new TPythonCallback(new_overload);
812 pymeth->AddMethod( cb );
813 Py_INCREF( Py_None );
817 PyMethodDef mp_methods[] = {
818 { (
char*)
"disp", (PyCFunction)mp_disp, METH_O, (
char*)
"select overload for dispatch" },
819 { (
char*)
"__add_overload__", (PyCFunction)mp_add_overload, METH_O, (
char*)
"add a new overload" },
829 PyTypeObject MethodProxy_Type = {
831 (
char*)
"ROOT.MethodProxy",
834 (destructor)mp_dealloc,
844 (ternaryfunc)mp_call,
849 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
850 (
char*)
"PyROOT method proxy (internal)",
851 (traverseproc)mp_traverse,
853 (richcmpfunc)mp_richcompare,
862 (descrgetfunc)mp_descrget,
875 #
if PY_VERSION_HEX >= 0x02030000
878 #
if PY_VERSION_HEX >= 0x02060000
881 #
if PY_VERSION_HEX >= 0x03040000
893 fMethodInfo->fName =
name;
894 fMethodInfo->fMethods.swap( methods );
899 if ( name ==
"__init__" )
904 name.find(
"Clone" ) != std::string::npos )
913 fMethodInfo->fMethods.push_back( pc );
921 fMethodInfo->fMethods.insert( fMethodInfo->fMethods.end(),
931 for ( Methods_t::iterator it = fMethods.begin(); it != fMethods.end(); ++it ) {
#define PyROOT_PyUnicode_FromString
void Set(const std::string &name, std::vector< PyCallable * > &methods)
std::vector< PyCallable * > Methods_t
#define PyVarObject_HEAD_INIT(type, size)
Bool_t IsSorted(UInt_t flags)
#define PyROOT_PyUnicode_FromFormat
#define PyROOT_PyUnicode_Append
MethodProxy::Methods_t fMethods
#define PyROOT_PyUnicode_AsString
Bool_t IsConstructor(UInt_t flags)
Bool_t ObjectProxy_Check(T *object)
R__EXTERN PyObject * gROOTns
MethodInfo_t * fMethodInfo
#define PyROOT_PyUnicode_AppendAndDel
void AddMethod(PyCallable *pc)
Fill in the data of a freshly created method proxy.
R__EXTERN PyObject * gLifeLine
#define PyROOT_PyUnicode_Check
~MethodInfo_t()
Destructor (this object is reference counted).
size_t SizeOf(TCppType_t klass)
Bool_t IsCreator(UInt_t flags)
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
Retrieve scope proxy from the known ones.
static ECallFlags sMemoryPolicy