diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h
index 5ab432c55e1b622cce46de93ecaf4685c9f3fa2a..8d140deb7a449893162646b49ffb7f857836c8f6 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h
@@ -160,7 +160,7 @@ private:
 
   std::string outputCalibFilename(const std::string &vanNo,
                                   const std::string &ceriaNo,
-                                  const std::string &bankName="");
+                                  const std::string &bankName = "");
 
   void parseCalibrateFilename(const std::string &path, std::string &instName,
                               std::string &vanNo, std::string &ceriaNo);
@@ -178,7 +178,7 @@ private:
   std::string
   buildCalibrateSuggestedFilename(const std::string &vanNo,
                                   const std::string &ceriaNo,
-                                  const std::string &bankName="") const;
+                                  const std::string &bankName = "") const;
 
   //@}
 
@@ -309,6 +309,12 @@ private:
   std::string
   plotDifcZeroWorkspace(const std::string &customisedBankName) const;
 
+  void writeOutCalibFile(const std::string &outFilename,
+                         const std::vector<double> &difc,
+                         const std::vector<double> &tzero,
+                         const std::vector<std::string> &bankNames,
+                         const std::string &templateFile = "");
+
   /// keep track of the paths the user "browses to", to add them in
   /// the file search path
   void recordPathBrowsedTo(const std::string &filename);
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h
index 361b1cec75459341277e0b54039825a5df4f95da..91fb65d216be7454155100dab45c62932ede3684 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionViewQtGUI.h
@@ -113,11 +113,7 @@ public:
   void newCalibLoaded(const std::string &vanadiumNo, const std::string &ceriaNo,
                       const std::string &fname) override;
 
