浏览代码

Merge branch '244-ensure-ctkAbstractPythonManager-executeFile-set-file-variable'

* 244-ensure-ctkAbstractPythonManager-executeFile-set-file-variable:
  Ensure ctkAbstractPythonManager::executeFile set __file__
Jean-Christophe Fillion-Robin 12 年之前
父节点
当前提交
5f35012272

+ 1 - 1
CMakeExternals/PythonQt.cmake

@@ -53,7 +53,7 @@ if(${add_project})
         message(FATAL_ERROR "error: Python is required to build ${PROJECT_NAME}")
       endif()
 
-      set(revision_tag 2114405a47836b3fb16a3f66fec6a02184f32e71)
+      set(revision_tag a386dc60f71c15e67c611bc31b26cee756ed833a)
       if(${proj}_REVISION_TAG)
         set(revision_tag ${${proj}_REVISION_TAG})
       endif()

+ 42 - 1
Libs/Scripting/Python/Core/Testing/Cpp/ctkAbstractPythonManagerTest.cpp

@@ -1,4 +1,8 @@
 
+// Qt includes
+#include <QTemporaryFile>
+#include <QTextStream>
+
 // CTK includes
 #include "ctkAbstractPythonManager.h"
 #include "ctkTest.h"
@@ -43,7 +47,8 @@ private Q_SLOTS:
   void testExecuteString();
   void testExecuteString_data();
 
-  //void testExecuteFile(); // TODO
+  void testExecuteFile();
+  void testExecuteFile_data();
 
   //void testPythonAttributes(); // TODO
 };
@@ -165,5 +170,41 @@ void ctkAbstractPythonManagerTester::testExecuteString_data()
 }
 
 // ----------------------------------------------------------------------------
+void ctkAbstractPythonManagerTester::testExecuteFile()
+{
+  QFETCH(QString, stringToExecute);
+  QFETCH(bool, pythonErrorExpected);
+
+  QTemporaryFile pythonFile("testExecuteFile-XXXXXX.py");
+  QVERIFY(pythonFile.open());
+  QTextStream out(&pythonFile);
+  out << stringToExecute;
+  pythonFile.close();
+
+  this->PythonManager.executeFile(pythonFile.fileName());
+
+  QCOMPARE(this->PythonManager.pythonErrorOccured(), pythonErrorExpected);
+}
+
+// ----------------------------------------------------------------------------
+void ctkAbstractPythonManagerTester::testExecuteFile_data()
+{
+  QTest::addColumn<QString>("stringToExecute");
+  QTest::addColumn<bool>("pythonErrorExpected");
+
+  QTest::newRow("0-emptyfile") << QString("")
+                     << false;
+
+  QTest::newRow("1-helloworld") << QString("print 'Hello world'")
+                     << false;
+
+  QTest::newRow("2-syntaxerror") << QString("print '") // SyntaxError
+                     << true;
+
+  QTest::newRow("3-check __file__ attribute") << QString("print 'This file is: %s' % __file__")
+                     << false;
+}
+
+// ----------------------------------------------------------------------------
 CTK_TEST_MAIN(ctkAbstractPythonManagerTest)
 #include "moc_ctkAbstractPythonManagerTest.cpp"

+ 24 - 3
Libs/Scripting/Python/Core/ctkAbstractPythonManager.cpp

@@ -187,6 +187,12 @@ bool ctkAbstractPythonManager::pythonErrorOccured()const
 }
 
 //-----------------------------------------------------------------------------
+void ctkAbstractPythonManager::resetErrorFlag()
+{
+  PythonQt::self()->resetErrorFlag();
+}
+
+//-----------------------------------------------------------------------------
 QStringList ctkAbstractPythonManager::pythonPaths()
 {
   return QStringList();
@@ -249,9 +255,24 @@ void ctkAbstractPythonManager::executeFile(const QString& filename)
   if (main)
     {
     QString path = QFileInfo(filename).absolutePath();
-    this->executeString(QString("import sys\nsys.path.insert(0, '%1')").arg(path));
-    this->executeString(QString("execfile('%1')").arg(filename));
-    this->executeString(QString("import sys\nif sys.path[0] == '%1': sys.path.pop(0)").arg(path));
+    // See http://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html
+    QStringList code = QStringList()
+        << "import sys"
+        << QString("sys.path.insert(0, '%1')").arg(path)
+        << "_updated_globals = globals()"
+        << QString("_updated_globals['__file__'] = '%1'").arg(filename)
+        << "_ctk_executeFile_exc_info = None"
+        << "try:"
+        << QString("    execfile('%1', _updated_globals)").arg(filename)
+        << "except Exception, e:"
+        << "    _ctk_executeFile_exc_info = sys.exc_info()"
+        << "finally:"
+        << "    del _updated_globals"
+        << QString("    if sys.path[0] == '%1': sys.path.pop(0)").arg(path)
+        << "    if _ctk_executeFile_exc_info:"
+        << "        raise _ctk_executeFile_exc_info[1], None, _ctk_executeFile_exc_info[2]";
+    this->executeString(code.join("\n"));
+    //PythonQt::self()->handleError(); // Clear errorOccured flag
     }
 }
 

+ 4 - 0
Libs/Scripting/Python/Core/ctkAbstractPythonManager.h

@@ -110,6 +110,10 @@ public:
   /// \sa PythonQt::errorOccured()
   bool pythonErrorOccured()const;
 
+  /// Reset error flag
+  /// \sa PythonQt::resetErrorFlag()
+  void resetErrorFlag();
+
 Q_SIGNALS:
 
   /// This signal is emitted after python is pre-initialized. Observers can listen