   (Yet) another python problem
  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]
  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 doimport 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::objectBstObject;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 objectBstObjectmodule, dict;// the module name (without path or extension)charname[ 32 ];// declare our manager as a friendfriend class GstScriptMgr;// the bind functionvoid Bind( BstObject& module, char* name );public:// default constructorGstScript() {}// gets an object (could be function or variable)PyObject* Get( char* object );// gets the script''s nameconst char* getName() { return name; }// checks what sort of object is under this nameKPyObjectType Type( char* object );// operator overloadsPyObject* operator[]( char* variable );};class GstScriptMgr : public GstSingleton< GstScriptMgr >{private:// loads the Python interpreterbool LoadPython( char* modPath );// frees the Python interpreterbool FreePython();public:// default constructorGstScriptMgr( char* modPath = _GHOST_MODULE_PATH_ );// destructor~GstScriptMgr();// retrieves a scriptbool LoadModule( char* modName, GstScript& script );};// pre-definition of the ''script'' Python moduleextern "C" {extern void __declspec(dllexport) initscript();}#endifAnd 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 variablemodule = 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 validif( !tmp ){PyErr_Print();// Log Error Herecout << "Couldn''t Find The Object: " << obj << "\n";cout.flush();}// it''s validreturn 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 interpreterPy_Initialize();// copy the script location into Pythonchar 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 successreturn true;}// frees the Python interpreterbool GstScriptMgr :: FreePython(){// free the interpreterPy_Finalize();return true;}// default constructorGstScriptMgr :: GstScriptMgr( char* modPath ){bool res;// load the python interpreterres = LoadPython( modPath );assert( res && "Unable To Start The Python Interpreter" );}// destructorGstScriptMgr :: ~GstScriptMgr(){bool res;// free the Python interpreterres = 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 messagecout << "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 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. ;"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]