[英]How to reinitialise an embedded Python interpreter?
I'm working on embedding Python in our test suite application. 我正在努力在我们的测试套件应用程序中嵌入Python。 The purpose is to use Python to run several tests scripts to collect data and make a report of tests.
目的是使用Python运行多个测试脚本来收集数据并生成测试报告。 Multiple test scripts for one test run can create global variables and functions that can be used in the next script.
一次测试运行的多个测试脚本可以创建可在下一个脚本中使用的全局变量和函数。
The application also provides extension modules that are imported in the embedded interpreter, and are used to exchange some data with the application. 该应用程序还提供在嵌入式解释器中导入的扩展模块,用于与应用程序交换某些数据。
But the user can also make multiple test runs. 但是用户也可以进行多次测试运行。 I don't want to share those globals, imports and the exchanged data between multiple test runs.
我不想在多次测试运行之间共享那些全局变量,导入和交换的数据。 I have to be sure I restart in a genuine state to control the test environment and get the same results.
我必须确保我以真实状态重新启动以控制测试环境并获得相同的结果。
How should I reinitialise the interpreter? 我该如何重新初始化翻译?
I used Py_Initialize() and Py_Finalize(), but get an exception on the second run when initialising a second time the extension modules I provide to the interpreter. 我使用了Py_Initialize()和Py_Finalize(),但在第二次运行时,我第二次将我提供给解释器的扩展模块初始化时获得异常。 And the documentation warns against using it more than once .
文档警告不要多次使用它 。
Using sub-interpreters seems to have the same caveats with extension modules initialization. 使用子解释器似乎与扩展模块初始化具有相同的警告。
I suspect that I'm doing something wrong with the initialisation of my extension modules, but I fear that the same problem happens with 3rd party extension modules. 我怀疑我的扩展模块初始化时出了问题,但我担心第三方扩展模块会出现同样的问题。
Maybe it's possible to get it to work by launching the interpreter in it's own process, so as to be sure that all the memory is released. 也许可以通过在其自己的进程中启动解释器来使其工作,以确保释放所有内存。
By the way, I'm using boost-python for it, that also warns AGAINST using Py_Finalize! 顺便说一句,我正在使用boost-python,它也使用Py_Finalize警告AGAINST!
Any suggestion? 有什么建议吗?
Thanks 谢谢
Here is another way I found to achieve what I want, start with a clean slate in the interpreter. 这是我发现实现我想要的另一种方式,从解释器中的一个干净的石板开始。
I can control the global and local namespaces I use to execute the code: 我可以控制用于执行代码的全局和本地命名空间:
// get the dictionary from the main module
// Get pointer to main module of python script
object main_module = import("__main__");
// Get dictionary of main module (contains all variables and stuff)
object main_namespace = main_module.attr("__dict__");
// define the dictionaries to use in the interpreter
dict global_namespace;
dict local_namespace;
// add the builtins
global_namespace["__builtins__"] = main_namespace["__builtins__"];
I can then use use the namespaces for execution of code contained in pyCode
: 然后我可以使用命名空间来执行
pyCode
包含的代码:
exec( pyCode, global_namespace, lobaca_namespace );
I can clean the namespaces when I want to run a new instance of my test, by cleaning the dictionaries: 当我想通过清理字典来运行我的测试的新实例时,我可以清理命名空间:
// empty the interpreters namespaces
global_namespace.clear();
local_namespace.clear();
// Copy builtins to new global namespace
global_namespace["__builtins__"] = main_namespace["__builtins__"];
Depending at what level I want the execution, I can use global = local 根据我想要执行的级别,我可以使用global = local
How about using code.IteractiveInterpreter
? 如何使用
code.IteractiveInterpreter
?
Something like this should do it: 这样的事情应该这样做:
#include <boost/python.hpp>
#include <string>
#include <stdexcept>
using namespace boost::python;
std::string GetPythonError()
{
PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
std::string message("");
if(pvalue && PyString_Check(pvalue)) {
message = PyString_AsString(pvalue);
}
return message;
}
// Must be called after Py_Initialize()
void RunInterpreter(std::string codeToRun)
{
object pymodule = object(handle<>(borrowed(PyImport_AddModule("__main__"))));
object pynamespace = pymodule.attr("__dict__");
try {
// Initialize the embedded interpreter
object result = exec( "import code\n"
"__myInterpreter = code.InteractiveConsole() \n",
pynamespace);
// Run the code
str pyCode(codeToRun.c_str());
pynamespace["__myCommand"] = pyCode;
result = eval("__myInterpreter.push(__myCommand)", pynamespace);
} catch(error_already_set) {
throw std::runtime_error(GetPythonError().c_str());
}
}
I'd write another shell script executing the sequence of test scripts with new instances of python each time. 我会编写另一个shell脚本,每次都使用新的python实例执行测试脚本序列。 Or write it in python like
或者用python写它
# run your tests in the process first
# now run the user scripts, each in new process to have virgin env
for script in userScript:
subprocess.call(['python',script])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.