// @(#)root/pyroot:$Name:  $:$Id: TPython.cxx,v 1.12 2005/09/09 05:19:10 brun Exp $
// Author: Wim Lavrijsen, Apr 2004

// Bindings
#include "PyROOT.h"
#include "TPython.h"
#include "ObjectProxy.h"
#include "RootWrapper.h"

// ROOT
#include "TROOT.h"
#include "TObject.h"

// Standard
#include <stdio.h>
#include <Riostream.h>
#include <string>

//______________________________________________________________________________
//                          Python interpreter access
//                          =========================
//
// The TPython class allows for access to python objects from CINT. The current
// functionality is only basic: ROOT objects and builtin types can freely cross
// the boundary between the two interpreters, python objects can be instantiated
// and their methods can be called. All other cross-coding is based on strings
// that are run on the python interpreter.
//
// Examples:
//
//  $ cat MyPyClass.py
//  print 'creating class MyPyClass ... '
//
//  class MyPyClass:
//     def __init__( self ):
//        print 'in MyPyClass.__init__'
//
//     def gime( self, what ):
//        return what
//
//  $ root -l
//  // Execute a string of python code.
//  root [0] TPython::Exec( "print \'Hello World!\'" );
//  Hello World!
//
//  // Create a TBrowser on the python side, and transfer it back and forth.
//  // Note the required explicit (void*) cast!
//  root [1] TBrowser* b = (void*)TPython::Eval( "ROOT.TBrowser()" );
//  root [2] TPython::Bind( b, "b" );
//  root [3] b == (void*) TPython::Eval( "b" )
//  (int)1
//
//  // Builtin variables can cross-over by using implicit casts.
//  root [4] int i = TPython::Eval( "1 + 1" );
//  root [5] i
//  (int)2
//
//  // Load a python module with a class definition, and use it.
//  root [6] TPython::LoadMacro( "MyPyClass.py" );
//  creating class MyPyClass ...
//  root [7] MyPyClass m;
//  in MyPyClass.__init__
//  root [8] char* s = m.gime( "aap" );
//  root [9] s
//  (char* 0x41ee7754)"aap"
//
// It is possible to switch between interpreters by calling "TPython::Prompt()"
// on the CINT side, while returning with ^D (EOF). State is preserved between
// successive switches.


//- data ---------------------------------------------------------------------
ClassImp(TPython)

namespace {

   PyObject* gMainDict = 0;

   PyObject* gClassString  = 0;
   PyObject* gNameString   = 0;
   PyObject* gModuleString = 0;

} // unnamed namespace


//- static public members ----------------------------------------------------
 Bool_t TPython::Initialize()
{
// Private initialization method: setup the python interpreter and load the
// ROOT module.

   if ( ! Py_IsInitialized() ) {
   // this happens if CINT comes in first
      PyEval_InitThreads();
      Py_Initialize();

   // try again
      if ( ! Py_IsInitialized() ) {
      // give up ...
         std::cerr << "Error: python has not been intialized; returning." << std::endl;           
         return kFALSE;
      }

   // set argv
      char* argv[] = { const_cast< char* >( "root" ) };
      PySys_SetArgv( sizeof(argv)/sizeof(argv[0]), argv );

   // force loading of ROOT
      PyRun_SimpleString( const_cast< char* >( "import ROOT" ) );
   }

   if ( ! gMainDict ) {
   // initialize some handy strings
      gClassString  = PyString_FromString( "__class__" );
      gNameString   = PyString_FromString( "__name__" );
      gModuleString = PyString_FromString( "__module__" );

   // retrieve the main dictionary
      gMainDict = PyModule_GetDict(
         PyImport_AddModule( const_cast< char* >( "__main__" ) ) );
      Py_INCREF( gMainDict );
   }

// declare success ...
   return kTRUE;
}

