Calling python eval from c++ - c++

I'm basically attempting to do the same as the following question but i'm getting run time errors at the call to PyObject_Print complaining about an error in "toupper() at 0x776e0226"
Python C API: Using PyEval_EvalCode
My code is:
int callExecFunction(const char* evalStr)
{
PyCodeObject* code = (PyCodeObject*)Py_CompileString(evalStr, "pyscript", Py_eval_input);
PyObject* global_dict = PyModule_GetDict(pModule);
PyObject* local_dict = PyDict_New();
PyObject* obj = PyEval_EvalCode(code, global_dict, local_dict);
PyObject* result = PyObject_Str(obj);
PyObject_Print(result, stdout, 0);
}
evalStr is "setCurrentFileDir()" and pModule was initialized earlier from a script without error and was working as this code: http://docs.python.org/2/extending/embedding.html#pure-embedding.
And inside the loaded module there is the function:
def setCurrentFileDir():
print "setCurrentFileDir"
return "5"
What have I missed/done wrong in the eval function call. Note that I cannot call the function setCurrentFileDir "directly" through the python API, I must use eval.

Actually this works fine. However I had a .pyd file in the directory that python must have built (and eclipse was hiding from me) from an older run of the python script that didn't have the function defined, causing the problem.
Here is where I got the idea that the problem maybe a .pyd file.
python NameError: name '<anything>' is not defined (but it is!)

Related

Embed Ruby in C and exntend

I have a requirement where I need to embed Ruby code in C++ (I could achieve this) and extend some functionality. When I try to call (require) my extension module, the program fails.
I have pasted a jist of the code below:
main.cpp
#include <ruby.h>
static VALUE Sum(VALUE rb_self, VALUE rb_param1, VALUE rb_param2)
{
double val1 = NUM2DBL(rb_param1);
double val2 = NUM2DBL(rb_param2);
return rb_float_new(val1+val2);
}
void Init_myMod()
{
myMod = rb_define_module("myMod");
rb_define_module_function(myMod, "Sum", Sum, 2);
}
int main()
{
... Init ruby method...
rb_require("myRubyfile");
Init_myMod(); // This is where I need to push my ruby extension.
rb_funcall(rb_mKernel, rb_intern("helloworld"), 0 , NULL);
....
}
myRubyfile.rb
require "myMod"
def helloworld()
puts "Hello world"
#puts "Sum of.. " + myMod.sum(4, 5)
end
The problem is if I dont use require "myMod" the code works and prints "Hello World", but if I use require.., the code dumps.
This is my requirement where I need to embed the ruby script in C, and reuse some of the C methods in ruby (extension).
Can someone help me with this?
You're getting a segfault because the Ruby VM segfaults when there is an uncaught exception. You need to use something like rb_rescue or rb_protect to wrap the code which could raise an exception.
require "myMod" is raising an exception because require is only used to load files. You don't need to require anything because you're creating the module directly in the VM's memory. So... why the error? Well, if you were to write your module in Ruby, you'd get a syntax error:
module myMod
...
end
# SyntaxError: class/module name must be CONSTANT
But when you use rb_define_module, rather than raise an exception, Ruby does a tricky thing: it creates the module but doesn't expose it to the Ruby code. In order to expose the module to Ruby, just make the name valid:
// .cpp
rb_define_module("MyMod");
and
# .rb
puts "Sum of.. " + MyMod.Sum(4, 5).to_s
Something like this should work. Make a bat script to your ruby script file and change system to the appropriate system call. Not sure if system() works in Windows. I have run many bash scripts this way so I would assume you can do the same thing in Windows.
#include <stdio.h>
#include <stdlib.h>
int main()
{
puts("Starting now:");
system("/path_to_script/script_name");
return 0;
}

boost::python hybrid embedding/exposing: how do I get globals() and see my own module?

I'm using boost::python to do a hybrid C++/python application: the C++ app calls a collection of python scripts, which in turn use the C++ program's functions, classes, etc., exposed as python objects. (Python 2.x.)
BOOST_PYTHON_MODULE(MyModule) exposes the C++ to python as expected.
My initialization code:
Py_Initialize();
initMyModule(); // import MyModule
namespace bpl = boost::python;
Now I want my C++ code to get at MyModule, too. In python, you just write globals()['MyModule']. But this (and things like it) don't work in C++:
bpl::object globals = bpl::eval("globals()");
This fails at run-time with
File "<string>", line 1, in <module>; NameError: name 'globals' is not defined
As an aside, I see many examples of setting up __main__ like this:
bpl::object m = bpl::import("__main__");
bpl::dict g = m.attr("__dict__"); // like locals(), but not globals()
This doesn't fail, and gives locals, but according to the Py_Initialize docs, __main__ is already set up. And it doesn't let you see globals, where you'd find your imported module.
You don't need the explicit bpl::import("__main__");.
Here are the globals:
bpl::dict globals()
{
bpl::handle<> mainH(bpl::borrowed(PyImport_GetModuleDict()));
return bpl::extract<bpl::dict>(bpl::object(mainH));
}
Since everything is managed by smart pointers, returning and manipulating bpl::dict directly works fine.
bpl::object myMod = globals()["MyModule"];
globals()["myNewGlobal"] = 88;

