MantidPlot crash when leaving a dialog open
<!-- TEMPLATE FOR BUG REPORTS -->
MantidPlot crashes on close with segmentation fault when one leaves the auto-generated GUI of a python algorithm open.

### Expected behaviour
MantidPlot should close normally.

### Actual behaviour
Segmentation fault on close

### Steps to reproduce the behaviour
1. Open MantidPlot.
2. Open the auto-generated GUI of any python algorithm
3. Close MantidPlot while the algorithm dialog is open

### Platforms affected
Discovered on OS X, but probably ALL.

diff --git a/Framework/API/inc/MantidAPI/Algorithm.h b/Framework/API/inc/MantidAPI/Algorithm.h
index faae3348a66..6fd4d6441f3 100644
--- a/Framework/API/inc/MantidAPI/Algorithm.h
+++ b/Framework/API/inc/MantidAPI/Algorithm.h
@@ -200,6 +200,11 @@ public:
   /// is provided
   const std::string alias() const override { return ""; }
 
+  /// function to return URL for algorithm documentation; A default
+  /// implementation is provided.
+  /// Override if the algorithm is not part of the Mantid distribution.
+  const std::string helpURL() const override { return ""; }
+
   const std::string workspaceMethodName() const override;
   const std::vector<std::string> workspaceMethodOn() const override;
   const std::string workspaceMethodInputProperty() const override;
diff --git a/Framework/API/inc/MantidAPI/AlgorithmProxy.h b/Framework/API/inc/MantidAPI/AlgorithmProxy.h
index 827d16e1454..23e2d3350ac 100644
--- a/Framework/API/inc/MantidAPI/AlgorithmProxy.h
+++ b/Framework/API/inc/MantidAPI/AlgorithmProxy.h
@@ -86,6 +86,8 @@ public:
   }
   /// Aliases to the algorithm
   const std::string alias() const override { return m_alias; }
+  /// Optional documentation URL for the real algorithm
+  const std::string helpURL() const override { return m_helpURL; }
   /// function returns a summary message that will be displayed in the default
   /// GUI, and in the help.
   const std::string summary() const override { return m_summary; }
@@ -176,6 +178,7 @@ private:
   const std::string
       m_categorySeparator;     ///< category seperator of the real algorithm
   const std::string m_alias;   ///< alias to the algorithm
+  const std::string m_helpURL; ///< Optional documentation URL
   const std::string m_summary; ///<Message to display in GUI and help.
   const int m_version;         ///< version of the real algorithm
 
diff --git a/Framework/API/inc/MantidAPI/IAlgorithm.h b/Framework/API/inc/MantidAPI/IAlgorithm.h
index 071e13f90f7..d22b7e91ac6 100644
--- a/Framework/API/inc/MantidAPI/IAlgorithm.h
+++ b/Framework/API/inc/MantidAPI/IAlgorithm.h
@@ -80,6 +80,10 @@ public:
   /// function to return any aliases of the algorithm.
   virtual const std::string alias() const = 0;
 
+  /// function to return an optional URL for documentation.
+  /// Override if the algorithm is not part of the Mantid distribution
+  virtual const std::string helpURL() const = 0;
+
   /** @name Algorithms As Methods */
   ///@{
   /// Returns a name that will be used when attached as a workspace method.
diff --git a/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/AlgorithmAdapter.h b/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/AlgorithmAdapter.h
index 32c0f58fa80..54c2f6efa87 100644
--- a/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/AlgorithmAdapter.h
+++ b/Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/AlgorithmAdapter.h
@@ -59,6 +59,8 @@ public:
   const std::string summary() const override;
   /// Returns a category of the algorithm.
   const std::string category() const override;
+  /// Returns optional documentation URL of the algorithm
+  const std::string helpURL() const override;
   /// Allow the isRunning method to be overridden
   bool isRunning() const override;
   /// Allow the cancel method to be overridden
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp b/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
index cc92119a4c6..889e326b374 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
@@ -346,6 +346,8 @@ void export_ialgorithm() {
            "Returns the list of categories this algorithm belongs to")
       .def("summary", &IAlgorithm::summary, arg("self"),
            "Returns a summary message describing the algorithm")
