Base: [skip ci] Various fixes in InterpreterSingleton::runStringWithKey:

+ fix memory leak (localDictionary) by replacing C API with PyCXX
+ don't write the whole code as error message if an error occurs. Python raises an exception with all relevant information for debugging
This commit is contained in:
wmayer
2020-09-04 09:58:21 +02:00
parent cc0e4ee953
commit 1c91c1287e

View File

@@ -303,44 +303,33 @@ std::string InterpreterSingleton::runString(const char *sCmd)
* if the error occurs after changing it inside the script.
*/
std::string InterpreterSingleton::runStringWithKey(const char *psCmd, const char *key, const char *key_initial_value){
std::string InterpreterSingleton::runStringWithKey(const char *psCmd, const char *key, const char *key_initial_value)
{
PyGILStateLocker locker;
PyObject* main = PP_Load_Module("__main__");
if (main == NULL)
throw PyException();
PyObject* globalDictionary = PyModule_GetDict(main);
if (globalDictionary == NULL)
throw PyException();
PyObject* localDictionary = PyDict_New();
if (localDictionary == NULL)
throw PyException();
PyObject* initial_value = PyUnicode_FromString(key_initial_value);
PyDict_SetItemString(localDictionary, key, initial_value);
PyObject* presult = PyRun_String(psCmd, Py_file_input, globalDictionary, localDictionary);
Py::Module module("__main__");
Py::Dict globalDictionary = module.getDict();
Py::Dict localDictionary;
Py::String initial_value(key_initial_value);
localDictionary.setItem(key, initial_value);
PyObject* presult = PyRun_String(psCmd, Py_file_input, globalDictionary.ptr(), localDictionary.ptr());
if (!presult) {
if (PyErr_ExceptionMatches(PyExc_SystemExit))
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
throw SystemExitException();
}
else {
Base::Console().Error("Python exception within Base::Interpreter().runStringWithKey()\nScript:\n");
Base::Console().Error(psCmd);
PyException::ThrowException();
return std::string(); // just to quieten code analyzers
//throw PyException();
}
}
Py_DECREF(presult);
PyObject* key_return_value = PyDict_GetItemString(localDictionary, key);
#if PY_MAJOR_VERSION >= 3
PyObject* str = PyUnicode_AsEncodedString(key_return_value, "utf-8", "~E~");
#else
PyObject* str = PyObject_Str(key_return_value);
#endif
const char* result = PyBytes_AS_STRING(str);
if(str){
Py_DECREF(str);
}
Py::Object key_return_value = localDictionary.getItem(key);
if (!key_return_value.isString())
key_return_value = key_return_value.str();
Py::Bytes str = Py::String(key_return_value).encode("utf-8", "~E~");
std::string result = static_cast<std::string>(str);
return result;
}