MethodHolder.cxx

Go to the documentation of this file.
00001 // @(#)root/pyroot:$Id: MethodHolder.cxx 37215 2010-12-03 09:31:18Z wlav $
00002 // Author: Wim Lavrijsen, Apr 2004
00003 
00004 // Bindings
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 // ROOT
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 // CINT
00024 #include "Api.h"
00025 #include "TInterpreter.h"
00026 
00027 // Standard
00028 #include <assert.h>
00029 #include <string.h>
00030 #include <exception>
00031 #include <string>
00032 
00033 
00034 //- data and local helpers ---------------------------------------------------
00035 R__EXTERN PyObject* gRootModule;
00036 
00037 namespace {
00038 
00039 // CINT temp level guard
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 } // unnamed namespace
00051 
00052 
00053 //- private helpers ----------------------------------------------------------
00054 template< class T, class M >
00055 inline void PyROOT::TMethodHolder< T, M >::Copy_( const TMethodHolder& other )
00056 {
00057 // do not copy caches
00058    fMethodCall = 0;
00059    fExecutor   = 0;
00060 
00061    fArgsRequired = -1;
00062    fOffset       =  0;
00063 
00064    fSignature = other.fSignature;
00065 
00066 // being uninitialized will trigger setting up caches as appropriate
00067    fIsInitialized  = kFALSE;
00068 }
00069 
00070 //____________________________________________________________________________
00071 template< class T, class M >
00072 inline void PyROOT::TMethodHolder< T, M >::Destroy_() const
00073 {
00074 // no deletion of fMethod (ROOT responsibility)
00075    delete fMethodCall;
00076 
00077 // destroy executor and argument converters
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 // helper code to prevent some duplication; this is called from CallSafe() as well
00089 // as directly from TMethodHolder::Execute in fast mode
00090 
00091    PyObject* result = 0;
00092 
00093    try {       // C++ try block
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 // helper code to prevent some code duplication; this code embeds a ROOT "try/catch"
00113 // block that saves the stack for restoration in case of an otherwise fatal signal
00114 
00115    PyObject* result = 0;
00116 
00117    TRY {       // ROOT "try block"
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 // build buffers for argument dispatching
00136    const size_t nArgs = fMethod.FunctionParameterSize();
00137    fConverters.resize( nArgs );
00138    fParameters.resize( nArgs );
00139    fParamPtrs.resize( nArgs );
00140 
00141 // setup the dispatch cache
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 } // namespace PyROOT
00159 
00160 template< class T, class M >
00161 Bool_t PyROOT::TMethodHolder< T, M >::InitCallFunc_()
00162 {
00163 // build buffers for argument dispatching
00164    const size_t nArgs = fMethod.FunctionParameterSize();
00165    fConverters.resize( nArgs );
00166    fParameters.resize( nArgs );
00167    fParamPtrs.resize( nArgs );
00168 
00169 // setup the dispatch cache
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    // setup call string
00182       if ( callString.length() == 0 )
00183          callString = fullType;
00184       else
00185          callString += "," + fullType;
00186    }
00187 
00188 // setup call func
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 // install executor conform to the return type
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 // built a signature a la TFunction::GetSignature as python string, using Adapters
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 // construct python string from the method's signature
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 // helper to report errors in a consistent format (derefs msg)
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 //- constructors and destructor ----------------------------------------------
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 // constructor; initialization is deferred
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 // copy constructor
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 // assignment operator
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 // destructor
00334    Destroy_();
00335 }
00336 
00337 
00338 //- public members -----------------------------------------------------------
00339 template< class T, class M >
00340 PyObject* PyROOT::TMethodHolder< T, M >::GetSignature()
00341 {
00342 // construct python string from the method's signature
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 // construct python string from the method's prototype
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 } // namespace PyROOT
00367 
00368 template< class T, class M >
00369 Int_t PyROOT::TMethodHolder< T, M >::GetPriority()
00370 {
00371 // Method priorities exist (in lieu of true overloading) there to prevent
00372 // void* or <unknown>* from usurping otherwise valid calls. TODO: extend this
00373 // to favour classes that are not bases.
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    // the following numbers are made up and may cause problems in specific
00382    // situations: use <obj>.<meth>.disp() for choice of exact dispatch
00383       if ( ! (bool)arg ) {
00384          priority -= 10000;   // class is gibberish
00385       } else if ( (arg.IsClass() || arg.IsStruct()) && ! arg.IsComplete() ) {
00386       // class is known, but no dictionary available, 2 more cases: * and &
00387          const std::string aname = arg.Name( ROOT::Reflex::Q );
00388          if ( aname[ aname.size() - 1 ] == '&' )
00389             priority -= 3000;
00390          else
00391             priority -= 1000; // prefer pointer passing over reference
00392       } else {
00393          const std::string aname = arg.Name( ROOT::Reflex::F | ROOT::Reflex::Q );
00394          if ( aname == "void*" )
00395             priority -= 100;  // void* shouldn't be too greedy
00396          else if ( aname == "float" )
00397             priority -= 30;   // double preferred over float (no float in python)
00398          else if ( aname == "double" )
00399             priority -= 10;   // char, int, long preferred over double
00400 
00401       // resolve a few special cases
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 // Scope, Type, what's in a name ...
00420    return ((TMethodHolder< ROOT::Reflex::Type, ROOT::Reflex::Member >*)this)->
00421       TMethodHolder< ROOT::Reflex::Type, ROOT::Reflex::Member >::GetPriority();
00422 }
00423 #endif
00424 
00425 } // endif
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    // attempt to evaluate the string representation (will work for all builtin types)
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 // done if cache is already setup
00489    if ( fIsInitialized == kTRUE )
00490       return kTRUE;
00491 
00492    if ( ! InitCallFunc_() )
00493       return kFALSE;
00494 
00495    if ( ! InitExecutor_( fExecutor ) )
00496       return kFALSE;
00497 
00498 // minimum number of arguments when calling
00499    fArgsRequired = (bool)fMethod == true ? fMethod.FunctionParameterSize( true ) : 0;
00500 
00501 // init done
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 // verify existence of self, return if ok
00512    if ( self != 0 ) {
00513       Py_INCREF( args );
00514       return args;
00515    }
00516 
00517 // otherwise, check for a suitable 'self' in args and update accordingly
00518    if ( PyTuple_GET_SIZE( args ) != 0 ) {
00519       ObjectProxy* pyobj = (ObjectProxy*)PyTuple_GET_ITEM( args, 0 );
00520 
00521    // demand PyROOT object, and an argument that may match down the road
00522       if ( ObjectProxy_Check( pyobj ) &&
00523            ( fClass.Name().size() == 0 ||                   // free global
00524            ( pyobj->ObjectIsA() == 0 ) ||                   // null pointer or ctor call
00525            ( pyobj->ObjectIsA()->GetBaseClass( (TClass*)fClass.Id() ) ) ) // matching types
00526          ) {
00527       // reset self (will live for the life time of args; i.e. call of function)
00528          self = pyobj;
00529 
00530       // offset args by 1 (new ref)
00531          return PyTuple_GetSlice( args, 1, PyTuple_GET_SIZE( args ) );
00532       }
00533    }
00534 
00535 // no self, set error and lament
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 // clean slate
00547    if ( fMethodCall )
00548       fMethodCall->ResetArg();
00549 
00550    int argc = PyTuple_GET_SIZE( args );
00551    int argMax = fConverters.size();
00552 
00553 // argc must be between min and max number of arguments
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 // convert the arguments to the method call array
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 // my first Reflex call ... this is all pretty wrong, but hey, it's a proto-prototype :)
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 } // namespace PyROOT
00612 
00613 template< class T, class M >
00614 PyObject* PyROOT::TMethodHolder< T, M >::Execute( void* self )
00615 {
00616 // call the interface method
00617    R__LOCKGUARD2( gCINTMutex );
00618    TempLevelGuard_t g;
00619 
00620    PyObject* result = 0;
00621 
00622    if ( Utility::gSignalPolicy == Utility::kFast ) {
00623    // bypasses ROOT try block (i.e. segfaults will abort)
00624       result = CallFast( self );
00625    } else {
00626    // at the cost of ~10% performance, don't abort the interpreter on any signal
00627       result = CallSafe( self );
00628    }
00629 
00630    if ( result && result != (PyObject*)TPyExceptionMagic
00631            && Utility::PyErr_Occurred_WithGIL() ) {
00632    // can happen in the case of a CINT error: trigger exception processing
00633       Py_DECREF( result );
00634       result = 0;
00635    }
00636 
00637 // recover from error, if not cleared (needed as we're returning to prompt)
00638    if ( G__get_return( 0 ) > G__RETURN_NORMAL )
00639       G__security_recover( 0 );    // 0 ensures silence
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 // preliminary check in case keywords are accidently used (they are ignored otherwise)
00650    if ( kwds != 0 && PyDict_Size( kwds ) ) {
00651       PyErr_SetString( PyExc_TypeError, "keyword arguments are not yet supported" );
00652       return 0;
00653    }
00654 
00655 // setup as necessary
00656    if ( ! Initialize() )
00657       return 0;                              // important: 0, not Py_None
00658 
00659 // fetch self, verify, and put the arguments in usable order
00660    if ( ! ( args = FilterArgs( self, args, kwds ) ) )
00661       return 0;
00662 
00663 // translate the arguments
00664    Bool_t bConvertOk = SetMethodArgs( args, user );
00665    Py_DECREF( args );
00666 
00667    if ( bConvertOk == kFALSE )
00668       return 0;                              // important: 0, not Py_None
00669 
00670 // get the ROOT object that this object proxy is a handle for
00671    void* object = self->GetObject();
00672 
00673 // validity check that should not fail
00674    if ( ! object ) {
00675       PyErr_SetString( PyExc_ReferenceError, "attempt to access a null-pointer" );
00676       return 0;
00677    }
00678 
00679 // get its class
00680    TClass* klass = self->ObjectIsA();
00681    if ( klass ) {             // TODO: check should not be needed; only for Reflex, which'll fail
00682    // reset this method's offset for the object as appropriate
00683       int objTag  = (G__ClassInfo*)klass->GetClassInfo()  ? ((G__ClassInfo*)klass->GetClassInfo())->Tagnum()  : -1;   // derived
00684       G__ClassInfo* cli = (G__ClassInfo*)((TClass*)fClass.Id())->GetClassInfo();
00685       int methTag = cli ? cli->Tagnum() : -1;                                         // base
00686       fOffset = objTag == methTag ? 0 : G__isanybase( methTag, objTag, (Long_t)object );
00687    }
00688 
00689 // actual call; recycle self instead of returning new object for same address objects
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

Generated on Tue Jul 5 14:10:13 2011 for ROOT_528-00b_version by  doxygen 1.5.1