Pracuję nad osadzeniem Pythona w naszej aplikacji Suite Test. Celem jest użycie Pythona do uruchomienia kilku testów skryptów, aby zbierać dane i zgłaszać raport z testów. Wiele skryptów testowych dla jednego przebiegu testowego może tworzyć zmienne globalne i funkcje, które mogą być używane w następnym skrypcie.

Aplikacja zapewnia również moduły rozszerzające importowane w wbudowanym tłumaczem i służą do wymiany niektórych danych z aplikacją.

Ale użytkownik może również wykonać wiele testów. Nie chcę dzielić się tymi światałami, importem i wymienionymi danymi między wieloma biegami testowymi. Muszę mieć pewność, że uruchomię się ponownie w prawdziwym stanie, aby kontrolować środowisko testowe i uzyskać te same wyniki.

Jak powinienem reinteitalizować tłumacz?

Użyłem Py_initialize () i Py_finalize (), ale uzyskać wyjątek na drugim uruchomieniu podczas inicjalizacji po raz drugi moduły przedłużające, które zapewniam tłumacz. Oraz dokumentacja ostrzega przed użyciem go więcej niż raz.

Korzystanie z podprojektory wydaje się mieć te same zastrzeżenia z inicjalizacją modułów rozszerzających.

Podejrzewam, że robię coś nie tak z inicjalizacją moich modułów rozszerzających, ale obawiam się, że ten sam problem dzieje się z 3rd modułami rozszerzeń.

Może to możliwe, aby pracować, uruchamiając tłumacz w swoim własnym procesie, aby mieć pewność, że cała pamięć zostanie zwolniona.

Przy okazji, używam dla niego Boost-Pythona, który również ostrzega przed użyciem Py_finalize!

Jakieś sugestie?

Dzięki

10
nab 13 październik 2011, 17:04

3 odpowiedzi

Najlepsza odpowiedź

Oto inny sposób, w jaki znalazłem, aby osiągnąć to, czego chcę, zacznij od czystego łupku w tłumaczeniu.

Mogę kontrolować globalne i lokalne przestrzenie przestrzeni nazw, które używam do wykonania kodu:

// 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__"];

Następnie mogę użyć użycia przestrzeni nazw do wykonywania kodu zawartego w pyCode:

exec( pyCode, global_namespace, lobaca_namespace );

Mogę oczyścić przestrzeń nazw, kiedy chcę uruchomić nową instancję mojego testu, czyszcząc słowniki:

// empty the interpreters namespaces
global_namespace.clear();
local_namespace.clear();        

// Copy builtins to new global namespace
global_namespace["__builtins__"] = main_namespace["__builtins__"];

W zależności od tego, jaki poziom chcę egzekucji, mogę użyć global = lokalny

4
nab 3 kwiecień 2012, 11:44

Co powiesz na używanie code.IteractiveInterpreter?

Coś takiego powinno to zrobić:

#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());
    }
}
1
Aleksey Vitebskiy 14 październik 2011, 01:25

Piszę inny skrypt powłoki wykonujący sekwencję skryptów testowych z nowymi instancjami Pythona za każdym razem. Lub napisz to w Pythonie

# 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])
0
eudoxos 14 październik 2011, 07:10