[C++-sig] Re: Problem with embedding python with boost.python

Dirk Gerrits dirk at gerrits.homeip.net
Mon Jul 7 11:39:58 CEST 2003


Pierre Barbier de Reuille wrote:
> I try to embed python in a C++ program. I wrote a module that works if I 
> compile it for extending python ... and I wrote a simple interpreter 
> that works as an embedded one !
> 
> But now I want to extend the embedded interpreter to allow access to the 
> C++ classes !
> 
> The extension module is called "editor". My problem is that whenever I 
> try to import the module in python, the program just abort ... the 
> import is done by evaluating 'import edtitor' inside the python 
> interpreter ... I show you the interpreter code ! Of course, the module 
> is defined using boost.python !
> 
> An extra-question is : if I use Py_file_input, I can't retrieve the 
> output of the python command, if I use Py_single_input, I can retrieve 
> the output, but I can't do any assignment or printing ... how can I have 
> both ??? I really begin to think python was not designed to embedded :(

Well this is not really a question of embedding or not. Python's eval, 
exec, and execfile statements work in the same way. Anyway, what you 
could do is use Py_file_input for all but the last line of code, then 
use Py_eval_input for the last line. Or you could let the code store the 
result in a variable and read that variable from the main_namespace:

PyObject *obj = PyRun_String("result = 5**2", Py_file_input,
     main_namespace.ptr(), main_namespace.ptr());
boost::python::handle<> hres(obj);
boost::python::object res = main_namespace["result"];

> Tthe interpreter class is :
> 
> class PythonWnd : public QMainWindow
> {
>  Q_OBJECT
> 
> public:
>  PythonWnd(QWidget * parent = 0, const char * name = 0, WFlags f = 
> WType_TopLevel);
>  ~PythonWnd();
> 
> public slots:
>  void evalCommand();
> 
> protected:
>  void LaunchPython();
>  void ClosePython();
>  void ExecutePython(const QString command);
>  QTextEdit *output;
>  QLineEdit *edit;
>  QVBox *layout;
>  boost::python::object main_module;
>  boost::python::dict main_namespace;
> 
> };
> 
> The initialization function that is :
> 
> void PythonWnd::LaunchPython()
> {
>  // register the module editor with the interpreter
>  if (PyImport_AppendInittab("editor", init_module_editor) == -1)
>    {
>      cerr << "Error, cannot load editor module !" << endl;
>      throw std::runtime_error("Failed to add embedded_hello to the 
> interpreter's "
>                   "builtin modules");
>    }
>  // Initialize the interpreter
>  Py_Initialize();
>  // Get the main module ...
>  main_module = 
> object(boost::python::handle<>(borrowed(PyImport_AddModule("__main__"))));
>  main_namespace = 
> dict(boost::python::handle<>(borrowed(PyModule_GetDict(main_module.ptr())))); 
> 
> }
> 
> Then the interpretor function (launched each time a line is to be 
> evaluated ... it's an iteractive interpretor) is:
> 
> void PythonWnd::ExecutePython(const QString command)
> {
>  char *cmd;
>  cmd = new char[command.length()+1];
>  strcpy(cmd, command.latin1());
>  stringstream ss;
>  try
>    {
>      PyObject *obj = PyRun_String(cmd, Py_file_input, 
> main_namespace.ptr(), main_namespace.ptr());
>      boost::python::handle<> hres(obj);
>      boost::python::object res(hres);
>      //std::string res_cmd = extract<std::string>(res.attr("__repr__")());
>      std::string res_cmd = call_method<std::string>(res.ptr(),"__repr__");
>      ss << res_cmd;
>    }
>  catch(error_already_set)
>    {
>      PyErr_Print();
>      ss << "Error, exception thrown ... look at console for details" << 
> endl;
>      PyObject *exception, *v, *tb, *hook;
>    }
>  output->append(ss.str().c_str());
>  delete cmd;
> }
> 
> 

command.latin1() is not null-terminated I think, which would make the 
strcpy fail. (Not sure, I don't use Qt.) Wouldn't it be easier and safer 
to do:

QString cmd = command + '\0';
...
PyObject *obj = PyRun_String(cmd.latin1(), Py_file_input,
     main_namespace.ptr(), main_namespace.ptr());

?

Are you sure the interpreter aborts only when you import your module? If 
latin1() does what I think it does then your program could crash on any 
piece of Python code.

Regards,
Dirk Gerrits






More information about the Cplusplus-sig mailing list