Quellcode durchsuchen

Fix memory leaks associated with ctkSimplePythonShell tests

* Calling "sys.exit()" within a python script ends up calling the
 function "std::exit()" [1] which terminate the application without calling
the destructor of variables with "automatic storage durations".

Considering the description of such variables [2], calling either
"std::exit()", "exit()" or "sys.exit(0)" from within python will prevent
the destruction of the QApplication singleton hence the proper destruction
of the object where the vtkObject have been instantiated (i.e. ctkTestWrappedVTKSlot and
ctkTestWrappedVTKQInvokable)


[1] http://en.cppreference.com/w/cpp/utility/program/exit
[2] http://en.cppreference.com/w/cpp/language/storage_duration


* To properly terminate the application, the solution consisted in
both running the test script after the event loop has been initiated and
calling "qt.QApplication.exit()" instead of "sys.exit()'. That said,
note that calling "sys.exit()"  in a pure python script is valid since
the implementation of "sys.exit()" takes care of doing the appropriate
cleaning before calling "exit()". [See Py_Finalize(), Py_Exit(), handle_system_exit]
in "pythonrun.c"

* An alternate solution could consist in using the "atexit" python module
and register a cleanup function. [3]

[3] http://docs.python.org/library/atexit.html
Jean-Christophe Fillion-Robin vor 13 Jahren
Ursprung
Commit
1da8d5498f

+ 7 - 7
Applications/ctkSimplePythonShell/Testing/Python/vtkPythonSmoke.py

@@ -3,19 +3,19 @@
 # Copied from VTK/Common/Testing/Python/PythonSmoke.py
 # Copied from VTK/Common/Testing/Python/PythonSmoke.py
 #
 #
 
 
-import sys
+import qt
 
 
 try:
 try:
   import vtk
   import vtk
 
 
 except:
 except:
   print "Cannot import vtk"
   print "Cannot import vtk"
-  sys.exit(1)
+  qt.QApplication.exit(1)
 try:
 try:
   print dir(vtk)
   print dir(vtk)
 except:
 except:
   print "Cannot print dir(vtk)"
   print "Cannot print dir(vtk)"
-  sys.exit(1)
+  qt.QApplication.exit(1)
 
 
 try:
 try:
   try:
   try:
@@ -30,7 +30,7 @@ try:
     print "Using Common"
     print "Using Common"
 except:
 except:
   print "Cannot create vtkObject"
   print "Cannot create vtkObject"
-  sys.exit(1)
+  qt.QApplication.exit(1)
 
 
 try:
 try:
   print o
   print o
@@ -38,7 +38,7 @@ try:
   print "Class name: %s" % o.GetClassName()
   print "Class name: %s" % o.GetClassName()
 except:
 except:
   print "Cannot print object"
   print "Cannot print object"
-  sys.exit(1)
+  qt.QApplication.exit(1)
 
 
 try:
 try:
   b = vtk.vtkObject()
   b = vtk.vtkObject()
@@ -46,7 +46,7 @@ try:
   print b, d
   print b, d
 except:
 except:
   print "Cannot downcast"
   print "Cannot downcast"
-  sys.exit(1)
+  qt.QApplication.exit(1)
 
 
-sys.exit(0)
+qt.QApplication.exit(0)
 
 

+ 6 - 6
Applications/ctkSimplePythonShell/Testing/Python/wrappedQInvokableTest.py

@@ -1,10 +1,10 @@
-import sys
+import qt
 
 
 if (_testWrappedQInvokableInstance.value() != 0):
 if (_testWrappedQInvokableInstance.value() != 0):
-  sys.exit(1)
-  
+  qt.QApplication.exit(1)
+
 _testWrappedQInvokableInstance.setValue(74)
 _testWrappedQInvokableInstance.setValue(74)
 if (_testWrappedQInvokableInstance.value() != 74):
 if (_testWrappedQInvokableInstance.value() != 74):
-  sys.exit(1)
-  
-sys.exit(0)
+  qt.QApplication.exit(1)
+
+qt.QApplication.exit(0)

+ 6 - 6
Applications/ctkSimplePythonShell/Testing/Python/wrappedQPropertyTest.py

@@ -1,11 +1,11 @@
 
 
-import sys
+import qt
 
 
 if (_testWrappedQPropertyInstance.value != 0):
 if (_testWrappedQPropertyInstance.value != 0):
-  sys.exit(1)
-  
+  qt.QApplication.exit(1)
+
 _testWrappedQPropertyInstance.value = 74
 _testWrappedQPropertyInstance.value = 74
 if (_testWrappedQPropertyInstance.value != 74):
 if (_testWrappedQPropertyInstance.value != 74):
-  sys.exit(1)
-  
-sys.exit(0)
+  qt.QApplication.exit(1)
+
+qt.QApplication.exit(0)

+ 6 - 6
Applications/ctkSimplePythonShell/Testing/Python/wrappedSlotTest.py

@@ -1,10 +1,10 @@
-import sys
+import qt
 
 
 if (_testWrappedSlotInstance.value() != 0):
 if (_testWrappedSlotInstance.value() != 0):
-  sys.exit(1)
-  
+  qt.QApplication.exit(1)
+
 _testWrappedSlotInstance.setValue(74)
 _testWrappedSlotInstance.setValue(74)
 if (_testWrappedSlotInstance.value() != 74):
 if (_testWrappedSlotInstance.value() != 74):
-  sys.exit(1)
-  
-sys.exit(0)
+  qt.QApplication.exit(1)
+
+qt.QApplication.exit(0)

+ 5 - 5
Applications/ctkSimplePythonShell/Testing/Python/wrappedVTKQInvokableTest.py

