diff --git a/libraries/dl-streamer/src/monolithic/gst/elements/gvapython/python_callback.cpp b/libraries/dl-streamer/src/monolithic/gst/elements/gvapython/python_callback.cpp index eb01f722a..1d922c85c 100644 --- a/libraries/dl-streamer/src/monolithic/gst/elements/gvapython/python_callback.cpp +++ b/libraries/dl-streamer/src/monolithic/gst/elements/gvapython/python_callback.cpp @@ -54,6 +54,92 @@ 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) { + PyErr_Print(); + if (pStr) + delete[] pStr; + 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)) { + PyErr_Print(); + } + } + + if (pStr) + delete[] pStr; + + return NULL; +} + PythonContextInitializer::PythonContextInitializer() { state = PyGILState_UNLOCKED; if (Py_IsInitialized()) { @@ -122,7 +208,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));