00001
00002
00003
00004
00005 #include "PyROOT.h"
00006 #include "MethodHolder.h"
00007 #include "Converters.h"
00008 #include "Executors.h"
00009 #include "ObjectProxy.h"
00010 #include "RootWrapper.h"
00011 #include "TPyException.h"
00012 #include "Utility.h"
00013 #include "Adapters.h"
00014
00015
00016 #include "TROOT.h"
00017 #include "TClass.h"
00018 #include "TString.h"
00019 #include "TClassEdit.h"
00020 #include "TVirtualMutex.h"
00021 #include "TException.h"
00022
00023
00024 #include "Api.h"
00025 #include "TInterpreter.h"
00026
00027
00028 #include <assert.h>
00029 #include <string.h>
00030 #include <exception>
00031 #include <string>
00032
00033
00034
00035 R__EXTERN PyObject* gRootModule;
00036
00037 namespace {
00038
00039
00040 struct TempLevelGuard_t {
00041 TempLevelGuard_t() { G__settemplevel( 1 ); }
00042 ~TempLevelGuard_t() { G__settemplevel( -1 ); }
00043 };
00044
00045 G__ClassInfo* GetGlobalNamespaceInfo() {
00046 static G__ClassInfo gcl;
00047 return &gcl;
00048 }
00049
00050 }
00051
00052
00053
00054 template< class T, class M >
00055 inline void PyROOT::TMethodHolder< T, M >::Copy_( const TMethodHolder& other )
00056 {
00057
00058 fMethodCall = 0;
00059 fExecutor = 0;
00060
00061 fArgsRequired = -1;
00062 fOffset = 0;
00063
00064 fSignature = other.fSignature;
00065
00066
00067 fIsInitialized = kFALSE;
00068 }
00069
00070
00071 template< class T, class M >
00072 inline void PyROOT::TMethodHolder< T, M >::Destroy_() const
00073 {
00074
00075 delete fMethodCall;
00076
00077
00078 delete fExecutor;
00079
00080 for ( int i = 0; i < (int)fConverters.size(); ++i )
00081 delete fConverters[ i ];
00082 }
00083
00084
00085 template< class T, class M >
00086 inline PyObject* PyROOT::TMethodHolder< T, M >::CallFast( void* self )
00087 {
00088
00089
00090
00091 PyObject* result = 0;
00092
00093 try {
00094 result = fExecutor->Execute( fMethodCall, (void*)((Long_t)self + fOffset) );
00095 } catch ( TPyException& ) {
00096 result = (PyObject*)TPyExceptionMagic;
00097 } catch ( std::exception& e ) {
00098 PyErr_Format( PyExc_Exception, "%s (C++ exception)", e.what() );
00099 result = 0;
00100 } catch ( ... ) {
00101 PyErr_SetString( PyExc_Exception, "unhandled, unknown C++ exception" );
00102 result = 0;
00103 }
00104
00105 return result;
00106 }
00107
00108
00109 template< class T, class M >
00110 inline PyObject* PyROOT::TMethodHolder< T, M >::CallSafe( void* self )
00111 {
00112
00113
00114
00115 PyObject* result = 0;
00116
00117 TRY {
00118 result = CallFast( self );
00119 } CATCH( excode ) {
00120 PyErr_SetString( PyExc_SystemError, "problem in C++; program state has been reset" );
00121 result = 0;
00122 Throw( excode );
00123 } ENDTRY;
00124
00125 return result;
00126 }
00127
00128
00129 namespace PyROOT {
00130
00131 #ifdef PYROOT_USE_REFLEX
00132 template<>
00133 Bool_t TMethodHolder< ROOT::Reflex::Scope, ROOT::Reflex::Member >::InitCallFunc_()
00134 {
00135
00136 const size_t nArgs = fMethod.FunctionParameterSize();
00137 fConverters.resize( nArgs );
00138 fParameters.resize( nArgs );
00139 fParamPtrs.resize( nArgs );
00140
00141
00142 for ( size_t iarg = 0; iarg < nArgs; ++iarg ) {
00143 std::string fullType =
00144 fMethod.TypeOf().FunctionParameterAt( iarg ).Name( ROOT::Reflex::QUALIFIED | ROOT::Reflex::SCOPED );
00145 fConverters[ iarg ] = CreateConverter( fullType );
00146
00147 if ( ! fConverters[ iarg ] ) {
00148 PyErr_Format( PyExc_TypeError, "argument type %s not handled", fullType.c_str() );
00149 return kFALSE;
00150 }
00151
00152 }
00153
00154 return kTRUE;
00155 }
00156 #endif
00157
00158 }
00159
00160 template< class T, class M >
00161 Bool_t PyROOT::TMethodHolder< T, M >::InitCallFunc_()
00162 {
00163
00164 const size_t nArgs = fMethod.FunctionParameterSize();
00165 fConverters.resize( nArgs );
00166 fParameters.resize( nArgs );
00167 fParamPtrs.resize( nArgs );
00168
00169
00170 std::string callString = "";
00171 for ( size_t iarg = 0; iarg < nArgs; ++iarg ) {
00172 std::string fullType =
00173 fMethod.TypeOf().FunctionParameterAt( iarg ).Name( ROOT::Reflex::QUALIFIED | ROOT::Reflex::SCOPED );
00174 fConverters[ iarg ] = CreateConverter( fullType );
00175
00176 if ( ! fConverters[ iarg ] ) {
00177 PyErr_Format( PyExc_TypeError, "argument type %s not handled", fullType.c_str() );
00178 return kFALSE;
00179 }
00180
00181
00182 if ( callString.length() == 0 )
00183 callString = fullType;
00184 else
00185 callString += "," + fullType;
00186 }
00187
00188
00189 assert( fMethodCall == 0 );
00190
00191 fMethodCall = new G__CallFunc();
00192 fMethodCall->Init();
00193
00194 G__ClassInfo* gcl = (G__ClassInfo*)((TClass*)fClass.Id())->GetClassInfo();
00195 if ( ! gcl )
00196 gcl = GetGlobalNamespaceInfo();
00197
00198 fMethodCall->SetFunc( gcl->GetMethod(
00199 (bool)fMethod == true ? fMethod.Name().c_str() : fClass.Name().c_str(), callString.c_str(),
00200 &fOffset, G__ClassInfo::ExactMatch ) );
00201
00202 return kTRUE;
00203 }
00204
00205
00206 template< class T, class M >
00207 Bool_t PyROOT::TMethodHolder< T, M >::InitExecutor_( TExecutor*& executor )
00208 {
00209
00210 executor = CreateExecutor( (bool)fMethod == true ?
00211 fMethod.TypeOf().ReturnType().Name( ROOT::Reflex::Q | ROOT::Reflex::S | ROOT::Reflex::F )
00212 : fClass.Name( ROOT::Reflex::S | ROOT::Reflex::F ) );
00213 if ( ! executor )
00214 return kFALSE;
00215
00216 return kTRUE;
00217 }
00218
00219
00220 template< class T, class M >
00221 void PyROOT::TMethodHolder< T, M >::CreateSignature_()
00222 {
00223
00224 Int_t ifirst = 0;
00225 fSignature = "(";
00226 const size_t nArgs = fMethod.FunctionParameterSize();
00227 for ( size_t iarg = 0; iarg < nArgs; ++iarg ) {
00228 if ( ifirst ) fSignature += ", ";
00229
00230 fSignature += fMethod.TypeOf().FunctionParameterAt( iarg ).Name( ROOT::Reflex::QUALIFIED );
00231
00232 const std::string& parname = fMethod.FunctionParameterNameAt( iarg );
00233 if ( ! parname.empty() ) {
00234 fSignature += " ";
00235 fSignature += parname;
00236 }
00237
00238 const std::string& defvalue = fMethod.FunctionParameterDefaultAt( iarg );
00239 if ( ! defvalue.empty() ) {
00240 fSignature += " = ";
00241 fSignature += defvalue;
00242 }
00243 ifirst++;
00244 }
00245 fSignature += ")";
00246 }
00247
00248
00249 template< class T, class M >
00250 const std::string& PyROOT::TMethodHolder< T, M >::GetSignatureString()
00251 {
00252
00253 if ( fSignature.empty() )
00254 CreateSignature_();
00255
00256 return fSignature;
00257 }
00258
00259
00260 template< class T, class M >
00261 void PyROOT::TMethodHolder< T, M >::SetPyError_( PyObject* msg )
00262 {
00263
00264 PyObject *etype, *evalue, *etrace;
00265 PyErr_Fetch( &etype, &evalue, &etrace );
00266
00267 std::string details = "";
00268 if ( evalue ) {
00269 PyObject* s = PyObject_Str( evalue );
00270 details = PyROOT_PyUnicode_AsString( s );
00271 Py_DECREF( s );
00272 }
00273
00274 Py_XDECREF( etype ); Py_XDECREF( evalue ); Py_XDECREF( etrace );
00275
00276 PyObject* doc = GetDocString();
00277
00278 if ( details != "" ) {
00279 PyErr_Format( PyExc_TypeError, "%s =>\n %s (%s)",
00280 PyROOT_PyUnicode_AsString( doc ), PyROOT_PyUnicode_AsString( msg ), details.c_str() );
00281 } else {
00282 PyErr_Format( PyExc_TypeError, "%s =>\n %s",
00283 PyROOT_PyUnicode_AsString( doc ), PyROOT_PyUnicode_AsString( msg ) );
00284 }
00285
00286 Py_DECREF( doc );
00287 Py_DECREF( msg );
00288 }
00289
00290
00291 template< class T, class M >
00292 PyROOT::TMethodHolder< T, M >::TMethodHolder( const T& klass, const M& method ) :
00293 fMethod( method ), fClass( klass )
00294 {
00295
00296 fMethodCall = 0;
00297 fExecutor = 0;
00298 fArgsRequired = -1;
00299 fOffset = 0;
00300
00301 fIsInitialized = kFALSE;
00302 }
00303
00304
00305 template< class T, class M >
00306 PyROOT::TMethodHolder< T, M >::TMethodHolder( const TMethodHolder< T, M >& other ) :
00307 PyCallable( other ), fMethod( other.fMethod ), fClass( other.fClass )
00308 {
00309
00310 Copy_( other );
00311 }
00312
00313
00314 template< class T, class M >
00315 PyROOT::TMethodHolder< T, M >& PyROOT::TMethodHolder< T, M >::operator=(
00316 const TMethodHolder< T, M >& other )
00317 {
00318
00319 if ( this != &other ) {
00320 Destroy_();
00321 Copy_( other );
00322 fClass = other.fClass;
00323 fMethod = other.fMethod;
00324 }
00325
00326 return *this;
00327 }
00328
00329
00330 template< class T, class M >
00331 PyROOT::TMethodHolder< T, M >::~TMethodHolder()
00332 {
00333
00334 Destroy_();
00335 }
00336
00337
00338
00339 template< class T, class M >
00340 PyObject* PyROOT::TMethodHolder< T, M >::GetSignature()
00341 {
00342
00343 return PyROOT_PyUnicode_FromString( GetSignatureString().c_str() );
00344 }
00345
00346
00347 template< class T, class M >
00348 PyObject* PyROOT::TMethodHolder< T, M >::GetPrototype()
00349 {
00350
00351 return PyROOT_PyUnicode_FromFormat( "%s%s %s::%s%s",
00352 ( fMethod.IsStatic() ? "static " : "" ),
00353 fMethod.TypeOf().ReturnType().Name( ROOT::Reflex::Q | ROOT::Reflex::S ).c_str(),
00354 fMethod.DeclaringScope().Name().c_str(), fMethod.Name().c_str(),
00355 GetSignatureString().c_str() );
00356 }
00357
00358
00359 namespace PyROOT {
00360
00361 #ifdef PYROOT_USE_REFLEX
00362 template<>
00363 Int_t TMethodHolder< ROOT::Reflex::Scope, ROOT::Reflex::Member >::GetPriority();
00364 #endif
00365
00366 }
00367
00368 template< class T, class M >
00369 Int_t PyROOT::TMethodHolder< T, M >::GetPriority()
00370 {
00371
00372
00373
00374
00375 Int_t priority = 0;
00376
00377 const size_t nArgs = fMethod.FunctionParameterSize();
00378 for ( size_t iarg = 0; iarg < nArgs; ++iarg ) {
00379 const T& arg = fMethod.TypeOf().FunctionParameterAt( iarg );
00380
00381
00382
00383 if ( ! (bool)arg ) {
00384 priority -= 10000;
00385 } else if ( (arg.IsClass() || arg.IsStruct()) && ! arg.IsComplete() ) {
00386
00387 const std::string aname = arg.Name( ROOT::Reflex::Q );
00388 if ( aname[ aname.size() - 1 ] == '&' )
00389 priority -= 3000;
00390 else
00391 priority -= 1000;
00392 } else {
00393 const std::string aname = arg.Name( ROOT::Reflex::F | ROOT::Reflex::Q );
00394 if ( aname == "void*" )
00395 priority -= 100;
00396 else if ( aname == "float" )
00397 priority -= 30;
00398 else if ( aname == "double" )
00399 priority -= 10;
00400
00401
00402 else if ( aname == "IBaseFunctionMultiDim")
00403 priority -= 1;
00404 else if ( aname == "RooAbsReal" )
00405 priority -= 1;
00406 }
00407
00408 }
00409
00410 return priority;
00411 }
00412
00413 namespace PyROOT {
00414
00415 #ifdef PYROOT_USE_REFLEX
00416 template<>
00417 Int_t TMethodHolder< ROOT::Reflex::Scope, ROOT::Reflex::Member >::GetPriority()
00418 {
00419
00420 return ((TMethodHolder< ROOT::Reflex::Type, ROOT::Reflex::Member >*)this)->
00421 TMethodHolder< ROOT::Reflex::Type, ROOT::Reflex::Member >::GetPriority();
00422 }
00423 #endif
00424
00425 }
00426
00427
00428 template< class T, class M >
00429 Int_t PyROOT::TMethodHolder< T, M >::GetMaxArgs()
00430 {
00431 return fMethod.FunctionParameterSize();
00432 }
00433
00434
00435 template< class T, class M>
00436 PyObject* PyROOT::TMethodHolder< T, M >::GetArgSpec( Int_t iarg )
00437 {
00438 if ( iarg >= (int)fMethod.FunctionParameterSize() )
00439 return 0;
00440
00441 std::string argrep = fMethod.TypeOf().FunctionParameterAt( iarg ).Name( ROOT::Reflex::Q );
00442
00443 const std::string& parname = fMethod.FunctionParameterNameAt( iarg );
00444 if ( ! parname.empty() ) {
00445 argrep += " ";
00446 argrep += parname;
00447 }
00448
00449 return PyROOT_PyUnicode_FromString( argrep.c_str() );
00450 }
00451
00452
00453 template< class T, class M>
00454 PyObject* PyROOT::TMethodHolder< T, M >::GetArgDefault( Int_t iarg )
00455 {
00456 if ( iarg >= (int)fMethod.FunctionParameterSize() )
00457 return 0;
00458
00459 const std::string& defvalue = fMethod.FunctionParameterDefaultAt( iarg ).c_str();
00460 if ( ! defvalue.empty() ) {
00461
00462
00463 PyObject* pyval = (PyObject*)PyRun_String(
00464 (char*)defvalue.c_str(), Py_eval_input, gRootModule, gRootModule );
00465 if ( ! pyval && PyErr_Occurred() ) {
00466 PyErr_Clear();
00467 return PyROOT_PyUnicode_FromString( defvalue.c_str() );
00468 }
00469
00470 return pyval;
00471 }
00472
00473 return 0;
00474 }
00475
00476
00477 template< class T, class M>
00478 PyObject* PyROOT::TMethodHolder< T, M >::GetScope()
00479 {
00480 return MakeRootClassFromString< TScopeAdapter, TBaseAdapter, TMemberAdapter >(
00481 fMethod.DeclaringScope().Name( ROOT::Reflex::SCOPED | ROOT::Reflex::FINAL ) );
00482 }
00483
00484
00485 template< class T, class M >
00486 Bool_t PyROOT::TMethodHolder< T, M >::Initialize()
00487 {
00488
00489 if ( fIsInitialized == kTRUE )
00490 return kTRUE;
00491
00492 if ( ! InitCallFunc_() )
00493 return kFALSE;
00494
00495 if ( ! InitExecutor_( fExecutor ) )
00496 return kFALSE;
00497
00498
00499 fArgsRequired = (bool)fMethod == true ? fMethod.FunctionParameterSize( true ) : 0;
00500
00501
00502 fIsInitialized = kTRUE;
00503
00504 return kTRUE;
00505 }
00506
00507
00508 template< class T, class M >
00509 PyObject* PyROOT::TMethodHolder< T, M >::FilterArgs( ObjectProxy*& self, PyObject* args, PyObject* )
00510 {
00511
00512 if ( self != 0 ) {
00513 Py_INCREF( args );
00514 return args;
00515 }
00516
00517
00518 if ( PyTuple_GET_SIZE( args ) != 0 ) {
00519 ObjectProxy* pyobj = (ObjectProxy*)PyTuple_GET_ITEM( args, 0 );
00520
00521
00522 if ( ObjectProxy_Check( pyobj ) &&
00523 ( fClass.Name().size() == 0 ||
00524 ( pyobj->ObjectIsA() == 0 ) ||
00525 ( pyobj->ObjectIsA()->GetBaseClass( (TClass*)fClass.Id() ) ) )
00526 ) {
00527
00528 self = pyobj;
00529
00530
00531 return PyTuple_GetSlice( args, 1, PyTuple_GET_SIZE( args ) );
00532 }
00533 }
00534
00535
00536 SetPyError_( PyROOT_PyUnicode_FromFormat(
00537 "unbound method %s::%s must be called with a %s instance as first argument",
00538 fClass.Name().c_str(), fMethod.Name().c_str(), fClass.Name().c_str() ) );
00539 return 0;
00540 }
00541
00542
00543 template< class T, class M >
00544 Bool_t PyROOT::TMethodHolder< T, M >::SetMethodArgs( PyObject* args, Long_t user )
00545 {
00546
00547 if ( fMethodCall )
00548 fMethodCall->ResetArg();
00549
00550 int argc = PyTuple_GET_SIZE( args );
00551 int argMax = fConverters.size();
00552
00553
00554 if ( argc < fArgsRequired ) {
00555 SetPyError_( PyROOT_PyUnicode_FromFormat(
00556 "takes at least %d arguments (%d given)", fArgsRequired, argc ) );
00557 return kFALSE;
00558 } else if ( argMax < argc ) {
00559 SetPyError_( PyROOT_PyUnicode_FromFormat(
00560 "takes at most %d arguments (%d given)", argMax, argc ) );
00561 return kFALSE;
00562 }
00563
00564
00565 for ( int i = 0; i < argc; ++i ) {
00566 if ( ! fConverters[ i ]->SetArg(
00567 PyTuple_GET_ITEM( args, i ), fParameters[i], fMethodCall, user ) ) {
00568 SetPyError_( PyROOT_PyUnicode_FromFormat( "could not convert argument %d", i+1 ) );
00569 return kFALSE;
00570 }
00571 fParamPtrs[i] = &fParameters[i];
00572 }
00573
00574 return kTRUE;
00575 }
00576
00577
00578 namespace PyROOT {
00579
00580 #ifdef PYROOT_USE_REFLEX
00581 template<>
00582 PyObject* TMethodHolder< ROOT::Reflex::Scope, ROOT::Reflex::Member >::Execute( void* self )
00583 {
00584
00585
00586 if ( fMethod.IsConstructor() )
00587 return (PyObject*)((ROOT::Reflex::Type)fClass).Construct( fMethod.TypeOf(), fParamPtrs ).Address();
00588
00589 Reflex::Object obj( fClass, (void*)((Long_t)self + fOffset) );
00590 Reflex::Object result;
00591 static Reflex::Type tVoid = Reflex::Type::ByName("void");
00592 bool returnsVoid = (fMethod.TypeOf().ReturnType() == tVoid);
00593 if ( !returnsVoid ) {
00594 result = fMethod.TypeOf().ReturnType().Construct();
00595 }
00596 fMethod.Invoke( obj, &result, fParamPtrs );
00597 if ( !returnsVoid ) {
00598 TConverter* converter = CreateConverter( fMethod.TypeOf().ReturnType().Name(Reflex::S|Reflex::Q|Reflex::F) );
00599 if ( converter ) {
00600 PyObject* pyresult = converter->FromMemory( result.Address() );
00601 delete converter;
00602 return pyresult;
00603 }
00604 }
00605
00606 Py_INCREF( Py_None );
00607 return Py_None;
00608 }
00609 #endif
00610
00611 }
00612
00613 template< class T, class M >
00614 PyObject* PyROOT::TMethodHolder< T, M >::Execute( void* self )
00615 {
00616
00617 R__LOCKGUARD2( gCINTMutex );
00618 TempLevelGuard_t g;
00619
00620 PyObject* result = 0;
00621
00622 if ( Utility::gSignalPolicy == Utility::kFast ) {
00623
00624 result = CallFast( self );
00625 } else {
00626
00627 result = CallSafe( self );
00628 }
00629
00630 if ( result && result != (PyObject*)TPyExceptionMagic
00631 && Utility::PyErr_Occurred_WithGIL() ) {
00632
00633 Py_DECREF( result );
00634 result = 0;
00635 }
00636
00637
00638 if ( G__get_return( 0 ) > G__RETURN_NORMAL )
00639 G__security_recover( 0 );
00640
00641 return result;
00642 }
00643
00644
00645 template< class T, class M >
00646 PyObject* PyROOT::TMethodHolder< T, M >::operator()(
00647 ObjectProxy* self, PyObject* args, PyObject* kwds, Long_t user )
00648 {
00649
00650 if ( kwds != 0 && PyDict_Size( kwds ) ) {
00651 PyErr_SetString( PyExc_TypeError, "keyword arguments are not yet supported" );
00652 return 0;
00653 }
00654
00655
00656 if ( ! Initialize() )
00657 return 0;
00658
00659
00660 if ( ! ( args = FilterArgs( self, args, kwds ) ) )
00661 return 0;
00662
00663
00664 Bool_t bConvertOk = SetMethodArgs( args, user );
00665 Py_DECREF( args );
00666
00667 if ( bConvertOk == kFALSE )
00668 return 0;
00669
00670
00671 void* object = self->GetObject();
00672
00673
00674 if ( ! object ) {
00675 PyErr_SetString( PyExc_ReferenceError, "attempt to access a null-pointer" );
00676 return 0;
00677 }
00678
00679
00680 TClass* klass = self->ObjectIsA();
00681 if ( klass ) {
00682
00683 int objTag = (G__ClassInfo*)klass->GetClassInfo() ? ((G__ClassInfo*)klass->GetClassInfo())->Tagnum() : -1;
00684 G__ClassInfo* cli = (G__ClassInfo*)((TClass*)fClass.Id())->GetClassInfo();
00685 int methTag = cli ? cli->Tagnum() : -1;
00686 fOffset = objTag == methTag ? 0 : G__isanybase( methTag, objTag, (Long_t)object );
00687 }
00688
00689
00690 ObjectProxy* pyobj = (ObjectProxy*)Execute( object );
00691 if ( pyobj != (ObjectProxy*)TPyExceptionMagic &&
00692 ObjectProxy_Check( pyobj ) &&
00693 pyobj->GetObject() == object &&
00694 klass && pyobj->ObjectIsA() == klass ) {
00695 Py_INCREF( (PyObject*)self );
00696 Py_DECREF( pyobj );
00697 return (PyObject*)self;
00698 }
00699
00700 return (PyObject*)pyobj;
00701 }
00702
00703
00704 template class PyROOT::TMethodHolder< PyROOT::TScopeAdapter, PyROOT::TMemberAdapter >;
00705 #ifdef PYROOT_USE_REFLEX
00706 template class PyROOT::TMethodHolder< ROOT::Reflex::Scope, ROOT::Reflex::Member >;
00707 #endif