How can I extract a wrapped C++ type from a Python type using boost::python?

I've wrapped a C++ class using Py++ and everything is working great in Python. I can instantiate the c++ class, call methods, etc.
I'm now trying to embed some Python into a C++ application. This is also working fine for the most-part. I can call functions on a Python module, get return values, etc.
The python code I'm calling returns one of the classes that I wrapped:
import _myextension as myext
def run_script(arg):
my_cpp_class = myext.MyClass()
return my_cpp_class
I'm calling this function from C++ like this:
// ... excluding error checking, ref counting, etc. for brevity ...
PyObject *pModule, *pFunc, *pArgs, *pReturnValue;
Py_Initialize();
pModule = PyImport_Import(PyString_FromString("cpp_interface"));
pFunc = PyObject_GetAttrString(pModule, "run_script");
pArgs = PyTuple_New(1); PyTuple_SetItem(pArgs, 0, PyString_FromString("an arg"));
pReturnValue = PyObject_CallObject(pFunc, pArgs);
bp::extract< MyClass& > extractor(pReturnValue); // PROBLEM IS HERE
if (extractor.check()) { // This check is always false
MyClass& cls = extractor();
}
The problem is the extractor never actually extracts/converts the PyObject* to MyClass (i.e. extractor.check() is always false).
According to the docs this is the correct way to extract a wrapped C++ class.
I've tried returning basic data types (ints/floats/dicts) from the Python function and all of them are extracted properly.
Is there something I'm missing? Is there another way to get the data and cast to MyClass?
I found the error. I wasn't linking my bindings in my main executable because the bindings were compiled in a separate project that created the python extension only.
I assumed that by loading the extension using pModule = PyImport_Import(PyString_FromString("cpp_interface")); the bindings would be loaded as well, but this is not the case.
To fix the problem, I simply added the files that contain my boost::python bindings (for me, just wrapper.cpp) to my main project and re-built.

pass callback from python to c++ using boost::python

I want to pass callback from my python code to c++
I want my code look something like this:
In C++ :
typedef void (*MyCallback_t) (CallbackInfo);
class MyClass
{...
void setcallback(MyCallback_t cb);
...
}
And to use it in python :
import mylib
def myCallback(mylib_CallbackInfo):
...
t = mylib.MyClass()
t.setcallback(myCallback)
I saw some topics near my problem but couldn't solve it
For example here :
Realtime processing and callbacks with Python and C++ there is advice to use boost::python and warning about GLI but no examples.
And here
How to call a python function from a foreign language thread (C++) there is no full description with python code part and with "BOOST_PYTHON_MODULE" part
I also found link to use py_boost_function.hpp for example in Boost python howto but it didn't compile and actualy I couldn't understand how to use it.
Ok, I'm still trying to figure this out too, but here's whats working for me so far:
#this is the variable that will hold a reference to the python function
PyObject *py_callback;
#the following function will invoked from python to populate the call back reference
PyObject *set_py_callback(PyObject *callable)
{
py_callback = callable; /* Remember new callback */
return Py_None;
}
...
#Initialize and acquire the global interpreter lock
PyEval_InitThreads();
#Ensure that the current thread is ready to call the Python C API
PyGILState_STATE state = PyGILState_Ensure();
#invoke the python function
boost::python::call<void>(py_callback);
#release the global interpreter lock so other threads can resume execution
PyGILState_Release(state);
The python function is invoked from C++, and executes as expected.
These test files from the boost::python source code repository contains great examples about how to pass callbacks from Python into C++:
https://github.com/boostorg/python/blob/develop/test/callbacks.cpp
https://github.com/boostorg/python/blob/develop/test/callbacks.py

Embedding Python and adding C functions to the interpreter

I'm currently writing an applications that embedds the python interpreter. The idea is to have the program call user specified scripts on certain events in the program. I managed this part but now I want the scripts to be able to call functions in my program.
Here's my code so far:
#include "python.h"
static PyObject* myTest(PyObject* self,PyObject *args)
{
return Py_BuildValue("s","123456789");
}
static PyMethodDef myMethods[] = {{"myTest",myTest},{NULL,NULL}};
int main()
{
Py_Initialize();
Py_InitModule("PROGRAM",myMethods);
PyRun_SimpleString("print PROGRAM.myTest()");
Py_Finalize();
}
Thanks!
You need to bind that function to some module, see http://docs.python.org/extending/embedding.html#extending-embedded-python
Edit:
Basicly your code should work. Whats not working?