@@ -1,7 +1,7 @@
 
 
-import sys
+import qt
 
 
-# Importing vtk initializes vtkPythonMap owned by vtkPythonUtil and prevent 
+# Importing vtk initializes vtkPythonMap owned by vtkPythonUtil and prevent
 # call to vtkPythonUtil::GetObjectFromPointer() from segfaulting.
 # call to vtkPythonUtil::GetObjectFromPointer() from segfaulting.
 # PythonQt internally uses vtkPythonUtil to properly wrap/unwrap VTK objects
 # PythonQt internally uses vtkPythonUtil to properly wrap/unwrap VTK objects
 from vtk import *
 from vtk import *
@@ -12,6 +12,6 @@ print t.GetClassName()
 t2 = vtkTable()
 t2 = vtkTable()
 _testWrappedVTKQInvokableInstance.setTable(t2)
 _testWrappedVTKQInvokableInstance.setTable(t2)
 if _testWrappedVTKQInvokableInstance.getTable() != t2:
 if _testWrappedVTKQInvokableInstance.getTable() != t2:
-  sys.exit(1)
-  
-sys.exit(0)
+  qt.QApplication.exit(1)
+
+qt.QApplication.exit(0)

+ 5 - 5
Applications/ctkSimplePythonShell/Testing/Python/wrappedVTKSlotTest.py

@@ -1,7 +1,7 @@
 
 
-import sys
+import qt
 
 
-# Importing vtk initializes vtkPythonMap owned by vtkPythonUtil and prevent 
+# Importing vtk initializes vtkPythonMap owned by vtkPythonUtil and prevent
 # call to vtkPythonUtil::GetObjectFromPointer() from segfaulting.
 # call to vtkPythonUtil::GetObjectFromPointer() from segfaulting.
 # PythonQt internally uses vtkPythonUtil to properly wrap/unwrap VTK objects
 # PythonQt internally uses vtkPythonUtil to properly wrap/unwrap VTK objects
 from vtk import *
 from vtk import *
@@ -12,6 +12,6 @@ print t.GetClassName()
 t2 = vtkTable()
 t2 = vtkTable()
 _testWrappedVTKSlotInstance.setTable(t2)
 _testWrappedVTKSlotInstance.setTable(t2)
 if _testWrappedVTKSlotInstance.getTable() != t2:
 if _testWrappedVTKSlotInstance.getTable() != t2:
-  sys.exit(1)
-  
-sys.exit(0)
+  qt.QApplication.exit(1)
+
+qt.QApplication.exit(0)

+ 30 - 7
Applications/ctkSimplePythonShell/ctkSimplePythonShellMain.cpp

@@ -21,8 +21,10 @@
 // Qt includes
 // Qt includes
 #include <QApplication>
 #include <QApplication>
 #include <QTextStream>
 #include <QTextStream>
+#include <QTimer>
 
 
 // CTK includes
 // CTK includes
+#include <ctkCallback.h>
 #include <ctkPythonConsole.h>
 #include <ctkPythonConsole.h>
 #include <ctkCommandLineParser.h>
 #include <ctkCommandLineParser.h>
 
 
@@ -39,6 +41,26 @@
 # include <vtkDebugLeaks.h>
 # include <vtkDebugLeaks.h>
 #endif
 #endif
 
 
+namespace
+{
+//-----------------------------------------------------------------------------
+void executeScripts(void * data)
+{
+  ctkSimplePythonManager * pythonManager = reinterpret_cast<ctkSimplePythonManager*>(data);
+  QStringList scripts = pythonManager->property("scripts").toStringList();
+  foreach(const QString& script, scripts)
+    {
+    pythonManager->executeFile(script);
+    if (pythonManager->pythonErrorOccured())
+      {
+      QApplication::exit(EXIT_FAILURE);
+      }
+    }
+}
+
+} // end of anonymous namespace
+
+//-----------------------------------------------------------------------------
 int main(int argc, char** argv)
 int main(int argc, char** argv)
 {
 {
 #ifdef CTK_WRAP_PYTHONQT_USE_VTK
 #ifdef CTK_WRAP_PYTHONQT_USE_VTK
@@ -75,9 +97,9 @@ int main(int argc, char** argv)
           << parser.helpText();
           << parser.helpText();
     return EXIT_SUCCESS;
     return EXIT_SUCCESS;
   }
   }
-  
+
   ctkSimplePythonManager pythonManager;
   ctkSimplePythonManager pythonManager;
-  
+
   ctkPythonConsole console;
   ctkPythonConsole console;
   console.initialize(&pythonManager);
   console.initialize(&pythonManager);
   console.setAttribute(Qt::WA_QuitOnClose, true);
   console.setAttribute(Qt::WA_QuitOnClose, true);
@@ -112,10 +134,11 @@ int main(int argc, char** argv)
   pythonManager.addObjectToPythonMain("_testWrappedQListOfVTKObjectInstance", &testWrappedQListOfVTKObject);
   pythonManager.addObjectToPythonMain("_testWrappedQListOfVTKObjectInstance", &testWrappedQListOfVTKObject);
 #endif
 #endif
 
 
-  foreach(const QString& script, parser.unparsedArguments())
-    {
-    pythonManager.executeFile(script);
-    }
-  
+  ctkCallback callback;
+  callback.setCallbackData(&pythonManager);
+  pythonManager.setProperty("scripts", parser.unparsedArguments());
+  callback.setCallback(executeScripts);
+  QTimer::singleShot(0, &callback, SLOT(invoke()));
+
   return app.exec();
   return app.exec();
 }
 }