Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,91 @@ gboolean callPython(GstBuffer *buffer, GstCaps *caps, PyObjectWrapper &py_frame_
}
} // namespace

// This function safely imports a Python module from a given file path using Python's importlib.
// It generates and executes Python code to load the module, handling errors and reporting them.
// Arguments:
// module_name - the name to assign to the imported module in sys.modules
// file_path - the path to the Python file (without .py extension)
// Returns:
// A PyObject* pointer to the imported module, or NULL on error.
PyObject *import_module_full_path(const char *module_name, const char *file_path) {
// Allocate memory for the file path with .py extension
char *pStr = new char[strlen(file_path) + 3];
sprintf(pStr, "%s.py", file_path);

// Prepare Python code to import the module safely
char python_code[4096];
snprintf(python_code, sizeof(python_code),
"import importlib.util\n"
"import sys\n"
"import os\n"
"\n"
"module_name = '%s'\n"
"file_path = r'%s'\n"
"\n"
"try:\n"
" # Check if file exists\n"
" if not os.path.exists(file_path):\n"
" raise FileNotFoundError(f'Python module file not found: {file_path}')\n"
" \n"
" # Create spec\n"
" spec = importlib.util.spec_from_file_location(module_name, file_path)\n"
" if spec is None:\n"
" raise ImportError(f'Cannot create spec for {file_path}')\n"
" \n"
" # Create module\n"
" module = importlib.util.module_from_spec(spec)\n"
" if module is None:\n"
" raise ImportError('Cannot create module from spec')\n"
" \n"
" # Add to sys.modules\n"
" sys.modules[module_name] = module\n"
" \n"
" # Execute module\n"
" spec.loader.exec_module(module)\n"
" \n"
" imported_module = module\n"
" success = True\n"
" error_msg = 'OK'\n"
"\n"
"except Exception as e:\n"
" imported_module = None\n"
" success = False\n"
" error_msg = f'{type(e).__name__}: {str(e)}'\n",
module_name, pStr);

PyObject *main_module = PyImport_AddModule("__main__");
PyObject *main_dict = PyModule_GetDict(main_module);

if (PyRun_String(python_code, Py_file_input, main_dict, main_dict) == NULL) {
printf("Error PyRun_String\n");
PyErr_Print();
return NULL;
}

// Check result
PyObject *success = PyDict_GetItemString(main_dict, "success");
if (success && success == Py_True) {
PyObject *module = PyDict_GetItemString(main_dict, "imported_module");
if (module != NULL) {
Py_INCREF(module);
if (pStr)
delete[] pStr;
return module;
}
} else {
PyObject *error = PyDict_GetItemString(main_dict, "error_msg");
if (error && PyUnicode_Check(error)) {
printf("Error: %s\n", PyUnicode_AsUTF8(error));
}
}

if (pStr)
delete[] pStr;

return NULL;
}

PythonContextInitializer::PythonContextInitializer() {
state = PyGILState_UNLOCKED;
if (Py_IsInitialized()) {
Expand Down Expand Up @@ -122,7 +207,7 @@ PythonCallback::PythonCallback(const char *module_path, const char *class_name,
module_name = std::string(filename, extension);
}

PyObjectWrapper pluginModule(PyImport_Import(WRAPPER(PyUnicode_FromString(module_name.c_str()))));
PyObjectWrapper pluginModule = import_module_full_path(module_name.c_str(), module_path);
if (!(PyObject *)pluginModule) {
log_python_error(nullptr, false);
throw std::runtime_error("Error loading Python module " + std::string(module_path));
Expand Down
Loading