Pybind11 embedded module does not run when imported - python

I'm losing many many hours trying to the find the reason why my imported module does not work.
py_actor.cpp:
#include <pybind11/embed.h>
#include "py_actor.h"
namespace py = pybind11;
void Py_AddSpeed(double speed)
{
py_speed = speed;
}
PYBIND11_EMBEDDED_MODULE(py_actor, m) {
m.def("Py_AddSpeed", &Py_AddSpeed, "A function that adds speed to all actors");
}
test.py (In the same folder of the compiled py_actor.cpython-38-x86_64-linux-gnu.so):
from py_actor import Py_AddSpeed
speed = 16.0
print('UPDATING SPEEED!')
Py_AddSpeed(speed)
Somewhere in main:
py::scoped_interpreter guard{}; // start the interpreter and keep it alive
py::print("Hello, World! GZDoom now runs Python :)"); // use the Python API
py::module test = py::module::import("test");
Does the py::print work? Yes! Does the "Updating Speed" work? No! Why? I have no idea. I've recompiled the project like, a thousand times now and the imported module does not "run". I've even tried this:
py::exec(R"(
import test
print('Speeedd')
print(test.speed)
)");
Nothing, no import errors, and no results either. What am I doing wrong?

I've found out what the problem was by doing
py::module test = py::module::import("test");
py::print(test.attr("__file__"));
It was then that I realized that there was a conflict with some internal module, and I renamed the module to "_test" and it worked. I hope this can save someone in the future.

Related

Using pybind11 within C++ in JUCE Framework

I'm trying to read a string list output from a Python script, in order to pass it to a JUCE MainComponent (written in C++).
The code is the following (which is a starting one, just to test the pybind library):
#include <pybind11/embed.h>
#include <pybind11/pybind11.h>
namespace py = pybind11;
MainComponent::MainComponent()
{
auto math = py::module::import("math");
auto resultobj = math.attr("sqrt")(2);
double result = resultobj.cast<double>();
}
However, I always encounter the following error:
_PyRuntime.gc.**generation0** was nullptr.
Any suggestions? Thanks in advance
You have to first initialize the Python interpreter, like this:
MainComponent::MainComponent()
{
py::scoped_interpreter guard{};
auto math = py::module::import("math");
auto resultobj = math.attr("sqrt")(2);
double result = resultobj.cast<double>();
}
You also have to link with the needed python libraries. In CMake, this means adding
target_link_libraries(your_target PRIVATE pybind11::embed)
to your CMakeLists.txt file.

How can I save a python function to a static c++ container using pybind11?

Essentially, on the C++ side I have a container that holds a certain type of function. Now I would like to expose this container to python with the possibility for the users to provide their own python functions.
The simplest example would look like this:
#include "pybind/common/Common.h"
using CppFunc = std::function< int (int) >;
PYBIND11_MODULE( test, m )
{
m.def("addFunc", [](const pybind11::function& f){
static std::vector<CppFunc> vec{};
vec.push_back(f.cast<CppFunc>());
});
}
Then in python I would like to just do something like this.
import test
def myFunc(number):
return number+1
test.addFunc(myFunc)
Interestingly enough, this works fine. However, if I run the script with "python script.py" it runs through and then never terminates. In an interactive console, the same code works fine until you try to close the console: the process gets stuck.
How can I safely store this python function in the C++ container?
static std::vector<CppFunc> vec{} stores references to python objects (user functions) which never get released due to static storage, therefore interpreter cannot terminate.
To ensure interpreter termination you can call a cleanup function at module termination:
#include "pybind11/pybind11.h"
#include "pybind11/functional.h"
namespace py = pybind11;
using CppFunc = std::function< int (int) >;
PYBIND11_MODULE( test , m )
{
static std::vector<CppFunc> vec{};
m.def("addFunc", [](CppFunc f){
vec.push_back(std::move(f));
});
m.add_object("_cleanup", py::capsule([]{ vec.clear(); }));
}
See doc for more details: https://pybind11.readthedocs.io/en/stable/advanced/misc.html#module-destructors

How to import boost module from C++ to python?

