14

I'm using boost::python to embed some python code into an app. I was able to get print statements or other expressions to be evaluated properly, but when I try to import modules, it is not importing and application is exiting. Further the globals() function call in the embedded code gives a runtime error too.

#include <boost/python.hpp>

using namespace boost;
using namespace boost::python;
using namespace boost::python::api;

int main(void) {
    Py_Initialize();
    object main_module = import("__main__");
    object main_namespace = main_module.attr("__dict__");
    main_namespace["urllib2"] = import("urllib2");

    object ignored = exec(
            "print 'time'\n", main_namespace);
}

Here, I've tried to import urllib2 using the boost import function, this compiles and runs properly, but with the following exec statement, it gives an error.

    object ignored = exec(
            "print urllib2\n"
            "print 'time'\n", main_namespace);

Or when I remove the boost import function and do the import from within the embedded code also, it gives an error. I tried using a try: except: block but that doesn't work either. Is this because the C++ app isn't able to find the location of the urllib2 py module or something? Is there a way to set the path of the module before trying to import?

This is being built only for internal use, so some hard coding of the paths is acceptable.

Edit: More info:
This is what happens. I did a try .. catch and called the PyErr_Print() when ever there is an exception, and got this as error all the time when there are module imports or even function calls. Error message:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: 'NoneType' object does not support item assignment

Can anyone think of any reason?

Piotr Dobrogost
  • 41,292
  • 40
  • 236
  • 366
Sahas
  • 10,637
  • 9
  • 41
  • 51

3 Answers3

5

If you haven't already, you need to

import sys
sys.path.append("/home/user/whatever")

That took care of my problems a couple of years ago when embedding boost::python (Python v2.5).

Edit:

Poked around in old code. Perhaps this does the trick:

Py_SetProgramName(argv[0]);
Py_InitializeEx(0);

Sounds unsure that you should really need the Py_SetProgramName(), but I faintly remember some fishy business there.

Jonas Byström
  • 25,316
  • 23
  • 100
  • 147
  • Thanks for the response, and really for the delay in trying it and telling you, Jonas. I tried it but this wasn't helping. I'm not even able to to get the program to run if it has this single statement "print globals()\n". I tried the same code on windows and linux, and same response everywhere. I'm using Boost 1.39.0 – Sahas Jun 07 '09 at 05:25
  • 1
    I was having a mysterious segmentation fault when importing certain libraries (such as gzip or numpy). Then this hack solves the problem like a charm: `Py_SetProgramName("");` `Py_InitializeEx(0);` Thanks @Jonas – anh_ng8 Oct 02 '14 at 05:56
5

That didn't help, but I found a different solution to my problem. My current code looks like this:

#include <boost/python.hpp>
#include <iostream>

using namespace std;
using namespace boost;
using namespace boost::python;
using namespace boost::python::api;

int main(void) {
        Py_Initialize();
        boost::python::object http = boost::python::import("urllib2");

        try
        {
                boost::python::object response = http.attr("urlopen")("http://www.google.com");
                boost::python::object read = response.attr("read")();
                std::string strResponse = boost::python::extract<string>(read);
                cout << strResponse << endl;
        }
        catch(...)
        {
                PyErr_Print();
                PyErr_Clear();
        }
}

Anyways, thanks for the answer Jonas

Sahas
  • 10,637
  • 9
  • 41
  • 51
  • Glad you got your code working. What do you want to do with it? – Jonas Byström Jun 15 '09 at 16:31
  • 1
    Oh. I was totally sick of the C++ sockets libraries. They need time to understand, and since I'm not a computers student, I take longer to understand. So I created something that feels like an asynchronous urllib++ with the python urllib2 in the back. :D I know it sounds crazy. But I have an extremely convenient solution now! – Sahas Jun 15 '09 at 17:17
1

I ran into the same problem as you, i e a very simple example resulting in the TypeError, and found the answer in this question, which was to supply the namespace twice, both as global and local.

Community
  • 1
  • 1
Magnus Österlind
  • 1,380
  • 1
  • 12
  • 13