🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

(Yet) another python problem

Started by
4 comments, last by Toni Petrina 20 years, 10 months ago
Why doesn't this work? Can anybody help?

#include <python.h>

int main() {
	Py_Initialize();

	FILE *p = fopen("test.py", "r");
	PyRun_SimpleFile(p, "test.py");
	fclose(p);

	if (Py_IsInitialized())
		Py_Finalize();
	return 0;
}
If you are using Boost.Python, tell me how are you actually calling python files within your application. It just crashes. [edited by - ffx on August 8, 2003 3:13:19 PM]
So... Muira Yoshimoto sliced off his head, walked 8 miles, and defeated a Mongolian horde... by beating them with his head?

Documentation? "We are writing games, we don't have to document anything".
Advertisement
I dont see your problem, but I can share with you how I call Python.

In my engine, I use only the Very High Level Embedding to call python. I wrap PyRun_SimpleString myself to provide error checking, but that is unnecessary here.

PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append("./scripts");PyRun_SimpleString("import scheduler");PyRun_SimpleString("secheduler.load(''ascript'')");while (true)   PyRun_SimpleString("scheduler.update()"); 


In other words, I have a class written in Python that calls out to other scripts.

Then, in the scripts, I do
import enginedef main()   ...   yield None #all my scripts have a generator function called main 

where engine is a static python extension module (this is where I''m having trouble myself, but I know it can be done).

No boost.python necessary until the static extension part.

HTH,
Dustin
I beleive that's a bug in Python. You have to use the multi-threaded dll runtime.

edit:
Alternatively you could load the whole script into a string and use PyRun_SimpleString.

[edited by - M_R_Ducs on August 8, 2003 4:14:38 PM]
Whoa, you guys really do use the high level stuff huh? If you want to have more control over your scripts, like I do, then use more lower level functions like so (this is my actual in-engine script class, that pretty much wraps all this good stuff up for me). First the header:
#ifndef _SCRIPT_H_#define _SCRIPT_H_#include "unknown.h"#include "singleton.h"#ifndef _GHOST_MODULE_PATH_#define _GHOST_MODULE_PATH_ "C:/Developer/Scripts/"#endiftypedef class boost::python::object		BstObject;typedef class boost::python::handle<>	BstHandle;enum KPyObjectType{	PYTYPE_INVALID = 0,	PYTYPE_FUNCTION,	PYTYPE_VARIABLE};#define CallScript PyObject_CallFunctionclass GstScript : public GstUnknown{private:	// the module object	BstObject		module, dict;	// the module name (without path or extension)	char				name[ 32 ];	// declare our manager as a friend	friend class GstScriptMgr;	// the bind function	void Bind( BstObject& module, char* name );public:	// default constructor	GstScript() {}		// gets an object (could be function or variable)	PyObject* Get( char* object );	// gets the script''s name	const char* getName() { return name; }	// checks what sort of object is under this name	KPyObjectType Type( char* object );	// operator overloads	PyObject* operator[]( char* variable );};class GstScriptMgr : public GstSingleton< GstScriptMgr >{private:	// loads the Python interpreter	bool LoadPython( char* modPath );	// frees the Python interpreter	bool FreePython();public:	// default constructor	GstScriptMgr( char* modPath = _GHOST_MODULE_PATH_ );	// destructor	~GstScriptMgr();	// retrieves a script	bool LoadModule( char* modName, GstScript& script );};// pre-definition of the ''script'' Python moduleextern "C" {	extern void __declspec(dllexport) initscript();}#endif


And now the implementation:

#ifdef _DEBUG#undef _DEBUG#define _ISDEBUG_#include <Python.h>#include <Boost/Python.h>#else#include <Python.h>#include <Boost/Python.h>#endif#ifdef _ISDEBUG_#pragma warning( disable : 4005 )#define _DEBUG#endif#include <iostream.h>#include <stdarg.h>#include "types.h"#include "hash.h"#include "script.h"#pragma comment( lib, "boost_python.lib" )using namespace boost::python;BOOST_PYTHON_MODULE(script){	class_<GstScript>( "KScript" )		.def( "Get", &GstScript::Get )		.def( "Type", &GstScript::Type )	;	class_<GstScriptMgr>( "KScriptMgr", no_init )		.def( "LoadModule", &GstScriptMgr::LoadModule )	;	def( "get", &GstScriptMgr::get, return_value_policy< reference_existing_object >() );}// the bind functionvoid GstScript :: Bind( BstObject& mod, char* str ){	// copy the passed objects into this variable	module = mod;		strcpy( name, str );	// get the dictionary (borrowed reference!)	dict = BstObject( BstHandle( boost::python::borrowed( PyModule_GetDict( module.ptr() ) ) ) );}// calls a functionPyObject* GstScript :: Get( char* obj ){	// get the requested function (borrowed!)	PyObject* tmp = PyDict_GetItemString( dict.ptr(), obj );		// check if it''s valid	if( !tmp )	{		PyErr_Print();		// Log Error Here		cout << "Couldn''t Find The Object: " << obj << "\n";		cout.flush();	}	// it''s valid	return tmp;}// checks what sort of object is under this nameKPyObjectType GstScript :: Type( char* object ){	PyObject* ptr = Get( object );	if( !dict || !module || !ptr )		return PYTYPE_INVALID;	if( PyCallable_Check( ptr ) )		return PYTYPE_FUNCTION;	return PYTYPE_VARIABLE;}// operator overloads////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// loads the Python interpreterbool GstScriptMgr :: LoadPython( char* modPath ){	// initialize the interpreter	Py_Initialize();	// copy the script location into Python	char buffer[ 128 ];	sprintf( buffer, "sys.path.append(''%s'')", modPath );	PyRun_SimpleString( "import sys" );	PyRun_SimpleString( buffer );	sprintf( buffer, "sys.path.append(''%s'' + ''Events/'')", modPath );	PyRun_SimpleString( buffer );	// return success	return true;}// frees the Python interpreterbool GstScriptMgr :: FreePython(){	// free the interpreter	Py_Finalize();	return true;}// default constructorGstScriptMgr :: GstScriptMgr( char* modPath ){	bool res;	// load the python interpreter	res = LoadPython( modPath );	assert( res && "Unable To Start The Python Interpreter" );}// destructorGstScriptMgr :: ~GstScriptMgr(){	bool res;	// free the Python interpreter	res = FreePython();	assert( res && "Unable To Free Python Interpreter" );}// retrieves a scriptbool GstScriptMgr :: LoadModule( char* modName, GstScript& script ){	PyObject* ptr = PyImport_Import( PyString_FromString( modName ) );	if( !ptr )	{		PyErr_Print();		// print an error message		cout << "Couldn''t GstScriptMgr::LoadModule() The Requested Module ''" << modName << "''\n";		cout.flush();		return false;	}	BstObject& mod = BstObject( BstHandle( ptr ) );	script.Bind( mod, modName );	return true;}


