// @(#)root/pyroot:$Id$ // Author: Wim Lavrijsen, May 2004 // Bindings #include "PyROOT.h" #include "TPyClassGenerator.h" #include "Utility.h" #include "TPyReturn.h" // ROOT #include "TClass.h" // CINT #include "Api.h" // Standard #include #include //- private helpers ---------------------------------------------------------- namespace { //_________________________________________________________________________ int PyCtorCallback( G__value* res, G__CONST char*, struct G__param*, int ) { // CINT-installable constructor callback. int tagnum = G__value_get_tagnum( res ); PyObject* pyclass = PyROOT::Utility::GetInstalledMethod( tagnum ); if ( ! pyclass ) return 0; PyObject* args = PyTuple_New( 0 ); PyObject* result = PyObject_Call( pyclass, args, NULL ); if ( ! result ) PyErr_Print(); Py_DECREF( args ); G__letint( res, 'u', (Long_t)result ); res->ref = (Long_t)result; G__set_tagnum( res, tagnum ); return 1; } //_________________________________________________________________________ int PyMemFuncCallback( G__value* res, G__CONST char*, struct G__param* libp, int ) { // CINT-installable member function callback. PyObject* pyfunc = PyROOT::Utility::GetInstalledMethod( G__value_get_tagnum(res) ); if ( ! pyfunc ) return 0; PyObject* self = (PyObject*)G__getstructoffset(); Py_INCREF( self ); PyObject* args = PyTuple_New( 1 + libp->paran ); PyTuple_SetItem( args, 0, self ); for ( int i = 0; i < libp->paran; ++i ) { PyObject* arg = 0; switch ( G__value_get_type(&libp->para[i]) ) { case 'd': arg = PyFloat_FromDouble( G__Mdouble(libp->para[i]) ); break; case 'f': arg = PyFloat_FromDouble( (double)G__Mfloat(libp->para[i]) ); break; case 'l': arg = PyLong_FromLong( G__Mlong(libp->para[i]) ); break; case 'k': arg = PyLong_FromUnsignedLong( G__Mulong(libp->para[i] ) ); break; case 'i': arg = PyInt_FromLong( (Long_t)G__Mint(libp->para[i]) ); break; case 'h': //arg = PyLong_FromUnsignedLong( (UInt_t)G__Muint(libp->para[i]) ); arg = PyLong_FromUnsignedLong( *(ULong_t*)((void*)G__Mlong(libp->para[i])) ); break; case 's': arg = PyInt_FromLong( (Long_t)G__Mshort(libp->para[i]) ); break; case 'r': arg = PyInt_FromLong( (Long_t)G__Mushort(libp->para[i]) ); break; case 'u': // longlong, ulonglong, longdouble break; case 'c': char cc[2]; cc[0] = G__Mchar(libp->para[i]); cc[1] = '\0'; arg = PyBytes_FromString( cc ); break; case 'b': // unsigned char break; case 'C': arg = PyBytes_FromString( (char*)G__Mlong(libp->para[i]) ); break; } if ( arg != 0 ) PyTuple_SetItem( args, i+1, arg ); // steals ref to arg else { PyErr_Format( PyExc_TypeError, "error converting parameter: %d (type: %c)", i, G__value_get_type(&libp->para[i]) ); break; } } PyObject* result = 0; if ( ! PyErr_Occurred() ) result = PyObject_Call( pyfunc, args, NULL ); Py_DECREF( args ); if ( ! result ) PyErr_Print(); TPyReturn* retval = new TPyReturn( result ); G__letint( res, 'u', (Long_t)retval ); res->ref = (Long_t)retval; G__set_tagnum( res, ((G__ClassInfo*)TPyReturn::Class()->GetClassInfo())->Tagnum() ); G__store_tempobject( *res ); return 1; } } // unnamed namespace //- public members ----------------------------------------------------------- TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load ) { // Just forward. return GetClass( name, load, kFALSE ); } //- public members ----------------------------------------------------------- TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load, Bool_t silent ) { // Class generator to make python classes available to CINT. // called if all other class generators failed, attempt to build from python class if ( PyROOT::gDictLookupActive == kTRUE ) return 0; // call originated from python if ( ! load || ! name ) return 0; // determine module and class name part std::string clName = name; std::string::size_type pos = clName.rfind( '.' ); if ( pos == std::string::npos ) return 0; // this isn't a python style class std::string mdName = clName.substr( 0, pos ); clName = clName.substr( pos+1, std::string::npos ); // ROOT doesn't know about python modules; the class may exist (TODO: add scopes) if ( TClass::GetClass( clName.c_str(), load, silent ) ) return TClass::GetClass( clName.c_str(), load, silent ); // locate and get class PyObject* mod = PyImport_AddModule( const_cast< char* >( mdName.c_str() ) ); if ( ! mod ) { PyErr_Clear(); return 0; // module apparently disappeared } Py_INCREF( mod ); PyObject* pyclass = PyDict_GetItemString( PyModule_GetDict( mod ), const_cast< char* >( clName.c_str() ) ); Py_XINCREF( pyclass ); Py_DECREF( mod ); if ( ! pyclass ) { PyErr_Clear(); // the class is no longer available?! return 0; } // get a listing of all python-side members PyObject* attrs = PyObject_Dir( pyclass ); if ( ! attrs ) { PyErr_Clear(); Py_DECREF( pyclass ); return 0; } // build CINT class placeholder G__linked_taginfo pti; pti.tagnum = -1; pti.tagtype = 'c'; pti.tagname = clName.c_str(); G__add_compiledheader( (clName+".h").c_str() ); int tagnum = G__get_linked_tagnum( &pti ); G__tagtable_setup( tagnum, sizeof(PyObject), G__CPPLINK, 0x00020000, "", 0, 0 ); G__ClassInfo gcl( tagnum ); G__tag_memfunc_setup( tagnum ); // special case: constructor; add method and store callback PyROOT::Utility::InstallMethod( &gcl, pyclass, clName, 0, "ellipsis", (void*)PyCtorCallback ); // loop over and add member functions for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) { PyObject* label = PyList_GET_ITEM( attrs, i ); Py_INCREF( label ); PyObject* attr = PyObject_GetAttr( pyclass, label ); // collect only member functions (i.e. callable elements in __dict__) if ( PyCallable_Check( attr ) ) { std::string mtName = PyROOT_PyUnicode_AsString( label ); // add method and store callback if ( mtName != "__init__" ) { PyROOT::Utility::InstallMethod( &gcl, attr, mtName, "TPyReturn", "ellipsis", (void*)PyMemFuncCallback ); } } Py_DECREF( attr ); Py_DECREF( label ); } G__tag_memfunc_reset(); // done, let ROOT manage the new class Py_DECREF( pyclass ); TClass* klass = new TClass( clName.c_str(), silent ); TClass::AddClass( klass ); return klass; } //____________________________________________________________________________ TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load, Bool_t silent ) { // Just forward; based on type name only. return GetClass( typeinfo.name(), load, silent ); } //____________________________________________________________________________ TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load ) { // Just forward; based on type name only return GetClass( typeinfo.name(), load ); }