Skip to main content
GameDev.net gamedev.net
🔒 Locked

Integrate python using boost.python

Started by mrmclovin Jun 25, 2009 at 12:42 PM 1 replies 2.2k views
Original Post
mrmclovin
mrmclovin
Hello! I'm trying to integrate Python into my application using boost.python. But things aren't going well. There are not many (none?) practical tutorials out there covering my problem. There's the boost.python own tutorial to get started but that's it! My problem is that I don't just want to expose c++ classes but also expose instances of these classes created in the c++ world. In many cases I just want to control objects in python, not create them. So I thought I'd get help from you guys here and build some practical examples and eventually gather all information into a tutorial/article here on gamedev. So, basically what I want to do is: 1. Write a class myClass in c++ 2. Make an instance of myClass in c++ 3. Expose myClass to python in a module called Game 4. Make an attribute to Game which holds a reference to the instance of myClass Im familiar with the boost.python expose/embed interface. But Im not sure how to use it properly according to my needs. This is some of my conditions if it can be done: * My game engine is object oriented * I'd like to put all expose-to-python-routines in class methods (like a ScriptManager class) * Avoid global/static functions and variables in my c++ framework * Be able to in runtime add/remove object-references in the Game module Lets 'abstract' the problem to a simple concrete structure:

class Car // to be exposed to python
{
	public:
	void drive();
};

class ScriptManager
{
	public:
	ScriptManager()
	{
		// create a python module called 'Game' here..?
	}

	void addReferenceToModule(Car* reference)
	{
		// add reference to the 'Game' module.
		// this reference should be named 'myCar' in the 'Game' module's global scope
	}

	runScript()
	{
		// run script 'testScript.py' here...?
	}
};

int main()
{
	SM = new ScriptManager();
	car = new Car();
	SM->addReferenceToModule(car);
	SM->runScript();
return 0;
}
How should I code these empty methods? :)

When testScript.py is run I should be able to do:
import Game
car = Game.myCar #get the instance which is created in the c++ world
car.drive()
Thank you for your time and help! EDIT: found this link http://forums.indiegamer.com/showthread.php?t=14280 helped me [Edited by - mrmclovin on August 18, 2009 10:01:46 AM]
mrmclovin
mrmclovin
Okey, some updates. I have managed to get somewhere but I still have problems. It works if I put it like this:
using namespace boost::python;class Destination // to be exposed to Python{   // class representing a destination   [...]}class Car // to be exposed to python{   public:   void drive(Destination* where);};int main (int argc, char * const argv[]){  try  {    // Initialize context    Py_Initialize();    // Retrieve the main module.    object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));    // Retrieve the main module's namespace    object main_namespace(main_module.attr("__dict__"));    // Expose Destination class    main_namespace["Destination"] = class_<Destination>("Destination");       // Expose Car class    main_namespace["Car"] = class_<Car>("Car")                                .def("drive", &Car::drive);    // Expose Car, Destination instance    Car car;    Destination dest;    main_namespace["myCar"] = ptr(&car);    main_namespace["myDest"] = ptr(&dest);    // Run script    handle<> ignored(( PyRun_String("myCar.drive(myDest)",                                    Py_file_input,                                    main_namespace.ptr(),                                    main_namespace.ptr() ) ));  }  catch( error_already_set )  {    PyErr_Print();  }    return 0;}


But if I do it like this:
BOOST_PYTHON_MODULE(Game){    // Expose Destination class    class_<Destination>("Destination");       // Expose Car class    class_<Car>("Car")       .def("drive", &Car::drive);}class ScriptManager{   public:   ScriptManager()   {	using namespace boost::python;        Py_Initialize();	initGame(); // init boost python module	mMainModule = import("__main__");	mMainNamespace = extract<dict>(mMainModule.attr("__dict__"));   }   void addReferenceToModule(Car* reference, Destination* dest)   {	object Module = object((handle<>(borrowed(PyImport_AddModule("GameSystem")))));	object Namespace = extract<dict>(Module.attr("__dict__"));	Namespace["myCar"] = ptr(reference);	Namespace["myDestination"] = ptr(dest);   }   runScript()   {	try {		object ignored3((exec_file("test.py", mMainNamespace, mMainNamespace)));	}	catch(...) {		PyErr_Print();	}   }};int main(){   SM = new ScriptManager();   car = new Car();   destination = new Destination()   SM->addReferenceToModule(car, dest);   SM->runScript();return 0;}

So when test.py is executed:
import GameGame.myCar.drive(Game.myDest)

I get a python error like this:
Quote:

Traceback (most recent call last):
File "test.py", line 2, in
Game.myCar.drive(Game.myDest)
Boost.Python.ArgumentError: Python argument types in
Car.drive(Car, Destination)
did not match C++ signature:
setPosition(class Car {lvalue}, class Destination*)


Can't figure it out. Maybe it has something to do with that Im using the BOOST_PYTHON_MODULE in the latter test?

[Edit]
The error occurred due to that i had inheritence in my classes and did'nt wrapped the class relation correct.
[/edit]

[Edited by - mrmclovin on August 18, 2009 9:07:19 AM]
Ezbez
Ezbez
Quote:
Original post by mrmclovin
My problem is that I don't just want to expose c++ classes but also expose instances of these classes created in the c++ world. In many cases I just want to control objects in python, not create them.


It's been a while since I've written any Boost::Python code, and I can't say I've read thoroughly over your code, but this leads me to think that you need to use call policies.

Edit: But the errors you're showing in the second post lead me to think you've got other problems, too.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.