And I''m sorry if it''s not really legible, the gamedev.net parser likes to take out empty lines... But as you can see, I ''import'' the module, and then grab it''s dictionary. This way, you know all the functions in that particular module. I originally had it such that I scanned through a directory and added all functions to a list, but then I realized you can have functions named the same with same arguments, but just different script files, so I trashed the idea... But here''s an example of the script object working. This is where I grab an API from each of the scripts so that I can call them without regard to which file or whatnot.

// load the APIscriptAPI.InitActive	= (void*) Script.Get( "InitActive" );scriptAPI.InitPriority	= (void*) Script.Get( "InitPriority" );scriptAPI.Create	= (void*) Script.Get( "Create" );scriptAPI.Start		= (void*) Script.Get( "Start" );scriptAPI.Update	= (void*) Script.Get( "Update" );scriptAPI.Stop		= (void*) Script.Get( "Stop" );scriptAPI.Destroy	= (void*) Script.Get( "Destroy" );// get the default values from the scriptactive   = extract<u16>( BstObject( BstHandle( CallScript( (PyObject*) scriptAPI.InitActive, "" ) ) ) );priority = extract<u16>( BstObject( BstHandle( CallScript( (PyObject*) scriptAPI.InitPriority, "" ) ) ) );


Oh yeah, and I couldn''t tell you why you''re codes not working. I just checked the API docs and it appears to be correct. Why not test your file pointer to make sure it''s valid? Technically, I''m assuming the test.py file is in the same directory as the workspace?

Chris Pergrossi
My Realm | "Good Morning, Dave"
Chris PergrossiMy Realm | "Good Morning, Dave"
Thanks c t o a n, I''ll try that. Whole Python API documentation is pretty good but it gives you no real examples of embeding. Also, there are no real examples of using Boost.Python, just detailed docs.

thedustbustr: I see where you are going, but when you execute one PyRun_SimpleString, the following one doesn''t know anything about it. Maybe I should concatenate more lines into one.
So... Muira Yoshimoto sliced off his head, walked 8 miles, and defeated a Mongolian horde... by beating them with his head?

Documentation? "We are writing games, we don't have to document anything".
"thedustbustr: I see where you are going, but when you execute one PyRun_SimpleString, the following one doesn't know anything about it. Maybe I should concatenate more lines into one. "

wrong. As far as I can tell, PyRun_SimpleString is like running a command in the python interpreter. Not only that, but take this for example:
PyRun_SimpleString("import katana"); //thats my static modulePyRun_SimpleString("katana.foo=42"); //create a new variable in katana module namespace  

and now every python script that does 'import katana' can access 'katana.foo'. It sounds like it wouldnt work, but try it, its great. I believe this works because katana is a static built-in (like 'sys'), I expect it would not work (and if it does, thats a security problem) for a normal pure python module (but I've never tried).

Now that I got my static python extension module working (thanks ctoan!) everything is beautiful. I use none of the python api functions except for PyRun_SimpleString, PyErr_Occurred, and PyErr_Print (and a whole bunch of boost.python wrapper stuff). Then I have a script handler class written in Python that gives each script execution time using generators (sort of like threads but, imo, much much better (simpler, more control, none of that typical threadsafe hassle)). And now that I fixed my static extension module I'm flying my camera around a 3d terrain mesh using bezier curves and circular orbits and its awesome.

The boost.python documentation is not for the faint of heart (they were way over my head), but at the end of each section there is usually an example (with c++ and python code), and the tutorial is great. For python embedding docs, python ships with a great tutorial (its seperate from the api reference).

cameras following Bezier curves are the shit, let me tell you

Enough ranting.
Dustin

[edited by - thedustbustr on August 10, 2003 7:33:57 PM]

This topic is closed to new replies.

Advertisement