Following is the c++ code which I want to import.
#include <boost/python.hpp>
#include <string>
/*
* This is the C++ function we write and want to expose to Python.
*/
const std::string hello() {
return std::string("hello, zoo");
}
/*
* This is a macro Boost.Python provides to signify a Python extension module.
*/
BOOST_PYTHON_MODULE(zoo) {
// An established convention for using boost.python.
using namespace boost::python;
// Expose the function hello().
def("hello", hello);
}
The following code is python script.
import zoo # In zoo.cpp we expose hello() function, and it now exists
in the zoo module.
assert 'hello' in dir(zoo) # zoo.hello is a callable.
assert callable(zoo.hello) # Call the C++ hello() function from Python.
print zoo.hello()
When I try to run the script, I am not getting "hello, zoo" at the terminal as output. Where am I making the mistake?
Following is the error message I am getting:
import: not authorized zoo' # error/constitute.c/WriteImage/1028.
./visit_zoo.py: line 3: syntax error near unexpected token('
./visit_zoo.py: line 3: `assert 'hello' in dir(zoo)'
Aren't you forgetting to indicate the script should be run by Python, as I did?
You can either include the python executable in the header of your script file:
#!/usr/bin/env python2
and make the file executable or call the script with Python:
$ python <filename>

PyObject_GetAttrString C++ function returning NULL: Unable to call Python functions from C++

I've just started working with Python with C++ and I'm a bit confused on why I'm unable to call functions in Python from C++.
Here is my current test code in C++:
#include <iostream>
#include <Python.h>
using namespace std;
int main()
{
Py_Initialize();
PyObject* myModuleString = PyString_FromString("test");
PyObject* myModule = PyImport_Import(myModuleString);
if( myModule )
{
PyObject* myFunction = PyObject_GetAttrString(myModule, "Hello");
if( myFunction )
{
PyEval_CallObject( myFunction, NULL );
}
else
{
fprintf( stderr, "myFunction is NULL" );
}
}
else
{
fprintf( stderr, "myModule is NULL" );
}
Py_Finalize();
cin.get();
return 0;
}
Here is my test.py Python code:
import sys
def Hello():
print "Hello, world!"
Before I had a more complicated test, but I ran into an issue where PyObject_GetAttrString passed back NULL, so I wanted to make a simpler test and I still received NULL after calling PyObject_GetAttrString. From my understanding PyObject_GetAttrString gets you the PyObject* to the function and then I call it after, so receiving NULL there basically means I can't call the function.
Also yes I have looked at https://docs.python.org/2.7/ and even tested the example given in step 5.3 of https://docs.python.org/release/2.6.5/extending/embedding.html#pure-embedding (I'm using 2.7.7 because I'm planning to integrate with 3ds Max ). It still runs into the same issues with PyObject_GetAttrString.
I'm assuming it's a simple mistake or step I'm missing in the C++ or Python code.
Changing the Python script name from test.py to anything else worked for me.
I was having a similar problem. I found that the whitespace in the string I was passing to python was way off. From what I could tell, your print statement has 6 spaces in lieu of 4. Back it up and see if everything doesn't clear up.
I had the same problem. Although test.py and mycode.c were in the same folder (/home/user/python/example), I had to add a reference to the path after Py_Initialize(); as shown in following line
PyRun_SimpleString ("import sys; sys.path.insert(0, '/home/user/python/spp')");*
Replace /home... to your path.
My previous code did not have that line of code but PyImport_Importwas working and PyObject_GetAttrString wasn't. Makes no sense to me, "don't ask me, I don't know - Ozzy".

Embedding Python into C

Win7 x64, Python3.3 32bit, Visual Studio 2010/2012 (same behavior). The following code compiles and runs just fine (i.e. prints current date):
extern "C"{ // not having it doesn't make any difference either
#include <Python.h>
}
int main() {
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
Py_Finalize();
return 0;
}
while this here fails with a MessageBox saying The application was unable to start correctly (0xc0000005). Click OK to close the application. before main executed (so no breakpoint possible).
extern "C"{ // not having it doesn't make any difference either
#include <Python.h>
}
int main() {
Py_Initialize();
PyObject *p = PyUnicode_FromString("test");
Py_Finalize();
return 0;
}
So the problem seems to have been the following: I was linking with python3.lib but since the string functions were completely overworked with Python3.3 there seemed to have been some problem with correctly linking them. (can't really explain why this would be so, since PyUnicode_FromString existed obviously in earlier versions of python3 too).
Why I couldn't get a useful error message about that fact is also beyond me, but there we go: linking against python33.lib solved the problem perfectly.
I think this could be for 2 reasons, but I'm pretty sure its this one:
http://docs.python.org/2/c-api/unicode.html
You need to null terminate y our constant string "test" by making it "test\0". If that doesn't work, it might have to do with the fact that c files are ansi and not utf8.
Your broken program is linking against a build of Python that uses UCS-2 as the internal unicode representation, but the installed Python uses UCS-4, and therefore the PyUnicodeUCS2_* imports can't be resolved. You'll need to link against the UCS-4 build instead.

Categories

Resources