Embedding Python into C - python

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.

Related

C++ Boost::Python Py_Initialize throwing Assertion Failed on object.c

I am trying to embed the Python 3.5 interpreter in a C++ program with Boost 1.76.0. While doing this, I am having issues as the program throws an assertion failed at the Py_Initialize();
Assertion failed: (op->_ob_prev == NULL) == (op->_ob_next == NULL), file ..\Objects\object.c, line 84
The minimal code in which this happens is as follows:
#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>
#include <Python.h>
int main(int argc, char** argv)
{
try
{
Py_Initialize();
}
catch (boost::python::error_already_set& e)
{
PyErr_PrintEx(0);
return 1;
}
return 0;
}
Looking online I found other few occurrences with no answers tho. Any ideas why this is happening?
As it turns out, the include order is important. I could not find any notes on this on the Boost documentation and examples, so I will add this here: putting the #include <Python.h> before the #include <boost/python.hpp> fixed the issue for me.
If anyone has some insight on how this happens, please feel free to add more details.
I also found this (C++ including python.h and boost/python.hpp causes SEH exception) so I don't know if I am just lucky it works, if this has been fixed in later versions of Boost or something else.
Update 1: Trying to just remove #include <Python.h> causes the error to present itself again. Is this a Boost bug/compilation issue?
Update 2: I have indeed incountered an issue as said in the aforementioned question, in particular when importing a python script. So I am back to mile 0, does anyone have any ideas?
Update 3: I tried to use precompiled DLLs, use other versions of Python, but I still keep getting this issue. I am really at a loss of ideas.

Pybind11 embedded module does not run when imported

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.

Embedding python 3.4 into C++ Qt Application?

I'm making an Qt Quick GUI application(for windows), which uses OpenGL and C++ for some computationally intensive stuff. I want to embed python code into the app, for doing some stuff which is comparatively easier in python.
Basically, I just want the c++ code to call a function in a python script and let the script do the job, then store the returned data in a variable(string, or float etc.) for further use. I'm using Qt creator, and I got python3 lib for MinGW compiler. I tried some code, but its looks like python lib is not quite compatible with Qt creator. IS using pyqt for this will be a good idea? What will be the best and easiest way to do this ?
EDIT: This is the basic code I tried, first it gave me an error saying, cannot find pyconfig.h. Then I added an INCUDEPATH to my python34 include directory.
#include "mainwindow.h"
#include <QApplication>
#include <boost/python.hpp>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
using namespace boost::python;
PyObject *pName, *pModule, *pDict, *pFunc, *pValue;
Py_Initialize();
pName = PyString_FromString(argv[1]);
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, argv[2]);
if (PyCallable_Check(pFunc))
{
PyObject_CallObject(pFunc, NULL);
} else
{
PyErr_Print();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
Py_Finalize();
return a.exec();
}
My .pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = TestWidgetApp
TEMPLATE = app
INCLUDEPATH += C:/boost_1_57_0
INCLUDEPATH += C:/Python34/include
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
OTHER_FILES +=
Then the following errors:
C:\Python34\include\object.h:435: error: C2059: syntax error : ';'
C:\Python34\include\object.h:435: error: C2238: unexpected token(s) preceding ';'
C:\Users\Amol\Desktop\TestWidgetApp\main.cpp:19: error: C3861: 'PyString_FromString': identifier not found
The problem here is that Python 3.4 has a struct member called "slots", (file object.h, in the typedef for PyType_Spec), which Qt defines out from under you so that you can say things like:
public slots:
in your code. The solution is to add:
#undef slots
just before you include Python.h, and to redefine it before you include anything that uses "slots" in the way that Qt does:
#undef slots
#include <Python.h>
#define slots
#include "myinclude.h"
#include <QString>
A bit of a hack (because you're depending on a particular definition of slots in Qt), but it should get you going.
I have removed all the Qt code from your example and then I tried to compile it (Qt has nothing to do with your compile error). And it compiles for me. The difference was I used the include files from Python 2.7.
So I did a little search for the string PyString_FromString in the folders: C:\Python33\includes (I noted you use python 3.4 and not 3.3 but I suspect this is a 3.x thing) and C:\Python27\includes.
Results:
Python 3.3
Python 2.7
So, apparently, Python 3.4 is not supported by your BoostPython version.
Python3 has no PyString_FromString function. Python3 str type internally is unicode objects with complex structure.
Use PyUnicode_FromString or PyUnicode_FromStringAndSize for constructing str object from UTF-8 encoded C string (char*).
Move your
#include "boost/python.hpp"
...to be before your other includes and it will resolve your problem.
The actual issue is as Scott Deerwester described in his answer.

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".

Redirect Embedded Python IO to a console created with AllocConsole

I am having some trouble getting Python IO redirected to a console that I've allocated for my Win32 app. Is there a Python-specific stream that I need to redirect?
Here's more-or-less what I'm doing now (error checking removed, etc.):
int __stdcall WinMain(/*Usual stuff here*/) {
// Create the console
AllocConsole();
SetConsoleTitle(L"My Console");
// Redirect Standard IO Streams to the new console
freopen("CONOUT$","w",stdout);
freopen("CONOUT$","w",stderr);
freopen("CONIN$","r",stdin);
// Test the console:
printf("This Works.\r\n");
cout << "So Does this" << endl;
// Python Stuff (This is where it fails)
Py_Initialize();
PyRun_SimpleString("print('I don't work.')\n");
Py_Finalize();
}
If I run the same thing but as a console app (Visual Studio 05, BTW) and remove the AllocConsole call everything works. Anyone know what I'm missing?
EDIT: Just for clarification, I am looking for a way to do it from the C API.
YET ANOTHER EDIT: Alex's solution is correct, but for anyone out there using Python 3.x you'll probably notice that the PyFile_FromString function is missing in the new API. While it may not be the best alternative, I found that this works fine in Python 3.x:
PyObject* sys = PyImport_ImportModule("sys");
PyObject* io = PyImport_ImportModule("io");
PyObject* pystdout = PyObject_CallMethod(io, "open", "ss", "CONOUT$", "wt");
if (-1 == PyObject_SetAttrString(sys, "stdout", pystdout)) {
/* Announce your error to the world */
}
Py_DECREF(sys);
Py_DECREF(io);
Py_DECREF(pystdout);
Set sys.stdout on the Python side (presumably to an open('CONOUT$', 'wt')) to make Python's print work, and similarly for sys.stderr and sys.stdin. (There are faster ways to make this happen from a C extension, but the simplest way is to just execute the Python statements, with a import sys in front;-).
Why: because Python's runtime, on startup, found the standard FDs closed, set sys.stdout and friends accordingly, and is not going to check again and set them differently -- so you just set them yourself, explicitly, and it will be fine.
If you're keen to do it all at C-API level, it will take a few lines, but of course it can be done...
PyObject* sys = PyImport_ImportModule("sys");
PyObject* pystdout = PyFile_FromString("CONOUT$", "wt");
if (-1 == PyObject_SetAttrString(sys, "stdout", pystdout)) {
/* raise errors and wail very loud */
}
Py_DECREF(sys);
Py_DECREF(pystdout);
this is the exact equivalent of the single Python line:
sys.stdout = open('CONOUT$', 'wt')
It is much easier to just tell the embedded python to redirect its output to a file.
Try this code:
PyRun_SimpleString("import sys\n");
PyRun_SimpleString( "sys.stdout = sys.stderr = open(\"C:\\embedded_log_file.txt\", \"w\")\n" );

Categories

Resources