2011-10-13 31 views
8

Estoy trabajando en la incrustación de Python en nuestra aplicación de suite de pruebas. El objetivo es utilizar Python para ejecutar varios scripts de prueba para recopilar datos y realizar un informe de pruebas. Varios scripts de prueba para una ejecución de prueba pueden crear variables globales y funciones que se pueden usar en el siguiente script.¿Cómo reiniciar un intérprete de Python incorporado?

La aplicación también proporciona módulos de extensión que se importan en el intérprete incorporado y se utilizan para intercambiar algunos datos con la aplicación.

Pero el usuario también puede realizar varias ejecuciones de prueba. No quiero compartir esos datos globales, las importaciones y los datos intercambiados entre varias pruebas. Debo asegurarme de reiniciar en un estado genuino para controlar el entorno de prueba y obtener los mismos resultados.

¿Cómo debo reiniciar el intérprete?

Utilicé Py_Initialize() y Py_Finalize(), pero obtengo una excepción en la segunda ejecución al inicializar por segunda vez los módulos de extensión que proporciono al intérprete. Y la documentación warns against using it more than once.

El uso de sub-interpreters parece tener las mismas advertencias con la inicialización de los módulos de extensión.

Sospecho que estoy haciendo algo mal con la inicialización de mis módulos de extensión, pero me temo que el mismo problema ocurre con los módulos de extensión de terceros.

Tal vez sea posible hacerlo funcionar al iniciar el intérprete en su propio proceso, para asegurarse de que se libera toda la memoria.

Por cierto, estoy usando boost-python para eso, que también advierte EN CONTRA de usar Py_Finalize!

¿Alguna sugerencia?

Gracias

Respuesta

4

Aquí hay otra manera que he encontrado para conseguir lo que quiero, comenzar con una pizarra limpia en el intérprete.

puedo controlar los espacios de nombres globales y locales que utilizo para ejecutar el código:

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

entonces puedo usar usar los espacios de nombres para la ejecución de código contenido en pyCode:

exec(pyCode, global_namespace, lobaca_namespace); 

que pueda limpiar los espacios de nombres cuando quiero ejecutar una nueva instancia de mi prueba, al limpiar los diccionarios:

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

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

Dependiendo en qué nivel quiero la ejecución, puedo usar global = local

0

Cómo sobre el uso code.IteractiveInterpreter?

Algo así debe hacerlo:

#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

Entonces, básicamente, debo instanciar una vez mi intérprete de Python, y usar este intérprete para iniciar subinterpretadores, ¿todos tienen su propio espacio de nombres? Parece una solución viable, si estos subinterpretadores no sufren las mismas advertencias que las hechas con Py_NewInterpreter. Voy a analizar detalladamente eso y experimentar con él. ¡Gracias! – nab

+0

Lo tienes. Instanciar un InteractiveInterpreter le proporciona un entorno nuevo en todo momento. No estoy seguro de cuáles son las reglas con respecto a lo que hereda del intérprete padre, pero eso debería ser fácil de controlar de cualquier manera. –

+0

Parece que está haciendo lo que quiero. Tenga en cuenta que tiene el mismo inconveniente para la inicialización de los módulos (solo se inicializan una vez). Pero funciona bien para limpiar el espacio de nombres. ¡Gracias! – nab

0

me gustaría escribir otro script ejecutar la secuencia de scripts de prueba con nuevas instancias de pitón cada vez. O escribir en Python como

# 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]) 
Cuestiones relacionadas