|
Boost : |
From: David Rostowsky (drostowsky_at_[hidden])
Date: 2004-04-01 11:02:21
Thanks for the feedback! Yes I am glad someone is posting me message! :)
Heres my full.cpp file that will hopefully shed some light on my Boost
bumbling. Below that is my python script too.
I was just typing the code snippets from memory and I noticed I misled on my
virtual function return value. In fact, its a void return value.
It does throw a runtime exception. Ive commented the line of code in main()
where it throws the exception.
Thanks for all the help! If I can get these passing C++ pointers to Python
issues hammered out, Ill forever proclaim Boost's greatness, and Ill never
look at Lua (or Perl) again ;)
-Dave
#include <windows.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <conio.h>
#undef _DEBUG // just forcing the non-debug library by doing this
#include <Python.h>
#define _DEBUG // just forcing the non-debug library by doing this
#include <boost/python/class.hpp>
#include <boost/python/def.hpp>
#include <boost/python/str.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/module.hpp>
#include <boost/python/call_method.hpp>
#include <boost/python/handle.hpp>
#include <boost/python.hpp>
using namespace boost::python;
// Error codes
#define Success 0
#define PY_InitError -100
#define PY_ConvertError -101
#define PY_CallError -102
// Global module pointer
boost::python::handle<> my_module;
////////////////////////////////////////////////////////////////////////////
//////////
////////////////////////////////////////////////////////////////////////////
//////////
class Base1
{
public:
int z;
Base1() { z= 1; };
/*
** I dont want Python to even care about this function! My other C++
code classes may (or may not)
** override this function. No Python script should ever override this.
The default behavior is
** to do nothing. I figured if I dont expose it to the
BOOST_PYTHON_MODULE, why would it need
** to care about this function? Again, if I comment this out, everything
works perfectly. Otherwise,
** I get a runtime exception about non_rtti_object.
*/
virtual void OnKeyUp(unsigned short virtual_key) { };
};
////////////////////////////////////////////////////////////////////////////
//////////
////////////////////////////////////////////////////////////////////////////
//////////
class TestC : public Base1
{
protected:
int x;
public:
TestC() { x = 0; };
void Set(int val) { x = val; };
int Get(void) { return x; };
void printPtr() { printf("C++ : Ptr=0x%p", this); }
};
////////////////////////////////////////////////////////////////////////////
//////////
// Python wrapper for TestC
////////////////////////////////////////////////////////////////////////////
//////////
BOOST_PYTHON_MODULE(grumsh)
{
using namespace boost::python;
object testClass = class_<TestC, boost::shared_ptr<TestC> >(
"TestC", init<>())
.def("Get", &TestC::Get)
.def("Set", &TestC::Set)
.def("printPtr", &TestC::printPtr)
;
} /* grumsh */
////////////////////////////////////////////////////////////////////////////
//////////
// Function prototypes
////////////////////////////////////////////////////////////////////////////
//////////
int initPython(std::string scriptName);
int callPython(std::string func, std::string msg, boost::python::object&
obj);
////////////////////////////////////////////////////////////////////////////
//////////
// Convenience functions
////////////////////////////////////////////////////////////////////////////
//////////
boost::python::handle<> import_module(std::string module_name)
{
using namespace boost::python;
PyObject *module_ptr =
PyImport_ImportModule(const_cast<char*>(module_name.c_str()));
if (module_ptr == NULL)
{
OutputDebugString("import_module, NULL\n");
exit(1);
}
return handle<>(module_ptr);
} /* import_module */
////////////////////////////////////////////////////////////////////////////
//////////
////////////////////////////////////////////////////////////////////////////
//////////
boost::python::object get_function(const char * func_name)
{
// Borrowed reference
PyObject * dict = PyModule_GetDict(my_module.get());
boost::python::str funcName(func_name);
return
boost::python::object(boost::python::handle<>(PyDict_GetItem(dict,
funcName.ptr())));
} /* get_function */
////////////////////////////////////////////////////////////////////////////
//////////
// Call a function in module (ptrPyModule) with two arguments
// func: Name of python function
// msg: Message string
// obj: Boost.Python object (an instance of a wrapped class)
////////////////////////////////////////////////////////////////////////////
//////////
int callPython(const std::string funcStr,
std::string msg,
boost::python::object& obj)
{
int rval;
boost::python::object func =
get_function(const_cast<char*>(funcStr.c_str()));
rval = boost::python::extract<int>(func(msg, obj));
return rval;
} /* callPython */
////////////////////////////////////////////////////////////////////////////
//////////
// Initialize Python interpreter
// Initialize Extension module that expose C++ classes/objects to Python
script
// Set up sys.path to include script path (Where the python scripts can be
found)
////////////////////////////////////////////////////////////////////////////
//////////
int initPython(std::string scriptName)
{
if(scriptName.length() == 0)
return PY_InitError;
// Register the extension module
PyImport_AppendInittab("grumsh", initgrumsh);
// Initialize the Python interpreter
Py_Initialize();
PySys_SetPath(strcat(Py_GetPath(),
";.\\scripts\\;\\code\\cpp\\python\\scripts\\"));
char * oldpath = Py_GetPath();
// Import the module, storing the pointer in a handle<>
my_module = import_module(const_cast<char*>(scriptName.c_str()));
return Success;
}
int main()
{
int rval;
/* Create a new Test class instance. */
TestC * test = new TestC();
/*
** Try any way to wrap it such that I can pass a pointer to my Python
script so it can call
** my exposed member functions.
*/
boost::shared_ptr<TestC> test1ptr(test);
std::cout << "C++ : Initializing Python and loading script" << std::endl;
int retv = initPython("test_script");
if( retv == Success )
{
test1ptr->printPtr(); std::cout << std::endl;
std::cout << "C++ : test1ptr->Get() in C++ before Python call: "
<< test1ptr->Get() << std::endl;
/*
** This is where I get a RUNTIME exception (non_rtti_object). If I
comment out the virtual
** member function out of the class Base1, this works perfectly!
*/
object arg2(test1ptr);
/* This works great too as long as I dont have the virtual member
function. */
int retv = callPython("myTestFunc", "Test String argument from c++",
arg2);
std::cout << "C++ : callPython() returned: " << retv << std::endl;
std::cout << "C++ : test1ptr->Get() after Python call: " <<
test1ptr->Get() << std::endl;
std::cout << "C++ : Press any key to quit" << std::endl;
getch();
}
return 0;
} /* main */
Ok, and heres the full test_script.py file:
==========================
try:
import grumsh
print "Python: Import SUCCEEDED!!!"
except:
print "Python: Import FAILED..."
############################################################################
#########
############################################################################
#########
def my_test(ptr):
return 0;
############################################################################
#########
# Test module
# Illustrate both instatiation and use of already instantiated C++ objects
############################################################################
#########
def myTestFunc(msg, cppObj):
# Print message from C++
print "Python: msg = ", msg
# Instantiate a MyClass object
a = grumsh.TestC()
# Show identity
print "Python: Identity of 'local' MyClass object: ",
a.printPtr()
print
# Change state of object
print "Python: Current state:", a.Get()
a.Set(1234)
print "Python: New state :", a.Get()
# Delete object
del a
# Test the object exposed from c++ (Passed as a formal parameter)
# Show identify of cppObj
print "Python: Identity of exposed cppObj: ",
cppObj.printPtr()
print
# Show state of cppObj
print "Python: cppObj.Get() on entry:", cppObj.Get()
# Change state of object
cppObj.Set(9)
# Show state of object
print "Python: cppObj.Get() on exit :", cppObj.Get()
return 999
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk