Как повторно инициализировать встроенный интерпретатор Python?
Я работаю над внедрением Python в наше приложение test suite. Цель состоит в том, чтобы использовать Python для запуска нескольких сценариев тестов для сбора данных и создания отчета о тестах. Несколько тестовых сценариев для одного тестового запуска могут создавать глобальные переменные и функции, которые могут использоваться в следующем сценарии.
приложение также предоставляет модули расширения, которые импортируются во встроенный интерпретатор и используются для обмена некоторыми данными с приложением.
но пользователь может также сделайте несколько тестовых запусков. Я не хочу делиться этими глобалами, импортом и обменом данными между несколькими тестовыми запусками. Я должен быть уверен, что перезапущен в подлинном состоянии, чтобы контролировать тестовую среду и получать те же результаты.
Как мне повторно инициализировать интерпретатор?
Я использовал Py_Initialize () и Py_Finalize (), но получаю исключение при втором запуске при инициализации во второй раз модулей расширения, которые я предоставляю интерпретатору. И документация предупреждает против использования его более одного раза.
используя суб-переводчиков кажется, имеют те же предостережения с инициализацией модулей расширения.
Я подозреваю, что я делаю что-то неправильно с инициализацией моих модулей расширения, но я боюсь, что та же проблема происходит с модулями расширения 3rd party.
возможно, его можно заставить работать, запустив интерпретатор в своем собственном процессе, чтобы быть уверенным, что все память освобождается.
кстати, я использую boost-python для него, что также предупреждает об использовании Py_Finalize!
какие будут предложения?
спасибо
3 ответов
вот еще один способ я нашел, чтобы достичь того, чего я хочу, начать с чистого листа в переводчик.
Я могу управлять глобальными и локальными пространствами имен, которые я использую для выполнения кода:
// 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__"];
затем я могу использовать пространства имен для выполнения кода, содержащегося в pyCode
:
exec( pyCode, global_namespace, lobaca_namespace );
Я могу очистить пространства имен, когда я хочу запустить новый экземпляр моего теста, очистив словари:
// empty the interpreters namespaces
global_namespace.clear();
local_namespace.clear();
// Copy builtins to new global namespace
global_namespace["__builtins__"] = main_namespace["__builtins__"];
в зависимости от того, на каком уровне я хочу выполнение, я могу использовать global = local
Как насчет использования code.IteractiveInterpreter
?
что-то вроде этого должны сделать это:
#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());
}
}
Я бы написал другой сценарий оболочки, выполняющий последовательность тестовых сценариев с новыми экземплярами python каждый раз. Или напишите его на 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])