+      .def("helpURL", &IAlgorithm::helpURL, arg("self"),
+           "Returns optional URL for algorithm documentation")
       .def("workspaceMethodName", &IAlgorithm::workspaceMethodName, arg("self"),
            "Returns a name that will be used when attached as a workspace "
            "method. Empty string indicates do not attach")
diff --git a/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp b/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp
index 8a110298ee5..515d5c2052a 100644
--- a/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp
+++ b/Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp
@@ -103,9 +103,21 @@ const std::string AlgorithmAdapter<BaseAlgorithm>::summary() const {
 }
 
 /**
- * @return True if the algorithm is considered to be running
+ * Optional documentation URL of the algorithm, empty string if not overridden.
  */
 template <typename BaseAlgorithm>
+const std::string AlgorithmAdapter<BaseAlgorithm>::helpURL() const {
+  try {
+    return callMethod<std::string>(getSelf(), "helpURL");
+  } catch (UndefinedAttributeError &) {
+    return std::string();
+  }
+}
+
+/**
+*@return True if the algorithm is considered to be running
+*/
+template <typename BaseAlgorithm>
 bool AlgorithmAdapter<BaseAlgorithm>::isRunning() const {
   if (!m_isRunningObj) {
     return SuperClass::isRunning();
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py
index 9eababd3b7b..5f5823d63a8 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py
@@ -15,6 +15,7 @@ class AlgorithmManagerTest(unittest.TestCase):
         self.assertEquals(alg.name(), "ConvertUnits")
         self.assertEquals(alg.version(), 1)
         self.assertEquals(alg.category(), "Transforms\\Units")
+        self.assertEquals(alg.helpURL(), "")
 
     def test_create_unknown_alg_throws(self):
         self.assertRaises(RuntimeError, AlgorithmManager.create,"DoesNotExist")
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
index 96e223076e5..e93b83e27ed 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
@@ -21,6 +21,7 @@ class AlgorithmTest(unittest.TestCase):
         self.assertEquals('DataHandling', self._load.category())
         self.assertEquals(1, len(self._load.categories()))
         self.assertEquals('DataHandling', self._load.categories()[0])
+        self.assertEquals('', self._load.helpURL())
 
     def test_get_unknown_property_raises_error(self):
         self.assertRaises(RuntimeError, self._load.getProperty, "NotAProperty")
diff --git a/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py b/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py
index 23d67225cf8..bbbf4a8895f 100644
--- a/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py
@@ -28,6 +28,9 @@ class TestPyAlgOverriddenAttrs(PythonAlgorithm):
     def category(self):
         return "BestAlgorithms"
 
+    def helpURL(self):
+        return "Optional documentation URL"
+
     def isRunning(self):
         return True
 
@@ -106,6 +109,7 @@ class PythonAlgorithmTest(unittest.TestCase):
         self.assertEquals(alg.name(), "TestPyAlgOverriddenAttrs")
         self.assertEquals(alg.version(), 2)
         self.assertEquals(alg.category(), "BestAlgorithms")
+        self.assertEquals(alg.helpURL(), "Optional documentation URL")
 
     def test_alg_can_be_cancelled(self):
         alg = AlgorithmManager.createUnmanaged("CancellableAlg")
diff --git a/MantidQt/MantidWidgets/src/MantidHelpWindow.cpp b/MantidQt/MantidWidgets/src/MantidHelpWindow.cpp
index c8613668120..281babbed39 100644
--- a/MantidQt/MantidWidgets/src/MantidHelpWindow.cpp
+++ b/MantidQt/MantidWidgets/src/MantidHelpWindow.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/AlgorithmManager.h"
 #include "MantidQtMantidWidgets/MantidHelpWindow.h"
 #include "MantidQtMantidWidgets/pqHelpWindow.h"
 #include "MantidQtAPI/InterfaceManager.h"
@@ -183,23 +184,38 @@ void MantidHelpWindow::showWikiPage(const QString &page) {
  */
 void MantidHelpWindow::showAlgorithm(const string &name, const int version) {
   auto versionStr("-v" + boost::lexical_cast<string>(version));
-  if (version <= 0)
+  if (version <= 0) {
     versionStr = ""; // let the redirect do its thing
+  }
 
+  QString help_url("");
+  if (!name.empty()) {
+    auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(name);
+    help_url = QString::fromStdString(alg->helpURL());
+  }
   if (bool(g_helpWindow)) {
-    QString url(BASE_URL);
-    url += "algorithms/";
-    if (name.empty())
-      url += "index.html";
-    else
-      url += QString(name.c_str()) + QString(versionStr.c_str()) + ".html";
-    this->showHelp(url);
-  } else // qt-assistant disabled
-  {
-    if (name.empty())
-      this->showWikiPage(std::string("Category:Algorithms"));
-    else
-      this->showWikiPage(name);
+    if (help_url.isEmpty()) {
+      QString url(BASE_URL);
+      url += "algorithms/";
+      if (name.empty()) {
+        url += "index.html";
+      } else {
+        url += QString(name.c_str()) + QString(versionStr.c_str()) + ".html";
+      }
+      this->showHelp(url);
+    } else {
+      this->showHelp(help_url);
+    }
+  } else { // qt-assistant disabled
+    if (help_url.isEmpty()) {
+      if (name.empty()) {
+        this->showWikiPage(std::string("Category:Algorithms"));
+      } else {
+        this->showWikiPage(name);
+      }
+    } else {
+      this->openWebpage(help_url);
+    }
   }
 }
 
diff --git a/MantidQt/MantidWidgets/src/pqHelpWindow.cxx b/MantidQt/MantidWidgets/src/pqHelpWindow.cxx
index 9722259573c..66f21c57bef 100644
--- a/MantidQt/MantidWidgets/src/pqHelpWindow.cxx
+++ b/MantidQt/MantidWidgets/src/pqHelpWindow.cxx
@@ -51,7 +51,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <QUrl>
 #include <QWebHistory>
 #include <QWebView>
-#include <iostream>
 
 using MantidQt::API::MantidDesktopServices;
 
@@ -299,7 +298,7 @@ void pqHelpWindow::errorMissingPage(const QUrl& url)
 //-----------------------------------------------------------------------------
 void pqHelpWindow::showPage(const QString& url)
 {
-  this->showPage(QUrl(url));
+  this->showPage(QUrl::fromUserInput(url));
 }
 
 //-----------------------------------------------------------------------------
diff --git a/docs/source/release/v3.10.0/framework.rst b/docs/source/release/v3.10.0/framework.rst
index a39d04d44e1..013cb475c93 100644
--- a/docs/source/release/v3.10.0/framework.rst
+++ b/docs/source/release/v3.10.0/framework.rst
@@ -17,6 +17,8 @@ Algorithms
 ----------
 
 - Removed the optional flag ``LocationParameters`` from ``ClearInstrumentParameters``.
+- New method `IAlgorithm::helpURL` returns an optional documentation webpage. Useful when registering Python
+  algorithms at runtime that are not part of the Mantid distribution.
 
 New
 ###
['Framework/PythonInterface/mantid/api/src/PythonAlgorithm/AlgorithmAdapter.cpp', 'Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py', 'Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py', 'docs/source/release/v3.10.0/framework.rst', 'Framework/PythonInterface/inc/MantidPythonInterface/api/PythonAlgorithm/AlgorithmAdapter.h', 'Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp', 'MantidQt/MantidWidgets/src/MantidHelpWindow.cpp', 'Framework/API/inc/MantidAPI/Algorithm.h', 'Framework/API/inc/MantidAPI/IAlgorithm.h', 'MantidQt/MantidWidgets/src/pqHelpWindow.cxx', 'Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py', 'Framework/API/inc/MantidAPI/AlgorithmProxy.h']