From 3743bd34e97e02f92fd9bcb8547ef7cb7a9ce9f0 Mon Sep 17 00:00:00 2001
From: Martyn Gigg <martyn.gigg@stfc.ac.uk>
Date: Tue, 22 Oct 2013 14:45:56 +0100
Subject: [PATCH] Unsubscribe any loader that has been replaced by a Python
 algorithm.

If we don't then we get a crash in the FileLoaderRegistry that tries
to cast to an incorrect type.

Refs #8177
---
 .../API/inc/MantidAPI/FileLoaderRegistry.h    |  7 ++++
 .../Framework/API/src/FileLoaderRegistry.cpp  | 42 +++++++++++++++++++
 .../api/src/Exports/AlgorithmFactory.cpp      |  6 ++-
 3 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/FileLoaderRegistry.h b/Code/Mantid/Framework/API/inc/MantidAPI/FileLoaderRegistry.h
index efee45e2c52..9707f11d361 100644
--- a/Code/Mantid/Framework/API/inc/MantidAPI/FileLoaderRegistry.h
+++ b/Code/Mantid/Framework/API/inc/MantidAPI/FileLoaderRegistry.h
@@ -80,6 +80,9 @@ namespace Mantid
         m_log.debug() << "Registered '" << nameVersion.first << "' version '" << nameVersion.second << "' as file loader\n";
       }
 
+      /// Unsubscribe a named algorithm and version from the loader registration
+      void unsubscribe(const std::string &name, const int version = -1);
+
       /// Returns the name of an Algorithm that can load the given filename
       const boost::shared_ptr<IAlgorithm> chooseLoader(const std::string &filename) const;
       /// Checks whether the given algorithm can load the file
@@ -121,6 +124,10 @@ namespace Mantid
         }
       };
 
+      /// Remove a named algorithm & version from the given map
+      void removeAlgorithm(const std::string & name, const int version, 
+                           std::multimap<std::string,int> & typedLoaders);
+
       /// The list of names. The index pointed to by LoaderFormat defines a set for that format
       std::vector<std::multimap<std::string,int> > m_names;
       /// Total number of names registered
diff --git a/Code/Mantid/Framework/API/src/FileLoaderRegistry.cpp b/Code/Mantid/Framework/API/src/FileLoaderRegistry.cpp
index 11836e3632b..084ce2c20f3 100644
--- a/Code/Mantid/Framework/API/src/FileLoaderRegistry.cpp
+++ b/Code/Mantid/Framework/API/src/FileLoaderRegistry.cpp
@@ -49,6 +49,7 @@ namespace Mantid
           const int version = it->second;
           logger.debug() << "Checking " << name << " version " << version << std::endl;
 
+          // Use static cast for speed. Checks have been done at registration to check the types
           auto alg = boost::static_pointer_cast<FileLoaderType>(factory.create(name, version)); // highest version
           try
           {
@@ -75,6 +76,20 @@ namespace Mantid
     // Public members
     //----------------------------------------------------------------------------------------------
 
+    /**
+     * If the name does not exist then it does nothing
+     * @param name Name of the algorithm to remove from the search list
+     * @aparam version An optional version to remove. -1 indicates remove all (Default=-1)
+     */
+    void FileLoaderRegistryImpl::unsubscribe(const std::string &name, const int version)
+    {
+      auto iend = m_names.end();
+      for(auto it = m_names.begin(); it != iend; ++it)
+      {
+        removeAlgorithm(name, version, *it);
+      }
+    }
+
     /**
      * Queries each registered algorithm and asks it how confident it is that it can
      * load the given file. The name of the one with the highest confidence is returned.
@@ -161,5 +176,32 @@ namespace Mantid
     {
     }
 
+    /**
+     * @param name A string containing the algorithm name
+     * @param version The version to remove. -1 indicates all instances
+     * @param typedLoaders A map of names to version numbers 
+     **/
+    void FileLoaderRegistryImpl::removeAlgorithm(const std::string & name, const int version, 
+                                                 std::multimap<std::string,int> & typedLoaders)
+    {
+      if(version == -1) // remove all
+      {
+        typedLoaders.erase(name);
+      }
+      else // find the right version
+      {
+        auto range = typedLoaders.equal_range(name);
+        for(auto ritr = range.first; ritr != range.second; ++ritr)
+        {
+          if(ritr->second == version)
+          {
+            typedLoaders.erase(ritr);
+            break;
+          }
+        }
+      }
+    }
+
+
   } // namespace API
 } // namespace Mantid
diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp
index 6dd925e9d04..d241f44b8a6 100644
--- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp
+++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/AlgorithmFactory.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/FileLoaderRegistry.h"
 #include "MantidKernel/WarningSuppressions.h"
 #include "MantidPythonInterface/kernel/PythonObjectInstantiator.h"
 #include "MantidPythonInterface/api/PythonAlgorithm/PythonAlgorithm.h"
@@ -90,7 +91,10 @@ GCC_DIAG_OFF(cast-qual)
     }
     boost::python::object classType(handle<>(borrowed(classObject)));
     // Takes ownership of instantiator and replaces any existing algorithm
-    self.subscribe(new PythonObjectInstantiator<Algorithm>(classType), AlgorithmFactoryImpl::OverwriteCurrent);
+    auto descr = self.subscribe(new PythonObjectInstantiator<Algorithm>(classType), AlgorithmFactoryImpl::OverwriteCurrent);
+
+    // Python algorithms cannot yet act as loaders so remove any registered ones from the FileLoaderRegistry
+    FileLoaderRegistry::Instance().unsubscribe(descr.first, descr.second);
   }
 
   ///@endcond
-- 
GitLab