4

Importing Python modules from files is relatively easy with the Python C API with PyImport_Import() however I would need to use functions stored in strings. Is there a way to import python modules from strings (to clarify: there is no file; the code is in a string) or will I have to save the strings as temp files?

Walter Nissen
  • 16,451
  • 4
  • 26
  • 27
Hullu2000
  • 261
  • 4
  • 19

3 Answers3

4

No need to use temp files. Use this code:

const char *MyModuleName = "blah";
const char *MyModuleCode = "print 'Hello world!'";
PyObject *pyModule = PyModule_New(MyModuleName);
// Set properties on the new module object
PyModule_AddStringConstant(pyModule, "__file__", "");
PyObject *localDict = PyModule_GetDict(pyModule);   // Returns a borrowed reference: no need to Py_DECREF() it once we are done
PyObject *builtins = PyEval_GetBuiltins();  // Returns a borrowed reference: no need to Py_DECREF() it once we are done
PyDict_SetItemString(localDict, "__builtins__", builtins);

// Define code in the newly created module
PyObject *pyValue = PyRun_String(MyModuleCode, Py_file_input, localDict, localDict);
if (pyValue == NULL) {
    // Handle error
}
else
    Py_DECREF(pyValue);

This is code taken from a real commercial application (I've slightly modified it by removing error handling and other non-needed details). Just set the wanted module name in MyModuleName and the Python code in MyModuleCode and you are done!

gog
  • 1,220
  • 11
  • 30
1

If my understanding is correct, you could use PyImport_ImportModule which takes a const char* name to specify the module to be imported.

Since my understanding was incorrect:

It would generally be better to dump the contents to a .py file and then execute them with PyRun_File but, if you have strings and want to work with those I guess you could use Py_CompileString to compile it to a code object and then feed it to PyEval_EvalCode for evaluation.

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
0

I've had success following the strategy laid out by Dimitirs.

            Py_Initialize();
            PyObject *module = Py_CompileString(
                // language: Python
                R"EOT(
fake_policy = {
      "maxConnections": 4,
      "policyDir": "/tmp",
      "enableVhostPolicy": True,
      "enableVhostNamePatterns": False,
})EOT",
                "test_module", Py_file_input);
            REQUIRE(module != nullptr);

            PyObject *pModuleObj = PyImport_ExecCodeModule("test_module", module);
            REQUIRE(pModuleObj != nullptr);
            // better to check with an if, use PyErr_Print() or such to read the error

            PyObject *pAttrObj = PyObject_GetAttrString(pModuleObj, "fake_policy");
            REQUIRE(pAttrObj != nullptr);

            auto *entity = reinterpret_cast<qd_entity_t *>(pAttrObj);
            REQUIRE(qd_entity_has(entity, "enableVhostNamePatterns"));  // sanity check for the test input

            // call Py_DecRef s

I used https://awasu.com/weblog/embedding-python/calling-python-code-from-your-program/ as another reference, when writing this.

user7610
  • 25,267
  • 15
  • 124
  • 150