Как повторно инициализировать встроенный интерпретатор Python? - PullRequest
8 голосов
/ 13 октября 2011

Я работаю над внедрением Python в наше приложение для тестирования.Цель состоит в том, чтобы использовать Python для запуска нескольких тестовых сценариев для сбора данных и составления отчета о тестах.Несколько сценариев тестирования для одного запуска теста могут создавать глобальные переменные и функции, которые можно использовать в следующем сценарии.

Приложение также предоставляет модули расширения, которые импортируются во встроенный интерпретатор и используются для обмена некоторыми данными с приложением.

Но пользователь также может выполнить несколько тестовых прогонов.Я не хочу делиться этими глобальными данными, импортом и данными обмена между несколькими запусками теста.Я должен быть уверен, что перезагружаюсь в подлинном состоянии, чтобы контролировать тестовую среду и получить те же результаты.

Как мне следует повторно инициализировать интерпретатор?

Я использовал Py_Initialize () и Py_Finalize (), но получите исключение при втором запуске при повторной инициализации модулей расширения, которые я предоставляю интерпретатору.И документация предостерегает от использования его более одного раза .

Использование суб-интерпретаторов , похоже, имеет те же предостережения с инициализацией модулей расширения.

Я подозреваю, что я что-то не так делаю с инициализацией моих модулей расширения, но боюсь, что та же проблема происходит с модулями расширения сторонних производителей.

Возможно, можно заставить его работать, запустив интерпретатор вэто собственный процесс, чтобы быть уверенным, что вся память освобождена.

Кстати, я использую для этого boost-python, который также предупреждает ПРОТИВ использования Py_Finalize!

Anyпредложение?

спасибо

Ответы [ 3 ]

4 голосов
/ 03 апреля 2012

Вот еще один способ достижения желаемого: начать с чистого листа в интерпретаторе.

Я могу контролировать глобальные и локальные пространства имен, которые я использую для выполнения кода:

// 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

1 голос
/ 13 октября 2011

Как насчет использования 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());
    }
}
0 голосов
/ 14 октября 2011

Я бы написал другой сценарий оболочки, выполняющий последовательность тестовых сценариев с новыми экземплярами 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])
...