5

I would like to create an embedded python 3 interpreter and let python scripts import modules created via the C Python API.

No problem to create a "top-level" module, but now I would like to organized my modules in packages ... But I failed.

Here is my current (simple) code :

#include <Python.h>

//// Definition of 'emb.sub' module
static PyObject* emb_sub_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am sub foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbSubMethods[] = {
    {"foo", emb_sub_foo, METH_VARARGS, "Returns sub foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbSubModule = {
    PyModuleDef_HEAD_INIT, "emb.sub", NULL, -1, EmbSubMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb_sub(void)
{
    return PyModule_Create(&EmbSubModule);
}

//// Embedded Python
int main()
{
    PyImport_AppendInittab("emb.emb", &PyInit_emb_sub);
    Py_Initialize();

    PyRun_SimpleString("import emb.sub\n");

    Py_Finalize();
    return 0;
}

When I executes the program, I get :

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named 'emb'

So I create an empty emb module, and I set its __path__ like this :

#include <Python.h>

//// Definition of 'emb' module
static PyModuleDef EmbModule = {
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, NULL,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void)
{
    PyObject *mod = PyModule_Create(&EmbModule);
    PyModule_AddObject(mod, "__path__", Py_BuildValue("()"));

    return mod;
}

//// Definition of 'emb.sub' module
static PyObject* emb_sub_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am sub foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbSubMethods[] = {
    {"foo", emb_sub_foo, METH_VARARGS, "Returns sub foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbSubModule = {
    PyModuleDef_HEAD_INIT, "emb.sub", NULL, -1, EmbSubMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb_sub(void)
{
    return PyModule_Create(&EmbSubModule);
}

//// Embedded Python
int main()
{
    PyImport_AppendInittab("emb", &PyInit_emb);
    PyImport_AppendInittab("emb.sub", &PyInit_emb_sub);
    Py_Initialize();

    PyRun_SimpleString("import emb.sub\n");

    Py_Finalize();
    return 0;
}

And now I get this error :

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named 'emb.sub'

I would like to know if it is possible to create a hierarchy of packages and modules in embedded python ?

Thanks !

2
  • 1
    Did you ever find a solution? Commented Jan 28, 2018 at 21:52
  • @Ha11owed Finally I did not used packages but accepted response works. Commented Mar 7, 2018 at 8:16

1 Answer 1

6

As far as I can tell the default builtin module handling fails to match against package+module names. This can be worked around by adding a custom import hook that does, just run this after Py_Initialize():

PyRun_SimpleString(
    "import importlib.abc\n" \
    "import importlib.machinery\n" \
    "import sys\n" \
    "\n" \
    "\n" \
    "class Finder(importlib.abc.MetaPathFinder):\n" \
    "    def find_spec(self, fullname, path, target=None):\n" \
    "        if fullname in sys.builtin_module_names:\n" \
    "            return importlib.machinery.ModuleSpec(\n" \
    "                fullname,\n" \
    "                importlib.machinery.BuiltinImporter,\n" \
    "            )\n" \
    "\n" \
    "\n" \
    "sys.meta_path.append(Finder())\n" \
);

I tried this with your complete code with success:

#include <Python.h>

//// Definition of 'emb' module
static PyModuleDef EmbModule = {
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, NULL,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void)
{
    PyObject *mod = PyModule_Create(&EmbModule);
    PyModule_AddObject(mod, "__path__", Py_BuildValue("()"));

    return mod;
}

//// Definition of 'emb.sub' module
static PyObject* emb_sub_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am sub foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbSubMethods[] = {
    {"foo", emb_sub_foo, METH_VARARGS, "Returns sub foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbSubModule = {
    PyModuleDef_HEAD_INIT, "emb.sub", NULL, -1, EmbSubMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb_sub(void)
{
    return PyModule_Create(&EmbSubModule);
}

//// Embedded Python
int main()
{
    PyImport_AppendInittab("emb", &PyInit_emb);
    PyImport_AppendInittab("emb.sub", &PyInit_emb_sub);
    Py_Initialize();

    PyRun_SimpleString(
        "import importlib.abc\n" \
        "import importlib.machinery\n" \
        "import sys\n" \
        "\n" \
        "\n" \
        "class Finder(importlib.abc.MetaPathFinder):\n" \
        "    def find_spec(self, fullname, path, target=None):\n" \
        "        if fullname in sys.builtin_module_names:\n" \
        "            return importlib.machinery.ModuleSpec(\n" \
        "                fullname,\n" \
        "                importlib.machinery.BuiltinImporter,\n" \
        "            )\n" \
        "\n" \
        "\n" \
        "sys.meta_path.append(Finder())\n" \
    );

    PyRun_SimpleString("import emb.sub\n");
    PyRun_SimpleString("print(emb.sub.foo())\n");

    Py_Finalize();
    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.