-  void writeOutCalibFile(const std::string &outFilename,
-                         const std::vector<double> &difc,
-                         const std::vector<double> &tzero,
-                         const std::vector<std::string> &bankNames,
-                         const std::string &templateFile) override;
+  std::string enggRunPythonCode(const std::string &pyCode) override;
 
   void enableTabs(bool enable) override;
 
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h
index e3d069c755c5c93d6f9fdffdb32beadf8c227c6d..e4050b2f0a49f17c7d65564b92ad2cd143584e95 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h
@@ -213,20 +213,17 @@ public:
                               const std::string &fname) = 0;
 
   /**
-   * Write a GSAS file. Temporarily here until we have a more final
-   * way of generating these files.
-   *
-   * @param outFilename output file name
-   * @param difc difc values (one per bank)
-   * @param tzero tzero values (one per bank)
-   * @param templateFile name of the template file to use (from the
-   * templates distributed with the Engg scripts and files)
-   */
-  virtual void writeOutCalibFile(const std::string &outFilename,
-                                 const std::vector<double> &difc,
-                                 const std::vector<double> &tzero,
-                                 const std::vector<std::string> &bankNames,
-                                 const std::string &templateFile = "") = 0;
+   * Run Python code received as a script string. This is used for
+   * example to write GSAS instrument parameters file, or other code
+   * included with the Engg scripts. Temporarily here until we have a
+   * more final way of generating these files. A SaveGSAS algorithm
+   * that can handle ENGIN-X files would be ideal.
+   *
+   * @param pyCode Python script as a string
+   *
+   * @return status string from running the code
+   */
+  virtual std::string enggRunPythonCode(const std::string &pyCode) = 0;
 
   /**
    * Enable/disable all the sections or tabs of the interface. To be
diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
index b74d4eebb63cbcd1cb70cf511d4566a06e114d35..30881505649fe1b2719507f149e39714133d6966 100644
--- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
@@ -1472,7 +1472,7 @@ void EnggDiffractionPresenter::doCalib(const EnggDiffCalibSettings &cs,
   // 2nd: because runPythonCode does this by emitting a signal that goes to
   // MantidPlot, it has to be done in the view (which is a UserSubWindow).
   // First write the all banks parameters file
-  m_view->writeOutCalibFile(outFullPath.toString(), difc, tzero, bankNames);
+  writeOutCalibFile(outFullPath.toString(), difc, tzero, bankNames);
   // Then write one individual file per bank, using different templates and the
   // specific bank name as suffix
   for (size_t bankIdx = 0; bankIdx < difc.size(); ++bankIdx) {
@@ -1485,9 +1485,8 @@ void EnggDiffractionPresenter::doCalib(const EnggDiffCalibSettings &cs,
       templateFile = "template_ENGINX_241391_236516_South_bank.prm";
     }
 
-    m_view->writeOutCalibFile(bankOutputFullPath.toString(), {difc[bankIdx]},
-                              {tzero[bankIdx]}, {bankNames[bankIdx]},
-                              templateFile);
+    writeOutCalibFile(bankOutputFullPath.toString(), {difc[bankIdx]},
+                      {tzero[bankIdx]}, {bankNames[bankIdx]}, templateFile);
   }
   g_log.notice() << "Calibration file written as " << outFullPath.toString()
                  << std::endl;
@@ -3049,6 +3048,60 @@ Poco::Path EnggDiffractionPresenter::outFilesDir(std::string addToDir) {
   return saveDir;
 }
 
+/**
+ * To write the calibration/instrument parameter for GSAS.
+ *
+ * @param outFilename name of the output .par/.prm/.iparm file for GSAS
+ * @param difc list of GSAS DIFC values to include in the file
+ * @param tzero list of GSAS TZERO values to include in the file
+ * @param bankNames list of bank names corresponding the the difc/tzero
+ * @param templateFile a template file where to replace the difc/zero
+ * values. An empty default implies using an "all-banks" template.
+ */
+void EnggDiffractionPresenter::writeOutCalibFile(
+    const std::string &outFilename, const std::vector<double> &difc,
+    const std::vector<double> &tzero, const std::vector<std::string> &bankNames,
+    const std::string &templateFile) {
+  // TODO: this is horrible and should be changed to avoid running
+  // Python code. Update this as soon as we have a more stable way of
+  // generating IPARM/PRM files.
+
+  // Writes a file doing this:
+  // write_ENGINX_GSAS_iparam_file(output_file, difc, zero, ceria_run=241391,
+  // vanadium_run=236516, template_file=None):
+
+  // this replace is to prevent issues with network drives on windows:
+  const std::string safeOutFname =
+      boost::replace_all_copy(outFilename, "\\", "/");
+  std::string pyCode = "import EnggUtils\n";
+  pyCode += "import os\n";
+  // normalize apparently not needed after the replace, but to be double-safe:
+  pyCode += "GSAS_iparm_fname = os.path.normpath('" + safeOutFname + "')\n";
+  pyCode += "bank_names = []\n";
+  pyCode += "Difcs = []\n";
+  pyCode += "Zeros = []\n";
+  std::string templateFileVal = "None";
+  if (!templateFile.empty()) {
+    templateFileVal = "'" + templateFile + "'";
+  }
+  pyCode += "template_file = " + templateFileVal + "\n";
+  for (size_t i = 0; i < difc.size(); i++) {
+    pyCode += "bank_names.append('" + bankNames[i] + "')\n";
+    pyCode +=
+        "Difcs.append(" + boost::lexical_cast<std::string>(difc[i]) + ")\n";
+    pyCode +=
+        "Zeros.append(" + boost::lexical_cast<std::string>(tzero[i]) + ")\n";
+  }
+  pyCode +=
+      "EnggUtils.write_ENGINX_GSAS_iparam_file(output_file=GSAS_iparm_fname, "
+      "bank_names=bank_names, difc=Difcs, tzero=Zeros, "
+      "template_file=template_file) \n";
+
+  const auto status = m_view->enggRunPythonCode(pyCode);
+  g_log.information() << "Saved output calibration file via Python. Status: "
+                      << status << std::endl;
+}
+
 /**
  * Note down a directory that needs to be added to the data search
  * path when looking for run files. This simply uses a vector and adds
diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
index 75b5bfb784a7e0bf9f4b91952bafbd5e7af02809..651fd101e43bec2581263ac74f9192f3a91e73bc 100644
--- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
+++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
@@ -960,54 +960,12 @@ void EnggDiffractionViewQtGUI::resetFocus() {
   m_uiTabFocus.lineEdit_texture_grouping_file->setText("");
 }
 
-void EnggDiffractionViewQtGUI::writeOutCalibFile(
-    const std::string &outFilename, const std::vector<double> &difc,
-    const std::vector<double> &tzero, const std::vector<std::string> &bankNames,
-    const std::string &templateFile) {
-  // TODO: move most of this to the presenter
-  // TODO: this is horrible and should not last much here.
-  // Avoid running Python code. Update this as soon as we have a more stable
-  // way of generating IPARM/PRM files.
-  // Writes a file doing this:
-  // write_ENGINX_GSAS_iparam_file(output_file, difc, zero, ceria_run=241391,
-  // vanadium_run=236516, template_file=None):
-
-  // this replace is to prevent issues with network drives on windows:
-  const std::string safeOutFname =
-      boost::replace_all_copy(outFilename, "\\", "/");
-  std::string pyCode = "import EnggUtils\n";
-  pyCode += "import os\n";
-  // normalize apparently not needed after the replace, but to be double-safe:
-  pyCode += "GSAS_iparm_fname = os.path.normpath('" + safeOutFname + "')\n";
-  pyCode += "bank_names = []\n";
-  pyCode += "Difcs = []\n";
-  pyCode += "Zeros = []\n";
-  std::string templateFileVal = "None";
-  if (!templateFile.empty()) {
-    templateFileVal = "'" + templateFile + "'";
-  }
-  pyCode += "template_file = " + templateFileVal + "\n";
-  for (size_t i = 0; i < difc.size(); i++) {
-    pyCode += "bank_names.append('" + bankNames[i] + "')\n";
-    pyCode +=
-        "Difcs.append(" + boost::lexical_cast<std::string>(difc[i]) + ")\n";
-    pyCode +=
-        "Zeros.append(" + boost::lexical_cast<std::string>(tzero[i]) + ")\n";
-  }
-  pyCode +=
-      "EnggUtils.write_ENGINX_GSAS_iparam_file(output_file=GSAS_iparm_fname, "
-      "bank_names=bank_names, difc=Difcs, tzero=Zeros, "
-      "template_file=template_file) \n";
-
+std::string
+EnggDiffractionViewQtGUI::enggRunPythonCode(const std::string &pyCode) {
   std::string status =
       runPythonCode(QString::fromStdString(pyCode), false).toStdString();
 
-  // g_log.information()
-  //     << "Saved output calibration file through Python. Status: " << status
-  //     << std::endl;
-  m_logMsgs.push_back(
-      "Run Python code to save output file, with status string: " + status);
-  m_presenter->notify(IEnggDiffractionPresenter::LogMsg);
+  return status;
 }
 
 std::string EnggDiffractionViewQtGUI::askExistingCalibFilename() {
diff --git a/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h b/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h
index 58f7a800dca3bd0adaf9263f9bcfc9db4ab51520..648a5e88ab509679ed4d925d9c333da80285ac00 100644
--- a/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h
+++ b/MantidQt/CustomInterfaces/test/EnggDiffractionViewMock.h
@@ -79,12 +79,8 @@ public:
   MOCK_METHOD3(newCalibLoaded, void(const std::string &, const std::string &,
                                     const std::string &));
 
-  // virtual void writeOutCalibFile(const std::string &outFilename,
-  //                                const std::vector<double> &difc,
-  //                                const std::vector<double> &tzero)
-  MOCK_METHOD3(writeOutCalibFile,
-               void(const std::string &, const std::vector<double> &,
-                    const std::vector<double> &));
+  // virtual std::string enggRunPythonCode(const std::string &pyCode)
+  MOCK_METHOD1(enggRunPythonCode, std::string(const std::string &));
 
   // virtual void enableTabs(bool enable);
   MOCK_METHOD1(enableTabs, void(bool));
@@ -165,7 +161,8 @@ public:
 
   // virtual void setDataVector
   MOCK_METHOD2(setDataVector,
-	  void(std::vector<boost::shared_ptr<QwtData>> &data, bool focused));
+               void(std::vector<boost::shared_ptr<QwtData>> &data,
+                    bool focused));
 
   // virtual void plotVanCurvesCalibOutput();
   MOCK_METHOD0(plotVanCurvesCalibOutput, void());