//____________________________________________________________________________
 void TPython::LoadMacro( const char* name )
{
// Execute the give python script as if it were a macro (effectively an
// execfile in __main__), and create CINT equivalents for any newly available
// python classes.

// setup
   if ( ! Initialize() )
      return;

// obtain a reference to look for new classes later
   PyObject* old = PyDict_Values( gMainDict );

// actual execution
   Exec( (std::string( "execfile(\"" ) + name + "\")").c_str() );

// obtain new __main__ contents
   PyObject* current = PyDict_Values( gMainDict );

// create CINT classes for all new python classes
   for ( int i = 0; i < PyList_GET_SIZE( current ); ++i ) {
      PyObject* value = PyList_GET_ITEM( current, i );
      Py_INCREF( value );

      if ( ! PySequence_Contains( old, value ) ) {
      // collect classes
         if ( PyClass_Check( value ) ||
              PyObject_HasAttrString( value, const_cast< char* >( "__bases__" ) ) ) {
         // force class creation
            PyObject* str = PyObject_Str( value );
            gROOT->GetClass( PyString_AS_STRING( str ) );
            Py_DECREF( str );
         }
      }

      Py_DECREF( value );
   }

   Py_DECREF( current );
   Py_DECREF( old );
};

//____________________________________________________________________________
 void TPython::Exec( const char* cmd )
{
// Execute a python statement (e.g. "import ROOT").

// setup
   if ( ! Initialize() )
      return;

// execute the command
   PyObject* result =
      PyRun_String( const_cast< char* >( cmd ), Py_file_input, gMainDict, gMainDict );

// test for error
   if ( result )
      Py_DECREF( result );
   else
      PyErr_Print();
}


//____________________________________________________________________________
 const TPyReturn TPython::Eval( const char* expr )
{
// Evaluate a python expression (e.g. "ROOT.TBrowser()").
//
// Caution: do not hold on to the return value: either store it in a builtin
// type (implicit casting will work), or in a pointer to a ROOT object (explicit
// casting to a void* is required).

// setup
   if ( ! Initialize() )
      return TPyReturn();

// evaluate the expression
   PyObject* result =
      PyRun_String( const_cast< char* >( expr ), Py_eval_input, gMainDict, gMainDict );

// report errors as appropriate; return void
   if ( ! result ) {
      PyErr_Print();
      return TPyReturn();
   }

// results that require no converion
   if ( result == Py_None || PyROOT::ObjectProxy_Check( result ) )
      return TPyReturn( result );

// explicit conversion for python type required
   PyObject* pyclass = PyObject_GetAttr( result, gClassString );
   if ( pyclass != 0 ) {
   // retrieve class name and the module in which it resides
      PyObject* name = PyObject_GetAttr( pyclass, gNameString );
      PyObject* module = PyObject_GetAttr( pyclass, gModuleString );

   // concat name
      std::string qname =
         std::string( PyString_AS_STRING( module ) ) + '.' + PyString_AS_STRING( name );
      Py_DECREF( module );
      Py_DECREF( name );
      Py_DECREF( pyclass );

   // locate ROOT style class with this name
      TClass* klass = gROOT->GetClass( qname.c_str() );

   // construct general ROOT python object that pretents to be of class 'klass'
      if ( klass != 0 )
         return TPyReturn( result );
   } else
      PyErr_Clear();

// no conversion, return null pointer object
   Py_DECREF( result );
   return TPyReturn();
}

//____________________________________________________________________________
 Bool_t TPython::Bind( TObject* object, const char* label )
{
// Bind a ROOT object with, at the python side, the name "label".

// check given address and setup
   if ( ! ( object && Initialize() ) )
      return kFALSE;

// bind object in the main namespace
   TClass* klass = object->IsA();
   if ( klass != 0 ) {
      PyObject* bound = PyROOT::BindRootObject( (void*)object, klass );

      if ( bound ) {
         Bool_t bOk = PyDict_SetItemString( gMainDict, const_cast< char* >( label ), bound ) == 0;
         Py_DECREF( bound );

         return bOk;
      }
   }

   return kFALSE;
}

//____________________________________________________________________________
 void TPython::Prompt() {
// Enter an interactive python session (exit with ^D). State is preserved
// between successive calls.

// setup
   if ( ! Initialize() ) {
      return;
   }

// enter i/o interactive mode
   PyRun_InteractiveLoop( stdin, const_cast< char* >( "\0" ) );
}


ROOT page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.