2011-10-13 96 views
8

我正在將Python嵌入到我們的測試套件應用程序中。目的是使用Python運行多個測試腳本來收集數據並生成測試報告。一次測試運行的多個測試腳本可以創建可在下一個腳本中使用的全局變量和函數。如何重新初始化嵌入式Python解釋器?

該應用程序還提供了在嵌入式解釋器中導入的擴展模塊,用於與應用程序交換一些數據。

但用戶也可以進行多次測試運行。我不想在多次測試運行之間共享這些全局變量,導入和交換數據。我必須確保在真正的狀態下重新啓動以控制測試環境並獲得相同的結果。

我應該如何重新初始化解釋器?

我使用了Py_Initialize()和Py_Finalize(),但是在第二次初始化我提供給解釋器的擴展模塊時得到第二次運行的異常。 和文檔warns against using it more than once

使用sub-interpreters似乎有與擴展模塊初始化相同的警告。

我懷疑我的擴展模塊的初始化出了問題,但我擔心同樣的問題會發生在第三方擴展模塊上。

也許可以通過在自己的進程中啓動解釋器來使其工作,以確保釋放所有內存。

順便說一句,我使用boost-python,它也警告反對使用Py_Finalize!

有什麼建議嗎?

感謝

回答

4

這裏是另一種方式,我發現達到我想要的,在解釋改過自新。

我可以控制我用它來執行代碼的全局和局部命名空間:

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

0

如何使用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

所以基本上,我應該實例化一次我的Python解釋器,並使用此解釋器來啓動子解釋器,它們都擁有自己的名稱空間? 看起來像一個可行的解決方案,如果這些子解釋器沒有受到與Py_NewInterpreter所做的相同的警告。 我會仔細研究一下,並試驗一下。謝謝! – nab

+0

你明白了。 InstInciating InteractiveInterpreter爲您提供全新的環境。我不確定關於從父解釋器繼承的內容的規則是什麼,但這應該很容易控制。 –

+0

似乎正在做我想做的事。請注意,它與模塊初始化有相同的缺點(它們只是初始化一次)。但它清理命名空間很有效。謝謝! – nab

0

我會寫執行,每次蟒蛇的新實例測試腳本的流程的一個shell腳本。或者,它用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])