diff --git a/Framework/API/src/FrameworkManager.cpp b/Framework/API/src/FrameworkManager.cpp
index c2c995445879b48ef42e507911d943ee0c900de1..fb0e20472637831374ffd7b49d5b0ded19f44e52 100644
--- a/Framework/API/src/FrameworkManager.cpp
+++ b/Framework/API/src/FrameworkManager.cpp
@@ -128,6 +128,7 @@ FrameworkManagerImpl::FrameworkManagerImpl()
   _set_output_format(_TWO_DIGIT_EXPONENT);
 #endif
 
+  ConfigService::Instance();
   g_log.notice() << Mantid::welcomeMessage() << '\n';
   loadPlugins();
   disableNexusOutput();
diff --git a/Framework/API/src/MDFrameValidator.cpp b/Framework/API/src/MDFrameValidator.cpp
index f8968c71e10bbeab428c9e932242a25f34579323..e80d0e6f442ed1b2137bcb0d40a22a1f412d90c7 100644
--- a/Framework/API/src/MDFrameValidator.cpp
+++ b/Framework/API/src/MDFrameValidator.cpp
@@ -36,8 +36,8 @@ std::string
 MDFrameValidator::checkValidity(const IMDWorkspace_sptr &workspace) const {
 
   for (size_t index = 0; index < workspace->getNumDims(); ++index) {
-    const auto &frame = workspace->getDimension(index)->getMDFrame();
-    if (frame.name() != m_frameID)
+    const auto dimension = workspace->getDimension(index);
+    if (dimension->getMDFrame().name() != m_frameID)
       return "MDWorkspace must be in the " + m_frameID + " frame.";
   }
 
diff --git a/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp b/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
index 5105eb76f6809f3ec5bd5d6cff416521aa794e4b..4a6ddcd9135ead281b38df1c827fb3499397d61f 100644
--- a/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
+++ b/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
@@ -275,30 +275,30 @@ void ReflectometryReductionOneAuto2::init() {
                   boost::make_shared<StringListValidator>(propOptions),
                   "Polarization analysis mode.");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("Pp", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("CPp", Direction::Input),
       "Effective polarizing power of the polarizing system. "
       "Expressed as a ratio 0 &lt; Pp &lt; 1");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("Ap", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("CAp", Direction::Input),
       "Effective polarizing power of the analyzing system. "
       "Expressed as a ratio 0 &lt; Ap &lt; 1");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("Rho", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("CRho", Direction::Input),
       "Ratio of efficiencies of polarizer spin-down to polarizer "
       "spin-up. This is characteristic of the polarizer flipper. "
       "Values are constants for each term in a polynomial "
       "expression.");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("Alpha", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("CAlpha", Direction::Input),
       "Ratio of efficiencies of analyzer spin-down to analyzer "
       "spin-up. This is characteristic of the analyzer flipper. "
       "Values are factors for each term in a polynomial "
       "expression.");
   setPropertyGroup("PolarizationAnalysis", "Polarization Corrections");
-  setPropertyGroup("Pp", "Polarization Corrections");
-  setPropertyGroup("Ap", "Polarization Corrections");
-  setPropertyGroup("Rho", "Polarization Corrections");
-  setPropertyGroup("Alpha", "Polarization Corrections");
+  setPropertyGroup("CPp", "Polarization Corrections");
+  setPropertyGroup("CAp", "Polarization Corrections");
+  setPropertyGroup("CRho", "Polarization Corrections");
+  setPropertyGroup("CAlpha", "Polarization Corrections");
 
   // Flood correction
   propOptions = {"Workspace", "ParameterFile"};
@@ -944,17 +944,17 @@ ReflectometryReductionOneAuto2::getPolarizationEfficiencies() {
   } else {
     auto effAlg = createChildAlgorithm("CreatePolarizationEfficiencies");
     effAlg->setProperty("InputWorkspace", workspace);
-    if (!isDefault("Pp")) {
-      effAlg->setProperty("Pp", getPropertyValue("Pp"));
+    if (!isDefault("CPp")) {
+      effAlg->setProperty("Pp", getPropertyValue("CPp"));
     }
-    if (!isDefault("Rho")) {
-      effAlg->setProperty("Rho", getPropertyValue("Rho"));
+    if (!isDefault("CRho")) {
+      effAlg->setProperty("Rho", getPropertyValue("CRho"));
     }
-    if (!isDefault("Ap")) {
-      effAlg->setProperty("Ap", getPropertyValue("Ap"));
+    if (!isDefault("CAp")) {
+      effAlg->setProperty("Ap", getPropertyValue("CAp"));
     }
-    if (!isDefault("Alpha")) {
-      effAlg->setProperty("Alpha", getPropertyValue("Alpha"));
+    if (!isDefault("CAlpha")) {
+      effAlg->setProperty("Alpha", getPropertyValue("CAlpha"));
     }
     effAlg->execute();
     efficiencies = effAlg->getProperty("OutputWorkspace");
diff --git a/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h b/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
index df6eb8e43654e6d6a90a318e935f7aab8d6e541b..0bbc3a825b77bef0bd7a9140cf7e139077d10186 100644
--- a/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
+++ b/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
@@ -728,10 +728,10 @@ public:
     alg.setProperty("ProcessingInstructions", "2");
     alg.setProperty("MomentumTransferStep", 0.04);
     alg.setProperty("PolarizationAnalysis", "PA");
-    alg.setProperty("Pp", "0.9,0,0");
-    alg.setProperty("Ap", "0.8,0,0");
-    alg.setProperty("Rho", "0.7778,0,0");
-    alg.setProperty("Alpha", "0.75,0");
+    alg.setProperty("CPp", "0.9,0,0");
+    alg.setProperty("CAp", "0.8,0,0");
+    alg.setProperty("CRho", "0.7778,0,0");
+    alg.setProperty("CAlpha", "0.75,0");
     alg.setPropertyValue("OutputWorkspace", "IvsQ");
     alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned");
     alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam");
@@ -776,10 +776,10 @@ public:
     alg.setProperty("ProcessingInstructions", "2");
     alg.setProperty("MomentumTransferStep", 0.04);
     alg.setProperty("PolarizationAnalysis", "PNR");
-    alg.setProperty("Pp", "1,1,2");
-    alg.setProperty("Ap", "1,1,2");
-    alg.setProperty("Rho", "1,1");
-    alg.setProperty("Alpha", "1");
+    alg.setProperty("CPp", "1,1,2");
+    alg.setProperty("CAp", "1,1,2");
+    alg.setProperty("CRho", "1,1");
+    alg.setProperty("CAlpha", "1");
     alg.setPropertyValue("OutputWorkspace", "IvsQ");
     alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned");
     alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam");
@@ -801,8 +801,8 @@ public:
     alg.setProperty("ProcessingInstructions", "2");
     alg.setProperty("MomentumTransferStep", 0.04);
     alg.setProperty("PolarizationAnalysis", "PNR");
-    alg.setProperty("Pp", "1,1,2");
-    alg.setProperty("Rho", "1,1");
+    alg.setProperty("CPp", "1,1,2");
+    alg.setProperty("CRho", "1,1");
     alg.setPropertyValue("OutputWorkspace", "IvsQ");
     alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned");
     alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam");
@@ -976,8 +976,8 @@ public:
     alg.setProperty("ProcessingInstructions", "2");
     alg.setProperty("MomentumTransferStep", 0.04);
     alg.setProperty("PolarizationAnalysis", "PNR");
-    alg.setProperty("Pp", "1");
-    alg.setProperty("Rho", "1");
+    alg.setProperty("CPp", "1");
+    alg.setProperty("CRho", "1");
     alg.setPropertyValue("OutputWorkspace", "IvsQ");
     alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned");
     alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam");
diff --git a/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp b/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp
index ca72f15a0de5b7c72cb7cc242355230f5a5e0c3b..0ffb0570e1bd49bef8688843226a9ff59e6a0f84 100644
--- a/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp
+++ b/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp
@@ -178,6 +178,7 @@ void CostFuncFitting::calFittingErrors(const GSLMatrix &covar, double chi2) {
   size_t np = m_function->nParams();
   auto covarMatrix = boost::shared_ptr<Kernel::Matrix<double>>(
       new Kernel::Matrix<double>(np, np));
+  m_function->setCovarianceMatrix(covarMatrix);
   size_t ia = 0;
   for (size_t i = 0; i < np; ++i) {
     if (!m_function->isActive(i)) {
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadSwans.h b/Framework/DataHandling/inc/MantidDataHandling/LoadSwans.h
index aa016c8d3aa67177a0df5810810c8bdd750e6786..7fe597619f5fac393d69ab7d17f1d4dd4f829df7 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadSwans.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadSwans.h
@@ -43,8 +43,7 @@ private:
   unsigned int getDetectorSize();
 
   // Member variables
-  DataObjects::EventWorkspace_sptr m_ws =
-      boost::make_shared<Mantid::DataObjects::EventWorkspace>();
+  DataObjects::EventWorkspace_sptr m_ws;
   unsigned int m_detector_size = 0;
 
   // Constants:
diff --git a/Framework/DataHandling/src/LoadSwans.cpp b/Framework/DataHandling/src/LoadSwans.cpp
index d7b9962e39102f4f75bcbf2f95bb9308f72e852b..4f26b6069ada58b6174238ff02c77be2176336f3 100644
--- a/Framework/DataHandling/src/LoadSwans.cpp
+++ b/Framework/DataHandling/src/LoadSwans.cpp
@@ -14,7 +14,6 @@
 #include <algorithm>
 #include <boost/tokenizer.hpp>
 #include <fstream>
-#include <iostream>
 #include <map>
 
 namespace Mantid {
@@ -88,7 +87,7 @@ void LoadSwans::init() {
 /** Execute the algorithm.
  */
 void LoadSwans::exec() {
-
+  m_ws = boost::make_shared<Mantid::DataObjects::EventWorkspace>();
   // Load instrument here to get the necessary Parameters from the XML file
   loadInstrument();
   m_detector_size = getDetectorSize();
diff --git a/Framework/Kernel/CMakeLists.txt b/Framework/Kernel/CMakeLists.txt
index 20123a0f94869668502d9a26e17c36153104e065..8e05862d0adea0190315ed7d8ba9ccc1b6967405 100644
--- a/Framework/Kernel/CMakeLists.txt
+++ b/Framework/Kernel/CMakeLists.txt
@@ -589,37 +589,6 @@ set ( COLORMAPS_FOLDER ${MANTID_ROOT}/installers/colormaps/ )
 set ( MANTIDPUBLISHER "http://upload.mantidproject.org/scriptrepository?debug=1" )
 set ( HTML_ROOT ${DOCS_BUILDDIR}/html )
 
-# Construct script paths.
-set ( MANTID_SCRIPTS ${MANTID_ROOT}/scripts )
-# First the required scripts variable...
-# Omitting the following (as of now) empty directories as CMake doesn't copy them on install and you then end up with a warning message....
-set ( REQUIREDSCRIPT_SUBDIRS Engineering Inelastic Reflectometry SANS)
-
-# If other external interfaces are added then we need a better approach here..
-set ( REQUIREDSCRIPT_DIRS ${MANTID_ROOT}/scripts;${CMAKE_BINARY_DIR}/scripts/ExternalInterfaces/mslice/src/mslice )
-foreach ( SUBDIR ${REQUIREDSCRIPT_SUBDIRS} )
-  set ( REQUIREDSCRIPT_DIRS "${REQUIREDSCRIPT_DIRS};${MANTID_SCRIPTS}/${SUBDIR}" )
-endforeach()
-
-# Second the standard scripts variable. The variable in the file is NOT recursive so add the top level directories from here
-set ( EXCLUDED_DIRS test )
-set ( PYTHONSCRIPT_DIRS "" )
-file ( GLOB SCRIPT_SUBDIRS RELATIVE ${MANTID_SCRIPTS} ${MANTID_SCRIPTS}/* )
-foreach ( SUBDIR ${SCRIPT_SUBDIRS} )
-  set ( DIR ${MANTID_SCRIPTS}/${SUBDIR} )
-  if ( IS_DIRECTORY ${DIR} AND NOT EXISTS ${DIR}/__init__.py )
-    list ( FIND REQUIREDSCRIPT_SUBDIRS ${SUBDIR} HAVE_DIR )
-    list ( FIND EXCLUDED_DIRS ${SUBDIR} EXCLUDE_DIR )
-    if ( HAVE_DIR EQUAL -1 AND EXCLUDE_DIR EQUAL -1 ) # If it is not in REQUIRED and not EXCLUDED
-      if ( PYTHONSCRIPT_DIRS )
-        set ( PYTHONSCRIPT_DIRS "${PYTHONSCRIPT_DIRS};${DIR}" )
-      else()
-        set ( PYTHONSCRIPT_DIRS "${DIR}" ) # Avoid first ;
-      endif()
-    endif()
-  endif()
-endforeach()
-
 # For an mpi-enabled build, do not log to file, format console output (which winds up in a file) differently
 # These settings carry down to the installation configuration below
 if ( MPI_BUILD )
@@ -694,25 +663,6 @@ set ( DATADIRS "" )
 set ( MANTIDPUBLISHER "http://upload.mantidproject.org/scriptrepository" )
 set ( HTML_ROOT ../share/doc/html )
 
-# script paths
-set ( MANTID_SCRIPTS ${MANTID_ROOT}/scripts )
-set ( REQUIREDSCRIPT_DIRS ${MANTID_SCRIPTS};${MANTID_SCRIPTS}/ExternalInterfaces )
-foreach ( SUBDIR ${REQUIREDSCRIPT_SUBDIRS} )
-  set ( REQUIREDSCRIPT_DIRS "${REQUIREDSCRIPT_DIRS};${MANTID_SCRIPTS}/${SUBDIR}" )
-endforeach()
-
-# PYTHONSCRIPT_DIRS
-set ( WITH_SEMICOLONS "" )
-foreach ( DIR ${PYTHONSCRIPT_DIRS} )
-  string ( REGEX REPLACE "${MANTID_ROOT_BUILD}" "${MANTID_ROOT}" DIR ${DIR} )
-  if ( WITH_SEMICOLONS )
-    set ( WITH_SEMICOLONS "${WITH_SEMICOLONS};${DIR}" )
-  else()
-    set ( WITH_SEMICOLONS "${DIR}" ) # Avoid first ;
-  endif()
-endforeach()
-set ( PYTHONSCRIPT_DIRS "${WITH_SEMICOLONS}" )
-
 # For a framework-only (e.g. MPI) build some of these are not relevant and should
 # be left empty to avoid warnings on starting Mantid
 if ( ${CMAKE_PROJECT_NAME} MATCHES "MantidFramework" )
diff --git a/Framework/Kernel/inc/MantidKernel/UsageService.h b/Framework/Kernel/inc/MantidKernel/UsageService.h
index b17a111f9c2d3a3d927411ef10b59631b5111a71..3572577984737497dd76e5f22c56ed3c64f40985 100644
--- a/Framework/Kernel/inc/MantidKernel/UsageService.h
+++ b/Framework/Kernel/inc/MantidKernel/UsageService.h
@@ -50,9 +50,9 @@ public:
 class MANTID_KERNEL_DLL UsageServiceImpl {
 public:
   /// Sets the application name that has invoked Mantid
-  void setApplication(const std::string &name);
+  void setApplicationName(const std::string &name);
   /// Returns the application name that has invoked Mantid
-  std::string getApplication() const;
+  std::string getApplicationName() const;
   /// Sets the interval that the timer checks for tasks
   void setInterval(const uint32_t seconds = 60);
   /// Registers the Startup of Mantid
diff --git a/Framework/Kernel/src/UsageService.cpp b/Framework/Kernel/src/UsageService.cpp
index e99031b1bf4143d480cd1bb8690d0e8746612672..d113bc4fa86e442501be9035bb4e81525adec173 100644
--- a/Framework/Kernel/src/UsageService.cpp
+++ b/Framework/Kernel/src/UsageService.cpp
@@ -68,6 +68,7 @@ UsageServiceImpl::UsageServiceImpl()
     : m_timer(), m_timerTicks(0), m_timerTicksTarget(0), m_FeatureQueue(),
       m_FeatureQueueSizeThreshold(50), m_isEnabled(false), m_mutex(),
       m_application("python"),
+      m_startTime(Types::Core::DateAndTime::getCurrentTime()),
       m_startupActiveMethod(this, &UsageServiceImpl::sendStartupAsyncImpl),
       m_featureActiveMethod(this, &UsageServiceImpl::sendFeatureAsyncImpl) {
   setInterval(60);
@@ -78,15 +79,16 @@ UsageServiceImpl::UsageServiceImpl()
   } else {
     m_url = url.get();
     g_log.debug() << "Root usage reporting url is " << m_url << "\n";
-  }
-  m_startTime = Types::Core::DateAndTime::getCurrentTime();
+  };
 }
 
-void UsageServiceImpl::setApplication(const std::string &name) {
+void UsageServiceImpl::setApplicationName(const std::string &name) {
   m_application = name;
 }
 
-std::string UsageServiceImpl::getApplication() const { return m_application; }
+std::string UsageServiceImpl::getApplicationName() const {
+  return m_application;
+}
 
 void UsageServiceImpl::setInterval(const uint32_t seconds) {
   // set the ticks target to by 24 hours / interval
diff --git a/Framework/Kernel/test/UsageServiceTest.h b/Framework/Kernel/test/UsageServiceTest.h
index 5187942f7041748c7a876e761ccce4157312ee23..3a5048c87aea34291bafb5405b0be4834b2734c5 100644
--- a/Framework/Kernel/test/UsageServiceTest.h
+++ b/Framework/Kernel/test/UsageServiceTest.h
@@ -63,7 +63,7 @@ public:
   void test_startupMessage() {
     TestableUsageService usageService;
     std::string name = "My testing application name";
-    usageService.setApplication(name);
+    usageService.setApplicationName(name);
     std::string message = usageService.generateStartupMessage();
 
     ::Json::Reader reader;
@@ -162,11 +162,11 @@ public:
   void test_setApplicationName() {
     TestableUsageService usageService;
     // test default first
-    TS_ASSERT_EQUALS(usageService.getApplication(), "python");
+    TS_ASSERT_EQUALS(usageService.getApplicationName(), "python");
 
     std::string name = "My testing application name";
-    usageService.setApplication(name);
-    TS_ASSERT_EQUALS(usageService.getApplication(), name);
+    usageService.setApplicationName(name);
+    TS_ASSERT_EQUALS(usageService.getApplicationName(), name);
   }
 };
 
diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template
index 36893c2f6af0bedfd0b10c412818a0e42924d328..5e3ede53bb217162e1c36d77408e91716b26de39 100644
--- a/Framework/Properties/Mantid.properties.template
+++ b/Framework/Properties/Mantid.properties.template
@@ -69,16 +69,9 @@ openclKernelFiles.directory = @MANTID_ROOT@/Framework/GPUAlgorithms/src
 # Where to load colormap files (.map)
 colormaps.directory = @COLORMAPS_FOLDER@
 
-# Location of Python scripts that are required for certain aspects of Mantid to function
-# correctly, i.e. customized interfaces
-#
-# WARNING: Altering this value will almost certainly break Mantid functionality
-#
-requiredpythonscript.directories = @REQUIREDSCRIPT_DIRS@
-
 # Additional directories for Python scripts. These are added to the Python path by the Python API.
 # This key is NOT recursive so sub-directories must be added in addition
-pythonscripts.directories = @PYTHONSCRIPT_DIRS@
+pythonscripts.directories =
 
 # Setting this to 1 will allow python algorithms to be reloaded before execution.
 pythonalgorithms.refresh.allowed = 0
diff --git a/Framework/PythonInterface/CMakeLists.txt b/Framework/PythonInterface/CMakeLists.txt
index 959fd20f4b05c09a3608187f64db10777981c223..ad78194c942f509f22abc61b319c91728d07a608 100644
--- a/Framework/PythonInterface/CMakeLists.txt
+++ b/Framework/PythonInterface/CMakeLists.txt
@@ -110,6 +110,7 @@ clean_orphaned_pyc_files ( ${CMAKE_CURRENT_SOURCE_DIR}/plugins )
 ###########################################################################
 # tests
 ###########################################################################
+set ( PYTHONINTERFACE_PLUGINS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/plugins )
 add_subdirectory( test )
 
 ###########################################################################
diff --git a/Framework/PythonInterface/mantid/__init__.py b/Framework/PythonInterface/mantid/__init__.py
index 727b87b9bcaf48e459ef8c044d195b8b6fdfe9f7..e7f52bfcb059f3fa5ac4581f04f58a63563b3614 100644
--- a/Framework/PythonInterface/mantid/__init__.py
+++ b/Framework/PythonInterface/mantid/__init__.py
@@ -25,33 +25,45 @@ algorithms and data objects that are:
 from __future__ import (absolute_import, division,
                         print_function)
 
-###############################################################################
-# Check the current Python version is correct
-###############################################################################
-from . import pyversion
+import os
+import site
+import sys
+
+from .pyversion import check_python_version
+check_python_version()
+
 
-###############################################################################
-# Define the api version
-###############################################################################
 def apiVersion():
     """Indicates that this is version 2
     of the API
     """
     return 2
 
-###############################################################################
-# GUI - Do this as early as possible
-###############################################################################
-# Flag indicating whether the GUI layer is loaded.
+
+# Bail out early if a Mantid.properties files is not found in the
+# parent directory - it indicates a broken installation or build.
+_moduledir = os.path.abspath(os.path.dirname(__file__))
+_bindir = os.path.dirname(_moduledir)
+if not os.path.exists(os.path.join(_bindir, 'Mantid.properties')):
+    raise ImportError("Unable to find Mantid.properties file next to this package - broken installation!")
+
+# Windows doesn"t have rpath settings so make sure the C-extensions can find the rest of the
+# mantid dlls. We assume they will be next to the properties file.
+if sys.platform == "win32":
+    os.environ["PATH"] = _bindir + ";" + os.environ.get("PATH", "")
+# Make sure the config service loads this properties file
+os.environ["MANTIDPATH"] = _bindir
+# Add directory as a site directory to process the .pth files
+site.addsitedir(_bindir)
+
 try:
+    # Flag indicating whether mantidplot layer is loaded.
     import _qti
     __gui__ = True
 except ImportError:
     __gui__ = False
 
-###############################################################################
 # Set deprecation warnings back to default (they are ignored in 2.7)
-###############################################################################
 import warnings as _warnings
 # Default we see everything
 _warnings.filterwarnings("default",category=DeprecationWarning,
@@ -62,112 +74,18 @@ _warnings.filterwarnings("ignore",category=DeprecationWarning,
                          module="numpy.oldnumeric")
 
 ###############################################################################
-# Try to be smarter when finding Mantid framework libraries
+# Load all non-plugin subpackages that contain a C-extension. The boost.python
+# registry will be missing entries if all are not loaded.
 ###############################################################################
-# Peek to see if a Mantid.properties file is in the parent directory,
-# if so assume that it is the required Mantid bin directory containing
-# the Mantid libraries and ignore any MANTIDPATH that has been set
-import os as _os
-_moduledir = _os.path.abspath(_os.path.dirname(__file__))
-_bindir = _os.path.dirname(_moduledir)
-if _os.path.exists(_os.path.join(_bindir, 'Mantid.properties')):
-    _os.environ['MANTIDPATH'] = _bindir
+from . import kernel as _kernel
+from . import api as _api
+from . import geometry as _geometry
+from . import dataobjects as _dataobjects
 
-###############################################################################
-# Ensure the sub package C libraries are loaded
-###############################################################################
-import contextlib as _context
-
-@_context.contextmanager
-def _shared_cextension():
-    """Our extensions need to shared symbols amongst them due to:
-      - the static boost python type registry
-      - static singleton instances marked as weak symbols by clang
-    gcc uses an extension to mark these attributes as globally unique
-    but clang marks them as weak and without RTLD_GLOBAL each shared
-    library has its own copy of each singleton.
-
-    See https://docs.python.org/3/library/sys.html#sys.setdlopenflags
-    """
-    import sys
-    if not sys.platform.startswith('linux'):
-        yield
-        return
-
-    import six
-    if six.PY2:
-        import DLFCN as dl
-    else:
-        import os as dl
-    flags_orig = sys.getdlopenflags()
-    sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
-    yield
-    sys.setdlopenflags(flags_orig)
-
-with _shared_cextension():
-    import mantid.kernel as kernel
-    import mantid.geometry as geometry
-    import mantid.api as api
-    import mantid.dataobjects as dataobjects
-    import mantid._plugins as _plugins
-    import mantid.plots as plots
-
-###############################################################################
-# Make the aliases from each module accessible in a the mantid namspace
-###############################################################################
-from mantid.kernel._aliases import *
-from mantid.api._aliases import *
+# Make the aliases from each module accessible in a the mantid namespace
+from .kernel._aliases import *
+from .api._aliases import *
 
-###############################################################################
 # Make the version string accessible in the standard way
-###############################################################################
-__version__ = kernel.version_str()
-
-###############################################################################
-# Load the Python plugins now everything has started.
-#
-# Before the plugins are loaded the simpleapi module is called to create
-# fake error-raising functions for all of the plugins. After the plugins have been
-# loaded the correction translation is applied to create the "real" simple
-# API functions.
-#
-# Although this seems odd it is necessary so that any PythonAlgorithm
-# can call any other PythonAlgorithm through the simple API mechanism. If left
-# to the simple import mechanism then plugins that are loaded later cannot
-# be seen by the earlier ones (chicken & the egg essentially).
-################################################################################
-from . import simpleapi as _simpleapi
-from mantid.kernel import plugins as _plugins
-from mantid.kernel.packagesetup import update_sys_paths as _update_sys_paths
-
-_plugins_key = 'python.plugins.directories'
-_user_key = 'user.%s' % _plugins_key
-plugin_dirs = _plugins.get_plugin_paths_as_set(_plugins_key)
-plugin_dirs.update(_plugins.get_plugin_paths_as_set(_user_key))
-_update_sys_paths(plugin_dirs, recursive=True)
-
-# Load
-plugin_files = []
-alg_files = []
-for directory in plugin_dirs:
-    try:
-        all_plugins, algs = _plugins.find_plugins(directory)
-        plugin_files += all_plugins
-        alg_files += algs
-    except ValueError as exc:
-        logger.warning('Exception encountered during plugin discovery: {0}'.format(str(exc)))
-        continue
-
-# Mockup the full API first so that any Python algorithm module has something to import
-_simpleapi._mockup(alg_files)
-# Load the plugins.
-plugin_modules = _plugins.load(plugin_files)
-# Create the proper algorithm definitions in the module
-new_attrs = _simpleapi._translate()
-# Finally, overwrite the mocked function definitions in the loaded modules with the real ones
-_plugins.sync_attrs(_simpleapi, new_attrs, plugin_modules)
-
-################################################################################
-
-from .fitfunctions import _attach_wrappers
-_attach_wrappers(_simpleapi)
+from .kernel import version_str as _version_str
+__version__ = _version_str()
diff --git a/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt b/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt
index 0b1fd0e1346bba88c238136742dbc0554895caaa..d75e5076b2f8770e5d87fa7c757d8aebf1a6553d 100644
--- a/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt
@@ -67,11 +67,12 @@ target_link_libraries ( PythonCurveFittingModule LINK_PRIVATE ${TCMALLOC_LIBRARI
 
 if (OSX_VERSION VERSION_GREATER 10.8)
   set_target_properties( PythonCurveFittingModule PROPERTIES
-                         INSTALL_RPATH "@loader_path/../../../MacOS;@loader_path/../kernel/;@loader_path/../geometry/;@loader_path/../api/")
+    INSTALL_RPATH "@loader_path/../../../MacOS;@loader_path/../../../../plugins;@loader_path/../kernel/;@loader_path/../geometry/;@loader_path/../api/")
 elseif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
   set_target_properties( PythonCurveFittingModule PROPERTIES
-                         INSTALL_RPATH "\$ORIGIN/../../../${LIB_DIR};\$ORIGIN/../kernel/;\$ORIGIN/../geometry/;\$ORIGIN/../api/")
+    INSTALL_RPATH "\$ORIGIN/../../../${LIB_DIR};\$ORIGIN/../../../${PLUGINS_DIR};\$ORIGIN/../kernel/;\$ORIGIN/../geometry/;\$ORIGIN/../api/")
 endif ()
+
 ###########################################################################
 # Installation settings
 ###########################################################################
diff --git a/Framework/PythonInterface/mantid/_plugins/__init__.py b/Framework/PythonInterface/mantid/_plugins/__init__.py
index 1227b4da9c95bd8fb3f5ee14be7565e0f54956ab..ac9e8c5039dffa843f4415d63b7fbbaa782a2883 100644
--- a/Framework/PythonInterface/mantid/_plugins/__init__.py
+++ b/Framework/PythonInterface/mantid/_plugins/__init__.py
@@ -25,4 +25,7 @@ from __future__ import (absolute_import, division,
 ###############################################################################
 # Load the C++ library and register the C++ class exports
 ###############################################################################
-from . import _curvefitting
+from ..kernel import _shared_cextension
+
+with _shared_cextension():
+    from . import _curvefitting
diff --git a/Framework/PythonInterface/mantid/api/__init__.py b/Framework/PythonInterface/mantid/api/__init__.py
index 1dcdc32e70ff78dfcc7bd3eaa914919d81b75392..882f1a5d5bd8e8efc23c611dc969492f2bedb541 100644
--- a/Framework/PythonInterface/mantid/api/__init__.py
+++ b/Framework/PythonInterface/mantid/api/__init__.py
@@ -15,20 +15,9 @@ from __future__ import (absolute_import, division,
                         print_function)
 
 # Load the C++ library
-from . import _api
-from ._api import *
-
-# stdlib imports
-import atexit as _atexit
-
-###############################################################################
-# Start the framework
-###############################################################################
-FrameworkManagerImpl.Instance()
-_atexit.register(FrameworkManagerImpl.Instance().shutdown)
-
-# Declare any additional C++ algorithms defined in this package
-_api._declareCPPAlgorithms()
+from ..kernel import _shared_cextension
+with _shared_cextension():
+    from ._api import *
 
 ###############################################################################
 # Make aliases accessible in this namespace
diff --git a/Framework/PythonInterface/mantid/api/_aliases.py b/Framework/PythonInterface/mantid/api/_aliases.py
index ee9537702786fdcbca6d332fc9614d9ddc35e3cd..bc27830f56542b56254647a29abce2b4bfcfb379 100644
--- a/Framework/PythonInterface/mantid/api/_aliases.py
+++ b/Framework/PythonInterface/mantid/api/_aliases.py
@@ -14,18 +14,28 @@ from ._api import (FrameworkManagerImpl, AnalysisDataServiceImpl,
                    AlgorithmFactoryImpl, AlgorithmManagerImpl,
                    FileFinderImpl, FileLoaderRegistryImpl, FunctionFactoryImpl,
                    WorkspaceFactoryImpl, CatalogManagerImpl)
+from ..kernel._aliases import lazy_instance_access
 
-###############################################################################
-# Singleton
-###############################################################################
+# Historically the singleton aliases mapped to the instances rather than
+# the class types, i.e. AnalysisDataService is the instance and not the type,
+# which doesn't match the C++ behaviour.
+#
+# Exit handlers are important in some cases as the associated singleton
+# stores references to python objects that need to be cleaned up
+# Without a python-based exit handler the singletons are only cleaned
+# up after main() and this is too late to acquire the GIL to be able to
+# delete the python objects.
+# If you see a segfault late in a python process related to the GIL
+# it is likely an exit handler is missing.
+AnalysisDataService = lazy_instance_access(AnalysisDataServiceImpl)
+AlgorithmFactory = lazy_instance_access(AlgorithmFactoryImpl)
+AlgorithmManager = lazy_instance_access(AlgorithmManagerImpl)
+FileFinder = lazy_instance_access(FileFinderImpl)
+FileLoaderRegistry = lazy_instance_access(FileLoaderRegistryImpl)
+FrameworkManager = lazy_instance_access(FrameworkManagerImpl)
+FunctionFactory = lazy_instance_access(FunctionFactoryImpl)
+WorkspaceFactory = lazy_instance_access(WorkspaceFactoryImpl)
+CatalogManager = lazy_instance_access(CatalogManagerImpl)
 
-FrameworkManager = FrameworkManagerImpl.Instance()
-AnalysisDataService = AnalysisDataServiceImpl.Instance()
-mtd = AnalysisDataService #tradition
-AlgorithmFactory = AlgorithmFactoryImpl.Instance()
-AlgorithmManager = AlgorithmManagerImpl.Instance()
-FileFinder = FileFinderImpl.Instance()
-FileLoaderRegistry = FileLoaderRegistryImpl.Instance()
-FunctionFactory = FunctionFactoryImpl.Instance()
-WorkspaceFactory = WorkspaceFactoryImpl.Instance()
-CatalogManager = CatalogManagerImpl.Instance()
+# backwards-compatible
+mtd = AnalysisDataService
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmManager.cpp b/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmManager.cpp
index cc0aee81a49a26b55cdc1852a5da5c6054457096..9c4b374f962326c2331b27b00fbee7461a3a0f95 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmManager.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmManager.cpp
@@ -18,6 +18,26 @@ using Mantid::PythonInterface::AlgorithmIDProxy;
 using namespace boost::python;
 
 namespace {
+
+std::once_flag INIT_FLAG;
+
+/**
+ * Returns a reference to the AlgorithmManager object, creating it
+ * if necessary. In addition to creating the object the first call also:
+ *   - register AlgorithmManager.shutdown as an atexit function
+ * @return A reference to the AlgorithmManager instance
+ */
+AlgorithmManagerImpl &instance() {
+  // start the framework (if necessary)
+  auto &mgr = AlgorithmManager::Instance();
+  std::call_once(INIT_FLAG, []() {
+    PyRun_SimpleString("import atexit\n"
+                       "from mantid.api import AlgorithmManager\n"
+                       "atexit.register(lambda: AlgorithmManager.clear())");
+  });
+  return mgr;
+}
+
 /**
  * Return the algorithm identified by the given ID. A wrapper version that takes
  * a
@@ -107,7 +127,7 @@ void export_AlgorithmManager() {
            "Clears the current list of managed algorithms")
       .def("cancelAll", &AlgorithmManagerImpl::cancelAll, arg("self"),
            "Requests that all currently running algorithms be cancelled")
-      .def("Instance", &AlgorithmManager::Instance,
+      .def("Instance", instance,
            return_value_policy<reference_existing_object>(),
            "Return a reference to the singleton instance")
       .staticmethod("Instance");
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp b/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp
index a778874d61efcc4268f749bec833acd75aa6abc0..23213e94b6b6e0792f1d055be77f1737a44d3f35 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp
@@ -24,6 +24,31 @@ using namespace boost::python;
 GET_POINTER_SPECIALIZATION(AnalysisDataServiceImpl)
 
 namespace {
+std::once_flag INIT_FLAG;
+
+/**
+ * Returns a reference to the AnalysisDataService object, creating it
+ * if necessary. In addition to creating the object the first call also:
+ *   - register AnalysisDataService.clear as an atexit function
+ * @return A reference to the FrameworkManagerImpl instance
+ */
+AnalysisDataServiceImpl &instance() {
+  // start the framework (if necessary)
+  auto &ads = AnalysisDataService::Instance();
+  std::call_once(INIT_FLAG, []() {
+    PyRun_SimpleString("import atexit\n"
+                       "from mantid.api import AnalysisDataService\n"
+                       "atexit.register(lambda: AnalysisDataService.clear())");
+  });
+  return ads;
+}
+
+/**
+ * @param self A reference to the AnalysisDataServiceImpl
+ * @param names The list of names to extract
+ * @param unrollGroups If true unroll the workspace groups
+ * @return a python list of the workspaces in the ADS
+ */
 list retrieveWorkspaces(AnalysisDataServiceImpl &self, const list &names,
                         bool unrollGroups = false) {
   return Converters::ToPyList<Workspace_sptr>()(self.retrieveWorkspaces(
@@ -45,7 +70,7 @@ void export_AnalysisDataService() {
       DataServiceExporter<AnalysisDataServiceImpl, Workspace_sptr>;
   auto pythonClass = ADSExporter::define("AnalysisDataServiceImpl");
   pythonClass
-      .def("Instance", &AnalysisDataService::Instance,
+      .def("Instance", instance,
            return_value_policy<reference_existing_object>(),
            "Return a reference to the singleton instance")
       .staticmethod("Instance")
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/FrameworkManager.cpp b/Framework/PythonInterface/mantid/api/src/Exports/FrameworkManager.cpp
index c87f29ca7f860497f05fad31c54e7246fed63518..97eef7a231407184b44e91010908cb212344bce6 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/FrameworkManager.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/FrameworkManager.cpp
@@ -5,15 +5,90 @@
 //     & Institut Laue - Langevin
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidKernel/ConfigService.h"
+#include "MantidKernel/WarningSuppressions.h"
+#include "MantidPythonInterface/api/Algorithms/RunPythonScript.h"
 
 #include <boost/python/class.hpp>
+#include <boost/python/import.hpp>
 #include <boost/python/reference_existing_object.hpp>
 #include <boost/python/return_value_policy.hpp>
 
+#include <mutex>
+
+using Mantid::API::AlgorithmFactory;
 using Mantid::API::FrameworkManager;
 using Mantid::API::FrameworkManagerImpl;
+using Mantid::Kernel::ConfigService;
 using namespace boost::python;
 
+namespace {
+
+std::once_flag INIT_FLAG;
+bool INSTANCE_CALLED = false;
+constexpr auto PYTHONPATHS_KEY = "pythonscripts.directories";
+
+/**
+ * We don't want to register the C++ algorithms on loading the api python
+ * module since we want then be able to control when the various singletons
+ * are created if we are being imported from vanilla Python. This function
+ * registers the any C++ algorithms and should be called once.
+ */
+void declareCPPAlgorithms() {
+  AlgorithmFactory::Instance()
+      .subscribe<Mantid::PythonInterface::RunPythonScript>();
+}
+
+/**
+ * @brief Append to the sys.path any paths defined in the config key
+ * pythonscripts.directories
+ */
+void updatePythonPaths() {
+  auto packagesetup = import("mantid.kernel.packagesetup");
+  packagesetup.attr("update_sys_paths")(
+      ConfigService::Instance()
+          .getValue<std::string>(PYTHONPATHS_KEY)
+          .get_value_or(""));
+}
+
+/**
+ * Returns a reference to the FrameworkManager object, creating it
+ * if necessary. In addition to creating the object the first call also:
+ *   - registers the C++ algorithms declared in this library
+ *   - updates the Python paths with any user-defined directories
+ *     declared in the `pythonscripts.directories`
+ *   - import mantid.simpleapi (if not already imported) to load python plugins
+ *   - register FrameworkManager.shutdown as an atexit function
+ * @param importSimpleApi If true the the mantid.simpleapi module is imported on
+ * first access
+ * @return A reference to the FrameworkManagerImpl instance
+ */
+FrameworkManagerImpl &instance() {
+  // start the framework (if necessary)
+  auto &frameworkMgr = FrameworkManager::Instance();
+  std::call_once(INIT_FLAG, []() {
+    INSTANCE_CALLED = true;
+    declareCPPAlgorithms();
+    updatePythonPaths();
+    import("mantid.simpleapi");
+    // Without a python-based exit handler the singletons are only cleaned
+    // up after main() and this is too late to acquire the GIL to be able to
+    // delete any python objects still stored in other singletons like the
+    // ADS or AlgorithmManager.
+    PyRun_SimpleString("import atexit\n"
+                       "from mantid.api import FrameworkManager\n"
+                       "atexit.register(lambda: FrameworkManager.shutdown())");
+
+  });
+  return frameworkMgr;
+}
+
+/**
+ * @return True if .instance has been called, false otherwise
+ */
+bool hasInstance() { return INSTANCE_CALLED; }
+} // namespace
+
 void export_FrameworkManager() {
   class_<FrameworkManagerImpl, boost::noncopyable>("FrameworkManagerImpl",
                                                    no_init)
@@ -53,8 +128,11 @@ void export_FrameworkManager() {
       .def("shutdown", &FrameworkManagerImpl::shutdown, arg("self"),
            "Effectively shutdown this service")
 
-      .def("Instance", &FrameworkManager::Instance,
-           return_value_policy<reference_existing_object>(),
-           "Return a reference to the singleton instance")
+      .def("hasInstance", hasInstance,
+           "Returns True if Instance has been called, false otherwise")
+      .staticmethod("hasInstance")
+
+      .def("Instance", instance, "Return a reference to the singleton instance",
+           return_value_policy<reference_existing_object>())
       .staticmethod("Instance");
 }
diff --git a/Framework/PythonInterface/mantid/api/src/api.cpp.in b/Framework/PythonInterface/mantid/api/src/api.cpp.in
index 27d5554925e19187a3ae602d5ad6eaf41521eb47..33566e819bf0aa561340d602ab4439ceb764d09a 100644
--- a/Framework/PythonInterface/mantid/api/src/api.cpp.in
+++ b/Framework/PythonInterface/mantid/api/src/api.cpp.in
@@ -20,22 +20,9 @@
 
 #include "MantidAPI/AlgorithmFactory.h"
 #include "MantidAPI/Workspace.h"
-#include "MantidPythonInterface/api/Algorithms/RunPythonScript.h"
 
 namespace
 {
-  /**
-   * We don't want to register the C++ algorithms on loading the python module
-   * since we want then be able to control when the various singletons are started if
-   * we are being imported from vanilla Python.
-   * Here we export a single function that can be called after the FrameworkManager
-   * has been started to registered any hard-coded C++ algorithms that are
-   * contained within this module.
-   */
-  void _declareCPPAlgorithms()
-  {
-    Mantid::API::AlgorithmFactory::Instance().subscribe<Mantid::PythonInterface::RunPythonScript>();
-  }
 
   /**
    * Checks if two workspace shared pointers point to the same workspace
@@ -56,9 +43,6 @@ BOOST_PYTHON_MODULE(_api)
   boost::python::docstring_options docstrings(true, true, false);
   // Import numpy
   _import_array();
-  
-  // Internal function to declare C++ algorithms that are a part of this module
-  boost::python::def("_declareCPPAlgorithms", &_declareCPPAlgorithms);
 
   // Workspace address comparison
   boost::python::def("isSameWorkspaceObject",
diff --git a/Framework/PythonInterface/mantid/dataobjects/__init__.py b/Framework/PythonInterface/mantid/dataobjects/__init__.py
index 6250fac0b906b76429f7930537ca9739f1e455aa..7760476fd2bb0c5912a32d7a6a59f44b3ae96ab4 100644
--- a/Framework/PythonInterface/mantid/dataobjects/__init__.py
+++ b/Framework/PythonInterface/mantid/dataobjects/__init__.py
@@ -25,5 +25,10 @@ from __future__ import (absolute_import, division,
 ###############################################################################
 # Load the C++ library and register the C++ class exports
 ###############################################################################
-from . import _dataobjects
-from ._dataobjects import *
+# Load library dependencies
+from ..kernel import _shared_cextension
+import mantid.api
+
+with _shared_cextension():
+    from . import _dataobjects
+    from ._dataobjects import *
diff --git a/Framework/PythonInterface/mantid/fitfunctions.py b/Framework/PythonInterface/mantid/fitfunctions.py
index 55b3c78a001a3d3569b5c3d4ce737f16ffc2321b..fd53996acf888f8fbeb16907b8f70db2c4de404b 100644
--- a/Framework/PythonInterface/mantid/fitfunctions.py
+++ b/Framework/PythonInterface/mantid/fitfunctions.py
@@ -768,11 +768,12 @@ def _create_wrapper_function(name):
     return wrapper_function
 
 
-def _attach_wrappers(source_module):
+def _wrappers():
+    wrappers = []
     for name in FunctionFactory.getFunctionNames():
         # Wrap all registered functions which are not in the black list
         if name not in _do_not_wrap:
-            setattr(source_module, name, _create_wrapper_function(name))
+            yield name, _create_wrapper_function(name)
 
 
 _ExportedIFunction1D = IFunction1D
diff --git a/Framework/PythonInterface/mantid/geometry/__init__.py b/Framework/PythonInterface/mantid/geometry/__init__.py
index cd0a7d88786c602c11ce401ef21bb021d0214699..b63d13eb8231eed4cbe2c72d8dfb9806acf0035b 100644
--- a/Framework/PythonInterface/mantid/geometry/__init__.py
+++ b/Framework/PythonInterface/mantid/geometry/__init__.py
@@ -17,7 +17,10 @@ from __future__ import (absolute_import, division,
 ###############################################################################
 # Load the C++ library
 ###############################################################################
-from ._geometry import *
+from ..kernel import _shared_cextension
+
+with _shared_cextension():
+    from ._geometry import *
 
 ###############################################################################
 # Make aliases accessible in this namespace
diff --git a/Framework/PythonInterface/mantid/geometry/_aliases.py b/Framework/PythonInterface/mantid/geometry/_aliases.py
index d0a14a43638d5a881e902b4fbf94155d9ac2bf63..fe1422d409a3a5f831fc1201beb24cfbd1fdb065 100644
--- a/Framework/PythonInterface/mantid/geometry/_aliases.py
+++ b/Framework/PythonInterface/mantid/geometry/_aliases.py
@@ -11,13 +11,14 @@
 from __future__ import (absolute_import, division,
                         print_function)
 
+from ..kernel._aliases import lazy_instance_access
 from ._geometry import (SpaceGroupFactoryImpl, SymmetryOperationFactoryImpl,
                         SymmetryElementFactoryImpl, PointGroupFactoryImpl)
 
 ###############################################################################
-# Singleton
+# Singletons
 ###############################################################################
-SpaceGroupFactory = SpaceGroupFactoryImpl.Instance()
-SymmetryOperationFactory = SymmetryOperationFactoryImpl.Instance()
-SymmetryElementFactory = SymmetryElementFactoryImpl.Instance()
-PointGroupFactory = PointGroupFactoryImpl.Instance()
+SpaceGroupFactory = lazy_instance_access(SpaceGroupFactoryImpl)
+SymmetryOperationFactory = lazy_instance_access(SymmetryOperationFactoryImpl)
+SymmetryElementFactory = lazy_instance_access(SymmetryElementFactoryImpl)
+PointGroupFactory = lazy_instance_access(PointGroupFactoryImpl)
diff --git a/Framework/PythonInterface/mantid/kernel/__init__.py b/Framework/PythonInterface/mantid/kernel/__init__.py
index 29267e05171689767fd3e9ca74220dd07e4d78a3..8afb89228bdf0451ebabeb6fbe9f1cc6f1d14637 100644
--- a/Framework/PythonInterface/mantid/kernel/__init__.py
+++ b/Framework/PythonInterface/mantid/kernel/__init__.py
@@ -14,18 +14,44 @@ Defines Python objects that wrap the C++ Kernel namespace.
 from __future__ import (absolute_import, division,
                         print_function)
 
+import os as _os
+from contextlib import contextmanager
+
+@contextmanager
+def _shared_cextension():
+    """Our extensions need to shared symbols amongst them due to:
+      - the static boost python type registry
+      - static singleton instances marked as weak symbols by clang
+    gcc uses an extension to mark these attributes as globally unique
+    but clang marks them as weak and without RTLD_GLOBAL each shared
+    library has its own copy of each singleton.
+
+    See https://docs.python.org/3/library/sys.html#sys.setdlopenflags
+    """
+    import sys
+    if not sys.platform.startswith('linux'):
+        yield
+        return
+
+    import six
+    if six.PY2:
+        import DLFCN as dl
+    else:
+        import os as dl
+    flags_orig = sys.getdlopenflags()
+    sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
+    yield
+    sys.setdlopenflags(flags_orig)
+
+
 # Imports boost.mpi if applicable
 from . import mpisetup
 
 ###############################################################################
 # Load the C++ library
 ###############################################################################
-from ._kernel import *
-
-###############################################################################
-# Do any site-specific setup for packages
-###############################################################################
-from . import packagesetup as _packagesetup
+with _shared_cextension():
+    from ._kernel import *
 
 ###############################################################################
 # Make modules available in this namespace
@@ -37,3 +63,8 @@ from ._aliases import *
 # module alias for backwards-compatability in user scripts
 funcreturns = funcinspect
 
+###############################################################################
+# Do site-specific setup for packages
+###############################################################################
+from . import packagesetup as _mantidsite
+_mantidsite.set_NEXUSLIB_var()
diff --git a/Framework/PythonInterface/mantid/kernel/_aliases.py b/Framework/PythonInterface/mantid/kernel/_aliases.py
index b51972a2912dcb377e5b1464ececdde46fa526cd..607055a7163afcf95ab9f3fba31dc1b24967c261 100644
--- a/Framework/PythonInterface/mantid/kernel/_aliases.py
+++ b/Framework/PythonInterface/mantid/kernel/_aliases.py
@@ -14,17 +14,58 @@ from __future__ import (absolute_import, division,
 from ._kernel import (ConfigServiceImpl, Logger, UnitFactoryImpl,
                       UsageServiceImpl, PropertyManagerDataServiceImpl)
 
-###############################################################################
-# Singletons - Make them just look like static classes
-###############################################################################
-UsageService = UsageServiceImpl.Instance()
-ConfigService = ConfigServiceImpl.Instance()
-config = ConfigService
 
-PropertyManagerDataService = PropertyManagerDataServiceImpl.Instance()
-pmds = PropertyManagerDataService
+def lazy_instance_access(cls):
+    """
+    Takes a singleton class and wraps it in an LazySingletonHolder
+    that constructs the instance on first access.
+
+     Historically, mantid <= v3.13, the singleton aliases mapped to the
+    instances rather than the class types, i.e. UsageService is the instance and not the type.
+    To preserve compatibility with existing scripts, where users have not called UsageService.Instance(),
+    but also allow the singleton instance startup to be delayed we create a thin wrapper that
+    delays the first .Instance() call until an attribute is accessed on the wrapper.
+
+
+    :param cls: The singleton class type
+    :return: A new LazySingletonHolder wrapping cls
+    """
+    class LazySingletonHolder(object):
+        """
+        Delays construction of a singleton instance until the
+        first attribute access.
+        """
+
+        def __getattribute__(self, item):
+            # Called for each attribute access. cls.Instance() constructs
+            # the singleton at first access
+            return cls.__getattribute__(cls.Instance(), item)
+
+        def __len__(self):
+            return cls.__getattribute__(cls.Instance(), "__len__")()
 
-UnitFactory = UnitFactoryImpl.Instance()
+        def __getitem__(self, item):
+            return cls.__getattribute__(cls.Instance(), "__getitem__")(item)
+
+        def __setitem__(self, item, value):
+            return cls.__getattribute__(cls.Instance(), "__setitem__")(item, value)
+
+        def __delitem__(self, item):
+            return cls.__getattribute__(cls.Instance(), "__delitem__")(item)
+
+        def __contains__(self, item):
+            return cls.__getattribute__(cls.Instance(), "__contains__")(item)
+
+    return LazySingletonHolder()
+
+
+UsageService = lazy_instance_access(UsageServiceImpl)
+ConfigService = lazy_instance_access(ConfigServiceImpl)
+PropertyManagerDataService = lazy_instance_access(PropertyManagerDataServiceImpl)
+UnitFactory = lazy_instance_access(UnitFactoryImpl)
+
+config = ConfigService
+pmds = PropertyManagerDataService
 
 ###############################################################################
 # Set up a general Python logger. Others can be created as they are required
diff --git a/Framework/PythonInterface/mantid/kernel/funcinspect.py b/Framework/PythonInterface/mantid/kernel/funcinspect.py
index ebec73649dfa5724f0d77ecb053bf7a417819359..ff8eac18c91100a0a34c8fe98f670d41fd13f4c1 100644
--- a/Framework/PythonInterface/mantid/kernel/funcinspect.py
+++ b/Framework/PythonInterface/mantid/kernel/funcinspect.py
@@ -20,7 +20,7 @@ import sys
 import dis
 from six import PY3
 
-#-------------------------------------------------------------------------------
+
 def replace_signature(func, varnames):
     """
     Replace the signature of the given function object with that given by
@@ -48,7 +48,7 @@ def replace_signature(func, varnames):
     #endif
     setattr(func, code_attr, c)
 
-#-------------------------------------------------------------------------------
+
 def customise_func(func, name, signature, docstring):
     """
     Takes the definition of the algorithm function and replaces
diff --git a/Framework/PythonInterface/mantid/kernel/packagesetup.py.in b/Framework/PythonInterface/mantid/kernel/packagesetup.py.in
index 5f355a3bd05efcfaedff052b687d59e98376dccf..f8831ef9599c1c80a94ea1f5e526fa6eafd8e1b8 100644
--- a/Framework/PythonInterface/mantid/kernel/packagesetup.py.in
+++ b/Framework/PythonInterface/mantid/kernel/packagesetup.py.in
@@ -8,7 +8,7 @@ from __future__ import (absolute_import, division,
                         print_function)
 import os as _os
 import sys as _sys
-###############################################################################
+
 
 def update_sys_paths(paths, recursive=False):
     """
@@ -25,7 +25,7 @@ def update_sys_paths(paths, recursive=False):
         paths = paths.split(";")
 
     def _append_to_path(path):
-        #sys.path doesn't like trailing slashes
+        # sys.path doesn't like trailing slashes
         _sys.path.append(path.rstrip("\\").rstrip("/"))
 
     for path in paths:
@@ -35,7 +35,6 @@ def update_sys_paths(paths, recursive=False):
                 for dirname in dirnames:
                     _append_to_path(_os.path.join(dirpath, dirname))
 
-########################################################################################
 
 def set_NEXUSLIB_var():
     """
@@ -52,18 +51,3 @@ def set_NEXUSLIB_var():
         _nexuslib = _os.path.normpath(_os.path.join(thisdir, _nexuslib))
 
     _os.environ['NEXUSLIB'] = _nexuslib
-
-#########################################################################################
-
-## Setup on import ##
-import os as _os
-update_sys_paths(_os.environ.get("MANTIDPATH",""))
-
-from ._aliases import config as _config
-_path_keys = ['requiredpythonscript.directories','pythonscripts.directories']
-for key in _path_keys:
-    paths = _config[key]
-    update_sys_paths(paths)
-
-# NeXus
-set_NEXUSLIB_var()
diff --git a/Framework/PythonInterface/mantid/kernel/plugins.py b/Framework/PythonInterface/mantid/kernel/plugins.py
index 9fa5b5c6d6d5d2b76a47d998cce8f0da8047740b..99e7a396b09699d17e60e935dc403223c68597e7 100644
--- a/Framework/PythonInterface/mantid/kernel/plugins.py
+++ b/Framework/PythonInterface/mantid/kernel/plugins.py
@@ -15,6 +15,7 @@ from __future__ import (absolute_import, division,
 
 import os as _os
 import sys as _sys
+from traceback import format_exc
 try:
     from importlib.machinery import SourceFileLoader
 except ImportError:
@@ -193,8 +194,8 @@ def load_from_file(filepath):
     try:
         name, module = load_plugin(filepath)
         loaded.append(module)
-    except Exception as exc:
-        logger.warning("Failed to load plugin %s. Error: %s" % (filepath, str(exc)))
+    except Exception:
+        logger.warning("Failed to load plugin %s.\nError: %s" % (filepath, format_exc()))
 
     return loaded
 
@@ -215,20 +216,19 @@ def load_plugin(plugin_path):
 
 #======================================================================================================================
 
-def sync_attrs(source_module, attrs, clients):
+def sync_attrs(source, attrs, clients):
     """
         Syncs the attribute definitions between the
         given list from the source module & list of client modules such
         that the function defintions point to the same
         one
-        @param source_module :: The module containing the "correct"
-                                definitions
+        @param source :: A dictionary containing the real attribute definitions
         @param attrs :: The list of attributes to change in the client modules
         @param clients :: A list of modules whose attribute definitions
                           should be taken from source
     """
     for func_name in attrs:
-        attr = getattr(source_module, func_name)
+        attr = source[func_name]
         for plugin in clients:
             if hasattr(plugin, func_name):
                 setattr(plugin, func_name, attr)
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp
index f29a7668252e02da1151e3306ed2dd2ad8e05e0f..628f8ffedd53fe599c8aa32ecd9a498f904f479b 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp
@@ -9,12 +9,36 @@
 #include <boost/python/class.hpp>
 #include <boost/python/reference_existing_object.hpp>
 
+#include <mutex>
+
 using Mantid::Kernel::UsageService;
 using Mantid::Kernel::UsageServiceImpl;
 using namespace boost::python;
 
 GET_POINTER_SPECIALIZATION(UsageServiceImpl)
 
+namespace {
+
+std::once_flag INIT_FLAG;
+
+/**
+ * Returns a reference to the UsageService object, creating it
+ * if necessary. In addition to creating the object the first call also:
+ *   - register UsageService.shutdown as an atexit function
+ * @return A reference to the UsageService instance
+ */
+UsageServiceImpl &instance() {
+  // start the framework (if necessary)
+  auto &svc = UsageService::Instance();
+  std::call_once(INIT_FLAG, []() {
+    PyRun_SimpleString("import atexit\n"
+                       "from mantid.kernel import UsageService\n"
+                       "atexit.register(lambda: UsageService.shutdown())");
+  });
+  return svc;
+}
+} // namespace
+
 void export_UsageService() {
 
   class_<UsageServiceImpl, boost::noncopyable>("UsageServiceImpl", no_init)
@@ -33,17 +57,17 @@ void export_UsageService() {
       .def("setInterval", &UsageServiceImpl::setEnabled,
            (arg("self"), arg("seconds")),
            "Sets the interval that the timer checks for tasks.")
-      .def("setApplication", &UsageServiceImpl::setApplication,
+      .def("setApplicationName", &UsageServiceImpl::setApplicationName,
            (arg("self"), arg("name")),
            "Sets the application name that has invoked Mantid.")
-      .def("getApplication", &UsageServiceImpl::getApplication, arg("self"),
-           "Gets the application name that has invoked Mantid.")
+      .def("getApplicationName", &UsageServiceImpl::getApplicationName,
+           arg("self"), "Gets the application name that has invoked Mantid.")
       .def("registerStartup", &UsageServiceImpl::registerStartup, arg("self"),
            "Registers the startup of Mantid.")
       .def("registerFeatureUsage", &UsageServiceImpl::registerFeatureUsage,
            (arg("self"), arg("type"), arg("name"), arg("internal")),
            "Registers the use of a feature in Mantid.")
-      .def("Instance", &UsageService::Instance,
+      .def("Instance", instance,
            return_value_policy<reference_existing_object>(),
            "Returns a reference to the UsageService")
       .staticmethod("Instance");
diff --git a/Framework/PythonInterface/mantid/plots/__init__.py b/Framework/PythonInterface/mantid/plots/__init__.py
index c5e64186540e7fad44da8c57f908deb4d404341a..b910bc6ff731d5aa7ff72a1532ce232f707230ba 100644
--- a/Framework/PythonInterface/mantid/plots/__init__.py
+++ b/Framework/PythonInterface/mantid/plots/__init__.py
@@ -20,7 +20,27 @@ import mantid.plots.plotfunctions
 import mantid.plots.plotfunctions3D
 from matplotlib.axes import Axes
 from matplotlib.projections import register_projection
-from mpl_toolkits.mplot3d.axes3d import Axes3D
+
+try:
+    from mpl_toolkits.mplot3d.axes3d import Axes3D
+except ImportError:
+    # Special case to handle issues with importing mpl_toolkits
+    #
+    # Matplotlib adds a *nspkg.pth file to the user site packages directory.
+    # When that file is processed a fake built-in mpl_toolkits is imported
+    # which forces the site packages version to take precidence over our
+    # local copy regardless of python sys path settings.
+    #
+    # Work around by removing the fake built-in module from sys modules,
+    # then forcing python to search the path as expected.
+    #
+    # This is mostly but not necessarily limited to being an issue on OSX
+    # where there are multiple versions of matplotlib installed across the
+    # system.
+    import sys
+    del sys.modules['mpl_toolkits']
+    from mpl_toolkits.mplot3d.axes3d import Axes3D
+
 
 
 class MantidAxes(Axes):
diff --git a/Framework/PythonInterface/mantid/pyversion.py.in b/Framework/PythonInterface/mantid/pyversion.py.in
index 93a01f798583964edeb7744b14b9308e87171385..fe62ff95890b7e5582d6c59554d88fd6666fc3c8 100644
--- a/Framework/PythonInterface/mantid/pyversion.py.in
+++ b/Framework/PythonInterface/mantid/pyversion.py.in
@@ -7,13 +7,15 @@ import sys
 # Define the target major.minor version (i.e. the one mantid was built against)
 TARGET_VERSION="@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@"
 
-_vers_info = sys.version_info
-_running_vers = "%d.%d" % (_vers_info[0],_vers_info[1])
-if _running_vers != TARGET_VERSION:
-    message = \
-"""Python version mismatch, cannot continue.
-Mantid was built against version '%s' but you are running version '%s'. These versions
-must match.
-"""
-    raise ImportError(message % (TARGET_VERSION, _running_vers))
+
+def check_python_version():
+    vers_info = sys.version_info
+    running_vers = "%d.%d" % (vers_info[0], vers_info[1])
+    if running_vers != TARGET_VERSION:
+        message = \
+    """Python version mismatch, cannot continue.
+    Mantid was built against version '%s' but you are running version '%s'. These versions
+    must match.
+    """
+        raise ImportError(message % (TARGET_VERSION, running_vers))
 
diff --git a/Framework/PythonInterface/mantid/simpleapi.py b/Framework/PythonInterface/mantid/simpleapi.py
index 129e222d05155266971f48ddd239363aada876f2..a31cea9392a7f3da5d4acd402d086bd04ce4cb67 100644
--- a/Framework/PythonInterface/mantid/simpleapi.py
+++ b/Framework/PythonInterface/mantid/simpleapi.py
@@ -5,7 +5,7 @@
 #     & Institut Laue - Langevin
 # SPDX - License - Identifier: GPL - 3.0 +
 """
-This module defines a simple function-style API for running Mantid
+This module defines a function-style API for running Mantid
 algorithms. Each algorithm within Mantid is mapped to a Python
 function of the same name with the parameters of the algorithm becoming
 arguments to the function.
@@ -22,21 +22,30 @@ the variable it is assigned to, i.e.
    rebinned = Rebin(input, Params = '0.1,0.05,10')
 
 would call Rebin with the given parameters and create a workspace called 'rebinned'
-and assign it to the rebinned variable
+and assign it to the rebinned variable.
+
+Importing this module starts the FrameworkManager instance.
 """
 from __future__ import (absolute_import, division,
                         print_function)
 
-import six
-from six import iteritems
+# stdlib imports
 from collections import OrderedDict, namedtuple
 import os
+import six
+from six import iteritems
+import sys
 
+import mantid
 from . import api as _api
 from . import kernel as _kernel
+from .kernel import plugins as _plugin_helper
+from .kernel.packagesetup import update_sys_paths as _update_sys_paths
 from .kernel.funcinspect import lhs_info as _lhs_info
 from .kernel.funcinspect import replace_signature as _replace_signature
 from .kernel.funcinspect import customise_func as _customise_func
+# register matplotlib projection
+from . import plots  # noqa
 
 # This is a simple API so give access to the aliases by default as well
 from . import apiVersion, __gui__
@@ -44,7 +53,8 @@ from .kernel._aliases import *
 from .api._aliases import *
 from .fitfunctions import *
 
-# ------------------------ Specialized function calls --------------------------
+MODULE_NAME = 'simpleapi'
+
 # List of specialized algorithms
 __SPECIALIZED_FUNCTIONS__ = ["Load", "StartLiveData", "CutMD", "RenameWorkspace"]
 # List of specialized algorithms
@@ -1280,8 +1290,6 @@ def _create_algorithm_dialog(algorithm, version, _algm_object):
     for alias in _algm_object.alias().strip().split(): # split on whitespace
         globals()["{}Dialog".format(alias)] = algm_wrapper
 
-# --------------------------------------------------------------------------------------------------
-
 
 def _create_fake_function(name):
     """Create fake functions for the given name
@@ -1296,13 +1304,10 @@ def _create_fake_function(name):
     _replace_signature(fake_function, ("", ""))
     globals()[name] = fake_function
 
-# ------------------------------------------------------------------------------------------------------------
-
 
 def _mockup(plugins):
     """
-        Creates fake, error-raising functions for all loaded algorithms plus
-        any plugins given.
+        Creates fake, error-raising functions for any plugins given.
         The function name for the Python algorithms are taken from the filename
         so this mechanism requires the algorithm name to match the filename.
         This mechanism solves the "chicken-and-egg" problem with Python algorithms trying
@@ -1315,7 +1320,8 @@ def _mockup(plugins):
         function definitions can overwrite the "fake" ones.
         :param plugins: A list of  modules that have been loaded
     """
-    # --------------------------------------------------------------------------------------------------------
+    module_attrs = globals()
+
     def create_fake_function(func_name):
         """Create fake functions for the given func_name
         """
@@ -1330,40 +1336,23 @@ def _mockup(plugins):
         if specialization_exists(func_name):
             return
         fake_function.__name__ = func_name
-        globals()[func_name] = fake_function
-    # --------------------------------------------------------
+        module_attrs[func_name] = fake_function
 
-    def create_fake_functions(alg_names):
-        """Create fake functions for all of the listed names
-        """
-        for alg_name in alg_names:
-            create_fake_function(alg_name)
-    # -------------------------------------
-
-    # Start with the loaded C++ algorithms
-    from mantid.api import AlgorithmFactory
-    cppalgs = AlgorithmFactory.getRegisteredAlgorithms(True)
-    create_fake_functions(cppalgs.keys())
-
-    # Now the plugins
     for plugin in plugins:
         name = os.path.basename(plugin)
         name = os.path.splitext(name)[0]
         create_fake_function(name)
 
-# ------------------------------------------------------------------------------------------------------------
-
 
 def _translate():
     """
         Loop through the algorithms and register a function call
         for each of them
-        :returns: a list of new function calls
+        :returns: a list of the name of new function calls
     """
     from mantid.api import AlgorithmFactory, AlgorithmManager
 
-    # Names of new functions added to the global namespace
-    new_functions = []
+    new_func_attrs = []
     # Method names mapped to their algorithm names. Used to detect multiple copies of same method name
     # on different algorithms, which is an error
     new_methods = {}
@@ -1393,12 +1382,12 @@ def _translate():
                                    % (method_name, algm_object.name(), other_alg))
             _attach_algorithm_func_as_method(method_name, algorithm_wrapper, algm_object)
             new_methods[method_name] = algm_object.name()
+        new_func_attrs.append(name)
 
         # Dialog variant
         _create_algorithm_dialog(name, max(versions), algm_object)
-        new_functions.append(name)
 
-    return new_functions
+    return new_func_attrs
 
 # -------------------------------------------------------------------------------------------------------------
 
@@ -1421,8 +1410,72 @@ def _attach_algorithm_func_as_method(method_name, algorithm_wrapper, algm_object
         raise RuntimeError("simpleapi: '%s' has requested to be attached as a workspace method but "
                            "Algorithm::workspaceMethodInputProperty() has returned a property name that "
                            "does not exist on the algorithm." % algm_object.name())
-
     _api._workspaceops.attach_func_as_method(method_name, algorithm_wrapper, input_prop,
                                              algm_object.workspaceMethodOn())
 
-# -------------------------------------------------------------------------------------------------------------
+
+# Initialization:
+#   - start FrameworkManager (if necessary). The check is necessary as
+#    _FrameworkManagerImpl.Instance() will import this module and deadlock if it
+#    calls Instance again while importing this module
+#   - loads the python plugins and create new algorithm functions
+if not _api.FrameworkManagerImpl.hasInstance():
+    _api.FrameworkManagerImpl.Instance()
+_translate()
+
+# Load the Python plugins
+# The exported C++ plugins
+from . import _plugins  # noqa
+
+# Now the algorithms
+# There is a chicken and egg problem with what we want to achieve here.
+# The simpleapi module should contain function definitions for all algorithms
+# and fit function classes but a python plugin can choose to import
+# simpleapi itself before we have been finished initializing the module
+# and creating a circular dependency. The only way to avoid this is to
+# restrict the usage of simpleapi in Python plugins so that
+# 'from simpleapi import *' is banned and all access is through
+# 'import mantid.simpleapi as sapi'
+
+# Set the .simpleapi attribute on the 'mantid' module before importing
+# the plugins. Python usual does this once the module has been fully imported
+# but we need to do this earlier
+setattr(mantid, MODULE_NAME, sys.modules['mantid.{}'.format(MODULE_NAME)])
+try:
+    _plugins_key = 'python.plugins.directories'
+    _user_key = 'user.%s' % _plugins_key
+    plugin_dirs = _plugin_helper.get_plugin_paths_as_set(_plugins_key)
+    plugin_dirs.update(_plugin_helper.get_plugin_paths_as_set(_user_key))
+    _update_sys_paths(plugin_dirs, recursive=True)
+
+    # Load
+    plugin_files = []
+    alg_files = []
+    for directory in plugin_dirs:
+        try:
+            all_plugins, algs = _plugin_helper.find_plugins(directory)
+            plugin_files += all_plugins
+            alg_files += algs
+        except ValueError as exc:
+            logger.warning('Exception encountered during plugin discovery: {0}'.format(str(exc)))
+            continue
+
+    # Mock out the expected functions
+    _mockup(alg_files)
+    # Load the plugins.
+    _plugin_modules = _plugin_helper.load(plugin_files)
+    # Create the final proper algorithm definitions for the plugins
+    _plugin_attrs = _translate()
+    # Finally, overwrite the mocked function definitions in the loaded modules with the real ones
+    _plugin_helper.sync_attrs(globals(), _plugin_attrs, _plugin_modules)
+
+    # Attach fit function wrappers
+    from .fitfunctions import _wrappers
+    _globals = globals()
+    for _name, _wrapper in _wrappers():
+        _globals[_name] = _wrapper
+except Exception:
+    # If an error gets raised remove the attribute to be consistent
+    # with standard python behaviour and reraise the exception
+    delattr(mantid, MODULE_NAME)
+    raise
diff --git a/Framework/PythonInterface/plugins/algorithms/Abins.py b/Framework/PythonInterface/plugins/algorithms/Abins.py
index 0981fa486689c289325390bd5fc4a84aba7adc1f..f3d82039caa4c9bc3ffd4493a6fd19d68daf4d1d 100644
--- a/Framework/PythonInterface/plugins/algorithms/Abins.py
+++ b/Framework/PythonInterface/plugins/algorithms/Abins.py
@@ -837,7 +837,4 @@ class Abins(PythonAlgorithm):
         self._bins = np.arange(start=start, stop=stop, step=step, dtype=AbinsModules.AbinsConstants.FLOAT_TYPE)
 
 
-try:
-    AlgorithmFactory.subscribe(Abins)
-except ImportError:
-    logger.debug('Failed to subscribe algorithm SimulatedDensityOfStates; The python package may be missing.')
+AlgorithmFactory.subscribe(Abins)
diff --git a/Framework/PythonInterface/plugins/algorithms/ReflectometryReductionOneLiveData.py b/Framework/PythonInterface/plugins/algorithms/ReflectometryReductionOneLiveData.py
index 9a03ee3a086b858914503a3433c02226c4ba09e1..a50d02a38671a768094e2a665089bc4b6c951529 100644
--- a/Framework/PythonInterface/plugins/algorithms/ReflectometryReductionOneLiveData.py
+++ b/Framework/PythonInterface/plugins/algorithms/ReflectometryReductionOneLiveData.py
@@ -48,7 +48,7 @@ class ReflectometryReductionOneLiveData(DataProcessorAlgorithm):
             'SecondTransmissionRun', 'Params', 'StartOverlap', 'EndOverlap',
             'CorrectionAlgorithm', 'Polynomial', 'C0', 'C1',
             'MomentumTransferMin', 'MomentumTransferStep', 'MomentumTransferMax',
-            'PolarizationAnalysis', 'Pp', 'Ap', 'Rho', 'Alpha', 'Debug', 'OutputWorkspace']
+            'PolarizationAnalysis', 'CPp', 'CAp', 'CRho', 'CAlpha', 'Debug', 'OutputWorkspace']
         self.copyProperties('ReflectometryReductionOneAuto', self._child_properties)
 
     def PyExec(self):
diff --git a/Framework/PythonInterface/plugins/algorithms/SaveGEMMAUDParamFile.py b/Framework/PythonInterface/plugins/algorithms/SaveGEMMAUDParamFile.py
index afb98fecc28b73fe5b8095683971ef4f7b96ecca..2fd7c1af90e190f7aced9518a7e3dbe80028b1e4 100644
--- a/Framework/PythonInterface/plugins/algorithms/SaveGEMMAUDParamFile.py
+++ b/Framework/PythonInterface/plugins/algorithms/SaveGEMMAUDParamFile.py
@@ -14,6 +14,17 @@ from string import Formatter
 
 from mantid.api import *
 from mantid.kernel import *
+import isis_powder.gem_routines
+
+_MAUD_TEMPLATE_PATH = None
+
+
+def _maud_template_path():
+    global _MAUD_TEMPLATE_PATH
+    if _MAUD_TEMPLATE_PATH is None:
+        _MAUD_TEMPLATE_PATH = os.path.join(os.path.dirname(isis_powder.gem_routines.__file__),
+                                           'maud_param_template.maud')
+    return _MAUD_TEMPLATE_PATH
 
 
 class SaveGEMMAUDParamFile(PythonAlgorithm):
@@ -52,7 +63,7 @@ class SaveGEMMAUDParamFile(PythonAlgorithm):
 
         self.declareProperty(FileProperty(name=self.PROP_TEMPLATE_FILE,
                                           action=FileAction.Load,
-                                          defaultValue=self._find_isis_powder_dir()),
+                                          defaultValue=_maud_template_path()),
                              doc="Template for the .maud file")
 
         self.declareProperty(IntArrayProperty(name=self.PROP_GROUPING_SCHEME),
@@ -135,20 +146,6 @@ class SaveGEMMAUDParamFile(PythonAlgorithm):
         """
         return (bank_param_list[grouping_scheme[spec_num] - 1] for spec_num in spectrum_numbers)
 
-    def _find_isis_powder_dir(self):
-        script_dirs = [directory for directory in config["pythonscripts.directories"].split(";")
-                       if "Diffraction" in directory]
-
-        for directory in script_dirs:
-            path_to_test = os.path.join(directory,
-                                        "isis_powder",
-                                        "gem_routines",
-                                        "maud_param_template.maud")
-            if os.path.exists(path_to_test):
-                return path_to_test
-
-        return ""
-
     def _format_param_list(self, param_list):
         return "\n".join(str(param) for param in param_list)
 
diff --git a/Framework/PythonInterface/plugins/algorithms/SortByQVectors.py b/Framework/PythonInterface/plugins/algorithms/SortByQVectors.py
index 0920554ba1ba2c5c149fa3b3d041897d60c2ebad..ac06d3a7590e7bed28ae0c878fd6d38133345340 100644
--- a/Framework/PythonInterface/plugins/algorithms/SortByQVectors.py
+++ b/Framework/PythonInterface/plugins/algorithms/SortByQVectors.py
@@ -6,8 +6,8 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 #pylint: disable=no-init,invalid-name
 from __future__ import (absolute_import, division, print_function)
-from mantid.kernel import *
 from mantid.api import *
+from mantid.kernel import *
 import mantid.simpleapi as ms
 import numpy as np
 
diff --git a/Framework/PythonInterface/test/python/mantid/ImportModuleTest.py b/Framework/PythonInterface/test/python/mantid/ImportModuleTest.py
index 8f8fd4015c0db626ca1197f944259695c991888a..7f7177dd07ba667ee2240c8bddd6301c1be97ed4 100644
--- a/Framework/PythonInterface/test/python/mantid/ImportModuleTest.py
+++ b/Framework/PythonInterface/test/python/mantid/ImportModuleTest.py
@@ -14,23 +14,12 @@ class ImportModuleTest(unittest.TestCase):
 
     def test_import_succeeds(self):
         import mantid
-        # Check content
         attrs = dir(mantid)
-        self.assertTrue('api' in attrs)
-        self.assertTrue('geometry' in attrs)
-        self.assertTrue('kernel' in attrs)
+        self.assertTrue('__version__' in attrs)
 
     def test_on_import_gui_flag_is_set_to_false_here(self):
         import mantid
         self.assertEquals(False, mantid.__gui__)
 
-    def test_python_algorithms_are_loaded_recursively(self):
-        """
-        Test needs improving when the old API goes to just check that everything loads okay
-        """
-        all_algs = AlgorithmFactory.getRegisteredAlgorithms(True)
-        self.assertTrue('SNSPowderReduction' in all_algs)
-        self.assertTrue('Squares' in all_algs)
-
 if __name__ == '__main__':
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py b/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py
index 8fce0e8d92bf2920378e319eda53e19db7ca6e11..a046c1c697e7b1a09f0591ad7dc237912c1a2ac6 100644
--- a/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py
+++ b/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py
@@ -21,8 +21,16 @@ class SimpleAPITest(unittest.TestCase):
     def tearDown(self):
         mtd.clear()
 
+    def test_python_algorithms_are_loaded_recursively(self):
+        """
+        Test needs improving when the old API goes to just check that everything loads okay
+        """
+        all_algs = AlgorithmFactory.getRegisteredAlgorithms(True)
+        self.assertTrue('SNSPowderReduction' in all_algs)
+        self.assertTrue('Squares' in all_algs)
+
     def test_version_number_equals_2(self):
-        self.assertEquals(simpleapi.apiVersion(), 2)
+        self.assertEqual(simpleapi.apiVersion(), 2)
 
     def test_module_dict_seems_to_be_correct_size(self):
         # Check that the module has at least the same number
@@ -36,7 +44,7 @@ class SimpleAPITest(unittest.TestCase):
         expected_doc = """Rebins data with new X bin boundaries. For EventWorkspaces, you can very quickly rebin in-place by keeping the same output name and PreserveEvents=true.\n\nProperty descriptions: \n\nInputWorkspace(Input:req) *MatrixWorkspace*       Workspace containing the input data\n\nOutputWorkspace(Output:req) *MatrixWorkspace*       The name to give the output workspace\n\nParams(Input:req) *dbl list*       A comma separated list of first bin boundary, width, last bin boundary. Optionally this can be followed by a comma and more widths and last boundary pairs. Optionally this can also be a single number, which is the bin width. In this case, the boundary of binning will be determined by minimum and maximum TOF values among all events, or previous binning boundary, in case of event Workspace, or non-event Workspace, respectively. Negative width values indicate logarithmic binning. \n\nPreserveEvents(Input) *boolean*       Keep the output workspace as an EventWorkspace, if the input has events. If the input and output EventWorkspace names are the same, only the X bins are set, which is very quick. If false, then the workspace gets converted to a Workspace2D histogram.\n\nFullBinsOnly(Input) *boolean*       Omit the final bin if it's width is smaller than the step size\n\nIgnoreBinErrors(Input) *boolean*       Ignore errors related to zero/negative bin widths in input/output workspaces. When ignored, the signal and errors are set to zero\n"""
         doc = simpleapi.rebin.__doc__
         self.assertTrue(len(doc) > 0)
-        self.assertEquals(doc, expected_doc)
+        self.assertEqual(doc, expected_doc)
 
     def test_function_call_executes_correct_algorithm_when_passed_correct_args(self):
         wsname = 'test_function_call_executes_correct_algorithm_when_passed_correct_args'
@@ -164,7 +172,7 @@ class SimpleAPITest(unittest.TestCase):
         self.assertTrue( wsname_box in mtd )
 
         self.assertTrue( isinstance(query, tuple) )
-        self.assertEquals( 2, len(query) )
+        self.assertEqual( 2, len(query) )
 
         self.assertTrue( isinstance(query[0], ITableWorkspace) )
         self.assertTrue( isinstance(query[1], ITableWorkspace) )
@@ -346,8 +354,8 @@ class SimpleAPITest(unittest.TestCase):
 
     def _is_initialized_test(self, alg, version, expected_class, expected_child):
         self.assertTrue(alg.isInitialized())
-        self.assertEquals(expected_child,alg.isChild())
-        self.assertEquals(alg.version(), version)
+        self.assertEqual(expected_child,alg.isChild())
+        self.assertEqual(alg.version(), version)
         self.assertTrue(isinstance(alg, expected_class))
 
     def test_validate_inputs_with_errors_stops_algorithm(self):
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmFactoryTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmFactoryTest.py
index 36307e8d7a9f3210090020980db0d9320368c2e7..ebe3b38b33080f4d9f37956be8c39f6eb48481c6 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmFactoryTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmFactoryTest.py
@@ -9,20 +9,36 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 import testhelpers
 
-from mantid.api import AlgorithmFactory, PythonAlgorithm
+from mantid.api import AlgorithmFactory, FrameworkManagerImpl, PythonAlgorithm
+
 
 class IsAnAlgorithm(PythonAlgorithm):
     def PyInit(self):
         pass
 
+
 class NotAnAlgorithm(object):
     pass
 
+
 class AlgorithmFactoryTest(unittest.TestCase):
 
+    def setUp(self):
+        FrameworkManagerImpl.Instance()
+
     def test_get_algorithm_factory_does_not_return_None(self):
         self.assertTrue(AlgorithmFactory is not None )
 
+    def test_getDescriptors(self):
+
+        descriptors = AlgorithmFactory.getDescriptors(True)
+        self.assertGreater(len(descriptors), 0)
+        d = descriptors[0]
+        self.assertTrue(hasattr(d, 'name'))
+        self.assertTrue(hasattr(d, 'alias'))
+        self.assertTrue(hasattr(d, 'category'))
+        self.assertTrue(hasattr(d, 'version'))
+
     def test_exists_returns_correct_value_for_given_args(self):
         self.assertTrue(AlgorithmFactory.exists('ConvertUnits')) #any version
         self.assertTrue(AlgorithmFactory.exists('ConvertUnits', 1)) #any version
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py
index 2375eadc1e8b9b67f89a33e60008e9c24e0f4282..0808a286ed4c557dd1690845fbb6af29c996dca9 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmManagerTest.py
@@ -8,12 +8,17 @@ from __future__ import (absolute_import, division, print_function)
 
 import unittest
 import testhelpers
-from mantid.api import (AlgorithmManager, IAlgorithm, Algorithm, AlgorithmProxy)
+from mantid.api import (AlgorithmManager, Algorithm, AlgorithmProxy,
+                        FrameworkManagerImpl, IAlgorithm)
 
-import sys
 
 class AlgorithmManagerTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        # Load the plugins
+        FrameworkManagerImpl.Instance()
+
     def test_create_default_version(self):
         alg = testhelpers.assertRaisesNothing(self, AlgorithmManager.create, "ConvertUnits")
         # Tests
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmPropertyTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmPropertyTest.py
index f58c87814a5935008a48accb12f5586b58fbc76a..b8da42e5edb8ec970ddc00de6f41a164efce9691 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmPropertyTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmPropertyTest.py
@@ -7,9 +7,10 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
-from mantid.api import AlgorithmProperty, IAlgorithm
+from mantid.api import AlgorithmProperty, FrameworkManagerImpl, IAlgorithm
 from mantid.kernel import Direction
 
+
 class AlgorithmPropertyTest(unittest.TestCase):
 
     def test_construction_with_name_produces_input_property(self):
@@ -18,12 +19,14 @@ class AlgorithmPropertyTest(unittest.TestCase):
         self.assertEquals(Direction.Input, prop.direction)
 
     def test_value_method_returns_an_algorithm_type(self):
+        # load plugins to register CreateWorkspace
+        FrameworkManagerImpl.Instance()
         prop = AlgorithmProperty("TestProperty")
-        prop.valueAsStr = '{"name":"CreateWorkspace","paramters":{"OutputWorkspace":"ws","DataY":"1","DataX":"1","NSpec":"1"}}'
-
+        prop.valueAsStr = '{"name": "CreateWorkspace",' \
+                          '"parameters": {"OutputWorkspace": "ws", "DataY": "1", "DataX": "1","NSpec": "1"}}'
         alg = prop.value
-        self.assertTrue(isinstance(alg,IAlgorithm))
-        self.assertEquals("CreateWorkspace",alg.name())
+        self.assertTrue(isinstance(alg, IAlgorithm))
+        self.assertEqual("CreateWorkspace", alg.name())
 
 
 if __name__ == '__main__':
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
index 2b737fc4c399d0afa59bf4b941ae6557dcf71062..85fca4c4e4aa6352b73b861adf2b56e16b606ec7 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
@@ -9,7 +9,7 @@ import six
 
 import unittest
 import json
-from mantid.api import AlgorithmID, AlgorithmManager
+from mantid.api import AlgorithmID, AlgorithmManager, FrameworkManagerImpl
 from testhelpers import run_algorithm
 
 class AlgorithmTest(unittest.TestCase):
@@ -17,6 +17,7 @@ class AlgorithmTest(unittest.TestCase):
     _load = None
 
     def setUp(self):
+        FrameworkManagerImpl.Instance()
         if self._load is None:
             self.__class__._load = AlgorithmManager.createUnmanaged('Load')
             self._load.initialize()
diff --git a/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py b/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py
index b87a6175d480b663e06ba347e206e57d9d4248d7..e2dc256c8c2126e608e833eb8ecdae64645adb3c 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py
@@ -8,11 +8,17 @@ from __future__ import (absolute_import, division, print_function)
 
 import unittest
 from testhelpers import run_algorithm
-from mantid.api import AnalysisDataService, AnalysisDataServiceImpl, MatrixWorkspace, Workspace
+from mantid.api import (AnalysisDataService, AnalysisDataServiceImpl,
+                        FrameworkManagerImpl, MatrixWorkspace, Workspace)
 from mantid import mtd
 
+
 class AnalysisDataServiceTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManagerImpl.Instance()
+
     def tearDown(self):
       AnalysisDataService.Instance().clear()
 
diff --git a/Framework/PythonInterface/test/python/mantid/api/CompositeFunctionTest.py b/Framework/PythonInterface/test/python/mantid/api/CompositeFunctionTest.py
index 6c79a5eecaf224b12f4cb196d2bfc67c2c1d4363..965d801071ef9e483119471c179062ce7fa4952b 100644
--- a/Framework/PythonInterface/test/python/mantid/api/CompositeFunctionTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/CompositeFunctionTest.py
@@ -7,12 +7,15 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
-from mantid.api import FunctionFactory, CompositeFunction, IFunction1D
-import numpy as np
+from mantid.api import FrameworkManagerImpl, FunctionFactory, CompositeFunction, IFunction1D
 
 
 class CompositeFunctionTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManagerImpl.Instance()
+
     def test_instance_can_be_created_standalone(self):
         func = CompositeFunction()
         self.assertTrue(isinstance(func, CompositeFunction))
@@ -51,7 +54,7 @@ class CompositeFunctionTest(unittest.TestCase):
         func[1].setParameter('A0', 20.0)
         self.assertEqual(func.getParameterValue('f0.A0'), 10.0)
         self.assertEqual(func.getParameterValue('f1.A0'), 20.0)
-        
+
     def test_nested_functions(self):
         s = 'name=FlatBackground,A0=1;(name=FlatBackground,A0=2;name=FlatBackground,A0=3)'
         func = FunctionFactory.createInitialized(s)
diff --git a/Framework/PythonInterface/test/python/mantid/api/DeprecatedAlgorithmCheckerTest.py b/Framework/PythonInterface/test/python/mantid/api/DeprecatedAlgorithmCheckerTest.py
index 86cd6d8a030a7a747ed7e6db78022f9df85d1ab8..0c0fe4d216ab7a49326b7073b6567bc66b3f9622 100644
--- a/Framework/PythonInterface/test/python/mantid/api/DeprecatedAlgorithmCheckerTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/DeprecatedAlgorithmCheckerTest.py
@@ -7,10 +7,15 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
-from mantid.api import DeprecatedAlgorithmChecker
+from mantid.api import DeprecatedAlgorithmChecker, FrameworkManagerImpl
+
 
 class DeprecatedAlgorithmCheckerTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManagerImpl.Instance()
+
     def test_constructor_throws_for_non_existant_algorithm(self):
         self.assertRaises(RuntimeError, DeprecatedAlgorithmChecker, "A_Very_Silly_Alg_Name",-1)
 
diff --git a/Framework/PythonInterface/test/python/mantid/api/FilePropertyTest.py b/Framework/PythonInterface/test/python/mantid/api/FilePropertyTest.py
index c534a6e1bb5bf36b886a55048fb8b8484e527954..47be4a61adcceda8bfc8c4b1450ca380260a4d31 100644
--- a/Framework/PythonInterface/test/python/mantid/api/FilePropertyTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/FilePropertyTest.py
@@ -7,11 +7,16 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
-from mantid.api import FileProperty, FileAction, AlgorithmManager
+from mantid.api import AlgorithmManager, FileProperty, FileAction, FrameworkManagerImpl
 from mantid.kernel import Direction
 
+
 class FilePropertyTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManagerImpl.Instance()
+
     def test_constructor_with_name_and_default_and_action(self):
         prop = FileProperty("LoadProperty", "", FileAction.Load)
         self.assertNotEquals("", prop.isValid)
diff --git a/Framework/PythonInterface/test/python/mantid/api/FunctionFactoryTest.py b/Framework/PythonInterface/test/python/mantid/api/FunctionFactoryTest.py
index c14317e485e31f08ee6852247902c1517bd9e353..c9f16486f6d46080bbb9904aa2d321e0a19d8f53 100644
--- a/Framework/PythonInterface/test/python/mantid/api/FunctionFactoryTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/FunctionFactoryTest.py
@@ -8,7 +8,7 @@ from __future__ import (absolute_import, division, print_function)
 
 import unittest
 
-from mantid.api import IFunction1D, FunctionFactory
+from mantid.api import FrameworkManagerImpl, IFunction1D, FunctionFactory
 
 
 class TestFunctionNoAttrs(IFunction1D):
@@ -38,6 +38,10 @@ class TestFunctionCorrectForm(IFunction1D):
 
 class FunctionFactoryTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManagerImpl.Instance()
+
     def test_get_function_factory_does_not_return_None(self):
         self.assertTrue(FunctionFactory is not None)
 
diff --git a/Framework/PythonInterface/test/python/mantid/api/FunctionPropertyTest.py b/Framework/PythonInterface/test/python/mantid/api/FunctionPropertyTest.py
index eaffcdb37cfc0922103afa8ac684d41390867624..e73376c8f79bcae6c3684a32555e580956289ad0 100644
--- a/Framework/PythonInterface/test/python/mantid/api/FunctionPropertyTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/FunctionPropertyTest.py
@@ -6,14 +6,14 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-from mantid.api import FunctionProperty,PythonAlgorithm, IFunction
+from mantid.api import FrameworkManagerImpl, FunctionProperty, PythonAlgorithm, IFunction
 from testhelpers import assertRaisesNothing
 import unittest
 import math
 
+
 class FunctionPropertyTest(unittest.TestCase):
 
-    #------------------------------------------------------------
     class TestFunctionPropAlg(PythonAlgorithm):
         def PyInit(self):
             self.declareProperty(FunctionProperty("fun"))
@@ -28,9 +28,11 @@ class FunctionPropertyTest(unittest.TestCase):
             height=func.getParamValue(0)
             if math.fabs(height - 1.0) > 1e-12:
                 raise RuntimeError("Height does not have the expected value")
-    #------------------------------------------------------------
 
-#---- Success cases ----
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManagerImpl.Instance()
+
     def test_constructor_succeeds_with_non_empty_string_name(self):
         assertRaisesNothing(self, FunctionProperty, "Function")
 
@@ -50,11 +52,11 @@ class FunctionPropertyTest(unittest.TestCase):
         alg.setRethrows(True)
         assertRaisesNothing(self, alg.execute)
 
-#---- Error cases ----
     def test_invalid_string_value_gives_function_object_as_value(self):
         alg=self.TestFunctionPropAlg()
         alg.initialize()
         self.assertRaises(ValueError, alg.setProperty, "fun", "blah")
 
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py b/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py
index 4a4e1ed7b147e332b0cec6f2bae8a500babc3f76..b7d6ad8e61c11f2e660e774ed467904581e5b13e 100644
--- a/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/PythonAlgorithmTraitsTest.py
@@ -11,9 +11,7 @@ from __future__ import (absolute_import, division, print_function)
 
 import unittest
 import testhelpers
-import types
 
-from mantid.kernel import Direction
 from mantid.api import (PythonAlgorithm, AlgorithmProxy, Algorithm, IAlgorithm,
                         AlgorithmManager, AlgorithmFactory)
 
@@ -133,5 +131,6 @@ class PythonAlgorithmTest(unittest.TestCase):
         base_running_attr = getattr(IAlgorithm, "isRunning")
         self.assertRaises(RuntimeError, base_running_attr, alg)
 
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/geometry/CSGObjectTest.py b/Framework/PythonInterface/test/python/mantid/geometry/CSGObjectTest.py
index e4ccc0577ef9fdd3ecff65bdc31bc77948a12538..0c76090b59a884566a804e54175cb0e2f9674273 100644
--- a/Framework/PythonInterface/test/python/mantid/geometry/CSGObjectTest.py
+++ b/Framework/PythonInterface/test/python/mantid/geometry/CSGObjectTest.py
@@ -9,6 +9,7 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 from mantid.geometry import BoundingBox, CSGObject
 
+
 class CSGObjectTest(unittest.TestCase):
 
     _testws = None
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/PropertyWithValueTest.py b/Framework/PythonInterface/test/python/mantid/kernel/PropertyWithValueTest.py
index 01d337ab14be65e7ba9abf734d47a09ed4f42c3f..3836be11ef458f84b3e804d3d0e14126f2271ea7 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/PropertyWithValueTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/PropertyWithValueTest.py
@@ -8,10 +8,11 @@ from __future__ import (absolute_import, division, print_function)
 
 import unittest
 from mantid.api import AlgorithmManager, MatrixWorkspace
-from testhelpers import run_algorithm
+from testhelpers import create_algorithm, run_algorithm
 import numpy as np
 import sys
 
+
 class PropertyWithValueTest(unittest.TestCase):
 
     # Integration algorithm handle
@@ -21,10 +22,10 @@ class PropertyWithValueTest(unittest.TestCase):
 
     def setUp(self):
         if self._integration is None:
-            self.__class__._integration = AlgorithmManager.createUnmanaged("Integration")
+            self.__class__._integration = create_algorithm("Integration")
             self.__class__._integration.initialize()
         if self._mask_dets is None:
-            self.__class__._mask_dets = AlgorithmManager.createUnmanaged("MaskDetectors")
+            self.__class__._mask_dets = create_algorithm("MaskDetectors")
             self.__class__._mask_dets.initialize()
 
     def test_value_setting_as_string_gives_expected_value_for_correct_type(self):
@@ -166,5 +167,6 @@ class PropertyWithValueTest(unittest.TestCase):
     def test_set_property_of_vector_int_succeeds_with_numpy_array_of_int_type(self):
         self._do_vector_int_numpy_test('WorkspaceIndexList')
 
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/TimeSeriesPropertyTest.py b/Framework/PythonInterface/test/python/mantid/kernel/TimeSeriesPropertyTest.py
index 419971c84d29f50d49930bd3f6befac691336bad..155c8d88de74bdb1ce86201ad63a74120e018ee3 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/TimeSeriesPropertyTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/TimeSeriesPropertyTest.py
@@ -9,7 +9,6 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 import numpy as np
 
-import mantid
 from mantid.kernel import (DateAndTime, BoolTimeSeriesProperty, FloatTimeSeriesProperty, Int64TimeSeriesProperty,
                            StringTimeSeriesProperty)
 from testhelpers import run_algorithm
@@ -64,33 +63,33 @@ class TimeSeriesPropertyTest(unittest.TestCase):
     def test_time_series_double_can_be_extracted(self):
         log_series = self._test_ws.getRun()["TEMP1"]
         self._check_has_time_series_attributes(log_series)
-        self.assertEquals(log_series.size(), self._ntemp)
+        self.assertEqual(log_series.size(), self._ntemp)
         self.assertAlmostEqual(log_series.nthValue(0), -0.00161)
         # Check the dtype return value
-        self.assertEquals(log_series.dtype(), "f")
+        self.assertEqual(log_series.dtype(), "f")
 
     def test_time_series_int_can_be_extracted(self):
         log_series = self._test_ws.getRun()["raw_frames"]
         self._check_has_time_series_attributes(log_series)
-        self.assertEquals(log_series.size(), self._nframes)
-        self.assertEquals(log_series.nthValue(1), 1436)
+        self.assertEqual(log_series.size(), self._nframes)
+        self.assertEqual(log_series.nthValue(1), 1436)
         # Check the dtype return value
-        self.assertEquals(log_series.dtype(), "i")
+        self.assertEqual(log_series.dtype(), "i")
 
     def test_time_series_string_can_be_extracted(self):
         log_series = self._test_ws.getRun()["icp_event"]
         self._check_has_time_series_attributes(log_series, list)
-        self.assertEquals(log_series.size(), 4)
-        self.assertEquals(log_series.nthValue(0).strip(), 'CHANGE_PERIOD 1')
+        self.assertEqual(log_series.size(), 4)
+        self.assertEqual(log_series.nthValue(0).strip(), 'CHANGE_PERIOD 1')
         # Check the dtype return value
-        self.assertEquals(log_series.dtype(), "S61")
+        self.assertEqual(log_series.dtype(), "S61")
 
     def test_time_series_bool_can_be_extracted(self):
         log_series = self._test_ws.getRun()["period 1"]
         self._check_has_time_series_attributes(log_series)
-        self.assertEquals(log_series.size(), 1)
+        self.assertEqual(log_series.size(), 1)
         # Check the dtype return value
-        self.assertEquals(log_series.dtype(), "b")
+        self.assertEqual(log_series.dtype(), "b")
 
     def _check_has_time_series_attributes(self, log, values_type=np.ndarray):
         self.assertTrue(hasattr(log, "value"))
@@ -99,7 +98,7 @@ class TimeSeriesPropertyTest(unittest.TestCase):
 
         values = log.value
         self.assertTrue(isinstance(values, values_type))
-        self.assertEquals(log.size(), len(values))
+        self.assertEqual(log.size(), len(values))
 
         # check the statistics
         stats = log.getStatistics()
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/UsageServiceTest.py b/Framework/PythonInterface/test/python/mantid/kernel/UsageServiceTest.py
index 78a4ca2fed938009714235ddb24501168259b69b..66662d4261314f9b30d9125ec8c91045f5a782f0 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/UsageServiceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/UsageServiceTest.py
@@ -10,6 +10,7 @@ import unittest
 
 from mantid.kernel import (UsageService, UsageServiceImpl)
 
+
 class UsageServiceTest(unittest.TestCase):
 
     def test_singleton_returns_instance_of_UsageService(self):
@@ -24,11 +25,11 @@ class UsageServiceTest(unittest.TestCase):
         self.assertEquals(UsageService.isEnabled(),False)
 
     def test_getSetApplication(self):
-        self.assertEquals(UsageService.getApplication(),"python")
-        UsageService.setApplication("python unit tests")
-        self.assertEquals(UsageService.getApplication(),"python unit tests")
-        UsageService.setApplication("python")
-        self.assertEquals(UsageService.getApplication(),"python")
+        self.assertEquals(UsageService.getApplicationName(), "python")
+        UsageService.setApplicationName("python unit tests")
+        self.assertEquals(UsageService.getApplicationName(), "python unit tests")
+        UsageService.setApplicationName("python")
+        self.assertEquals(UsageService.getApplicationName(), "python")
 
     def test_setInterval(self):
         UsageService.setEnabled(False)
@@ -42,7 +43,7 @@ class UsageServiceTest(unittest.TestCase):
     def test_registerFeatureUsage(self):
         UsageService.setEnabled(False)
         #this will do nothing as it is disabled
-        UsageService.registerFeatureUsage("Algorithm","Test.v1",True)
+        UsageService.registerFeatureUsage("Algorithm", "Test.v1", True)
 
 
     def test_Flush(self):
@@ -53,5 +54,6 @@ class UsageServiceTest(unittest.TestCase):
     def test_Shutdown(self):
         UsageService.shutdown()
 
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/AbinsAdvancedParametersTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/AbinsAdvancedParametersTest.py
index 7bf32aa6d278bd98e5cdabc45d2c68f32c67676d..7780ab00899e7f19b008ea85f75077469dd01b09 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/AbinsAdvancedParametersTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/AbinsAdvancedParametersTest.py
@@ -6,8 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-from mantid.simpleapi import mtd
-from mantid.simpleapi import Abins, DeleteWorkspace
+from mantid.simpleapi import Abins, DeleteWorkspace, mtd
 
 from AbinsModules import AbinsParameters, AbinsTestHelpers
 
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
index e43ec3186865819907ed935a97b3f8f9d11865a7..b4bc9506769944334f4c5ee668de905f41278ac0 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
@@ -118,4 +118,5 @@ set ( TEST_PY_FILES
 check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} )
 
 # Prefix for test name=PythonAlgorithms
+set ( PYUNITTEST_PYTHONPATH_EXTRA ${PYTHONINTERFACE_PLUGINS_DIR}/algorithms )
 pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} python.algorithms ${TEST_PY_FILES} )
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CheckForSampleLogsTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/CheckForSampleLogsTest.py
index 9f5ef3e36519cf4309de16acda6a6fca3c22d087..3fe1a792cd56873ede46c078ed5ed69e421f2a50 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/CheckForSampleLogsTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/CheckForSampleLogsTest.py
@@ -6,19 +6,20 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest,os
-import mantid
+import unittest
+from mantid import simpleapi
 
 
 class CheckForSampleLogsTest(unittest.TestCase):
     def test_simple(self):
-    	w=mantid.simpleapi.Load('CNCS_7860_event.nxs')
-    	result=mantid.simpleapi.CheckForSampleLogs(w)
-    	self.assertEquals(result,'')
-    	result=mantid.simpleapi.CheckForSampleLogs(w,'Phase1')
-    	self.assertEquals(result,'')
-    	result=mantid.simpleapi.CheckForSampleLogs(w,'Phrase1')
-    	self.assertNotEquals(result,'')
+        w = simpleapi.Load('CNCS_7860_event.nxs')
+        result = simpleapi.CheckForSampleLogs(w)
+        self.assertEquals(result, '')
+        result = simpleapi.CheckForSampleLogs(w, 'Phase1')
+        self.assertEquals(result, '')
+        result = simpleapi.CheckForSampleLogs(w, 'Phrase1')
+        self.assertNotEquals(result, '')
+
 
 if __name__=="__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py
index 6af45362f2230b624d01c8c38861921fbbb755d9..b0147653b82d42102fbe1af8e869c91b9cf5c247 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py
@@ -6,105 +6,105 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest,os
-import mantid
+import unittest, os
+from mantid import AnalysisDataServiceImpl, config, simpleapi
 
 
 class DakotaChiSquaredTest(unittest.TestCase):
 
     def makeFiles(self):
-    	mantid.simpleapi.CreateWorkspace(OutputWorkspace='data',DataX='1,2,3,4,5',DataY='1,0,1,4,4',DataE='1,0,1,2,2')
-    	mantid.simpleapi.CreateWorkspace(OutputWorkspace='sim',DataX='1,2,3,4,5',DataY='1,1,1,1,1',DataE='0,0,0,0,0')
-    	mantid.simpleapi.CreateWorkspace(OutputWorkspace='simwrong',DataX='1,2,3,4',DataY='1,1,1,1',DataE='0,0,0,0')
+        simpleapi.CreateWorkspace(OutputWorkspace='data', DataX='1,2,3,4,5', DataY='1,0,1,4,4', DataE='1,0,1,2,2')
+        simpleapi.CreateWorkspace(OutputWorkspace='sim', DataX='1,2,3,4,5', DataY='1,1,1,1,1', DataE='0,0,0,0,0')
+        simpleapi.CreateWorkspace(OutputWorkspace='simwrong', DataX='1,2,3,4', DataY='1,1,1,1', DataE='0,0,0,0')
 
-    	self.datafile=os.path.join(mantid.config.getString('defaultsave.directory'),'DakotaChiSquared_data.nxs')
-    	self.simfile=os.path.join(mantid.config.getString('defaultsave.directory'),'DakotaChiSquared_sim.nxs')
-    	self.simwrongfile=os.path.join(mantid.config.getString('defaultsave.directory'),'DakotaChiSquared_simwrong.nxs')
-    	self.chifile=os.path.join(mantid.config.getString('defaultsave.directory'),'DakotaChiSquared_chi.txt')
+        self.datafile = os.path.join(config.getString('defaultsave.directory'), 'DakotaChiSquared_data.nxs')
+        self.simfile = os.path.join(config.getString('defaultsave.directory'), 'DakotaChiSquared_sim.nxs')
+        self.simwrongfile = os.path.join(config.getString('defaultsave.directory'), 'DakotaChiSquared_simwrong.nxs')
+        self.chifile = os.path.join(config.getString('defaultsave.directory'), 'DakotaChiSquared_chi.txt')
 
-    	mantid.simpleapi.SaveNexus('data',self.datafile)
-    	mantid.simpleapi.SaveNexus('sim',self.simfile)
-    	mantid.simpleapi.SaveNexus('simwrong',self.simwrongfile)
-
-    	mantid.api.AnalysisDataService.remove("data")
-    	mantid.api.AnalysisDataService.remove("sim")
-    	mantid.api.AnalysisDataService.remove("simwrong")
+        simpleapi.SaveNexus('data', self.datafile)
+        simpleapi.SaveNexus('sim', self.simfile)
+        simpleapi.SaveNexus('simwrong', self.simwrongfile)
 
+        ads = AnalysisDataServiceImpl.Instance()
+        ads.remove("data")
+        ads.remove("sim")
+        ads.remove("simwrong")
 
     def cleanup(self):
-    	if os.path.exists(self.datafile):
-                	os.remove(self.datafile)
-    	if os.path.exists(self.simfile):
-                	os.remove(self.simfile)
-    	if os.path.exists(self.simwrongfile):
-                	os.remove(self.simwrongfile)
-    	if os.path.exists(self.chifile):
-                	os.remove(self.chifile)
+        if os.path.exists(self.datafile):
+            os.remove(self.datafile)
+        if os.path.exists(self.simfile):
+            os.remove(self.simfile)
+        if os.path.exists(self.simwrongfile):
+            os.remove(self.simwrongfile)
+        if os.path.exists(self.chifile):
+            os.remove(self.chifile)
 
     def test_wrongType(self):
-    	self.makeFiles()
-    	try:
-    		mantid.simpleapi.DakotaChiSquared(self.datafile,'CNCS_7860_event.nxs',self.chifile)
-    	except RuntimeError as e:
-    		self.assertNotEquals(str(e).find('Wrong workspace type for calculated file'),-1)
-    	except:
-    		assert False, "Raised the wrong exception type"
-    	else:
-    		assert False, "Didn't raise any exception"
-    	try:
-    		mantid.simpleapi.DakotaChiSquared('CNCS_7860_event.nxs',self.simfile,self.chifile)
-    	except RuntimeError as e:
-    		self.assertNotEquals(str(e).find('Wrong workspace type for data file'),-1)
-    	except:
-    		assert False, "Raised the wrong exception type"
-    	else:
-    		assert False, "Didn't raise any exception"
-    	self.cleanup()
-
+        self.makeFiles()
+        try:
+            simpleapi.DakotaChiSquared(self.datafile, 'CNCS_7860_event.nxs', self.chifile)
+        except RuntimeError as e:
+            self.assertNotEquals(str(e).find('Wrong workspace type for calculated file'), -1)
+        except:
+            assert False, "Raised the wrong exception type"
+        else:
+            assert False, "Didn't raise any exception"
+        try:
+            simpleapi.DakotaChiSquared('CNCS_7860_event.nxs', self.simfile, self.chifile)
+        except RuntimeError as e:
+            self.assertNotEquals(str(e).find('Wrong workspace type for data file'), -1)
+        except:
+            assert False, "Raised the wrong exception type"
+        else:
+            assert False, "Didn't raise any exception"
+        self.cleanup()
 
     def test_wrongSize(self):
-    	self.makeFiles()
-    	try:
-    		mantid.simpleapi.DakotaChiSquared(self.datafile,self.simwrongfile,self.chifile)
-    	except RuntimeError as e:
-    		self.assertNotEquals(str(e).find('The file sizes are different'),-1)
-    	except:
-    		assert False, "Raised the wrong exception type"
-    	else:
-    		assert False, "Didn't raise any exception"
-    	self.cleanup()
-
+        self.makeFiles()
+        try:
+            simpleapi.DakotaChiSquared(self.datafile, self.simwrongfile, self.chifile)
+        except RuntimeError as e:
+            self.assertNotEquals(str(e).find('The file sizes are different'), -1)
+        except:
+            assert False, "Raised the wrong exception type"
+        else:
+            assert False, "Didn't raise any exception"
+        self.cleanup()
 
     def test_value(self):
-    	self.makeFiles()
-    	try:
-    		mantid.simpleapi.DakotaChiSquared(self.datafile,self.simfile,self.chifile)
-    		f = open(self.chifile,'r')
-    		chistr=f.read()
-    		self.assertEquals(chistr,'4.5 obj_fn\n')
-    		f.close()
-    	except:
-    		assert False, "Raised an exception"
-    	self.cleanup()
+        self.makeFiles()
+        try:
+            simpleapi.DakotaChiSquared(self.datafile, self.simfile, self.chifile)
+            f = open(self.chifile, 'r')
+            chistr = f.read()
+            self.assertEquals(chistr, '4.5 obj_fn\n')
+            f.close()
+        except:
+            assert False, "Raised an exception"
+        self.cleanup()
 
     def test_output(self):
-    	self.makeFiles()
-    	try:
-    		alg=mantid.simpleapi.DakotaChiSquared(self.datafile,self.simfile,self.chifile)
-    		self.assertEquals(len(alg),2)
-    		self.assertEquals(alg[0],4.5)
-    		self.assertEquals(alg[1].name(),"alg")
-    		self.assertEquals(alg[1].blocksize(),5)
-    		self.assertEquals(alg[1].getNumberHistograms(),1)
-    		self.assertEquals(alg[1].dataY(0)[3],1.5)
-    		mantid.api.AnalysisDataService.remove("alg")
-    		alg1=mantid.simpleapi.DakotaChiSquared(self.datafile,self.simfile,self.chifile,ResidualsWorkspace="res")
-    		self.assertEquals(alg1[0],4.5)
-    		self.assertEquals(alg1[1].name(),"res")
-    		mantid.api.AnalysisDataService.remove("res")
-    	except:
-    		assert False, "Raised an exception"
-    	self.cleanup()
-
-if __name__=="__main__":
+        self.makeFiles()
+        try:
+            alg = simpleapi.DakotaChiSquared(self.datafile, self.simfile, self.chifile)
+            self.assertEquals(len(alg), 2)
+            self.assertEquals(alg[0], 4.5)
+            self.assertEquals(alg[1].name(), "alg")
+            self.assertEquals(alg[1].blocksize(), 5)
+            self.assertEquals(alg[1].getNumberHistograms(), 1)
+            self.assertEquals(alg[1].dataY(0)[3], 1.5)
+            ads = AnalysisDataServiceImpl.Instance()
+            ads.remove("alg")
+            alg1 = simpleapi.DakotaChiSquared(self.datafile, self.simfile, self.chifile, ResidualsWorkspace="res")
+            self.assertEquals(alg1[0], 4.5)
+            self.assertEquals(alg1[1].name(), "res")
+            ads.remove("res")
+        except:
+            assert False, "Raised an exception"
+        self.cleanup()
+
+
+if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SortByQVectorsTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SortByQVectorsTest.py
index f4b7d5291918215d2e08d98a472ec91b7fa57287..d61834e7b2dafe4aba17342297a21fc44e24dd6e 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SortByQVectorsTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SortByQVectorsTest.py
@@ -6,21 +6,21 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest, os
-import mantid
+import unittest
+from mantid import AnalysisDataServiceImpl, simpleapi
 
 
 class SortByQVectorsTest(unittest.TestCase):
     def test_output(self):
-        ws = mantid.simpleapi.LoadSassena("outputSassena_1.4.1.h5", TimeUnit=1.0)
-        mantid.simpleapi.SortByQVectors('ws')
+        ws = simpleapi.LoadSassena("outputSassena_1.4.1.h5", TimeUnit=1.0)
+        simpleapi.SortByQVectors('ws')
         self.assertAlmostEqual(ws[0].getNumberHistograms(), 5)
         self.assertAlmostEqual(ws[0].dataY(0)[0], 0.0)
         self.assertAlmostEqual(ws[0].dataY(1)[0], 0.00600600591861)
         self.assertAlmostEqual(ws[0].dataY(2)[0], 0.0120120118372)
         self.assertAlmostEqual(ws[0].dataY(3)[0], 0.0180180184543)
         self.assertAlmostEqual(ws[0].dataY(4)[0], 0.0240240236744)
-        mantid.api.AnalysisDataService.remove("ws")
+        AnalysisDataServiceImpl.Instance().remove("ws")
 
 
 if __name__ == "__main__":
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/StringToPngTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/StringToPngTest.py
index 890bd55bafa2782aeff579c980fedc78414635e0..0853ccd8ff884ac677a52d4d352d964d265e4f97 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/StringToPngTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/StringToPngTest.py
@@ -6,34 +6,35 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest,os
-import mantid
+import unittest, os
+from mantid import AnalysisDataServiceImpl, config, simpleapi
 
-class StringToPngTest(unittest.TestCase):
 
-    plotfile=os.path.join(mantid.config.getString('defaultsave.directory'),"StringToPngTest.png")
+class StringToPngTest(unittest.TestCase):
+    plotfile = os.path.join(config.getString('defaultsave.directory'), "StringToPngTest.png")
 
     def cleanup(self):
         if os.path.exists(self.plotfile):
             os.remove(self.plotfile)
 
     def testPlot(self):
-        to_plot='This is a string\nAnd this is a second line'
-        ok2run=''
+        to_plot = 'This is a string\nAnd this is a second line'
+        ok2run = ''
         try:
             import matplotlib
             from distutils.version import LooseVersion
-            if LooseVersion(matplotlib.__version__)<LooseVersion("1.2.0"):
-                ok2run='Wrong version of matplotlib. Required >= 1.2.0'
+            if LooseVersion(matplotlib.__version__) < LooseVersion("1.2.0"):
+                ok2run = 'Wrong version of matplotlib. Required >= 1.2.0'
             else:
                 matplotlib.use("agg")
                 import matplotlib.pyplot as plt
         except:
-            ok2run='Problem importing matplotlib'
-        if ok2run=='':
-            mantid.simpleapi.StringToPng(String=to_plot,OutputFilename=self.plotfile)
-            self.assertTrue(os.path.getsize(self.plotfile)>1e3)
+            ok2run = 'Problem importing matplotlib'
+        if ok2run == '':
+            simpleapi.StringToPng(String=to_plot, OutputFilename=self.plotfile)
+            self.assertTrue(os.path.getsize(self.plotfile) > 1e3)
         self.cleanup()
 
-if __name__=="__main__":
+
+if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibCNCSTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibCNCSTest.py
index 4833129337652e9416bb16f80c6d1bb631755992..7c5702b36d37242b1b837ab009dbc3e2f3528a30 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibCNCSTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibCNCSTest.py
@@ -6,27 +6,28 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest,os
-import mantid
+import unittest
+from mantid import simpleapi
 import numpy
 
 
 class SuggestTibCNCSTest(unittest.TestCase):
     def test_simple(self):
-        result=mantid.simpleapi.SuggestTibCNCS(3.)
-        self.assertAlmostEqual(result[0]*0.1,4491.5,0)
-        self.assertAlmostEqual(result[1]*0.1,4731.5,0)
-        result=mantid.simpleapi.SuggestTibCNCS(1.)
-        self.assertAlmostEqual(result[0]*0.1,9562.1,0)
-        self.assertAlmostEqual(result[1]*0.1,9902.1,0)
-        result=mantid.simpleapi.SuggestTibCNCS(6.)
-        self.assertAlmostEqual(result[0]*0.1,2983.3,0)
-        self.assertAlmostEqual(result[1]*0.1,3323.3,0)
+        result = simpleapi.SuggestTibCNCS(3.)
+        self.assertAlmostEqual(result[0] * 0.1, 4491.5, 0)
+        self.assertAlmostEqual(result[1] * 0.1, 4731.5, 0)
+        result = simpleapi.SuggestTibCNCS(1.)
+        self.assertAlmostEqual(result[0] * 0.1, 9562.1, 0)
+        self.assertAlmostEqual(result[1] * 0.1, 9902.1, 0)
+        result = simpleapi.SuggestTibCNCS(6.)
+        self.assertAlmostEqual(result[0] * 0.1, 2983.3, 0)
+        self.assertAlmostEqual(result[1] * 0.1, 3323.3, 0)
 
     def test_someresult(self):
-        for en in numpy.arange(1.,30.,0.1):
-            result=mantid.simpleapi.SuggestTibCNCS(en)
-            self.assertTrue(result[1]-result[0]>1000.)
+        for en in numpy.arange(1., 30., 0.1):
+            result = simpleapi.SuggestTibCNCS(en)
+            self.assertTrue(result[1] - result[0] > 1000.)
 
-if __name__=="__main__":
+
+if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibHYSPECTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibHYSPECTest.py
index 222c8150d20a7322fcf88c561ea8eb03a6a8a975..feddaaa75f0058263ac0f30e005e8b9f1a947dcc 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibHYSPECTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SuggestTibHYSPECTest.py
@@ -6,18 +6,19 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest,os
-import mantid
+import unittest
+from mantid import simpleapi
 
 
 class SuggestTibHYSPECTest(unittest.TestCase):
     def test_simple(self):
-    	result=mantid.simpleapi.SuggestTibHYSPEC(5.)
-    	self.assertAlmostEqual(result[0]*.1,3951.5,0)
-    	self.assertAlmostEqual(result[1]*.1,4151.5,0)
-    	result=mantid.simpleapi.SuggestTibHYSPEC(40.)
-    	self.assertAlmostEqual(result[0]*.1,1189.8,0)
-    	self.assertAlmostEqual(result[1]*.1,1389.8,0)
+        result = simpleapi.SuggestTibHYSPEC(5.)
+        self.assertAlmostEqual(result[0] * .1, 3951.5, 0)
+        self.assertAlmostEqual(result[1] * .1, 4151.5, 0)
+        result = simpleapi.SuggestTibHYSPEC(40.)
+        self.assertAlmostEqual(result[0] * .1, 1189.8, 0)
+        self.assertAlmostEqual(result[1] * .1, 1389.8, 0)
 
-if __name__=="__main__":
+
+if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt
index 004444cd49a60a8e39413c959705b92bbba7c3f5..a164ade4d65e699d5cd103d8dda7df8fb6006fef 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt
@@ -69,5 +69,6 @@ set ( TEST_PY_FILES
 check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} )
 
 # Prefix for test name=PythonWorkflowAlgorithms
+set ( PYUNITTEST_PYTHONPATH_EXTRA ${PYTHONINTERFACE_PLUGINS_DIR}/algorithms/WorkflowAlgorithms )
 pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} python.WorkflowAlgorithms ${TEST_PY_FILES} )
 add_subdirectory( sans )
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrectionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrectionTest.py
index 701a05443891cfcf1457d8f6bcbfc9a178acc29a..3d192f849ae11b796faa574150b58dc76ddd5dc0 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrectionTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrectionTest.py
@@ -16,6 +16,7 @@ from SANSDarkRunBackgroundCorrection import DarkRunMonitorAndDetectorRemover
 from SANSDarkRunBackgroundCorrection import SANSDarkRunBackgroundCorrection
 from six.moves import range
 
+
 class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
     #-----
     # Workspace2D tests
@@ -58,7 +59,7 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
 
         # Assert
         # We should sum up all bins in the dark run (all y values, hence bin_boundaries_dark_run - 1).
-        # Then multpliy by the normalization ratio 
+        # Then multpliy by the normalization ratio
         # Then divide by the bins in the scatterer.
         expected_integration = y_value_dark_run* float(bin_boundaries_dark_run - 1)
         expected_correction_value = (normalization_ratio*expected_integration/float(bin_boundaries_scatter - 1))
@@ -86,7 +87,7 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
         bin_boundaries_dark_run = 20
         y_value_spectra_even_dark_run = [0.3 for element in range(bin_boundaries_dark_run - 1)]
         y_value_spectra_odd_dark_run = [0.2 for element in range(bin_boundaries_dark_run - 1)]
-        y_value_dark_run = (y_value_spectra_even_dark_run + y_value_spectra_odd_dark_run + 
+        y_value_dark_run = (y_value_spectra_even_dark_run + y_value_spectra_odd_dark_run +
                             y_value_spectra_even_dark_run + y_value_spectra_odd_dark_run)
         e_value_dark_run = 0
         name_dark_run = "_dark_run_SANS_test"
@@ -157,16 +158,16 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
                     DarkRun = name_dark_run,
                     Mean = mean,
                     Uniform =uniform,
-                    NormalizationRatio=normalization_ratio, 
+                    NormalizationRatio=normalization_ratio,
                     OutputWorkspace = out_ws_name,
                     ApplyToDetectors = True,
                     ApplyToMonitors = False,
                     SelectedMonitors = [],
                     rethrow = True)
-        
+
         # Assert
         # We should sum up all bins in the dark run (all y values, hence bin_boundaries_dark_run - 1).
-        # Then multpliy by the normalization ratio 
+        # Then multpliy by the normalization ratio
         # Then divide by the bins in the scatterer.
         expected_correction_value = normalization_ratio
         self.assertTrue(AnalysisDataService.doesExist(out_ws_name))
@@ -246,7 +247,7 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
         applyToMonitors = True
         applyToDetectors = False
         out_ws_name = "out_test"
-        selected_monitor = [2] 
+        selected_monitor = [2]
         # Act
         ws = self._do_run_dark_subtraction(scatter_ws, dark_run, mean, uniform, normalization_ratio,
                                       out_ws_name, applyToMonitors, applyToDetectors, selected_monitor)
@@ -401,7 +402,8 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
 
         AnalysisDataService.add(scatter_name, scatter_ws)
         AnalysisDataService.add(dark_name, dark_run)
-        self.assertRaises(RuntimeError, SANSDarkRunBackgroundCorrection, **kwds)
+        self.assertRaises(RuntimeError, run_algorithm, 'SANSDarkRunBackgroundCorrection',
+                          rethrow=True, **kwds)
 
         # Clean up
         ws_to_clean = [scatter_name, dark_name]
@@ -446,7 +448,8 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
 
         AnalysisDataService.add(scatter_name, scatter_ws)
         AnalysisDataService.add(dark_name, dark_run)
-        self.assertRaises(RuntimeError, SANSDarkRunBackgroundCorrection, **kwds)
+        self.assertRaises(RuntimeError, run_algorithm, 'SANSDarkRunBackgroundCorrection',
+                          rethrow=True, **kwds)
 
         # Clean up
         ws_to_clean = [scatter_name, dark_name]
@@ -526,7 +529,7 @@ class SANSDarkRunBackgroundCorrectionTest(unittest.TestCase):
         out_ws_name = "sans_workspace_test"
         if as_dark_run:
             out_ws_name = "dark_run_workspace_test"
-        
+
         alg_load  = AlgorithmManager.createUnmanaged("LoadNexusProcessed")
         alg_load.initialize()
         alg_load.setChild(True)
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SavePlot1DTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SavePlot1DTest.py
index 11783386f32cfceb363c1683b8701969b9fc88b2..a0f0393885efe24395411e4a61941f4eac56fffe 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SavePlot1DTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SavePlot1DTest.py
@@ -6,40 +6,46 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 
-import unittest,os
-import mantid
+import unittest, os
+from mantid import AnalysisDataServiceImpl, config, simpleapi
+
 
 class SavePlot1DTest(unittest.TestCase):
     def makeWs(self):
-        mantid.simpleapi.CreateWorkspace(OutputWorkspace='test1',DataX='1,2,3,4,5,1,2,3,4,5',DataY='1,2,3,4,2,3,4,5',DataE='1,2,3,4,2,3,4,5',NSpec='2',UnitX='TOF',Distribution='1',YUnitlabel="S(q)")
-        mantid.simpleapi.CreateWorkspace(OutputWorkspace='test2',DataX='1,2,3,4,5,1,2,3,4,5',DataY='1,2,3,4,2,3,4,5',DataE='1,2,3,4,2,3,4,5',NSpec='2',
-                                         UnitX='Momentum',VerticalAxisUnit='TOF',VerticalAxisValues='1,2',Distribution='1',YUnitLabel='E',WorkspaceTitle='x')
-        mantid.simpleapi.GroupWorkspaces("test1,test2",OutputWorkspace="group")
-        self.plotfile=os.path.join(mantid.config.getString('defaultsave.directory'),'plot.png')
+        simpleapi.CreateWorkspace(OutputWorkspace='test1', DataX='1,2,3,4,5,1,2,3,4,5', DataY='1,2,3,4,2,3,4,5',
+                                  DataE='1,2,3,4,2,3,4,5', NSpec='2', UnitX='TOF', Distribution='1', YUnitlabel="S(q)")
+        simpleapi.CreateWorkspace(OutputWorkspace='test2', DataX='1,2,3,4,5,1,2,3,4,5', DataY='1,2,3,4,2,3,4,5',
+                                  DataE='1,2,3,4,2,3,4,5', NSpec='2',
+                                  UnitX='Momentum', VerticalAxisUnit='TOF', VerticalAxisValues='1,2', Distribution='1',
+                                  YUnitLabel='E', WorkspaceTitle='x')
+        simpleapi.GroupWorkspaces("test1,test2", OutputWorkspace="group")
+        self.plotfile = os.path.join(config.getString('defaultsave.directory'), 'plot.png')
 
     def cleanup(self):
-        mantid.api.AnalysisDataService.remove("group")
-        mantid.api.AnalysisDataService.remove("test1")
-        mantid.api.AnalysisDataService.remove("test2")
+        ads = AnalysisDataServiceImpl.Instance()
+        ads.remove("group")
+        ads.remove("test1")
+        ads.remove("test2")
         if os.path.exists(self.plotfile):
             os.remove(self.plotfile)
 
     def testPlot(self):
         self.makeWs()
-        ok2run=''
+        ok2run = ''
         try:
             import matplotlib
             from distutils.version import LooseVersion
-            if LooseVersion(matplotlib.__version__)<LooseVersion("1.2.0"):
-                ok2run='Wrong version of matplotlib. Required >= 1.2.0'
+            if LooseVersion(matplotlib.__version__) < LooseVersion("1.2.0"):
+                ok2run = 'Wrong version of matplotlib. Required >= 1.2.0'
             matplotlib.use("agg")
             import matplotlib.pyplot as plt
         except:
-            ok2run='Problem importing matplotlib'
-        if ok2run=='':
-            mantid.simpleapi.SavePlot1D("group",self.plotfile)
-            self.assertGreater(os.path.getsize(self.plotfile),1e4)
+            ok2run = 'Problem importing matplotlib'
+        if ok2run == '':
+            simpleapi.SavePlot1D("group", self.plotfile)
+            self.assertGreater(os.path.getsize(self.plotfile), 1e4)
         self.cleanup()
 
-if __name__=="__main__":
+
+if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCalculateTransmissionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCalculateTransmissionTest.py
index 2621be81638033fce4a5bcfe2d640bc3e7ef0636..4d396e96bd8122ff51d86784794cc5abdcc2e13e 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCalculateTransmissionTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCalculateTransmissionTest.py
@@ -6,7 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
+from mantid.api import FrameworkManager
 import numpy as np
 from sans.test_helper.test_director import TestDirector
 from sans.state.calculate_transmission import get_calculate_transmission_builder
@@ -63,6 +63,10 @@ class SANSCalculateTransmissionTest(unittest.TestCase):
     sample_workspace = None
     sample_workspace_2 = None
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _load_workspace(file_name):
         load_name = "Load"
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToQTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToQTest.py
index af20737f2cf08466308f148b6931cf1d977323f7..31570e466232a973ef8ea1ee53de9d1330b82d86 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToQTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToQTest.py
@@ -6,7 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
+from mantid.api import FrameworkManager
 
 from sans.common.general_functions import (create_unmanaged_algorithm)
 from sans.common.constants import EMPTY_NAME
@@ -18,6 +18,11 @@ from sans.test_helper.file_information_mock import SANSFileInformationMock
 
 
 class SANSConvertToQTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _get_workspace(x_unit="Wavelength", is_adjustment=False):
         bank_pixel_width = 1 if is_adjustment else 2
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToWavelengthTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToWavelengthTest.py
index 687c84b27a0025ce2b548eee16d9a88471b54729..c46d526617dea8097540a6be4cfd5062cca48c24 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToWavelengthTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSConvertToWavelengthTest.py
@@ -6,8 +6,8 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
 
+from mantid.api import FrameworkManager
 from mantid.dataobjects import EventWorkspace
 from sans.common.general_functions import (create_unmanaged_algorithm)
 from sans.common.constants import EMPTY_NAME
@@ -30,6 +30,11 @@ def provide_workspace(is_event=True):
 
 
 class SANSSConvertToWavelengthImplementationTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     def test_that_event_workspace_and_interpolating_rebin_raises(self):
         workspace = provide_workspace(is_event=True)
         convert_options = {"InputWorkspace": workspace,
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateAdjustmentWorkspacesTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateAdjustmentWorkspacesTest.py
index 820e230736decfb130e98d673f8b1825c3aa21a7..9963034b4ba6747248b8bb163f4447e6af09519b 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateAdjustmentWorkspacesTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateAdjustmentWorkspacesTest.py
@@ -6,7 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
+from mantid.api import FrameworkManager
 from sans.test_helper.test_director import TestDirector
 from sans.common.general_functions import create_unmanaged_algorithm
 from sans.common.constants import EMPTY_NAME
@@ -22,6 +22,10 @@ class SANSCreateAdjustmentWorkspacesTest(unittest.TestCase):
     test_wav_max = 11.
     test_wav_width = 2.
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _get_state():
         test_director = TestDirector()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateWavelengthAndPixelAdjustmentTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateWavelengthAndPixelAdjustmentTest.py
index d28d24d7f8c8b3c3e7b7d869da7320b162fc9067..e24f76f23a1ca4be6e19293dfe0a341ad72c7f58 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateWavelengthAndPixelAdjustmentTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSCreateWavelengthAndPixelAdjustmentTest.py
@@ -6,7 +6,8 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
+from mantid.api import FrameworkManager
+from mantid.kernel import config
 
 import os
 import numpy as np
@@ -18,6 +19,11 @@ from sans.common.constants import EMPTY_NAME
 
 
 class SANSCalculateTransmissionTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _create_test_wavelength_adjustment_file(file_name):
         test_file = ("  Tue 24-MAR-2015 00:02 Workspace: directbeam_new_hist\n"
@@ -32,7 +38,7 @@ class SANSCalculateTransmissionTest(unittest.TestCase):
                      "     9.00000    5.000000e-01    5.000000e-01\n"
                      "    11.00000    5.000000e-01    5.000000e-01\n")
 
-        full_file_path = os.path.join(mantid.config.getString('defaultsave.directory'), file_name)
+        full_file_path = os.path.join(config.getString('defaultsave.directory'), file_name)
         if os.path.exists(full_file_path):
             os.remove(full_file_path)
 
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSNormalizeToMonitorTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSNormalizeToMonitorTest.py
index b59fadc3b34f9c4cc74ded5fbc23060f98f8ed1b..b374265a10ffce018285d6dcff4168b0155d6353 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSNormalizeToMonitorTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSNormalizeToMonitorTest.py
@@ -6,7 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
+from mantid.api import FrameworkManager
 
 from sans.test_helper.test_director import TestDirector
 from sans.state.normalize_to_monitor import get_normalize_to_monitor_builder
@@ -45,6 +45,10 @@ def get_expected_for_spectrum_1_case(monitor_workspace, selected_detector):
 
 class SANSNormalizeToMonitorTest(unittest.TestCase):
 
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _get_monitor_workspace(data=None):
         create_name = "CreateSampleWorkspace"
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSScaleTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSScaleTest.py
index 843ec870816ad6cb48f3391e0a4ee75c2fbb7e9c..be7e864d5de29359777b942f5d6a747e594d7160 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSScaleTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSScaleTest.py
@@ -6,7 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
+from mantid.api import FrameworkManager
 import math
 
 from sans.common.general_functions import (create_unmanaged_algorithm)
@@ -19,6 +19,11 @@ from sans.test_helper.file_information_mock import SANSFileInformationMock
 
 
 class SANSScaleTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _get_workspace():
         sample_name = "CreateSampleWorkspace"
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSSliceEventTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSSliceEventTest.py
index 6ba19de33c4d41b27a744b9aa21cb3a318766602..982b51ae158ff60003900fd052c4130bdd4ac17b 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSSliceEventTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/sans/SANSSliceEventTest.py
@@ -6,8 +6,8 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
 
+from mantid.api import FrameworkManager
 from mantid.kernel import DateAndTime
 from mantid.dataobjects import Workspace2D
 from sans.common.general_functions import (create_unmanaged_algorithm)
@@ -46,6 +46,11 @@ def provide_workspace_with_proton_charge(is_event=True):
 
 
 class SANSSliceEventTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _provide_workspaces(is_event=True):
         workspace = provide_workspace_with_proton_charge(is_event=is_event)
diff --git a/Framework/PythonInterface/test/testhelpers/__init__.py b/Framework/PythonInterface/test/testhelpers/__init__.py
index de00ffc779168ac1f48ea0e9201623d95bde3376..7adc48f9c59ca43919e51140d8b34371ddc8e784 100644
--- a/Framework/PythonInterface/test/testhelpers/__init__.py
+++ b/Framework/PythonInterface/test/testhelpers/__init__.py
@@ -10,11 +10,9 @@ are for use in unit tests only!
 from __future__ import (absolute_import, division,
                         print_function)
 
-from six import iteritems
-# Define all mantid exported classes first
-import mantid
-
-#Add workspace creation namespace
+# Import mantid to set MANTIDPATH for any ConfigService call that may be done
+import mantid  # noqa
+# Add workspace creation namespace
 from . import WorkspaceCreationHelper
 
 # Define some pure-Python functions to add to the mix
@@ -46,6 +44,8 @@ def create_algorithm(name, **kwargs):
         kwargs - A dictionary of property name:value pairs
     @returns The algorithm handle
     """
+    # Initialize the whole framework
+    import mantid.simpleapi  # noqa
     if 'Version' in kwargs:
         alg = mantid.api.AlgorithmManager.createUnmanaged(name, kwargs['Version'])
         del kwargs['Version']
diff --git a/Framework/PythonInterface/test/testhelpers/testrunner.py b/Framework/PythonInterface/test/testhelpers/testrunner.py
index 3b0ceb75cd05c9862a571152fe6a66b507a015ef..64edae69cbfba0e1a074a7b6349cdc7b4dfb8819 100644
--- a/Framework/PythonInterface/test/testhelpers/testrunner.py
+++ b/Framework/PythonInterface/test/testhelpers/testrunner.py
@@ -149,9 +149,4 @@ def result_class(pathname):
 
 
 if __name__ == "__main__":
-    if "TESTRUNNER_IMPORT_MANTID" in os.environ:
-        # Import mantid so that it sets up the additional paths to scripts etc
-        # It would be good to try & remove this to soften the impact on tests
-        # that don't require importing mantid at all
-        import mantid  # noqa
     main(sys.argv)
diff --git a/MantidPlot/src/Mantid/MantidApplication.cpp b/MantidPlot/src/Mantid/MantidApplication.cpp
index b37e859a26a3f2deed47ec7758f3f08dbcfbd0d9..b439635135cafcdb3be217c532fdcd13a8d95626 100644
--- a/MantidPlot/src/Mantid/MantidApplication.cpp
+++ b/MantidPlot/src/Mantid/MantidApplication.cpp
@@ -29,7 +29,7 @@ Mantid::Kernel::Logger g_log("MantidApplication");
 MantidApplication::MantidApplication(int &argc, char **argv)
     : QApplication(argc, argv) {
   try {
-    Mantid::Kernel::UsageService::Instance().setApplication("mantidplot");
+    Mantid::Kernel::UsageService::Instance().setApplicationName("mantidplot");
   } catch (std::runtime_error &rexc) {
     g_log.error() << "Failed to initialize the Mantid usage service. This "
                      "is probably a sign that this Mantid is not fully or "
diff --git a/MantidPlot/src/ProjectSerialiser.cpp b/MantidPlot/src/ProjectSerialiser.cpp
index 5458948111a9fdd8c06f9a5b1e9b174aa0eb4a90..1780da0ed033afc156251067a469b48ca90d2873 100644
--- a/MantidPlot/src/ProjectSerialiser.cpp
+++ b/MantidPlot/src/ProjectSerialiser.cpp
@@ -130,7 +130,7 @@ constexpr auto PY_INTERFACE_SECTION = "pythoninterface";
 //     w = MainWindow()
 //     w.show()
 //
-QStringList SERIALISABLE_PY_INTERFACES;
+QStringList SERIALISABLE_PY_INTERFACES = {"Muon_Analysis_2"};
 
 } // namespace
 
diff --git a/Testing/SystemTests/tests/analysis/GUIStartupTest.py b/Testing/SystemTests/tests/analysis/GUIStartupTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b0eea635a971f9a447d6b01ceebb6820cf165df
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/GUIStartupTest.py
@@ -0,0 +1,70 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+from __future__ import (absolute_import, division, print_function)
+import os
+import platform
+import subprocess
+import systemtesting
+import mantid
+
+
+class GUIStartupTest(systemtesting.MantidSystemTest):
+    '''This test is supposed to start MantidPlot, and execute a simple
+    script If the script is run correctly, the "Hello Mantid" will be
+    printed to stdout If the script fails, there will be a fatal error
+    mesage in stderr
+    '''
+
+    def __init__(self):
+        super(GUIStartupTest, self).__init__()
+        self.maxDiff = None
+        # create simple script
+        self.script = os.path.join(mantid.config.getString('defaultsave.directory'),
+                                   'GUIStartupTest_script.py')
+        with open(self.script, 'w') as f:
+            f.write('import mantid\n'
+                    'print("Hello Mantid")\n')
+        # get the mantidplot executable
+        current_platform = platform.platform()
+        mantid_init_dirname = os.path.dirname(os.path.abspath(mantid.__file__))
+        if 'Linux' in current_platform:
+            mantid_exe = os.path.join(mantid_init_dirname, "../launch_mantidplot.sh")
+        elif 'Darwin' in current_platform:
+            mantid_exe = os.path.join(mantid_init_dirname, "../MantidPlot")
+        elif 'Windows' in current_platform:
+            mantid_exe = 'wscript.exe {}'.format(os.path.join(mantid_init_dirname,
+                                                              "../bin/launch_mantidplot.vbs"))
+        else:
+            raise RuntimeError("Unknown operating system")
+
+        # verify the launch script exists
+        if os.path.exists(mantid_exe):
+            self.cmd = '{0} -xq {1}'.format(mantid_exe, self.script)
+        else:
+            self.cmd = None
+
+    def skipTests(self):
+        return self.cmd is None
+
+    def cleanup(self):
+        if os.path.exists(self.script):
+            os.remove(self.script)
+
+    def runTest(self):
+        # good startup
+        p = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+        out, err = p.communicate()
+        self.assertEquals(out, b'Hello Mantid\n')
+
+        # failing script
+        with open(self.script, 'a') as f:
+            f.write('raise RuntimeError("GUITest")')
+        p = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+        out, err = p.communicate()
+        out += err
+        self.assertTrue(b'Hello Mantid\n' in out)
+        self.assertTrue(b'RuntimeError: GUITest' in out)
diff --git a/buildconfig/CMake/FindPyUnitTest.cmake b/buildconfig/CMake/FindPyUnitTest.cmake
index df9ad62931979d5f26a48b9e7840c96b936998aa..5ac987e2e6291f92d6adc0e70198daeafd859e0e 100644
--- a/buildconfig/CMake/FindPyUnitTest.cmake
+++ b/buildconfig/CMake/FindPyUnitTest.cmake
@@ -2,6 +2,8 @@
 # PYUNITTEST_ADD_TEST (public macro to add unit tests)
 #   Adds a set of python tests based upon the unittest module
 #
+#   The variable PYUNITTEST_PYTHONPATH_EXTRA can be defined with
+#   extra paths to add to PYTHONPATH during the tests
 #   Parameters:
 #       _test_src_dir_base :: A base directory when added to the relative test paths gives
 #                             an absolute path to that test. This directory is added to the
@@ -17,27 +19,27 @@ function ( PYUNITTEST_ADD_TEST _test_src_dir _testname_prefix )
   else()
     set ( _module_dir ${CMAKE_BINARY_DIR}/bin )
   endif()
+
   set ( _test_runner ${_module_dir}/mantidpython )
   if ( WIN32 )
     set ( _test_runner ${_test_runner}.bat )
   endif ()
   set ( _test_runner_module ${CMAKE_SOURCE_DIR}/Framework/PythonInterface/test/testhelpers/testrunner.py )
+
   # Environment
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
-    set ( _python_path ${PYTHON_XMLRUNNER_DIR};${_test_src_dir};$ENV{PYTHONPATH} )
+    set ( _python_path ${PYTHON_XMLRUNNER_DIR};${_test_src_dir};${PYUNITTEST_PYTHONPATH_EXTRA}$ENV{PYTHONPATH} )
     # cmake list separator and Windows environment separator are the same so escape the cmake one
     string ( REPLACE ";" "\\;" _python_path "${_python_path}" )
   else()
-    set ( _python_path ${PYTHON_XMLRUNNER_DIR}:${_test_src_dir}:$ENV{PYTHONPATH} )
+    string ( REPLACE ";" ":" _python_path "${PYUNITTEST_PYTHONPATH_EXTRA}" )
+    set ( _python_path ${PYTHON_XMLRUNNER_DIR}:${_test_src_dir}:${_python_path}:$ENV{PYTHONPATH} )
   endif()
   # Define the environment
   list ( APPEND _test_environment "PYTHONPATH=${_python_path}" )
   if ( PYUNITTEST_QT_API )
     list ( APPEND _test_environment "QT_API=${PYUNITTEST_QT_API}" )
   endif()
-  if ( PYUNITTEST_TESTRUNNER_IMPORT_MANTID )
-    list ( APPEND _test_environment "TESTRUNNER_IMPORT_MANTID=1" )
-  endif()
 
   # Add all of the individual tests so that they can be run in parallel
   foreach ( part ${ARGN} )
diff --git a/buildconfig/CMake/LinuxPackageScripts.cmake b/buildconfig/CMake/LinuxPackageScripts.cmake
index 8fb1be25b6be2633e98510ccc7f2dab2ece4510a..7c48de4f85345676a1ec33872bf06c6ecc4b994e 100644
--- a/buildconfig/CMake/LinuxPackageScripts.cmake
+++ b/buildconfig/CMake/LinuxPackageScripts.cmake
@@ -36,24 +36,21 @@ set ( CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /opt /usr/share/applications
 # default shell (bash-like)
 file ( WRITE ${CMAKE_CURRENT_BINARY_DIR}/mantid.sh
   "#!/bin/sh\n"
-  "MANTIDPATH=${CMAKE_INSTALL_PREFIX}/${BIN_DIR}\n"
   "PV_PLUGIN_PATH=${CMAKE_INSTALL_PREFIX}/${PVPLUGINS_DIR}\n"
-  "PATH=$PATH:$MANTIDPATH\n"
+  "PATH=$PATH:${CMAKE_INSTALL_PREFIX}/${BIN_DIR}\n"
 
-  "export MANTIDPATH PV_PLUGIN_PATH PATH\n"
+  "export PV_PLUGIN_PATH PATH\n"
 )
 
 # c-shell
 file ( WRITE ${CMAKE_CURRENT_BINARY_DIR}/mantid.csh
   "#!/bin/csh\n"
-  "setenv MANTIDPATH \"${CMAKE_INSTALL_PREFIX}/${BIN_DIR}\"\n"
   "setenv PV_PLUGIN_PATH \"${CMAKE_INSTALL_PREFIX}/${PVPLUGINS_DIR}\"\n"
-  "setenv PATH \"\${PATH}:\${MANTIDPATH}\"\n"
+  "setenv PATH \"\${PATH}:${CMAKE_INSTALL_PREFIX}/${BIN_DIR}\"\n"
 )
 
 install ( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/mantid.sh
   ${CMAKE_CURRENT_BINARY_DIR}/mantid.csh
-  ${CMAKE_CURRENT_BINARY_DIR}/mantid.pth
   DESTINATION ${ETC_DIR}
 )
 
@@ -66,10 +63,15 @@ print(sc.get_python_lib(plat_specific=True))"
   OUTPUT_VARIABLE PYTHON_SITE
   OUTPUT_STRIP_TRAILING_WHITESPACE)
 
-file ( WRITE ${CMAKE_CURRENT_BINARY_DIR}/mantid.pth
+file ( WRITE ${CMAKE_CURRENT_BINARY_DIR}/mantid.pth.install
   "${CMAKE_INSTALL_PREFIX}/${BIN_DIR}\n"
 )
 
+install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/mantid.pth.install
+  DESTINATION ${ETC_DIR}
+  RENAME mantid.pth
+)
+
 ############################################################################
 # Setup file variables for pre/post installation
 # These are very different depending on the distribution so are contained
@@ -181,9 +183,6 @@ else
     TCM_REPORT=\${TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD}
 fi" )
 
-# chunk of code for fixing MANTIDPATH
-set ( MTD_PATH_DEFINITION "MANTIDPATH=\${INSTALLDIR}/bin" )
-
 # chunk of code for launching gdb
 set ( GDB_DEFINITIONS
 "# run with gdb THIS OPTION MUST BE SUPPLIED FIRST
diff --git a/buildconfig/CMake/Packaging/launch_mantidplot.bat b/buildconfig/CMake/Packaging/launch_mantidplot.bat
index 8a0c0ca176dcd98f6b7cbc04fc1be183ea0c6940..872f71d7fa6c6733d7cb763a7e2d130eb5fb9bea 100755
--- a/buildconfig/CMake/Packaging/launch_mantidplot.bat
+++ b/buildconfig/CMake/Packaging/launch_mantidplot.bat
@@ -2,7 +2,7 @@
 setlocal enableextensions
 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 :: Launch script for MantidPlot
-:: 
+::
 :: Sets the required environment variables for MantidPlot to run correctly.
 :: All variables that are passed to this script are passed directly to
 :: MantidPlot.exe
@@ -24,7 +24,6 @@ set _EXTRA_PATH_DIRS=%_INSTALL_DIR%\bin;%_INSTALL_DIR%\plugins\qt4
 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 :: Required environment variables for Mantid
 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-set MANTIDPATH=%_BIN_DIR%
 set PATH=%_EXTRA_PATH_DIRS%;%PATH%
 set PV_PLUGIN_PATH=%_INSTALL_DIR%\plugins\paraview\qt4
 :: Matplotlib backend should default to Qt if not set (requires matplotlib >= 1.5)
@@ -44,4 +43,4 @@ start "MantidPlot" /B /WAIT %_BIN_DIR%\MantidPlot.exe %*
 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 if %errorlevel% NEQ 0 (
 python %_INSTALL_DIR%\scripts\ErrorReporter\error_dialog_app.py --exitcode=%1 --directory=%_BIN_DIR%
-)
\ No newline at end of file
+)
diff --git a/buildconfig/CMake/Packaging/launch_mantidplot.sh.in b/buildconfig/CMake/Packaging/launch_mantidplot.sh.in
index dc4c9d534d9ecfa1500ea81080660b4553a1328a..0ba17b9ad15420e63018f7fd27d534876159d876 100644
--- a/buildconfig/CMake/Packaging/launch_mantidplot.sh.in
+++ b/buildconfig/CMake/Packaging/launch_mantidplot.sh.in
@@ -9,8 +9,6 @@ THISFILE=$(readlink -f "$0")
 INSTALLDIR=$(dirname $THISFILE)   # directory of executable
 INSTALLDIR=$(dirname $INSTALLDIR) # root install directory
 
-@MTD_PATH_DEFINITION@
-
 @TCMALLOC_DEFINITIONS@
 
 @VIRTUAL_GL_WRAPPER@
diff --git a/buildconfig/CMake/Packaging/launch_mantidworkbench.sh.in b/buildconfig/CMake/Packaging/launch_mantidworkbench.sh.in
index 25a5d1354b675f266e61a519bb321768cf9d066f..476e533daac4a1a18b2615862db746548e937faf 100644
--- a/buildconfig/CMake/Packaging/launch_mantidworkbench.sh.in
+++ b/buildconfig/CMake/Packaging/launch_mantidworkbench.sh.in
@@ -9,8 +9,6 @@ THISFILE=$(readlink -f "$0")
 INSTALLDIR=$(dirname $THISFILE)   # directory of executable
 INSTALLDIR=$(dirname $INSTALLDIR) # root install directory
 
-@MTD_PATH_DEFINITION@
-
 @TCMALLOC_DEFINITIONS@
 
 @VIRTUAL_GL_WRAPPER@
diff --git a/buildconfig/CMake/Packaging/mantidpython.bat.in b/buildconfig/CMake/Packaging/mantidpython.bat.in
index 6359d97741b8b2cfaaeb2ec2717514788512ba79..4a3d510d80548fdf90430ee2447d0907a7a15c65 100644
--- a/buildconfig/CMake/Packaging/mantidpython.bat.in
+++ b/buildconfig/CMake/Packaging/mantidpython.bat.in
@@ -2,7 +2,7 @@
 setlocal enableextensions
 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 :: Launch script for command line python
-:: 
+::
 :: Sets the required environment variables for the Python to run correctly.
 :: All variables that are passed to this script are passed directly to
 :: python.exe
@@ -14,8 +14,7 @@ set _BIN_DIR=%_SCRIPT_DIR:~,-1%
 :: Set paths for dependencies, including Python
 @MANTIDPYTHON_PREAMBLE@
 
-set MANTIDPATH=%_BIN_DIR%
-set PYTHONPATH=%MANTIDPATH%;%PYTHONPATH%@PARAVIEW_PYTHON_PATHS@
+set PYTHONPATH=%_BIN_DIR%;%PYTHONPATH%@PARAVIEW_PYTHON_PATHS@
 
 :: Python drivers
 set _PYTHON_EXE=%PYTHONHOME%\python.exe
diff --git a/buildconfig/CMake/Packaging/mantidpython.in b/buildconfig/CMake/Packaging/mantidpython.in
index 5904a86f1ec2092e12cc1bb43dbb1af8fd03bb3e..c96304ffa464f047d88ec95a74f6dde1d20230bd 100755
--- a/buildconfig/CMake/Packaging/mantidpython.in
+++ b/buildconfig/CMake/Packaging/mantidpython.in
@@ -9,8 +9,6 @@ THISFILE=$(readlink -f "$0")
 INSTALLDIR=$(dirname $THISFILE)   # directory of executable
 INSTALLDIR=$(dirname $INSTALLDIR) # root install directory
 
-@MTD_PATH_DEFINITION@
-
 @TCMALLOC_DEFINITIONS@
 
 LOCAL_LDPATH=@EXTRA_LDPATH@
diff --git a/buildconfig/CMake/Packaging/osx/mantidpython.in b/buildconfig/CMake/Packaging/osx/mantidpython.in
index 51b9910c5d9054519344194894fcb9cc942829d1..4c758b0af004bbe9e7372733deb12f66720a3889 100755
--- a/buildconfig/CMake/Packaging/osx/mantidpython.in
+++ b/buildconfig/CMake/Packaging/osx/mantidpython.in
@@ -25,22 +25,15 @@ if [ -n "${PYTHONPATH}" ]; then
 	LOCAL_PYTHONPATH=${LOCAL_PYTHONPATH}:${PYTHONPATH}
 fi
 
-# Define MANTIDPATH
-MANTIDPATH="${INSTALLDIR}"
 if [ -n "$1" ] && [ "$1" = "--classic" ]; then
     shift
-
     set -- @WRAPPER_PREFIX@@PYTHON_EXECUTABLE@ $*@WRAPPER_POSTFIX@
-
 else
     IPYTHON_STARTUP="import IPython;IPython.start_ipython()"
-
     set -- @WRAPPER_PREFIX@@PYTHON_EXECUTABLE@ -c "${IPYTHON_STARTUP}" $*@WRAPPER_POSTFIX@
-
 fi
 
 
 PV_PLUGIN_PATH=${PV_PLUGIN_PATH} \
-  MANTIDPATH=${MANTIDPATH} \
   PYTHONPATH=${LOCAL_PYTHONPATH} \
   exec "$@"
diff --git a/buildconfig/CMake/WindowsNSIS.cmake b/buildconfig/CMake/WindowsNSIS.cmake
index 222ffc67e1ec4c551e75754d18b3ae7d00a9aa24..ce43ee33addeee0b2eb717ff5e69458278832480 100644
--- a/buildconfig/CMake/WindowsNSIS.cmake
+++ b/buildconfig/CMake/WindowsNSIS.cmake
@@ -79,6 +79,7 @@ set ( BOOST_DIST_DLLS
     boost_python27-mt.dll
     boost_regex-mt.dll
     boost_serialization-mt.dll
+    boost_system-mt.dll
 )
 set ( POCO_DIST_DLLS
     PocoCrypto64.dll
diff --git a/buildconfig/Jenkins/buildscript b/buildconfig/Jenkins/buildscript
index e71ef1ce819b997ba276b9f47d7618493cb18fe6..de1841b7e5e33c401a6f5789c23ec8ac0facb017 100755
--- a/buildconfig/Jenkins/buildscript
+++ b/buildconfig/Jenkins/buildscript
@@ -382,11 +382,6 @@ fi
 # documentation
 ###############################################################################
 if [[ ${DO_BUILD_PKG} == true ]]; then
-  # Workaround so that the target can find the properties file
-  # CMake doesn't easily allow environment variables on custom targets
-  if [[ ${ON_MACOS} == true ]]; then
-    export MANTIDPATH=$PWD/bin
-  fi
   ${CMAKE_EXE} --build . --target docs-qthelp
   ${CPACK_EXE}
 
diff --git a/docs/runsphinx.py.in b/docs/runsphinx.py.in
index 3ee4654fae408bf969f62a0b301a2434003498e8..f1dd3e7075ccfa825ff719ddb8cdc7f3c7c38cf4 100644
--- a/docs/runsphinx.py.in
+++ b/docs/runsphinx.py.in
@@ -47,9 +47,6 @@ def main(sysarg):
         raise RuntimeError("Unexpected command line arguments: %s. "
                            "Use -h for help" % ' '.join(args))
 
-    # Update sys path if we need to
-    update_path()
-
     # Find test files
     testpaths = find_test_files(CONF_DIR, opts.testinclude)
 
@@ -68,8 +65,8 @@ def main(sysarg):
     doctree_dir = pathjoin(SPHINX_BUILD_DIR, "doctrees")
     argv = []
     if LooseVersion(get_sphinx_version()) < LooseVersion("1.7.0"):
-        # prior to v1.7.0 paths positional argument required       
-        argv = [sys.executable] 
+        # prior to v1.7.0 paths positional argument required
+        argv = [sys.executable]
     argv += ["-N",
             "-b", BUILDER,
             "-d", doctree_dir]
@@ -107,7 +104,6 @@ def main(sysarg):
         RegexLexer.get_tokens_unprocessed = pygments_highlighter.get_tokens_unprocessed
     sys.exit(return_value)
 
-#-----------------------------------------------------------------------------------------------
 
 def parseargs(arglist):
     """
@@ -123,45 +119,6 @@ def parseargs(arglist):
                       "filename when considering whether to run a test.")
     return parser.parse_args(arglist[1:]) # hack off filename
 
-#-----------------------------------------------------------------------------------------------
-
-def update_path():
-    """
-    If not inside MantidPlot (current check is whether we can import _qti)
-    then insert given path as first directory in sys.path
-    """
-    try:
-        import _qti
-        gui = True
-    except ImportError:
-        gui = False
-
-
-    # If it's MantidPlot then we already know what our paths should be so ignore it
-    if gui:
-        return
-
-    # the python wrapper sets this environment variable
-    mantidpath = os.environ.get('MANTIDPATH', None)
-
-    # otherwise try to expand based off of information in cmake
-    if mantidpath is None or len(mantidpath) == 0:
-        mantidpath = BUILD_DIR
-        if os.path.split(mantidpath)[-1] != 'bin' and \
-           os.path.isdir(os.path.join(mantidpath, 'bin')):
-            mantidpath = os.path.join(mantidpath, 'bin')
-
-    # check for directory
-    if not os.path.isdir(os.path.join(mantidpath, "mantid")):
-        raise ValueError("Unable to find mantid package in '%s'" % mantidpath)
-    # is package valid
-    if not os.path.isfile(os.path.join(mantidpath, "mantid", "__init__.py")):
-        raise ValueError("Invalid mantid package. No __init__ found in '%s' %s")
-
-    # Update sys.path
-    sys.path.insert(0, mantidpath)
-
-#-----------------------------------------------------------------------------------------------
 
 def find_test_files(src_dir, name_re):
     """
@@ -206,7 +163,7 @@ def find_matching_tests(filenames, name_re):
 
     return testfiles
 
-#-----------------------------------------------------------------------------------------------
+
 def pathjoin(left, *args):
     """
     Similar to os.path.join but just uses "/" as it's populated with CMake-style paths that are
@@ -214,10 +171,6 @@ def pathjoin(left, *args):
     """
     return left + "/" + "/".join(args)
 
-#-----------------------------------------------------------------------------------------------
-
-
-##################################################################################
 
 if __name__ == "__main__":
     main(sys.argv)
diff --git a/docs/source/release/v3.14.0/framework.rst b/docs/source/release/v3.14.0/framework.rst
index 2ddcd7ddd015026c428be337854d386301cf4a89..935a994d705f8ef67d9bc17d377006bf4d26ff88 100644
--- a/docs/source/release/v3.14.0/framework.rst
+++ b/docs/source/release/v3.14.0/framework.rst
@@ -100,12 +100,17 @@ New
  * :class:`mantid.api.SpectrumInfo`
 
 - :class:`mantid.geometry.ComponentInfo` is exposed to allow the user to access geometric information about the components which are part of a beamline.
-
 - :class:`mantid.geometry.DetectorInfo` offers the user the ability to access geometric information about the detector(s) which are part of a beamline. ``DetectorInfo`` has also been given an iterator to allow users to write more Pythonic loops rather than normal index based loops.
-
 - :class:`mantid.api.SpectrumInfo` allows the user to access information about the spectra being used in a beamline. ``SpectrumInfo`` has also been given an iterator to allow users to write more Pythonic loops rather than normal index based loops. In addition to this ``SpectrumDefinition`` objects can also be accessed via a :class:`mantid.api.SpectrumInfo` object. The ``SpectrumDefinition`` object can be used to obtain information about the spectrum to detector mapping and provides a definition of what a spectrum comprises, i.e. indices of all detectors that contribute to the data stored in the spectrum.
-
 - Added new :ref:`unit <Unit Factory>` called ``Temperature`` which has units of Kelvin.
+- Importing ``mantid`` no longer initializes the ``FrameworkManager``. This allows separate classes to be imported without requiring a long delay in waiting for the framework to start. Amongst other things this allows the application name to be set correctly:
+
+.. code-block:: python
+
+   from mantid import FrameworkManager, UsageService
+   UsageService.setApplicationName('myapp')
+   FrameworkManager.Instance()
+
 
 Improvements
 ############
diff --git a/docs/source/release/v3.14.0/reflectometry.rst b/docs/source/release/v3.14.0/reflectometry.rst
index b7473f39939dec96b5ce2b3de4c124eb42a0dc79..1c56173d515d99e81abc58ed428a9becd8f5de73 100644
--- a/docs/source/release/v3.14.0/reflectometry.rst
+++ b/docs/source/release/v3.14.0/reflectometry.rst
@@ -40,6 +40,7 @@ Bug fixes
 - A bug has been fixed on the Settings tab where the IncludePartialBins check box had been hidden by a misplaced text entry box.
 - :ref:`algm-ReflectometryReductionOneAuto` No longer sums all of a transmission run's workspaces and instead will use the first run only
 - In :ref:`algm-ReflectometryReductionOneAuto` an issue where if you gave only one of either MomentumTransferMax or MomentumTransferMin were specified it would be ignored, this has been fixed.
+- Reverted property names for polarization correction coefficients in :ref:`ReflectometryReductionOneAuto <algm-ReflectometryReductionOneAuto-v2>` for backwards compatibility.
 
 Liquids Reflectometer
 ---------------------
diff --git a/qt/applications/workbench/workbench/app/mainwindow.py b/qt/applications/workbench/workbench/app/mainwindow.py
index 5ba5d0f575293a8438dc0cab54bb5ca1c28a4a43..4022774d702953148e9a21622b3091707ec4d710 100644
--- a/qt/applications/workbench/workbench/app/mainwindow.py
+++ b/qt/applications/workbench/workbench/app/mainwindow.py
@@ -12,13 +12,19 @@ Defines the QMainWindow of the application and the main() entry point.
 """
 from __future__ import (absolute_import, division,
                         print_function, unicode_literals)
+
+# std imports
 import argparse  # for command line options
 import atexit
-import imp
 import importlib
 import os
 import sys
 
+# third party imports
+from mantid.kernel import (ConfigService, logger, UsageService,
+                           version_str as mantid_version_str)
+from mantid.api import FrameworkManagerImpl
+
 # -----------------------------------------------------------------------------
 # Constants
 # -----------------------------------------------------------------------------
@@ -41,14 +47,16 @@ from qtpy.QtCore import (QEventLoop, Qt, QCoreApplication, QPoint, QSize, QSetti
 from qtpy.QtGui import (QColor, QGuiApplication, QIcon, QPixmap)  # noqa
 from qtpy.QtWidgets import (QApplication, QDesktopWidget, QFileDialog,
                             QMainWindow, QSplashScreen)  # noqa
-from mantidqt.utils.qt import plugins, widget_updates_disabled  # noqa
 from mantidqt.algorithminputhistory import AlgorithmInputHistory  # noqa
+from mantidqt.widgets.manageuserdirectories import ManageUserDirectories  # noqa
 from mantidqt.widgets.codeeditor.execution import PythonCodeExecution  # noqa
+from mantidqt.utils.qt import (add_actions, create_action, plugins,
+                               widget_updates_disabled)  # noqa
 
 # Pre-application setup
 plugins.setup_library_paths()
 
-from workbench.config import APPNAME, CONF, ORG_DOMAIN, ORGANIZATION, set_config_format  # noqa
+from workbench.config import APPNAME, CONF, ORG_DOMAIN, ORGANIZATION  # noqa
 
 
 # -----------------------------------------------------------------------------
@@ -66,15 +74,22 @@ def qapplication():
         QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
         argv = sys.argv[:]
         argv[0] = APPNAME  # replace application name
+        # Workaround a segfault with the IPython console when using Python 3.5 + PyQt 5
+        # Without this using this fix the above combination causes a segfault when the IPython
+        # console is started
+        # The workaround mentioned in https://groups.google.com/forum/#!topic/leo-editor/ghiIN7irzY0
+        # is to ensure readline is imported before the QApplication object is created
+        if sys.version_info[0] == 3 and sys.version_info[1] == 5:
+            importlib.import_module("readline")
         app = QApplication(argv)
         app.setOrganizationName(ORGANIZATION)
         app.setOrganizationDomain(ORG_DOMAIN)
         app.setApplicationName(APPNAME)
-        # not calling app.setApplicationVersion(mantid.kernel.version_str())
-        # because it needs to happen after logging is monkey-patched in
+        app.setApplicationVersion(mantid_version_str())
+        # Spin up the usage service and set the name for the usage reporting
+        # The report is sent when the FrameworkManager kicks up
+        UsageService.setApplicationName(APPNAME)
 
-        # Set the config format to IniFormat globally
-        set_config_format(QSettings.IniFormat)
     return app
 
 
@@ -108,12 +123,6 @@ SPLASH.showMessage("Starting...", Qt.AlignBottom | Qt.AlignLeft
 # The event loop has not started - force event processing
 QApplication.processEvents(QEventLoop.AllEvents)
 
-# -----------------------------------------------------------------------------
-# Utilities/Widgets
-# -----------------------------------------------------------------------------
-from mantidqt.utils.qt import add_actions, create_action  # noqa
-from mantidqt.widgets.manageuserdirectories import ManageUserDirectories  # noqa
-
 
 # -----------------------------------------------------------------------------
 # MainWindow
@@ -205,6 +214,13 @@ class MainWindow(QMainWindow):
         self.create_actions()
         self.populate_menus()
 
+    def post_mantid_init(self):
+        """Run any setup that requires mantid
+        to have been initialized
+        """
+        self.populate_interfaces_menu()
+        self.algorithm_selector.refresh()
+
     def set_splash(self, msg=None):
         if not self.splash:
             return
@@ -266,14 +282,12 @@ class MainWindow(QMainWindow):
         add_actions(self.file_menu, self.file_menu_actions)
         add_actions(self.view_menu, self.view_menu_actions)
 
-    def launchCustomGUI(self, filename):
-        from mantid.kernel import logger  # noqa
+    def launch_custom_gui(self, filename):
         executioner = PythonCodeExecution()
         executioner.sig_exec_error.connect(lambda errobj: logger.warning(str(errobj)))
         executioner.execute(open(filename).read(), filename)
 
-    def populateAfterMantidImport(self):
-        from mantid.kernel import ConfigService, logger  # noqa
+    def populate_interfaces_menu(self):
         interface_dir = ConfigService['mantidqt.python_interfaces_directory']
         items = ConfigService['mantidqt.python_interfaces'].split()
 
@@ -307,7 +321,7 @@ class MainWindow(QMainWindow):
             for name in names:
                 action = submenu.addAction(name.replace('.py', '').replace('_', ' '))
                 script = os.path.join(interface_dir, name)
-                action.triggered.connect(lambda checked, script=script: self.launchCustomGUI(script))
+                action.triggered.connect(lambda checked, script=script: self.launch_custom_gui(script))
 
     def add_dockwidget(self, plugin):
         """Create a dockwidget around a plugin and add the dock to window"""
@@ -512,13 +526,13 @@ def start_workbench(app, command_line_options):
     from workbench.plotting.config import initialize_matplotlib  # noqa
     initialize_matplotlib()
 
-    # Setup widget layouts etc. mantid cannot be imported before this
-    # or the log messages don't get through
+    # Setup widget layouts etc. mantid.simple cannot be used before this
+    # or the log messages don't get through to the widget
     main_window.setup()
     # start mantid
-    main_window.set_splash('Preloading mantid')
-    importlib.import_module('mantid')
-    main_window.populateAfterMantidImport()
+    main_window.set_splash('Initializing mantid framework')
+    FrameworkManagerImpl.Instance()
+    main_window.post_mantid_init()
     main_window.show()
     main_window.setWindowIcon(QIcon(':/images/MantidIcon.ico'))
 
@@ -540,16 +554,6 @@ def start_workbench(app, command_line_options):
 
 def main():
     """Main entry point for the application"""
-    # Mantid needs to be able to find its .properties file. It looks
-    # in the application directory by default but this is
-    # the directory of python[.exe] and not guaranteed to be where
-    # the properties files is located. MANTIDPATH overrides this.
-    # If we allow a user to override MANTIDPATH then we could end up
-    # loading the wrong properties file and plugins built against
-    # a different version of Mantid and this would likely result in
-    # segfault.
-    _, pkgpath, _ = imp.find_module('mantid')
-    os.environ['MANTIDPATH'] = os.path.dirname(pkgpath)
 
     # setup command line arguments
     parser = argparse.ArgumentParser(description='Mantid Workbench')
diff --git a/qt/applications/workbench/workbench/config/__init__.py b/qt/applications/workbench/workbench/config/__init__.py
index e19faa2d2fb3e558172471695e0e05375ffa229f..897b7fcb040bbf12d4ed590ca07ef8442c350c5b 100644
--- a/qt/applications/workbench/workbench/config/__init__.py
+++ b/qt/applications/workbench/workbench/config/__init__.py
@@ -41,8 +41,5 @@ DEFAULTS = {
 # -----------------------------------------------------------------------------
 # 'Singleton' instance
 # -----------------------------------------------------------------------------
+QSettings.setDefaultFormat(QSettings.IniFormat)
 CONF = UserConfig(ORGANIZATION, APPNAME, defaults=DEFAULTS)
-
-
-def set_config_format(format):
-    QSettings.setDefaultFormat(format)
diff --git a/qt/applications/workbench/workbench/config/user.py b/qt/applications/workbench/workbench/config/user.py
index a832e3ac316618c18dc9c49d2cf6bd28725d68e7..066338d1067ec9d55f7c240e94344a4f370d43fe 100644
--- a/qt/applications/workbench/workbench/config/user.py
+++ b/qt/applications/workbench/workbench/config/user.py
@@ -49,7 +49,10 @@ class UserConfig(object):
         # fixup the values of booleans - they do not evaluate correctly when read from the config file
         # TODO come up with a unit test for this
         for key in self.all_keys():
-            value = self.get(key)
+            try:
+                value = self.get(key)
+            except KeyError:
+                continue
             if value == 'true':
                 self.set(key, True)
             elif value == 'false':
diff --git a/qt/applications/workbench/workbench/plotting/test/test_functions.py b/qt/applications/workbench/workbench/plotting/test/test_functions.py
index 9d89d2c4f78f6533a2fe1f1a0361ad823e902b6a..fe5142ca40871b98b16f659e815d3b3eb4854055 100644
--- a/qt/applications/workbench/workbench/plotting/test/test_functions.py
+++ b/qt/applications/workbench/workbench/plotting/test/test_functions.py
@@ -18,6 +18,8 @@ except ImportError:
 
 # third party imports
 from mantid.api import AnalysisDataService, WorkspaceFactory
+# register mantid projection
+import mantid.plots  # noqa
 import matplotlib
 matplotlib.use('AGG')  # noqa
 import matplotlib.pyplot as plt
diff --git a/qt/applications/workbench/workbench/plugins/algorithmselectorwidget.py b/qt/applications/workbench/workbench/plugins/algorithmselectorwidget.py
index 366ed3958f58412e95e92b1fb941f3ea802b0187..efa69bf258e4283e10065de0c9be971d332b5f73 100644
--- a/qt/applications/workbench/workbench/plugins/algorithmselectorwidget.py
+++ b/qt/applications/workbench/workbench/plugins/algorithmselectorwidget.py
@@ -32,6 +32,10 @@ class AlgorithmSelector(PluginWidget):
         layout.addWidget(self.algorithm_selector)
         self.setLayout(layout)
 
+    def refresh(self):
+        """Refreshes the algorithm list"""
+        self.algorithm_selector.refresh()
+
 # ----------------- Plugin API --------------------
 
     def register_plugin(self):
diff --git a/qt/python/mantidqt/widgets/algorithmselector/model.py b/qt/python/mantidqt/widgets/algorithmselector/model.py
index 6d98be3fac0d86366a7c0d26d76ff327c0e74591..821fe117edeefd9bb5b82d69b60addaf36a7eabe 100644
--- a/qt/python/mantidqt/widgets/algorithmselector/model.py
+++ b/qt/python/mantidqt/widgets/algorithmselector/model.py
@@ -6,7 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import absolute_import, print_function
 
-from mantid import AlgorithmFactory
+from mantid.api import AlgorithmFactoryImpl
 
 
 class AlgorithmSelectorModel(object):
@@ -54,7 +54,7 @@ class AlgorithmSelectorModel(object):
             Here self.algorithm_key == '_'
 
         """
-        descriptors = AlgorithmFactory.getDescriptors(self.include_hidden)
+        descriptors = AlgorithmFactoryImpl.Instance().getDescriptors(self.include_hidden)
         algorithm_names = []
         data = {}
         for descriptor in descriptors:
diff --git a/qt/python/mantidqt/widgets/algorithmselector/presenter.py b/qt/python/mantidqt/widgets/algorithmselector/presenter.py
index c05ebeb171e4465717f9b9d21ff756a2af14fc65..e62bc37f326a2e80fa1437501c0df38733f1012b 100644
--- a/qt/python/mantidqt/widgets/algorithmselector/presenter.py
+++ b/qt/python/mantidqt/widgets/algorithmselector/presenter.py
@@ -33,6 +33,9 @@ class IAlgorithmSelectorView(object):
     def populate_ui(self, data):
         raise NotImplementedError('Method has to be implemented in a subclass')
 
+    def refresh(self):
+        raise NotImplementedError('Method has to be implemented in a subclass')
+
     def get_selected_algorithm(self):
         raise NotImplementedError('Method has to be implemented in a subclass')
 
@@ -50,5 +53,8 @@ class AlgorithmSelectorPresenter(object):
     def __init__(self, view, include_hidden):
         self.view = view
         self.model = AlgorithmSelectorModel(self, include_hidden)
+        self.refresh()
+
+    def refresh(self):
         algorithm_data = self.model.get_algorithm_data()
         self.view.populate_ui(algorithm_data)
diff --git a/qt/python/mantidqt/widgets/algorithmselector/test/test_algorithmselector.py b/qt/python/mantidqt/widgets/algorithmselector/test/test_algorithmselector.py
index fb2d7cc8f0cfc9956ed2a58e8793868ff1b581b8..47015e452e176484a967117c71df0a8593b1a695 100644
--- a/qt/python/mantidqt/widgets/algorithmselector/test/test_algorithmselector.py
+++ b/qt/python/mantidqt/widgets/algorithmselector/test/test_algorithmselector.py
@@ -18,40 +18,31 @@ import unittest
 from qtpy.QtCore import Qt
 from qtpy.QtTest import QTest
 
+from mantid.api import AlgorithmFactoryImpl
 from mantidqt.utils.qt.test import select_item_in_combo_box, select_item_in_tree, GuiTest
 from mantidqt.widgets.algorithmselector.model import AlgorithmSelectorModel
 from mantidqt.widgets.algorithmselector.widget import AlgorithmSelectorWidget
 
 AlgorithmDescriptorMock = namedtuple('AlgorithmDescriptorMock', ['name', 'alias', 'category', 'version'])
 mock_get_algorithm_descriptors = Mock()
-mock_get_algorithm_descriptors.return_value = [AlgorithmDescriptorMock(name='Rebin', version=1,
-                                                                       category='Transform', alias=''),
-                                               AlgorithmDescriptorMock(name='Rebin', version=1,
-                                                                       category='Transform\\Rebin', alias=''),
-                                               AlgorithmDescriptorMock(name='Load', version=1,
-                                                                       category='Data', alias=''),
-                                               AlgorithmDescriptorMock(name='DoStuff', version=1,
-                                                                       category='Stuff', alias=''),
-                                               AlgorithmDescriptorMock(name='DoStuff', version=2,
-                                                                       category='Stuff', alias=''),
-                                               ]
-
-
-class AlgorithmFactoryTest(unittest.TestCase):
-
-    def test_getDescriptors(self):
-        from mantid import AlgorithmFactory
-        descriptors = AlgorithmFactory.getDescriptors(True)
-        self.assertGreater(len(descriptors), 0)
-        d = descriptors[0]
-        self.assertFalse(isinstance(d, AlgorithmDescriptorMock))
-        self.assertTrue(hasattr(d, 'name'))
-        self.assertTrue(hasattr(d, 'alias'))
-        self.assertTrue(hasattr(d, 'category'))
-        self.assertTrue(hasattr(d, 'version'))
-
-
-@patch('mantid.AlgorithmFactory.getDescriptors', mock_get_algorithm_descriptors)
+mock_get_algorithm_descriptors.return_value = [
+    AlgorithmDescriptorMock(name='Rebin', version=1,
+                            category='Transform', alias=''),
+    AlgorithmDescriptorMock(name='Rebin', version=1,
+                            category='Transform\\Rebin', alias=''),
+    AlgorithmDescriptorMock(name='Load', version=1,
+                            category='Data', alias=''),
+    AlgorithmDescriptorMock(name='DoStuff', version=1,
+                            category='Stuff', alias=''),
+    AlgorithmDescriptorMock(name='DoStuff', version=2,
+                            category='Stuff', alias=''),
+]
+
+empty_mock_get_algorithm_descriptors = Mock()
+empty_mock_get_algorithm_descriptors.return_value = []
+
+
+@patch.object(AlgorithmFactoryImpl, 'getDescriptors', mock_get_algorithm_descriptors)
 class ModelTest(unittest.TestCase):
 
     def test_get_algorithm_data(self):
@@ -74,9 +65,16 @@ class ModelTest(unittest.TestCase):
         self.assertEqual(mock_get_algorithm_descriptors.mock_calls[-1], call(True))
 
 
-@patch('mantid.AlgorithmFactory.getDescriptors', mock_get_algorithm_descriptors)
+@patch.object(AlgorithmFactoryImpl, 'getDescriptors', mock_get_algorithm_descriptors)
 class WidgetTest(GuiTest):
 
+    # def setUp(self):
+    #     self.getDescriptors_orig = AlgorithmFactoryImpl.getDescriptors
+    #     AlgorithmFactoryImpl.getDescriptors = mock_get_algorithm_descriptors
+    #
+    # def tearDown(self):
+    #     AlgorithmFactoryImpl.getDescriptors = self.getDescriptors_orig
+
     def _select_in_tree(self, widget, item_label):
         select_item_in_tree(widget.tree, item_label)
 
@@ -120,7 +118,7 @@ class WidgetTest(GuiTest):
                           "and the default Qt behaviour is used")
         else:
             widget = AlgorithmSelectorWidget()
-            self.assertEquals(widget.search_box.completer().filterMode(), Qt.MatchContains)
+            self.assertEqual(widget.search_box.completer().filterMode(), Qt.MatchContains)
 
     def test_search_box_selection_ignores_tree_selection(self):
         widget = AlgorithmSelectorWidget()
@@ -159,6 +157,18 @@ class WidgetTest(GuiTest):
             QTest.keyClick(widget.search_box, Qt.Key_Return)
             createDialog.assert_called_once_with('DoStuff', 2)
 
+    def test_refresh(self):
+        # Set a mock to return an empty descriptor list
+        getDescriptors_orig = AlgorithmFactoryImpl.getDescriptors
+        AlgorithmFactoryImpl.getDescriptors = empty_mock_get_algorithm_descriptors
+
+        widget = AlgorithmSelectorWidget()
+        self.assertEqual(0, widget.tree.topLevelItemCount())
+        # put back the original
+        AlgorithmFactoryImpl.getDescriptors = getDescriptors_orig
+        widget.refresh()
+        self.assertEqual(3, widget.tree.topLevelItemCount())
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/qt/python/mantidqt/widgets/algorithmselector/widget.py b/qt/python/mantidqt/widgets/algorithmselector/widget.py
index 45276cce822da00a5d9a7b1751670f1988f13009..05106b177edb8fac47f0bd4f0f9d155799d9c08f 100644
--- a/qt/python/mantidqt/widgets/algorithmselector/widget.py
+++ b/qt/python/mantidqt/widgets/algorithmselector/widget.py
@@ -54,6 +54,10 @@ class AlgorithmSelectorWidget(IAlgorithmSelectorView, QWidget):
         QWidget.__init__(self, parent)
         IAlgorithmSelectorView.__init__(self, include_hidden)
 
+    def refresh(self):
+        """Update the algorithms list"""
+        self.presenter.refresh()
+
     def _make_execute_button(self):
         """
         Make the button that starts the algorithm.
diff --git a/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp b/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp
index d8377bdc3564a761775445b3c195f072e27319a5..dd7e68e2f9bf7a09f8104b53f0ec7348c5dcc526 100644
--- a/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp
@@ -159,10 +159,10 @@ void QtReflSettingsView::registerExperimentSettingsWidgets(
   registerSettingWidget(*m_ui.startOverlapEdit, "StartOverlap", alg);
   registerSettingWidget(*m_ui.endOverlapEdit, "EndOverlap", alg);
   registerSettingWidget(*m_ui.polCorrComboBox, "PolarizationAnalysis", alg);
-  registerSettingWidget(*m_ui.CRhoEdit, "Rho", alg);
-  registerSettingWidget(*m_ui.CAlphaEdit, "Alpha", alg);
-  registerSettingWidget(*m_ui.CApEdit, "Ap", alg);
-  registerSettingWidget(*m_ui.CPpEdit, "Pp", alg);
+  registerSettingWidget(*m_ui.CRhoEdit, "CRho", alg);
+  registerSettingWidget(*m_ui.CAlphaEdit, "CAlpha", alg);
+  registerSettingWidget(*m_ui.CApEdit, "CAp", alg);
+  registerSettingWidget(*m_ui.CPpEdit, "CPp", alg);
   registerSettingWidget(stitchOptionsLineEdit(), "Params", alg);
 }
 
diff --git a/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp b/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp
index 06425ad01c06082b5d02f34db295111192a5cce0..61c7b89f5428dac6eb261ac63c6415c17964651f 100644
--- a/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp
@@ -231,13 +231,13 @@ OptionsQMap ReflSettingsPresenter::getReductionOptions() const {
     auto const pa = m_view->getPolarisationCorrections();
     addIfNotEmpty(options, "PolarizationAnalysis", pa);
     if (pa == "PA") {
-      addIfNotEmpty(options, "Rho", m_view->getCRho());
-      addIfNotEmpty(options, "Alpha", m_view->getCAlpha());
-      addIfNotEmpty(options, "Ap", m_view->getCAp());
-      addIfNotEmpty(options, "Pp", m_view->getCPp());
+      addIfNotEmpty(options, "CRho", m_view->getCRho());
+      addIfNotEmpty(options, "CAlpha", m_view->getCAlpha());
+      addIfNotEmpty(options, "CAp", m_view->getCAp());
+      addIfNotEmpty(options, "CPp", m_view->getCPp());
     } else if (pa == "PNR") {
-      addIfNotEmpty(options, "Ap", m_view->getCAp());
-      addIfNotEmpty(options, "Pp", m_view->getCPp());
+      addIfNotEmpty(options, "CAp", m_view->getCAp());
+      addIfNotEmpty(options, "CPp", m_view->getCPp());
     }
     addIfNotEmpty(options, "StartOverlap", m_view->getStartOverlap());
     addIfNotEmpty(options, "EndOverlap", m_view->getEndOverlap());
diff --git a/qt/scientific_interfaces/Indirect/CMakeLists.txt b/qt/scientific_interfaces/Indirect/CMakeLists.txt
index a1ca49ee8acdb5b85cad5d3533376f183d8f4d55..f3319726973fef3bf1a82681c244275ec6742406 100644
--- a/qt/scientific_interfaces/Indirect/CMakeLists.txt
+++ b/qt/scientific_interfaces/Indirect/CMakeLists.txt
@@ -67,7 +67,7 @@ set ( SRC_FILES
 # Include files aren't required, but this makes them appear in Visual Studio
 # IMPORTANT: Include files are required in the MOC_FILES set. Scroll down to find it.
 set ( INC_FILES
-    DllConfig.h
+	DllConfig.h
 	AbsorptionCorrections.h
 	ApplyAbsorptionCorrections.h
 	CalculatePaalmanPings.h
@@ -81,6 +81,7 @@ set ( INC_FILES
 	DensityOfStates.h
 	Elwin.h
 	IAddWorkspaceDialog.h
+	IIndirectFitPlotView.h
 	ILLEnergyTransfer.h
 	ISISCalibration.h
 	ISISDiagnostics.h
@@ -147,6 +148,7 @@ set ( MOC_FILES
     CorrectionsTab.h
     DensityOfStates.h
     Elwin.h
+    IIndirectFitPlotView.h
     ILLEnergyTransfer.h
     IndirectAddWorkspaceDialog.h
     IndirectBayes.h
diff --git a/qt/scientific_interfaces/Indirect/IIndirectFitPlotView.h b/qt/scientific_interfaces/Indirect/IIndirectFitPlotView.h
new file mode 100644
index 0000000000000000000000000000000000000000..06c0ed9e70b17100cab7830098f8a8d56251b8c1
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/IIndirectFitPlotView.h
@@ -0,0 +1,103 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTIDQTCUSTOMINTERFACESIDA_IINDIRECTFITPLOTVIEW_H_
+#define MANTIDQTCUSTOMINTERFACESIDA_IINDIRECTFITPLOTVIEW_H_
+
+#include "DllConfig.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidQtWidgets/Common/MantidWidget.h"
+
+#include <QObject>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+namespace IDA {
+
+class MANTIDQT_INDIRECT_DLL IIndirectFitPlotView : public API::MantidWidget {
+  Q_OBJECT
+
+public:
+  IIndirectFitPlotView(QWidget *parent = nullptr) : API::MantidWidget(parent){};
+  virtual ~IIndirectFitPlotView(){};
+
+  virtual std::size_t getSelectedSpectrum() const = 0;
+  virtual int getSelectedSpectrumIndex() const = 0;
+  virtual int getSelectedDataIndex() const = 0;
+  virtual std::size_t dataSelectionSize() const = 0;
+  virtual bool isPlotGuessChecked() const = 0;
+
+  virtual void hideMultipleDataSelection() = 0;
+  virtual void showMultipleDataSelection() = 0;
+
+  virtual void setAvailableSpectra(std::size_t minimum,
+                                   std::size_t maximum) = 0;
+  virtual void
+  setAvailableSpectra(const std::vector<std::size_t>::const_iterator &from,
+                      const std::vector<std::size_t>::const_iterator &to) = 0;
+
+  virtual void setMinimumSpectrum(int minimum) = 0;
+  virtual void setMaximumSpectrum(int maximum) = 0;
+  virtual void setPlotSpectrum(int spectrum) = 0;
+  virtual void appendToDataSelection(const std::string &dataName) = 0;
+  virtual void setNameInDataSelection(const std::string &dataName,
+                                      std::size_t index) = 0;
+  virtual void clearDataSelection() = 0;
+
+  virtual void plotInTopPreview(const QString &name,
+                                Mantid::API::MatrixWorkspace_sptr workspace,
+                                std::size_t spectrum,
+                                Qt::GlobalColor colour) = 0;
+  virtual void plotInBottomPreview(const QString &name,
+                                   Mantid::API::MatrixWorkspace_sptr workspace,
+                                   std::size_t spectrum,
+                                   Qt::GlobalColor colour) = 0;
+
+  virtual void removeFromTopPreview(const QString &name) = 0;
+  virtual void removeFromBottomPreview(const QString &name) = 0;
+
+  virtual void enableFitSingleSpectrum(bool enable) = 0;
+  virtual void enablePlotGuess(bool enable) = 0;
+  virtual void enableSpectrumSelection(bool enable) = 0;
+  virtual void enableFitRangeSelection(bool enable) = 0;
+
+  virtual void setBackgroundLevel(double value) = 0;
+
+  virtual void setFitRange(double minimum, double maximum) = 0;
+  virtual void setFitRangeMinimum(double minimum) = 0;
+  virtual void setFitRangeMaximum(double maximum) = 0;
+
+  virtual void setBackgroundRangeVisible(bool visible) = 0;
+  virtual void setHWHMRangeVisible(bool visible) = 0;
+
+  virtual void displayMessage(const std::string &message) const = 0;
+
+public slots:
+  virtual void clearTopPreview() = 0;
+  virtual void clearBottomPreview() = 0;
+  virtual void clear() = 0;
+  virtual void setHWHMRange(double minimum, double maximum) = 0;
+  virtual void setHWHMMaximum(double minimum) = 0;
+  virtual void setHWHMMinimum(double maximum) = 0;
+
+signals:
+  void selectedFitDataChanged(std::size_t);
+  void plotCurrentPreview();
+  void plotSpectrumChanged(std::size_t);
+  void plotGuessChanged(bool);
+  void fitSelectedSpectrum();
+  void startXChanged(double);
+  void endXChanged(double);
+  void hwhmMinimumChanged(double);
+  void hwhmMaximumChanged(double);
+  void hwhmChanged(double, double);
+  void backgroundChanged(double);
+};
+} // namespace IDA
+} // namespace CustomInterfaces
+} // namespace MantidQt
+
+#endif
\ No newline at end of file
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.cpp b/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.cpp
index acd7e0644c72ac6d48d3620587910e660dcb9041..5ee5ceed39d37b3099e9b939d9a3e52a51d8dc92 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.cpp
@@ -264,7 +264,7 @@ void IndirectFitAnalysisTab::setFitDataPresenter(
   m_dataPresenter = std::move(presenter);
 }
 
-void IndirectFitAnalysisTab::setPlotView(IndirectFitPlotView *view) {
+void IndirectFitAnalysisTab::setPlotView(IIndirectFitPlotView *view) {
   m_plotPresenter = Mantid::Kernel::make_unique<IndirectFitPlotPresenter>(
       m_fittingModel.get(), view);
 }
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.h b/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.h
index 0c3d71b7d6259e2d6fc56091dfb0f80a34efb631..11ea2ce31dfbea9268892eced68d85647622bbf9 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.h
+++ b/qt/scientific_interfaces/Indirect/IndirectFitAnalysisTab.h
@@ -36,7 +36,7 @@ public:
                          QWidget *parent = nullptr);
 
   void setFitDataPresenter(std::unique_ptr<IndirectFitDataPresenter> presenter);
-  void setPlotView(IndirectFitPlotView *view);
+  void setPlotView(IIndirectFitPlotView *view);
   void setSpectrumSelectionView(IndirectSpectrumSelectionView *view);
   void
   setFitPropertyBrowser(MantidWidgets::IndirectFitPropertyBrowser *browser);
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPlotModel.cpp b/qt/scientific_interfaces/Indirect/IndirectFitPlotModel.cpp
index 634c668f12269b0bd42eec48997c7fffe22e2e0a..e2773c4d051b7a9f6eab09f83c9e59b66eed4aef 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitPlotModel.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectFitPlotModel.cpp
@@ -194,8 +194,9 @@ std::string IndirectFitPlotModel::getFitDataName() const {
 }
 
 std::string IndirectFitPlotModel::getLastFitDataName() const {
-  if (m_fittingModel->numberOfWorkspaces())
-    return getFitDataName(m_fittingModel->numberOfWorkspaces() - 1);
+  auto const numberOfWorkspaces = m_fittingModel->numberOfWorkspaces();
+  if (numberOfWorkspaces > 0)
+    return getFitDataName(numberOfWorkspaces - 1);
   return "";
 }
 
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.cpp b/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.cpp
index 2593a40942d8d5a14e10cdd57661546dfb113a55..4831660c1c3cc193b1180e6b285744bd5f372203 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.cpp
@@ -10,7 +10,7 @@
 
 namespace {
 using MantidQt::CustomInterfaces::IDA::DiscontinuousSpectra;
-using MantidQt::CustomInterfaces::IDA::IndirectFitPlotView;
+using MantidQt::CustomInterfaces::IDA::IIndirectFitPlotView;
 
 std::string createPlotString(const std::string &workspaceName,
                              const std::string &spectra) {
@@ -26,7 +26,7 @@ std::string createPlotString(const std::string &workspaceName,
 
 struct UpdateAvailableSpectra : public boost::static_visitor<> {
 public:
-  explicit UpdateAvailableSpectra(IndirectFitPlotView *view) : m_view(view) {}
+  explicit UpdateAvailableSpectra(IIndirectFitPlotView *view) : m_view(view) {}
 
   void operator()(const std::pair<std::size_t, std::size_t> &spectra) {
     m_view->setAvailableSpectra(spectra.first, spectra.second);
@@ -37,7 +37,7 @@ public:
   }
 
 private:
-  IndirectFitPlotView *m_view;
+  IIndirectFitPlotView *m_view;
 };
 } // namespace
 
@@ -48,7 +48,7 @@ namespace IDA {
 using namespace Mantid::API;
 
 IndirectFitPlotPresenter::IndirectFitPlotPresenter(IndirectFittingModel *model,
-                                                   IndirectFitPlotView *view)
+                                                   IIndirectFitPlotView *view)
     : m_model(new IndirectFitPlotModel(model)), m_view(view),
       m_plotGuessInSeparateWindow(false) {
   connect(m_view, SIGNAL(selectedFitDataChanged(std::size_t)), this,
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.h b/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.h
index 931060398b72a392c22165d22415da1d1754edde..85a6440fc2f5031d05f3646db3f61d4af8ae008c 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.h
+++ b/qt/scientific_interfaces/Indirect/IndirectFitPlotPresenter.h
@@ -7,20 +7,22 @@
 #ifndef MANTIDQTCUSTOMINTERFACESIDA_INDIRECTFITPLOTPRESENTER_H_
 #define MANTIDQTCUSTOMINTERFACESIDA_INDIRECTFITPLOTPRESENTER_H_
 
+#include "DllConfig.h"
+
 #include "IndirectFitPlotModel.h"
 
-#include "IndirectFitPlotView.h"
+#include "IIndirectFitPlotView.h"
 #include "LazyAsyncRunner.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
 namespace IDA {
 
-class DLLExport IndirectFitPlotPresenter : public QObject {
+class MANTIDQT_INDIRECT_DLL IndirectFitPlotPresenter : public QObject {
   Q_OBJECT
 public:
   IndirectFitPlotPresenter(IndirectFittingModel *model,
-                           IndirectFitPlotView *view);
+                           IIndirectFitPlotView *view);
 
   std::size_t getSelectedDataIndex() const;
   std::size_t getSelectedSpectrum() const;
@@ -96,7 +98,7 @@ private:
   std::string getPlotString(std::size_t spectrum) const;
 
   std::unique_ptr<IndirectFitPlotModel> m_model;
-  IndirectFitPlotView *m_view;
+  IIndirectFitPlotView *m_view;
 
   bool m_plotGuessInSeparateWindow;
   MantidQt::API::PythonRunner m_pythonRunner;
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPlotView.cpp b/qt/scientific_interfaces/Indirect/IndirectFitPlotView.cpp
index d7ca039c2e60b4d4abf8ca505d6adbe6753a0a76..c8fc513b388d6f25d24066a7a94704b13dd714e2 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitPlotView.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectFitPlotView.cpp
@@ -17,7 +17,7 @@ namespace CustomInterfaces {
 namespace IDA {
 
 IndirectFitPlotView::IndirectFitPlotView(QWidget *parent)
-    : API::MantidWidget(parent), m_plotForm(new Ui::IndirectFitPreviewPlot) {
+    : IIndirectFitPlotView(parent), m_plotForm(new Ui::IndirectFitPreviewPlot) {
   m_plotForm->setupUi(this);
 
   connect(m_plotForm->cbDataSelection, SIGNAL(currentIndexChanged(int)), this,
diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPlotView.h b/qt/scientific_interfaces/Indirect/IndirectFitPlotView.h
index 3e4311c4a07c9b35b4829671cf39e1591cf21047..ec73575f7927837563f71c941c11c98fe54634fa 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFitPlotView.h
+++ b/qt/scientific_interfaces/Indirect/IndirectFitPlotView.h
@@ -9,86 +9,79 @@
 
 #include "ui_IndirectFitPreviewPlot.h"
 
+#include "DllConfig.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
+#include "IIndirectFitPlotView.h"
+
 #include "MantidQtWidgets/Common/MantidWidget.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
 namespace IDA {
 
-class DLLExport IndirectFitPlotView : public API::MantidWidget {
+class MANTIDQT_INDIRECT_DLL IndirectFitPlotView : public IIndirectFitPlotView {
   Q_OBJECT
 public:
-  IndirectFitPlotView(QWidget *parent);
-  ~IndirectFitPlotView() override;
-
-  std::size_t getSelectedSpectrum() const;
-  int getSelectedSpectrumIndex() const;
-  int getSelectedDataIndex() const;
-  std::size_t dataSelectionSize() const;
-  bool isPlotGuessChecked() const;
-
-  void hideMultipleDataSelection();
-  void showMultipleDataSelection();
-
-  void setAvailableSpectra(std::size_t minimum, std::size_t maximum);
-  void setAvailableSpectra(const std::vector<std::size_t>::const_iterator &from,
-                           const std::vector<std::size_t>::const_iterator &to);
-
-  void setMinimumSpectrum(int minimum);
-  void setMaximumSpectrum(int maximum);
-  void setPlotSpectrum(int spectrum);
-  void appendToDataSelection(const std::string &dataName);
-  void setNameInDataSelection(const std::string &dataName, std::size_t index);
-  void clearDataSelection();
+  IndirectFitPlotView(QWidget *parent = nullptr);
+  virtual ~IndirectFitPlotView() override;
+
+  std::size_t getSelectedSpectrum() const override;
+  int getSelectedSpectrumIndex() const override;
+  int getSelectedDataIndex() const override;
+  std::size_t dataSelectionSize() const override;
+  bool isPlotGuessChecked() const override;
+
+  void hideMultipleDataSelection() override;
+  void showMultipleDataSelection() override;
+
+  void setAvailableSpectra(std::size_t minimum, std::size_t maximum) override;
+  void setAvailableSpectra(
+      const std::vector<std::size_t>::const_iterator &from,
+      const std::vector<std::size_t>::const_iterator &to) override;
+
+  void setMinimumSpectrum(int minimum) override;
+  void setMaximumSpectrum(int maximum) override;
+  void setPlotSpectrum(int spectrum) override;
+  void appendToDataSelection(const std::string &dataName) override;
+  void setNameInDataSelection(const std::string &dataName,
+                              std::size_t index) override;
+  void clearDataSelection() override;
 
   void plotInTopPreview(const QString &name,
                         Mantid::API::MatrixWorkspace_sptr workspace,
-                        std::size_t spectrum, Qt::GlobalColor colour);
+                        std::size_t spectrum, Qt::GlobalColor colour) override;
   void plotInBottomPreview(const QString &name,
                            Mantid::API::MatrixWorkspace_sptr workspace,
-                           std::size_t spectrum, Qt::GlobalColor colour);
+                           std::size_t spectrum,
+                           Qt::GlobalColor colour) override;
 
-  void removeFromTopPreview(const QString &name);
-  void removeFromBottomPreview(const QString &name);
+  void removeFromTopPreview(const QString &name) override;
+  void removeFromBottomPreview(const QString &name) override;
 
-  void enableFitSingleSpectrum(bool enable);
-  void enablePlotGuess(bool enable);
-  void enableSpectrumSelection(bool enable);
-  void enableFitRangeSelection(bool enable);
+  void enableFitSingleSpectrum(bool enable) override;
+  void enablePlotGuess(bool enable) override;
+  void enableSpectrumSelection(bool enable) override;
+  void enableFitRangeSelection(bool enable) override;
 
-  void setBackgroundLevel(double value);
+  void setBackgroundLevel(double value) override;
 
-  void setFitRange(double minimum, double maximum);
-  void setFitRangeMinimum(double minimum);
-  void setFitRangeMaximum(double maximum);
+  void setFitRange(double minimum, double maximum) override;
+  void setFitRangeMinimum(double minimum) override;
+  void setFitRangeMaximum(double maximum) override;
 
-  void setBackgroundRangeVisible(bool visible);
-  void setHWHMRangeVisible(bool visible);
+  void setBackgroundRangeVisible(bool visible) override;
+  void setHWHMRangeVisible(bool visible) override;
 
-  void displayMessage(const std::string &message) const;
+  void displayMessage(const std::string &message) const override;
 
 public slots:
-  void clearTopPreview();
-  void clearBottomPreview();
-  void clear();
-  void setHWHMRange(double minimum, double maximum);
-  void setHWHMMaximum(double minimum);
-  void setHWHMMinimum(double maximum);
-
-signals:
-  void selectedFitDataChanged(std::size_t);
-  void plotCurrentPreview();
-  void plotSpectrumChanged(std::size_t);
-  void plotGuessChanged(bool);
-  void fitSelectedSpectrum();
-  void startXChanged(double);
-  void endXChanged(double);
-  void hwhmMinimumChanged(double);
-  void hwhmMaximumChanged(double);
-  void hwhmChanged(double, double);
-  void backgroundChanged(double);
+  void clearTopPreview() override;
+  void clearBottomPreview() override;
+  void clear() override;
+  void setHWHMRange(double minimum, double maximum) override;
+  void setHWHMMaximum(double minimum) override;
+  void setHWHMMinimum(double maximum) override;
 
 private slots:
   void emitPlotSpectrumChanged(int);
diff --git a/qt/scientific_interfaces/Indirect/IndirectFittingModel.h b/qt/scientific_interfaces/Indirect/IndirectFittingModel.h
index c9879f49bf2f11bf1e79d12cf0546fc1902a9470..f0c9f168409215fc61e7b8e684834e7a6ac495c5 100644
--- a/qt/scientific_interfaces/Indirect/IndirectFittingModel.h
+++ b/qt/scientific_interfaces/Indirect/IndirectFittingModel.h
@@ -47,15 +47,16 @@ public:
   IndirectFittingModel();
   virtual ~IndirectFittingModel() = default;
 
-  Mantid::API::MatrixWorkspace_sptr getWorkspace(std::size_t index) const;
+  virtual Mantid::API::MatrixWorkspace_sptr
+  getWorkspace(std::size_t index) const;
   Spectra getSpectra(std::size_t index) const;
-  std::pair<double, double> getFittingRange(std::size_t dataIndex,
-                                            std::size_t spectrum) const;
+  virtual std::pair<double, double> getFittingRange(std::size_t dataIndex,
+                                                    std::size_t spectrum) const;
   virtual std::string getExcludeRegion(std::size_t dataIndex,
                                        std::size_t index) const;
-  std::string createDisplayName(const std::string &formatString,
-                                const std::string &rangeDelimiter,
-                                std::size_t dataIndex) const;
+  virtual std::string createDisplayName(const std::string &formatString,
+                                        const std::string &rangeDelimiter,
+                                        std::size_t dataIndex) const;
   std::string createOutputName(const std::string &formatString,
                                const std::string &rangeDelimiter,
                                std::size_t dataIndex) const;
@@ -63,7 +64,7 @@ public:
   bool isPreviouslyFit(std::size_t dataIndex, std::size_t spectrum) const;
   bool hasZeroSpectra(std::size_t dataIndex) const;
   virtual boost::optional<std::string> isInvalidFunction() const;
-  std::size_t numberOfWorkspaces() const;
+  virtual std::size_t numberOfWorkspaces() const;
   std::size_t getNumberOfSpectra(std::size_t index) const;
   std::vector<std::string> getFitParameterNames() const;
   virtual Mantid::API::IFunction_sptr getFittingFunction() const;
@@ -74,8 +75,10 @@ public:
   void setSpectra(const std::string &spectra, std::size_t dataIndex);
   void setSpectra(Spectra &&spectra, std::size_t dataIndex);
   void setSpectra(const Spectra &spectra, std::size_t dataIndex);
-  void setStartX(double startX, std::size_t dataIndex, std::size_t spectrum);
-  void setEndX(double endX, std::size_t dataIndex, std::size_t spectrum);
+  virtual void setStartX(double startX, std::size_t dataIndex,
+                         std::size_t spectrum);
+  virtual void setEndX(double endX, std::size_t dataIndex,
+                       std::size_t spectrum);
   void setExcludeRegion(const std::string &exclude, std::size_t dataIndex,
                         std::size_t spectrum);
 
@@ -89,8 +92,8 @@ public:
   PrivateFittingData clearWorkspaces();
   void setFittingMode(FittingMode mode);
   virtual void setFitFunction(Mantid::API::IFunction_sptr function);
-  void setDefaultParameterValue(const std::string &name, double value,
-                                std::size_t dataIndex);
+  virtual void setDefaultParameterValue(const std::string &name, double value,
+                                        std::size_t dataIndex);
   void addSingleFitOutput(Mantid::API::IAlgorithm_sptr fitAlgorithm,
                           std::size_t index);
   virtual void addOutput(Mantid::API::IAlgorithm_sptr fitAlgorithm);
diff --git a/qt/scientific_interfaces/Indirect/LazyAsyncRunner.h b/qt/scientific_interfaces/Indirect/LazyAsyncRunner.h
index ecfada107f88293ec69a4ddc0b9cd6df90705c58..567bbb06fc11265a5c01697286ce4e7e9aa26216 100644
--- a/qt/scientific_interfaces/Indirect/LazyAsyncRunner.h
+++ b/qt/scientific_interfaces/Indirect/LazyAsyncRunner.h
@@ -20,7 +20,7 @@ namespace MantidQt {
 namespace CustomInterfaces {
 namespace IDA {
 
-class DLLExport QtLazyAsyncRunnerBase : public QObject {
+class MANTIDQT_INDIRECT_DLL QtLazyAsyncRunnerBase : public QObject {
   Q_OBJECT
 
 signals:
@@ -35,7 +35,7 @@ protected:
 };
 
 template <typename Callback>
-class DLLExport QtLazyAsyncRunner : public QtLazyAsyncRunnerBase {
+class MANTIDQT_INDIRECT_DLL QtLazyAsyncRunner : public QtLazyAsyncRunnerBase {
 public:
   using ReturnType = typename std::result_of<Callback()>::type;
 
diff --git a/qt/scientific_interfaces/Indirect/test/CMakeLists.txt b/qt/scientific_interfaces/Indirect/test/CMakeLists.txt
index 53d64ce7ee128d5518d72c3f7b4f156bd1c18e24..c402c6ca2c551c8e65cf191d18256e192ea6dcf3 100644
--- a/qt/scientific_interfaces/Indirect/test/CMakeLists.txt
+++ b/qt/scientific_interfaces/Indirect/test/CMakeLists.txt
@@ -5,6 +5,7 @@ set ( TEST_FILES
   IndirectFitDataTest.h
   IndirectFitOutputTest.h
   IndirectFitPlotModelTest.h
+  IndirectFitPlotPresenterTest.h
   IndirectFittingModelTest.h
   IndirectSpectrumSelectionPresenterTest.h
 )
@@ -37,6 +38,7 @@ mtd_add_qt_tests (TARGET_NAME MantidQtInterfacesIndirectTest
   MTD_QT_LINK_LIBS
     MantidScientificInterfacesIndirect
     MantidQtWidgetsCommon
+    MantidQtWidgetsLegacyQwt
   PARENT_DEPENDENCIES
     GUITests
 )
diff --git a/qt/scientific_interfaces/Indirect/test/IndirectFitPlotPresenterTest.h b/qt/scientific_interfaces/Indirect/test/IndirectFitPlotPresenterTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..74b425440fa32d82f4f00c2df5cd9164f9b095c4
--- /dev/null
+++ b/qt/scientific_interfaces/Indirect/test/IndirectFitPlotPresenterTest.h
@@ -0,0 +1,636 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTIDQT_INDIRECTFITPLOTPRESENTERTEST_H_
+#define MANTIDQT_INDIRECTFITPLOTPRESENTERTEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include <gmock/gmock.h>
+
+#include "IIndirectFitPlotView.h"
+#include "IndirectFitPlotPresenter.h"
+#include "IndirectFittingModel.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IFunction.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidKernel/WarningSuppressions.h"
+#include "MantidTestHelpers/IndirectFitDataCreationHelper.h"
+
+using namespace Mantid::API;
+using namespace Mantid::IndirectFitDataCreationHelper;
+using namespace MantidQt::CustomInterfaces;
+using namespace MantidQt::CustomInterfaces::IDA;
+using namespace testing;
+
+namespace {
+
+IFunction_sptr getFunction(std::string const &functionString) {
+  return FunctionFactory::Instance().createInitialized(functionString);
+}
+
+IFunction_sptr getFunctionWithWorkspaceName(std::string const &workspaceName) {
+  std::string const functionString =
+      "name=LinearBackground,A0=0,A1=0,ties=(A0=0.000000,A1=0.0);"
+      "(composite=Convolution,FixResolution=true,NumDeriv=true;"
+      "name=Resolution,Workspace=" +
+      workspaceName +
+      ",WorkspaceIndex=0;((composite=ProductFunction,NumDeriv="
+      "false;name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0."
+      "0175)))";
+  return getFunction(functionString);
+}
+
+} // namespace
+
+GNU_DIAG_OFF_SUGGEST_OVERRIDE
+
+/// Mock object to mock the view
+class MockIndirectFitPlotView : public IIndirectFitPlotView {
+public:
+  /// Signals
+  void emitSelectedFitDataChanged(std::size_t index) {
+    emit selectedFitDataChanged(index);
+  }
+
+  void emitPlotCurrentPreview() { emit plotCurrentPreview(); }
+
+  void emitPlotSpectrumChanged(std::size_t spectrum) {
+    emit plotSpectrumChanged(spectrum);
+  }
+
+  void emitPlotGuessChanged(bool doPlotGuess) {
+    emit plotGuessChanged(doPlotGuess);
+  }
+
+  void emitStartXChanged(double startX) { emit startXChanged(startX); }
+
+  void emitEndXChanged(double endX) { emit endXChanged(endX); }
+
+  void emitHWHMMinimumChanged(double minimum) {
+    emit hwhmMinimumChanged(minimum);
+  }
+
+  void emitHWHMMaximumChanged(double maximum) {
+    emit hwhmMaximumChanged(maximum);
+  }
+
+  void emitBackgroundChanged(double value) { emit backgroundChanged(value); }
+
+  /// Public methods
+  MOCK_CONST_METHOD0(getSelectedSpectrum, std::size_t());
+  MOCK_CONST_METHOD0(getSelectedSpectrumIndex, int());
+  MOCK_CONST_METHOD0(getSelectedDataIndex, int());
+  MOCK_CONST_METHOD0(dataSelectionSize, std::size_t());
+  MOCK_CONST_METHOD0(isPlotGuessChecked, bool());
+
+  MOCK_METHOD0(hideMultipleDataSelection, void());
+  MOCK_METHOD0(showMultipleDataSelection, void());
+
+  MOCK_METHOD2(setAvailableSpectra,
+               void(std::size_t minimum, std::size_t maximum));
+  MOCK_METHOD2(setAvailableSpectra,
+               void(std::vector<std::size_t>::const_iterator const &from,
+                    std::vector<std::size_t>::const_iterator const &to));
+
+  MOCK_METHOD1(setMinimumSpectrum, void(int minimum));
+  MOCK_METHOD1(setMaximumSpectrum, void(int maximum));
+  MOCK_METHOD1(setPlotSpectrum, void(int spectrum));
+  MOCK_METHOD1(appendToDataSelection, void(std::string const &dataName));
+  MOCK_METHOD2(setNameInDataSelection,
+               void(std::string const &dataName, std::size_t index));
+  MOCK_METHOD0(clearDataSelection, void());
+
+  MOCK_METHOD4(plotInTopPreview,
+               void(QString const &name,
+                    Mantid::API::MatrixWorkspace_sptr workspace,
+                    std::size_t spectrum, Qt::GlobalColor colour));
+  MOCK_METHOD4(plotInBottomPreview,
+               void(QString const &name,
+                    Mantid::API::MatrixWorkspace_sptr workspace,
+                    std::size_t spectrum, Qt::GlobalColor colour));
+
+  MOCK_METHOD1(removeFromTopPreview, void(QString const &name));
+  MOCK_METHOD1(removeFromBottomPreview, void(QString const &name));
+
+  MOCK_METHOD1(enableFitSingleSpectrum, void(bool enable));
+  MOCK_METHOD1(enablePlotGuess, void(bool enable));
+  MOCK_METHOD1(enableSpectrumSelection, void(bool enable));
+  MOCK_METHOD1(enableFitRangeSelection, void(bool enable));
+
+  MOCK_METHOD1(setBackgroundLevel, void(double value));
+
+  MOCK_METHOD2(setFitRange, void(double minimum, double maximum));
+  MOCK_METHOD1(setFitRangeMinimum, void(double minimum));
+  MOCK_METHOD1(setFitRangeMaximum, void(double maximum));
+
+  MOCK_METHOD1(setBackgroundRangeVisible, void(bool visible));
+  MOCK_METHOD1(setHWHMRangeVisible, void(bool visible));
+
+  MOCK_CONST_METHOD1(displayMessage, void(std::string const &message));
+
+  /// Public Slots
+  MOCK_METHOD0(clearTopPreview, void());
+  MOCK_METHOD0(clearBottomPreview, void());
+  MOCK_METHOD0(clear, void());
+
+  MOCK_METHOD2(setHWHMRange, void(double minimum, double maximum));
+  MOCK_METHOD1(setHWHMMinimum, void(double minimum));
+  MOCK_METHOD1(setHWHMMaximum, void(double maximum));
+};
+
+class MockIndirectFittingModel : public IndirectFittingModel {
+public:
+  /// Public methods
+  MOCK_CONST_METHOD1(getWorkspace, MatrixWorkspace_sptr(std::size_t index));
+  MOCK_CONST_METHOD2(getFittingRange,
+                     std::pair<double, double>(std::size_t dataIndex,
+                                               std::size_t spectrum));
+  MOCK_CONST_METHOD3(createDisplayName,
+                     std::string(std::string const &formatString,
+                                 std::string const &rangeDelimiter,
+                                 std::size_t dataIndex));
+  MOCK_CONST_METHOD0(isMultiFit, bool());
+  MOCK_CONST_METHOD0(numberOfWorkspaces, std::size_t());
+  MOCK_CONST_METHOD0(getFittingFunction, IFunction_sptr());
+
+  MOCK_METHOD3(setStartX, void(double startX, std::size_t dataIndex,
+                               std::size_t spectrum));
+  MOCK_METHOD3(setEndX,
+               void(double endX, std::size_t dataIndex, std::size_t spectrum));
+
+  MOCK_METHOD3(setDefaultParameterValue,
+               void(std::string const &name, double value,
+                    std::size_t dataIndex));
+
+private:
+  std::string sequentialFitOutputName() const override { return ""; };
+  std::string simultaneousFitOutputName() const override { return ""; };
+  std::string singleFitOutputName(std::size_t index,
+                                  std::size_t spectrum) const override {
+    UNUSED_ARG(index);
+    UNUSED_ARG(spectrum);
+    return "";
+  };
+
+  std::vector<std::string> getSpectrumDependentAttributes() const override {
+    return {};
+  };
+};
+
+GNU_DIAG_ON_SUGGEST_OVERRIDE
+
+class IndirectFitPlotPresenterTest : public CxxTest::TestSuite {
+public:
+  /// Needed to make sure everything is initialized
+  IndirectFitPlotPresenterTest() { FrameworkManager::Instance(); }
+
+  static IndirectFitPlotPresenterTest *createSuite() {
+    return new IndirectFitPlotPresenterTest();
+  }
+
+  static void destroySuite(IndirectFitPlotPresenterTest *suite) {
+    delete suite;
+  }
+
+  void setUp() override {
+    /// Note that the IndirectFitPlotModel could not be mocked as the Presenter
+    /// takes an IndirectFittingModel. This means the IndirectFittingModel is
+    /// mocked instead - which is a good substitute anyway
+    m_view = std::make_unique<NiceMock<MockIndirectFitPlotView>>();
+    m_fittingModel = std::make_unique<NiceMock<MockIndirectFittingModel>>();
+    m_presenter = std::make_unique<IndirectFitPlotPresenter>(
+        std::move(m_fittingModel.get()), std::move(m_view.get()));
+
+    SetUpADSWithWorkspace m_ads("WorkspaceName", createWorkspace(10));
+    m_fittingModel->addWorkspace("WorkspaceName");
+  }
+
+  void tearDown() override {
+    AnalysisDataService::Instance().clear();
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(m_view.get()));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(m_fittingModel.get()));
+
+    m_presenter.reset();
+    m_fittingModel.reset();
+    m_view.reset();
+  }
+
+  ///----------------------------------------------------------------------
+  /// Unit tests to check for successful presenter instantiation
+  ///----------------------------------------------------------------------
+
+  void test_that_the_model_and_view_have_been_instantiated_correctly() {
+    std::size_t const selectedSpectrum(3);
+
+    ON_CALL(*m_view, getSelectedSpectrum())
+        .WillByDefault(Return(selectedSpectrum));
+    ON_CALL(*m_fittingModel, isMultiFit()).WillByDefault(Return(false));
+
+    EXPECT_CALL(*m_view, getSelectedSpectrum())
+        .Times(1)
+        .WillOnce(Return(selectedSpectrum));
+    EXPECT_CALL(*m_fittingModel, isMultiFit()).Times(1).WillOnce(Return(false));
+
+    m_view->getSelectedSpectrum();
+    m_fittingModel->isMultiFit();
+  }
+
+  void
+  test_that_invoking_a_presenter_method_will_call_the_relevant_methods_in_the_model_and_view() {
+    std::size_t const selectionSize(2);
+
+    ON_CALL(*m_view, dataSelectionSize()).WillByDefault(Return(selectionSize));
+
+    EXPECT_CALL(*m_fittingModel, numberOfWorkspaces())
+        .Times(2)
+        .WillRepeatedly(Return(1));
+    EXPECT_CALL(*m_view, dataSelectionSize())
+        .Times(1)
+        .WillOnce(Return(selectionSize));
+
+    m_presenter->appendLastDataToSelection();
+  }
+
+  ///----------------------------------------------------------------------
+  /// Unit Tests that test the signals (only the view emits signals here)
+  ///----------------------------------------------------------------------
+
+  void test_that_the_selectedFitDataChanged_signal_will_set_the_activeIndex() {
+    m_view->emitSelectedFitDataChanged(1);
+    TS_ASSERT_EQUALS(m_presenter->getSelectedDataIndex(), 1);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_set_the_available_spectra() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    EXPECT_CALL(*m_view, setAvailableSpectra(0, 9)).Times(1);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_disable_selectors_when_there_is_no_workspace() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(nullptr));
+
+    EXPECT_CALL(*m_view, enableSpectrumSelection(false)).Times(1);
+    EXPECT_CALL(*m_view, enableFitRangeSelection(false)).Times(1);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_plot_the_input_when_there_is_only_an_input_workspace() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    EXPECT_CALL(*m_fittingModel, getWorkspace(index)).Times(3);
+    EXPECT_CALL(*m_view, removeFromBottomPreview(QString("Difference")))
+        .Times(1);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_clear_the_plots_when_there_is_no_input_workspace() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(nullptr));
+
+    EXPECT_CALL(*m_fittingModel, getWorkspace(index)).Times(2);
+    EXPECT_CALL(*m_view, clear()).Times(1);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_set_the_minimum_and_maximum_of_the_fit_range() {
+    std::size_t const index(0);
+    auto const range = std::make_pair(1.0, 2.0);
+    ON_CALL(*m_fittingModel, getFittingRange(index, 0))
+        .WillByDefault(Return(range));
+
+    EXPECT_CALL(*m_fittingModel, getFittingRange(index, 0))
+        .Times(2)
+        .WillRepeatedly(Return(range));
+    EXPECT_CALL(*m_view, setFitRangeMinimum(1.0)).Times(2);
+    EXPECT_CALL(*m_view, setFitRangeMaximum(2.0)).Times(2);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_enable_PlotGuess_when_there_is_a_fit_function_and_workspace() {
+    std::size_t const index(0);
+    std::string const workspaceName("WorkspaceName");
+    auto const fitFunction = getFunctionWithWorkspaceName(workspaceName);
+
+    ON_CALL(*m_fittingModel, getFittingFunction())
+        .WillByDefault(Return(fitFunction));
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace(workspaceName)));
+
+    EXPECT_CALL(*m_view, enablePlotGuess(true)).Times(1);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void
+  test_that_the_selectedFitDataChanged_signal_will_disable_the_guess_plot_when_there_is_no_fit_function() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    EXPECT_CALL(*m_view, enablePlotGuess(false)).Times(1);
+
+    m_view->emitSelectedFitDataChanged(index);
+  }
+
+  void test_that_the_plotSpectrumChanged_signal_will_set_the_active_spectrum() {
+    m_view->emitPlotSpectrumChanged(2);
+    TS_ASSERT_EQUALS(m_presenter->getSelectedSpectrum(), 2);
+  }
+
+  void
+  test_that_the_plotSpectrumChanged_signal_will_plot_the_input_when_there_is_only_an_input_workspace() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    EXPECT_CALL(*m_fittingModel, getWorkspace(index)).Times(2);
+    EXPECT_CALL(*m_view, removeFromBottomPreview(QString("Difference")))
+        .Times(1);
+
+    m_view->emitPlotSpectrumChanged(index);
+  }
+
+  void
+  test_that_the_plotSpectrumChanged_signal_will_clear_the_plots_when_there_is_no_input_workspace() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(nullptr));
+
+    EXPECT_CALL(*m_fittingModel, getWorkspace(index)).Times(1);
+    EXPECT_CALL(*m_view, clear()).Times(1);
+
+    m_view->emitPlotSpectrumChanged(index);
+  }
+
+  void
+  test_that_the_plotSpectrumChanged_signal_will_set_the_minimum_and_maximum_of_the_fit_range() {
+    std::size_t const index(0);
+    auto const range = std::make_pair(1.0, 2.0);
+    ON_CALL(*m_fittingModel, getFittingRange(index, 0))
+        .WillByDefault(Return(range));
+
+    EXPECT_CALL(*m_fittingModel, getFittingRange(index, 0))
+        .Times(2)
+        .WillRepeatedly(Return(range));
+    EXPECT_CALL(*m_view, setFitRangeMinimum(1.0)).Times(2);
+    EXPECT_CALL(*m_view, setFitRangeMaximum(2.0)).Times(2);
+
+    m_view->emitPlotSpectrumChanged(index);
+  }
+
+  void
+  test_that_the_plotCurrentPreview_signal_will_display_an_error_message_if_there_is_no_input_workspace() {
+    std::size_t const index(0);
+    std::string const message("Workspace not found - data may not be loaded.");
+
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(nullptr));
+
+    Expectation getWorkspace =
+        EXPECT_CALL(*m_fittingModel, getWorkspace(index)).Times(1);
+    EXPECT_CALL(*m_view, displayMessage(message)).Times(1).After(getWorkspace);
+
+    m_view->emitPlotCurrentPreview();
+  }
+
+  void
+  test_that_the_plotGuessChanged_signal_will_not_clear_the_guess_plot_when_passed_true() {
+    std::size_t const index(0);
+    std::string const workspaceName("WorkspaceName");
+    auto const range = std::make_pair(1.0, 2.0);
+    auto const fitFunction = getFunctionWithWorkspaceName(workspaceName);
+
+    ON_CALL(*m_fittingModel, getFittingRange(index, 0))
+        .WillByDefault(Return(range));
+    ON_CALL(*m_fittingModel, getFittingFunction())
+        .WillByDefault(Return(fitFunction));
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace(workspaceName)));
+
+    EXPECT_CALL(*m_view, removeFromTopPreview(QString("Guess"))).Times(0);
+
+    m_view->emitPlotGuessChanged(true);
+  }
+
+  void
+  test_that_the_plotGuessChanged_signal_will_clear_the_guess_plot_when_passed_false() {
+    std::size_t const index(0);
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    EXPECT_CALL(*m_view, removeFromTopPreview(QString("Guess"))).Times(1);
+
+    m_view->emitPlotGuessChanged(false);
+  }
+
+  void test_that_the_startXChanged_signal_will_set_the_fitting_models_startX() {
+    auto const range = std::make_pair(0.0, 2.0);
+    ON_CALL(*m_fittingModel, getFittingRange(0, 0))
+        .WillByDefault(Return(range));
+
+    EXPECT_CALL(*m_fittingModel, setStartX(1.0, 0, 0)).Times(1);
+
+    m_view->emitStartXChanged(1.0);
+  }
+
+  void test_that_the_endXChanged_signal_will_set_the_fitting_models_endX() {
+    EXPECT_CALL(*m_fittingModel, setEndX(2.0, 0, 0)).Times(1);
+    m_view->emitEndXChanged(2.0);
+  }
+
+  void test_that_the_hwhmMaximumChanged_signal_will_set_the_hwhm_minimum() {
+    EXPECT_CALL(*m_view, setHWHMMinimum(-2.0)).Times(1);
+    m_view->emitHWHMMaximumChanged(2.0);
+  }
+
+  void test_that_the_hwhmMinimumChanged_signal_will_set_the_hwhm_maximum() {
+    EXPECT_CALL(*m_view, setHWHMMaximum(-2.0)).Times(1);
+    m_view->emitHWHMMinimumChanged(2.0);
+  }
+
+  void
+  test_that_the_backgroundChanged_signal_will_set_the_functions_background() {
+    double const background(1.2);
+    auto const fitFunction = getFunctionWithWorkspaceName("WorkspaceName");
+
+    ON_CALL(*m_fittingModel, getFittingFunction())
+        .WillByDefault(Return(fitFunction));
+
+    Expectation setDefault =
+        EXPECT_CALL(*m_fittingModel,
+                    setDefaultParameterValue("A0", background, 0))
+            .Times(1);
+    EXPECT_CALL(*m_fittingModel, getFittingFunction())
+        .Times(1)
+        .After(setDefault);
+
+    m_view->emitBackgroundChanged(background);
+  }
+
+  ///----------------------------------------------------------------------
+  /// Unit Tests that test the methods and slots
+  ///----------------------------------------------------------------------
+
+  void
+  test_that_getSelectedSpectrumIndex_will_get_the_selected_spectrum_from_the_view() {
+    EXPECT_CALL(*m_view, getSelectedSpectrumIndex())
+        .Times(1)
+        .WillOnce(Return(0));
+    m_presenter->getSelectedSpectrumIndex();
+  }
+
+  void
+  test_that_isCurrentlySelected_returns_true_if_the_index_and_spectrum_given_are_selected() {
+    m_view->emitSelectedFitDataChanged(2);
+    TS_ASSERT(m_presenter->isCurrentlySelected(2, 0));
+  }
+
+  void
+  test_that_isCurrentlySelected_returns_false_if_the_index_and_spectrum_given_are_not_selected() {
+    m_view->emitSelectedFitDataChanged(2);
+    TS_ASSERT(!m_presenter->isCurrentlySelected(0, 0));
+  }
+
+  void test_that_setStartX_will_set_the_fit_range_minimum_in_the_view() {
+    EXPECT_CALL(*m_view, setFitRangeMinimum(2.0)).Times(1);
+    m_presenter->setStartX(2.0);
+  }
+
+  void test_that_setEndX_will_set_the_fit_range_maximum_in_the_view() {
+    EXPECT_CALL(*m_view, setFitRangeMaximum(3.0)).Times(1);
+    m_presenter->setEndX(3.0);
+  }
+
+  void
+  test_that_hideMultipleDataSelection_will_call_hideMultipleDataSelection_in_the_view() {
+    EXPECT_CALL(*m_view, hideMultipleDataSelection()).Times(1);
+    m_presenter->hideMultipleDataSelection();
+  }
+
+  void
+  test_that_showMultipleDataSelection_will_call_showMultipleDataSelection_in_the_view() {
+    EXPECT_CALL(*m_view, showMultipleDataSelection()).Times(1);
+    m_presenter->showMultipleDataSelection();
+  }
+
+  void test_that_updateRangeSelectors_will_update_the_background_selector() {
+    auto const fitFunction = getFunctionWithWorkspaceName("WorkspaceName");
+
+    ON_CALL(*m_fittingModel, getFittingFunction())
+        .WillByDefault(Return(fitFunction));
+
+    Expectation setVisible =
+        EXPECT_CALL(*m_view, setBackgroundRangeVisible(true)).Times(1);
+    EXPECT_CALL(*m_view, setBackgroundLevel(0.0)).Times(1).After(setVisible);
+
+    m_presenter->updateRangeSelectors();
+  }
+
+  void test_that_updateRangeSelectors_will_update_the_hwhm_selector() {
+    auto const fitFunction = getFunctionWithWorkspaceName("WorkspaceName");
+
+    ON_CALL(*m_fittingModel, getFittingFunction())
+        .WillByDefault(Return(fitFunction));
+
+    Expectation setVisible =
+        EXPECT_CALL(*m_view, setHWHMRangeVisible(true)).Times(1);
+    EXPECT_CALL(*m_view, setHWHMMinimum(-0.00875)).Times(1).After(setVisible);
+    EXPECT_CALL(*m_view, setHWHMMaximum(0.00875)).Times(1).After(setVisible);
+
+    m_presenter->updateRangeSelectors();
+  }
+
+  void
+  test_that_appendLastDataToSelection_will_set_the_name_of_the_data_selection_if_the_dataSelectionSize_and_numberOfWorkspaces_are_equal() {
+    std::size_t const index(1);
+
+    ON_CALL(*m_view, dataSelectionSize()).WillByDefault(Return(2));
+    ON_CALL(*m_fittingModel, numberOfWorkspaces()).WillByDefault(Return(2));
+    ON_CALL(*m_fittingModel, createDisplayName("%1% (%2%)", "-", index))
+        .WillByDefault(Return("DisplayName-1"));
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    Expectation createName =
+        EXPECT_CALL(*m_fittingModel, createDisplayName("%1% (%2%)", "-", index))
+            .Times(1);
+    EXPECT_CALL(*m_view, setNameInDataSelection("DisplayName-1", index))
+        .Times(1)
+        .After(createName);
+
+    m_presenter->appendLastDataToSelection();
+  }
+
+  void
+  test_that_appendLastDataToSelection_will_add_to_the_data_selection_if_the_dataSelectionSize_and_numberOfWorkspaces_are_not_equal() {
+    std::size_t const index(1);
+
+    ON_CALL(*m_view, dataSelectionSize()).WillByDefault(Return(1));
+    ON_CALL(*m_fittingModel, numberOfWorkspaces()).WillByDefault(Return(2));
+    ON_CALL(*m_fittingModel, createDisplayName("%1% (%2%)", "-", index))
+        .WillByDefault(Return("DisplayName-1"));
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    Expectation createName =
+        EXPECT_CALL(*m_fittingModel, createDisplayName("%1% (%2%)", "-", index))
+            .Times(1);
+    EXPECT_CALL(*m_view, appendToDataSelection("DisplayName-1"))
+        .Times(1)
+        .After(createName);
+
+    m_presenter->appendLastDataToSelection();
+  }
+
+  void
+  test_that_updateSelectedDataName_will_update_the_name_in_the_data_selection() {
+    std::size_t const index(0);
+
+    ON_CALL(*m_fittingModel, createDisplayName("%1% (%2%)", "-", index))
+        .WillByDefault(Return("DisplayName-1"));
+    ON_CALL(*m_fittingModel, getWorkspace(index))
+        .WillByDefault(Return(m_ads->retrieveWorkspace("WorkspaceName")));
+
+    Expectation createName =
+        EXPECT_CALL(*m_fittingModel, createDisplayName("%1% (%2%)", "-", index))
+            .Times(1);
+    EXPECT_CALL(*m_view, setNameInDataSelection("DisplayName-1", 0))
+        .Times(1)
+        .After(createName);
+
+    m_presenter->updateSelectedDataName();
+  }
+
+private:
+  std::unique_ptr<MockIndirectFitPlotView> m_view;
+  std::unique_ptr<MockIndirectFittingModel> m_fittingModel;
+  std::unique_ptr<IndirectFitPlotPresenter> m_presenter;
+
+  SetUpADSWithWorkspace *m_ads;
+};
+
+#endif
\ No newline at end of file
diff --git a/qt/scientific_interfaces/Indirect/test/IndirectSpectrumSelectionPresenterTest.h b/qt/scientific_interfaces/Indirect/test/IndirectSpectrumSelectionPresenterTest.h
index 3962e59f60e143d2b4fc6af2be08b7610309485f..cfcf11936cf5e61216434f07a904ed4221151a6a 100644
--- a/qt/scientific_interfaces/Indirect/test/IndirectSpectrumSelectionPresenterTest.h
+++ b/qt/scientific_interfaces/Indirect/test/IndirectSpectrumSelectionPresenterTest.h
@@ -93,7 +93,7 @@ public:
 /// Note that there is limited (if any) interaction going from this model to the
 /// IndirectSpectrumSelectionView, meaning that not many methods are required
 /// for mocking.
-class MockIndirectFittingModel : public IndirectFittingModel {
+class MockIndirectSpectrumSelectionModel : public IndirectFittingModel {
 public:
   /// Public methods
   MOCK_CONST_METHOD2(getExcludeRegion,
@@ -131,9 +131,10 @@ public:
   }
 
   void setUp() override {
-    m_view = new NiceMock<MockIndirectSpectrumSelectionView>();
-    m_model = new NiceMock<MockIndirectFittingModel>();
-    m_presenter = new IndirectSpectrumSelectionPresenter(m_model, m_view);
+    m_view = std::make_unique<NiceMock<MockIndirectSpectrumSelectionView>>();
+    m_model = std::make_unique<NiceMock<MockIndirectSpectrumSelectionModel>>();
+    m_presenter = std::make_unique<IndirectSpectrumSelectionPresenter>(
+        std::move(m_model.get()), std::move(m_view.get()));
 
     SetUpADSWithWorkspace ads("WorkspaceName", createWorkspace(10));
     m_model->addWorkspace("WorkspaceName");
@@ -142,11 +143,12 @@ public:
   void tearDown() override {
     AnalysisDataService::Instance().clear();
 
-    TS_ASSERT(Mock::VerifyAndClearExpectations(m_view));
-    TS_ASSERT(Mock::VerifyAndClearExpectations(m_model));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(m_view.get()));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(m_model.get()));
 
-    delete m_presenter; /// Note that the m_view destructor is called here
-    delete m_model;
+    m_presenter.reset(); /// The views destructor is called at this point
+    m_model.reset();
+    m_view.release();
   }
 
   ///----------------------------------------------------------------------
@@ -358,9 +360,9 @@ public:
   }
 
 private:
-  MockIndirectSpectrumSelectionView *m_view;
-  MockIndirectFittingModel *m_model;
-  IndirectSpectrumSelectionPresenter *m_presenter;
+  std::unique_ptr<MockIndirectSpectrumSelectionView> m_view;
+  std::unique_ptr<MockIndirectSpectrumSelectionModel> m_model;
+  std::unique_ptr<IndirectSpectrumSelectionPresenter> m_presenter;
 };
 
 #endif
diff --git a/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h b/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h
index 373645d4039ff511815de82aa03774dbdba9ceca..435a6012813952422de09fb230f5c82781e46659 100644
--- a/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h
+++ b/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h
@@ -204,10 +204,10 @@ public:
 
     auto options = presenter.getReductionOptions();
     TS_ASSERT_EQUALS(variantToString(options["PolarizationAnalysis"]), "PNR");
-    TS_ASSERT_EQUALS(variantToString(options["Rho"]), "");
-    TS_ASSERT_EQUALS(variantToString(options["Alpha"]), "");
-    TS_ASSERT_EQUALS(variantToString(options["Ap"]), "100.0,17.0,44.0");
-    TS_ASSERT_EQUALS(variantToString(options["Pp"]), "0.54,0.33,1.81");
+    TS_ASSERT_EQUALS(variantToString(options["CRho"]), "");
+    TS_ASSERT_EQUALS(variantToString(options["CAlpha"]), "");
+    TS_ASSERT_EQUALS(variantToString(options["CAp"]), "100.0,17.0,44.0");
+    TS_ASSERT_EQUALS(variantToString(options["CPp"]), "0.54,0.33,1.81");
 
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
   }
diff --git a/qt/widgets/common/src/WorkspacePresenter/WorkspaceTreeWidgetSimple.cpp b/qt/widgets/common/src/WorkspacePresenter/WorkspaceTreeWidgetSimple.cpp
index 0fa4eef0b8671dd803e9874048c2cf3666c38de5..8cd58c9de557b4c6736ff336d21980f03d98f616 100644
--- a/qt/widgets/common/src/WorkspacePresenter/WorkspaceTreeWidgetSimple.cpp
+++ b/qt/widgets/common/src/WorkspacePresenter/WorkspaceTreeWidgetSimple.cpp
@@ -6,14 +6,15 @@
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "MantidQtWidgets/Common/WorkspacePresenter/WorkspaceTreeWidgetSimple.h"
 #include "MantidQtWidgets/Common/MantidTreeModel.h"
-#include <MantidQtWidgets/Common/MantidTreeWidget.h>
-#include <MantidQtWidgets/Common/MantidTreeWidgetItem.h>
+#include "MantidQtWidgets/Common/MantidTreeWidget.h"
+#include "MantidQtWidgets/Common/MantidTreeWidgetItem.h"
 
-#include <MantidAPI/AlgorithmManager.h>
-#include <MantidAPI/FileProperty.h>
-#include <MantidAPI/ITableWorkspace.h>
-#include <MantidAPI/MatrixWorkspace.h>
-#include <MantidAPI/WorkspaceGroup.h>
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidGeometry/Instrument.h"
 
 #include <QMenu>
 #include <QSignalMapper>
@@ -85,7 +86,8 @@ void WorkspaceTreeWidgetSimple::popupContextMenu() {
     } catch (Exception::NotFoundError &) {
       return;
     }
-    if (boost::dynamic_pointer_cast<MatrixWorkspace>(workspace)) {
+    if (auto matrixWS =
+            boost::dynamic_pointer_cast<MatrixWorkspace>(workspace)) {
       QMenu *plotSubMenu(new QMenu("Plot", menu));
       plotSubMenu->addAction(m_plotSpectrum);
       plotSubMenu->addAction(m_overplotSpectrum);
@@ -97,6 +99,9 @@ void WorkspaceTreeWidgetSimple::popupContextMenu() {
       menu->addSeparator();
       menu->addAction(m_showData);
       menu->addAction(m_showInstrument);
+      m_showInstrument->setEnabled(
+          matrixWS->getInstrument() &&
+          !matrixWS->getInstrument()->getName().empty());
       menu->addSeparator();
     }
     menu->addAction(m_rename);
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index b3cf15b9d79b71efe3905c1f127feaa2ea5d7226..f7838b680f04ed8535d8daf45960e8d914f7b36f 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -19,13 +19,63 @@ set_property ( TARGET CompileUIErrorReporter PROPERTY FOLDER "CompilePyUI" )
 add_subdirectory ( ExternalInterfaces )
 
 # --------------------------------------------------------------------
-# Testing
+# .pth files
 # --------------------------------------------------------------------
-# All of the following tests (and those in subdirectories) require the
-# test format to import mantid to setup paths to the scripts
-# directory
-set ( PYUNITTEST_TESTRUNNER_IMPORT_MANTID 1 )
+set ( _pth_dirs .
+  Calibration
+  DiamondAttenuationCorrection
+  Diffraction
+  Engineering
+  GSAS-II
+  Inelastic
+  Interface
+  Reflectometry
+  SANS
+  SCD_Reduction
+  TemporaryREF_MScripts
+  Vates
+)
+
+set ( _pth_list_dev )
+set ( _pth_list_install )
+if ( APPLE )
+  set ( _scripts_rel_path "../../scripts" )
+else ()
+  set ( _scripts_rel_path "../scripts" )
+endif()
+
+foreach ( _dir ${_pth_dirs} )
+  list ( APPEND _pth_list_dev "${CMAKE_SOURCE_DIR}/scripts/${_dir}" )
+  list ( APPEND _pth_list_install "${_scripts_rel_path}/${_dir}" )
+endforeach()
+list ( APPEND _pth_list_dev ${MSLICE_DEV} )
+list ( APPEND _pth_list_install "${_scripts_rel_path}/Externalinterfaces" )
+
+# development copy
+set ( _scripts_pth_src "${CMAKE_CURRENT_BINARY_DIR}/mantid-scripts.pth.src" )
+set ( _scripts_pth_dest "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/mantid-scripts.pth" )
+string ( REPLACE ";" "\n" _pth_list_dev "${_pth_list_dev}" )
+file ( WRITE ${_scripts_pth_src} "${_pth_list_dev}\n" )
+add_custom_command ( OUTPUT ${_scripts_pth_dest}
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different
+    ${_scripts_pth_src} ${_scripts_pth_dest}
+  DEPENDS ${_scripts_pth_src}
+  COMMENT "Generating scripts .pth file"
+)
+add_custom_target ( ScriptsDotPth ALL DEPENDS ${_scripts_pth_dest} )
+add_dependencies ( PythonInterface ScriptsDotPth )
 
+# install copy
+set ( _scripts_pth_install "${CMAKE_CURRENT_BINARY_DIR}/mantid-scripts.pth.install" )
+string ( REPLACE ";" "\n" _pth_list_install "${_pth_list_install}" )
+file ( WRITE ${_scripts_pth_install} "${_pth_list_install}\n" )
+install ( FILES ${_scripts_pth_install} DESTINATION ${BIN_DIR}
+  RENAME mantid-scripts.pth
+)
+
+# --------------------------------------------------------------------
+# Testing
+# --------------------------------------------------------------------
 set ( TEST_PY_FILES
       test/AbinsAtomsDataTest.py
       test/AbinsCalculateDWSingleCrystalTest.py
@@ -52,6 +102,7 @@ set ( TEST_PY_FILES
       test/IndirectCommonTests.py
       test/ISISDirecInelasticConfigTest.py
       test/PyChopTest.py
+      test/pythonTSVTest.py
       test/ReductionSettingsTest.py
       test/ReductionWrapperTest.py
       test/ReflectometryQuickAuxiliaryTest.py
diff --git a/scripts/ExternalInterfaces/CMakeLists.txt b/scripts/ExternalInterfaces/CMakeLists.txt
index b1156a8446f01c08efd19f1133d79818f07c8feb..dced936ed5047f8b39eae5c8e77209d7f1c6f96b 100644
--- a/scripts/ExternalInterfaces/CMakeLists.txt
+++ b/scripts/ExternalInterfaces/CMakeLists.txt
@@ -14,7 +14,6 @@ ExternalProject_Add ( mslice
   TEST_COMMAND ""
   INSTALL_COMMAND ""
 )
-set ( _mslice_src ${_mslice_external_root}/src/mslice )
 message ( STATUS "Fetching/updating mslice" )
 execute_process ( COMMAND ${CMAKE_COMMAND} ARGS -P ${_mslice_external_root}/tmp/mslice-gitclone.cmake
                   RESULT_VARIABLE _exit_code )
@@ -27,7 +26,10 @@ if ( _exit_code EQUAL 0 )
 else ()
   message ( FATAL_ERROR "Unable to clone mslice" )
 endif()
+# Let the parent lists file know where dev copy of mslice is
+set ( MSLICE_DEV ${_mslice_external_root}/src/mslice PARENT_SCOPE )
 
 # Installation
+# MSLICE_DEV is only set in PARENT_SCOPE!
 install ( DIRECTORY ${_mslice_external_root}/src/mslice/mslice/
           DESTINATION ${INBUNDLE}scripts/ExternalInterfaces/mslice )
diff --git a/scripts/Interface/ui/sans_isis/__init__.py b/scripts/Interface/ui/sans_isis/__init__.py
index 17a894e3f9249dd4edeec240f5970db9a9fe5bd8..d2cfb75232dfb59fac674e2b49dba356e18ebbc1 100644
--- a/scripts/Interface/ui/sans_isis/__init__.py
+++ b/scripts/Interface/ui/sans_isis/__init__.py
@@ -4,19 +4,3 @@
 #     NScD Oak Ridge National Laboratory, European Spallation Source
 #     & Institut Laue - Langevin
 # SPDX - License - Identifier: GPL - 3.0 +
-# Note that this a workaround
-# When introduced? During the Python2 to Python3 conversion
-# Why introduced? The autogenerated file ui_XXX.py contains a line
-#                 from XXXX import YYYY
-#                 which should be
-#                 from .XXXX import YYYY
-#                 for Python3, but since it is autogenerated we cannot change
-#                 this easily.
-import os
-import sys
-
-import mantid
-
-path = mantid.config["pythonscripts.directories"].split(";")[0]
-path = os.path.join(path[:path.index("scripts")], "scripts", "Interface", "ui", "sans_isis")
-sys.path.append(path)
diff --git a/scripts/Interface/ui/sans_isis/add_runs_page.py b/scripts/Interface/ui/sans_isis/add_runs_page.py
index 1d492b06ec73a4bdfeb9b3e61d7026140164695c..eebb3c8769626c8871d6d7a722bf49a036750b63 100644
--- a/scripts/Interface/ui/sans_isis/add_runs_page.py
+++ b/scripts/Interface/ui/sans_isis/add_runs_page.py
@@ -4,9 +4,11 @@
 #     NScD Oak Ridge National Laboratory, European Spallation Source
 #     & Institut Laue - Langevin
 # SPDX - License - Identifier: GPL - 3.0 +
+from __future__ import absolute_import
+
 from PyQt4 import QtGui
 from PyQt4.QtCore import pyqtSignal
-import ui_add_runs_page
+from . import ui_add_runs_page
 
 
 class AddRunsPage(QtGui.QWidget, ui_add_runs_page.Ui_AddRunsPage):
diff --git a/scripts/Interface/ui/sans_isis/beam_centre.py b/scripts/Interface/ui/sans_isis/beam_centre.py
index 4e851a4db09aad2b8238ead794c543bb51f843d1..7746bf68d5c688d9b4422703444d3b6510c16158 100644
--- a/scripts/Interface/ui/sans_isis/beam_centre.py
+++ b/scripts/Interface/ui/sans_isis/beam_centre.py
@@ -10,7 +10,7 @@ from abc import ABCMeta, abstractmethod
 
 from PyQt4 import QtGui, QtCore
 from six import with_metaclass
-import ui_beam_centre
+from . import ui_beam_centre
 from mantidqtpython import MantidQt
 from sans.gui_logic.gui_common import get_detector_from_gui_selection, \
     get_detector_strings_for_gui, get_string_for_gui_from_reduction_mode
diff --git a/scripts/Interface/ui/sans_isis/diagnostics_page.py b/scripts/Interface/ui/sans_isis/diagnostics_page.py
index 8887fc8827a6c6eab42b7877c4e760e13acabba1..f59ea65a73ece7c211c2a5bba99f886883c406ba 100644
--- a/scripts/Interface/ui/sans_isis/diagnostics_page.py
+++ b/scripts/Interface/ui/sans_isis/diagnostics_page.py
@@ -10,7 +10,7 @@ from abc import ABCMeta, abstractmethod
 
 from PyQt4 import QtGui, QtCore
 from six import with_metaclass
-import ui_diagnostics_page
+from . import ui_diagnostics_page
 from sans.gui_logic.gui_common import (load_file, GENERIC_SETTINGS)
 
 try:
diff --git a/scripts/Interface/ui/sans_isis/masking_table.py b/scripts/Interface/ui/sans_isis/masking_table.py
index 2a6b305fb18a21108d3a7d1bef5537327f138ca7..14143323350f200fc43dd557e2105302b91b28cf 100644
--- a/scripts/Interface/ui/sans_isis/masking_table.py
+++ b/scripts/Interface/ui/sans_isis/masking_table.py
@@ -16,7 +16,7 @@ from abc import ABCMeta, abstractmethod
 
 from PyQt4 import QtGui
 from six import with_metaclass
-import ui_masking_table
+from . import ui_masking_table
 
 
 class MaskingTable(QtGui.QWidget, ui_masking_table.Ui_MaskingTable):
diff --git a/scripts/Interface/ui/sans_isis/run_selector_widget.py b/scripts/Interface/ui/sans_isis/run_selector_widget.py
index 63110fbefb7474544fd34c1d059e658bf4189368..b32530558fa82ff682f0819def89199a99eaa955 100644
--- a/scripts/Interface/ui/sans_isis/run_selector_widget.py
+++ b/scripts/Interface/ui/sans_isis/run_selector_widget.py
@@ -8,7 +8,7 @@ from __future__ import (absolute_import, division, print_function)
 
 from PyQt4 import QtGui, QtCore
 
-import ui_run_selector_widget
+from . import ui_run_selector_widget
 from PyQt4.QtCore import pyqtSignal
 from mantidqtpython import MantidQt
 
diff --git a/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py b/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py
index a0b6b79777fe7dce37a250d380bd4c89be0f4e4e..d3bcec09a14a8a0b75480d85aba74045d9fe8e24 100644
--- a/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py
+++ b/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py
@@ -10,12 +10,11 @@
 
 from __future__ import (absolute_import, division, print_function)
 
-import os
 from abc import ABCMeta, abstractmethod
 from inspect import isclass
 
 from six import with_metaclass
-from qtpy.QtWidgets import (QListWidget, QListWidgetItem, QMainWindow, QMessageBox)  # noqa
+from qtpy.QtWidgets import (QListWidgetItem, QMainWindow, QMessageBox)  # noqa
 from qtpy.QtCore import (QRegExp, QSettings)  # noqa
 from qtpy.QtGui import (QDoubleValidator, QIcon, QIntValidator, QRegExpValidator)  # noqa
 
diff --git a/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py b/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py
index 91b0d39cf84cb3db63d6f6986bae38cc97fbbe52..7c5b924a3a62bf2b505813628cd66f1b026f6f0d 100644
--- a/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py
+++ b/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py
@@ -21,7 +21,7 @@ from six import with_metaclass
 from PyQt4 import QtGui
 
 from sans.gui_logic.gui_common import (GENERIC_SETTINGS, JSON_SUFFIX, load_file)
-import ui_settings_diagnostic_tab
+from . import ui_settings_diagnostic_tab
 
 if six.PY3:
     unicode = str
diff --git a/scripts/Interface/ui/sans_isis/summation_settings_widget.py b/scripts/Interface/ui/sans_isis/summation_settings_widget.py
index 07beaf43ec46e40980dab793c3e67f24b1b775f7..caf7e4e3d3f7dd12b6af478c2bd911ea4cad61ae 100644
--- a/scripts/Interface/ui/sans_isis/summation_settings_widget.py
+++ b/scripts/Interface/ui/sans_isis/summation_settings_widget.py
@@ -9,7 +9,7 @@ from __future__ import (absolute_import, division, print_function)
 from PyQt4 import QtGui
 from PyQt4.QtCore import pyqtSignal
 
-import ui_summation_settings_widget
+from . import ui_summation_settings_widget
 from sans.gui_logic.models.binning_type import BinningType
 
 
diff --git a/scripts/Interface/ui/sans_isis/work_handler.py b/scripts/Interface/ui/sans_isis/work_handler.py
index a093cd5142b5e9c5318f1a66588a8ce399d084f5..3ad548b5612a0188a789b97a73266d1e1cd66d1d 100644
--- a/scripts/Interface/ui/sans_isis/work_handler.py
+++ b/scripts/Interface/ui/sans_isis/work_handler.py
@@ -14,14 +14,16 @@ The "worker" handles running the function via a unique process ID; "listeners" m
 each process which are then notified upon certain actions (such as an error being thrown by the
 worker, or the worker finishing its task) using the nested class WorkListener.
 """
+from __future__ import absolute_import
 
 from PyQt4.QtCore import pyqtSlot, QThreadPool
 from abc import ABCMeta, abstractmethod
 from six import with_metaclass
-from worker import Worker
 import functools
 import uuid
 
+from .worker import Worker
+
 
 class WorkHandler(object):
     """
diff --git a/scripts/Muon/GUI/Common/context_example/context_example_model.py b/scripts/Muon/GUI/Common/context_example/context_example_model.py
index 5f860dc3274e4b1395e360c179b2080864070eea..e2a5338f5a4f0994fc666fe07ffcab5922141438 100644
--- a/scripts/Muon/GUI/Common/context_example/context_example_model.py
+++ b/scripts/Muon/GUI/Common/context_example/context_example_model.py
@@ -21,11 +21,21 @@ class ContextExampleModel(object):
     def getSubContext(self):
         subContext = {}
         group_names = []
+        group_dets = []
         tmp = self._context.get(Groups)
         for group in tmp:
             group_names.append(group.name)
+            group_dets.append(group.dets)
         subContext["Group Names"] = group_names
+        subContext["Group dets"] = group_dets
+
         pair = self._context.get(Pairs)[0]  # there is only one
+        # do some validation on pairs
+        if pair.FGroup not in group_names:
+            pair.setFGroup(group_names[0])
+        if pair.BGroup not in group_names:
+            pair.setBGroup(group_names[1])
+
         subContext["Pair_F"] = pair.FGroup
         subContext["Pair_B"] = pair.BGroup
         subContext["Pair_alpha"] = pair.alpha
@@ -34,14 +44,19 @@ class ContextExampleModel(object):
 
     def updateContext(self, subContext):
         group_names = subContext["Group Names"]
+        group_dets = subContext["Group dets"]
         groups = []
-        for name in group_names:
-            groups.append(group_object.group(name))
+        for k in range(len(group_names)):
+            groups.append(group_object.group(group_names[k], group_dets[k]))
         self._context.set(Groups, groups)
 
         alpha = subContext["Pair_alpha"]
         F_group = subContext["Pair_F"]
+        if F_group not in group_names:
+            F_group = group_names[0]
         B_group = subContext["Pair_B"]
+        if B_group not in group_names:
+            B_group = group_names[0]
         name = "pair test"
         pair = pair_object.pair(name, F_group, B_group, alpha)
         self._context.set(Pairs, [pair])
diff --git a/scripts/Muon/GUI/Common/context_example/context_example_view.py b/scripts/Muon/GUI/Common/context_example/context_example_view.py
index fe249aad739bd1b20352c7d5c5ee6f2925f9b6a3..c06283ec817f1f84392a68705a314f1fc742dd4e 100644
--- a/scripts/Muon/GUI/Common/context_example/context_example_view.py
+++ b/scripts/Muon/GUI/Common/context_example/context_example_view.py
@@ -95,6 +95,9 @@ class ContextExampleView(QtGui.QWidget):
         self.ws1.setText(group_name[1])
         self.ws2.setText(group_name[2])
 
+        #store the detectors
+        self.dets = context["Group dets"]
+
         # update combo boxes (clear and repopulate)
         self.g1.clear()
         self.g2.clear()
@@ -120,6 +123,7 @@ class ContextExampleView(QtGui.QWidget):
         context = {}
         context["Group Names"] = [
             self.ws0.text(), self.ws1.text(), self.ws2.text()]
+        context["Group dets"] = self.dets
         context["Pair_F"] = str(self.g1.currentText())
         context["Pair_B"] = str(self.g2.currentText())
         context["Pair_alpha"] = float(self.alpha.text())
diff --git a/scripts/Muon/GUI/Common/context_example/context_example_widget.py b/scripts/Muon/GUI/Common/context_example/context_example_widget.py
index ca9f70084a5e1fe2fc3fb4e7c1c56778fbaabd29..750271218e6379d27c8649307d4a34997408c6f7 100644
--- a/scripts/Muon/GUI/Common/context_example/context_example_widget.py
+++ b/scripts/Muon/GUI/Common/context_example/context_example_widget.py
@@ -47,7 +47,7 @@ class ContextExampleWidget(object):
     def updateContext(self):
         self._presenter.updateContext()
 
-    def loadFromContext(self, context):
+    def loadFromContext(self):
         # extract relevant info from context via model
         model = self._presenter.model
         sub_context = model.getSubContext()
diff --git a/scripts/Muon/GUI/Common/dummy_label/dummy_label_widget.py b/scripts/Muon/GUI/Common/dummy_label/dummy_label_widget.py
index b2e518b23a3b5b86a15eac7a8939d8181cc116e8..a1d12aaf1aa28732894b3274aa52924b9d800eb7 100644
--- a/scripts/Muon/GUI/Common/dummy_label/dummy_label_widget.py
+++ b/scripts/Muon/GUI/Common/dummy_label/dummy_label_widget.py
@@ -33,7 +33,7 @@ class DummyLabelWidget(object):
     def updateContext(self):
         self._presenter.updateContext()
 
-    def loadFromContext(self, context):
+    def loadFromContext(self):
         # extract relevant info from context via model
         model = self._presenter.model
         sub_context = model.getSubContext()
diff --git a/scripts/Muon/GUI/Common/group_object.py b/scripts/Muon/GUI/Common/group_object.py
index 089cf2f0da880923675c4a0c554a5fd7c4d49823..d4fe34107223e81a00d3022c29a26be2fd690513 100644
--- a/scripts/Muon/GUI/Common/group_object.py
+++ b/scripts/Muon/GUI/Common/group_object.py
@@ -5,6 +5,9 @@
 #     & Institut Laue - Langevin
 # SPDX - License - Identifier: GPL - 3.0 +
 
+from __future__ import (absolute_import, division, print_function)
+import pythonTSV as TSVHelper
+
 
 class group(object):
 
@@ -16,6 +19,13 @@ class group(object):
     def name(self):
         return self._name
 
+    @property
+    def dets(self):
+        return self._dets
+
+    def Print(self):
+        print(self._name, self._dets)
+
     def setName(self, name):
         self._name = name
 
@@ -27,3 +37,18 @@ class group(object):
             return True
 
         return False
+
+    def save(self, TSV):
+        TSVHelper.writeLine(TSV, self._name)
+        TSV.storeInt(len(self._dets))
+        for detector in self._dets:
+            TSV.storeInt(detector)
+
+    def load(self, TSV, name):
+        self._name = name
+        safeName = TSVHelper.makeLineNameSafe(name)
+        TSV.selectLine(safeName)
+        num = TSV.readInt()
+        self._dets = []
+        for k in range(num):
+            self._dets.append(TSV.readInt())
diff --git a/scripts/Muon/GUI/Common/mock_widget.py b/scripts/Muon/GUI/Common/mock_widget.py
index 45df940ce2cd49a0e9fd308dc08ee8f17ca8d5ca..d5be17d997eb983e2022716390ed78d00a11be0a 100644
--- a/scripts/Muon/GUI/Common/mock_widget.py
+++ b/scripts/Muon/GUI/Common/mock_widget.py
@@ -4,13 +4,20 @@
 #     NScD Oak Ridge National Laboratory, European Spallation Source
 #     & Institut Laue - Langevin
 # SPDX - License - Identifier: GPL - 3.0 +
+from __future__ import unicode_literals
 
 import PyQt4.QtGui as QtGui
 
+_QAPP = None
+
 
 def mockQapp():
-    qapp = QtGui.QApplication.instance()
-    if qapp is None:
-        return QtGui.QApplication([''])
-    else:
-        return qapp
+    """
+    Constructs a QApplication object if one does not already exist
+    :return: The QApplication object
+    """
+    global _QAPP
+    if _QAPP is None:
+        _QAPP = QtGui.QApplication([''])
+
+    return _QAPP
diff --git a/scripts/Muon/GUI/Common/muon_context/muon_context.py b/scripts/Muon/GUI/Common/muon_context/muon_context.py
index ccdd8ef3dca5449c3eaa0bf06885186265030257..6d9e515937dd104023500f807f0c4fc2c3f5231e 100644
--- a/scripts/Muon/GUI/Common/muon_context/muon_context.py
+++ b/scripts/Muon/GUI/Common/muon_context/muon_context.py
@@ -7,34 +7,41 @@
 
 # Muon context - contains all of the values from the GUI
 from __future__ import (absolute_import, division, print_function)
+from collections import OrderedDict
+import copy
+
 from Muon.GUI.Common import group_object
 from Muon.GUI.Common import pair_object
 
+import pythonTSV as TSVHelper
+from mantidqtpython import MantidQt
+
 # constant variable names
 Tab2Text = "some text"
-HelpText = "help text"
-LoadText = "load dummy"
+HelpText = "help_text"
+LoadText = "load-dummy"
 Groups = "groups"
 Pairs = "pairs"
 
 
 class MuonContext(object):
 
-    def __init__(self):
-        self.common_context = {}
-        self.common_context[Tab2Text] = "boo - start up"
-        self.common_context[HelpText] = "Help dummy"
-        self.common_context[LoadText] = "load dummy"
+    def __init__(self, name):
+        self._name = name
+        self.common_context = OrderedDict()
+        self.common_context[Tab2Text] = "boo-start up"
+        self.common_context[HelpText] = "Help_dummy"
+        self.common_context[LoadText] = "load_dummy"
         self.common_context[Groups] = [group_object.group(
-                                       "fwd"),
-                                       group_object.group("bwd"),
-                                       group_object.group("top")]
+                                       "fwd", [1, 2]),
+                                       group_object.group("bwd", [3, 4, 5]),
+                                       group_object.group("top", [1, 2, 3, 4, 5])]
         self.common_context[
             Pairs] = [
                 pair_object.pair(
-                    "test pair",
+                    "test_pair",
+                    "fwd",
                     "bwd",
-                    "top",
                     0.9)]
 
     def set(self, key, value):
@@ -49,9 +56,84 @@ class MuonContext(object):
         print(LoadText, self.common_context[LoadText])
         print(Groups)
         for group in self.common_context[Groups]:
-            print(group.name)
+            group.Print()
         print
         print(Pairs)
         for pair in self.common_context[Pairs]:
             print(pair.name, pair.FGroup, pair.BGroup, pair.alpha)
         print()
+
+    def save(self):
+        # save ....
+        TSVSec = MantidQt.API.TSVSerialiser()
+        TSV0 = MantidQt.API.TSVSerialiser()
+        keys = self.common_context.keys()
+
+        TSV0.writeLine("keys")
+        TSV0.storeInt(len(keys))
+        for key in keys:
+            TSV0.storeString(key)
+        for key in keys:
+            TSVHelper.writeLine(TSV0, key)
+            value = self.common_context[key]
+            try:
+                TSVHelper.saveToTSV(TSV0, value)
+            except:
+                try:
+                    self.saveCustom(TSV0, key, value)
+                except:
+                    pass
+        lines = TSV0.outputLines()
+        safeName = TSVHelper.makeLineNameSafe(self._name)
+        TSVSec.writeSection(safeName, lines)
+        return TSVSec.outputLines()
+
+    def saveCustom(self, TSV0, key, value):
+        tmpTSV = MantidQt.API.TSVSerialiser()
+        tmpTSV.writeLine("members")
+        tmpTSV.storeInt(len(value))
+        # store all of the names/keys on one line
+        for obj in value:
+            tmpTSV.storeString(obj.name)
+        # the below method writes a new line
+        for obj in value:
+            obj.save(tmpTSV)
+        safeKey = TSVHelper.makeLineNameSafe(key)
+        TSV0.writeSection(safeKey, tmpTSV.outputLines())
+
+    def loadFromProject(self, project):
+        full_load = MantidQt.API.TSVSerialiser(project)
+        # get section
+        safeName = TSVHelper.makeLineNameSafe(self._name)
+        secs = full_load.sections(safeName)
+
+        load = MantidQt.API.TSVSerialiser(secs[0])
+        load.selectLine("keys")
+        numKeys = load.readInt()
+        keys = []
+        for k in range(numKeys):
+            tmp = load.readString()
+            keys.append(tmp)
+        for key in keys:
+            value = self.common_context[key]
+            try:
+                self.common_context[
+                    key] = TSVHelper.loadFromTSV(load, key, value)
+            except:
+                self.customLoad(load, key, value)
+                pass
+
+    def customLoad(self, load, key, value):
+        safeKey = TSVHelper.makeLineNameSafe(key)
+        sec = load.sections(safeKey)
+        tmpTSV = MantidQt.API.TSVSerialiser(sec[0])
+        tmpTSV.selectLine("members")
+        num = tmpTSV.readInt()
+        names = []
+        for k in range(num):
+            names.append(tmpTSV.readString())
+        loaded_values = []
+        for name in names:
+            loaded_values.append(copy.deepcopy(value[0]))
+            loaded_values[-1].load(tmpTSV, name)
+        self.common_context[key] = loaded_values
diff --git a/scripts/Muon/GUI/Common/pair_object.py b/scripts/Muon/GUI/Common/pair_object.py
index 544918714a4285bb0effaebfa78705a4ccc01108..0c901c289c3db5f73e7b25afdaf92935d48e61c7 100644
--- a/scripts/Muon/GUI/Common/pair_object.py
+++ b/scripts/Muon/GUI/Common/pair_object.py
@@ -5,6 +5,8 @@
 #     & Institut Laue - Langevin
 # SPDX - License - Identifier: GPL - 3.0 +
 
+import pythonTSV as TSVHelper
+
 
 class pair(object):
 
@@ -47,3 +49,17 @@ class pair(object):
             return True
 
         return False
+
+    def save(self, TSV):
+        TSVHelper.writeLine(TSV, self._name)
+        TSV.storeString(self._F_group)
+        TSV.storeString(self._B_group)
+        TSV.storeDouble(self._alpha)
+
+    def load(self, TSV, name):
+        self._name = name
+        safeName = TSVHelper.makeLineNameSafe(name)
+        TSV.selectLine(safeName)
+        self._F_group = TSV.readString()
+        self._B_group = TSV.readString()
+        self._alpha = TSV.readDouble()
diff --git a/scripts/Muon/GUI/MuonAnalysis/dock/dock_widget.py b/scripts/Muon/GUI/MuonAnalysis/dock/dock_widget.py
index e50f98460c84b56208cd81c02810e86bed32cdca..77ea9f91fee04583bcb31f6baafcd80066e31758 100644
--- a/scripts/Muon/GUI/MuonAnalysis/dock/dock_widget.py
+++ b/scripts/Muon/GUI/MuonAnalysis/dock/dock_widget.py
@@ -75,9 +75,9 @@ class DockWidget(QtGui.QWidget):
         self.label.updateContext()
         self.context_example.updateContext()
 
-    def loadFromContext(self, context):
-        self.label.loadFromContext(context)
-        self.context_example.loadFromContext(context)
+    def loadFromContext(self):
+        self.label.loadFromContext()
+        self.context_example.loadFromContext()
 
     # needed for docking
     @property
diff --git a/scripts/Muon_Analysis_2.py b/scripts/Muon_Analysis_2.py
index c7f9f016ba68db1fb96ec1b9d3328540454abde5..54d8b2cfe9ae8c3aa5b0f4a61de3dcb227fbcfc7 100644
--- a/scripts/Muon_Analysis_2.py
+++ b/scripts/Muon_Analysis_2.py
@@ -14,7 +14,10 @@ import PyQt4.QtCore as QtCore
 
 from Muon.GUI.Common.dummy_label.dummy_label_widget import DummyLabelWidget
 from Muon.GUI.MuonAnalysis.dock.dock_widget import DockWidget
-from Muon.GUI.Common.muon_context.muon_context import *#MuonContext
+from Muon.GUI.Common.muon_context.muon_context import *  # MuonContext
+from save_python import getWidgetIfOpen
+
+Name = "Muon_Analysis_2"
 
 muonGUI = None
 
@@ -24,12 +27,12 @@ class MuonAnalysis2Gui(QtGui.QMainWindow):
     def __init__(self, parent=None):
         super(MuonAnalysis2Gui, self).__init__(parent)
 
-        self._context = MuonContext()
+        self._context = MuonContext(Name)
 
-        self.loadWidget = DummyLabelWidget(self._context ,LoadText, self)
-        self.dockWidget = DockWidget(self._context,self)
+        self.loadWidget = DummyLabelWidget(self._context, LoadText, self)
+        self.dockWidget = DockWidget(self._context, self)
 
-        self.helpWidget = DummyLabelWidget(self._context,HelpText, self)
+        self.helpWidget = DummyLabelWidget(self._context, HelpText, self)
 
         splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
         splitter.addWidget(self.loadWidget.widget)
@@ -37,23 +40,32 @@ class MuonAnalysis2Gui(QtGui.QMainWindow):
         splitter.addWidget(self.helpWidget.widget)
 
         self.setCentralWidget(splitter)
-        self.setWindowTitle("Muon Analysis version 2")
+        self.setWindowTitle(Name)
 
         self.dockWidget.setUpdateContext(self.update)
 
+    def saveToProject(self):
+        return self._context.save()
+
     def update(self):
         # update load
         self.loadWidget.updateContext()
         self.dockWidget.updateContext()
         self.helpWidget.updateContext()
 
-        self._context.printContext()
-        self.dockWidget.loadFromContext(self._context)
+        self.dockWidget.loadFromContext()
+
+    def loadFromContext(self, project):
+        self._context.loadFromProject(project)
+        self.loadWidget.loadFromContext()
+        self.dockWidget.loadFromContext()
+        self.helpWidget.loadFromContext()
 
     # cancel algs if window is closed
     def closeEvent(self, event):
         self.dockWidget.closeEvent(event)
         global muonGUI
+        muonGUI.deleteLater()
         muonGUI = None
 
 
@@ -66,31 +78,43 @@ def qapp():
 
 
 def main():
+    widget = getWidgetIfOpen(Name)
+    if widget is not None:
+        # if GUI is open bring to front
+        widget.raise_()
+        return widget
     app = qapp()
     try:
-        global muonGUI
-        muonGUI = MuonAnalysis2Gui()
-        muonGUI.resize(700, 700)
-        muonGUI.show()
+        muon = MuonAnalysis2Gui()
+        muon.resize(700, 700)
+        muon.setProperty("launcher", Name)
+        muon.show()
+        muon.setAccessibleName(Name)
         app.exec_()
-        return muonGUI
+        return muon
     except RuntimeError as error:
-        muonGUI = QtGui.QWidget()
-        QtGui.QMessageBox.warning(muonGUI, "Muon Analysis version 2", str(error))
-        return muonGUI
+        muon = QtGui.QWidget()
+        QtGui.QMessageBox.warning(muon, Name, str(error))
+        return muon
 
 
 def saveToProject():
-    if muonGUI is None:
+    widget = getWidgetIfOpen(Name)
+    if widget is None:
         return ""
-    project = "test"
+    widget.update()
+    project = widget.saveToProject()
     return project
 
 
 def loadFromProject(project):
+    global muonGUI
     muonGUI = main()
-    muonGUI.dockWidget.loadFromProject(project)
+    muonGUI.loadFromContext(project)
     return muonGUI
 
 if __name__ == '__main__':
-    muonGUI = main()
+    muon = main()
+    # cannot assign straight to muonGUI
+    # prevents reopening to the same GUI
+    muonGUI = muon
diff --git a/scripts/pythonTSV.py b/scripts/pythonTSV.py
new file mode 100644
index 0000000000000000000000000000000000000000..f13ca614ae5c6b93953d2886f9c2bb709a605737
--- /dev/null
+++ b/scripts/pythonTSV.py
@@ -0,0 +1,79 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+# pylint: disable=invalid-name
+from __future__ import (absolute_import, division, print_function)
+
+"""
+Some simple helpers for dealing with the TSV
+"""
+
+
+def saveToTSV(TSV, value):
+    """
+    This will record the value based on its type,
+    will only record default TSV data types
+    """
+    if isinstance(value, int):
+        TSV.storeInt(value)
+    elif isinstance(value, float):
+        TSV.storeDouble(value)
+    elif isinstance(value, bool):
+        TSV.storeBool(value)
+    elif isinstance(value, str):
+        TSV.storeString(value)
+    else:
+        raise TypeError("Value is not recognised by TSVSerialiser")
+
+
+def loadFromTSV(TSV, key, value):
+    """
+    Will return the stored data from a TSV
+    with from the line called key and with
+    a data type of value
+    """
+    safeKey = makeLineNameSafe(key)
+    TSV.selectLine(safeKey)
+    if isinstance(value, int):
+        return TSV.readInt()
+    elif isinstance(value, float):
+        return TSV.readDouble()
+    elif isinstance(value, bool):
+        return TSV.readBool()
+    elif isinstance(value, str):
+        return TSV.readString()
+    else:
+        raise TypeError("Value is not recognised by TSVSerialiser")
+
+"""
+The line name cannot contain:
+spaces, underscores or dashes
+"""
+
+
+def makeLineNameSafe(oldName):
+    newName = removeUnsafeCharacter(oldName, " ")
+    newName = removeUnsafeCharacter(newName, "_")
+    newName = removeUnsafeCharacter(newName, "-")
+    return newName
+
+
+"""
+write a lines and make sure it is safe
+"""
+
+
+def writeLine(TSV, name):
+    newName = makeLineNameSafe(name)
+    TSV.writeLine(newName)
+
+
+def removeUnsafeCharacter(oldName, character):
+    tmp = oldName.split(character)
+    newName = ""
+    for word in tmp:
+        newName += word[0].upper() + word[1:]
+    return newName
diff --git a/scripts/save_python.py b/scripts/save_python.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4674eb9f83c730accb3f32ed9e0f46a5ff0ebe5
--- /dev/null
+++ b/scripts/save_python.py
@@ -0,0 +1,18 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+# pylint: disable=invalid-name
+from __future__ import (absolute_import, division, print_function)
+
+import PyQt4.QtGui as QtGui
+
+
+def getWidgetIfOpen(name):
+    allWidgets = QtGui.QApplication.allWidgets()
+    for widget in allWidgets:
+        if widget.accessibleName() == name:
+            return widget
+    return None
diff --git a/scripts/test/Muon/AxisChangerView_test.py b/scripts/test/Muon/AxisChangerView_test.py
index 1dc81dca66934e5fd6e15d31deee34a0be7e9c4c..c7608bca328057cf8da79575d6b40a3aae9b3230 100644
--- a/scripts/test/Muon/AxisChangerView_test.py
+++ b/scripts/test/Muon/AxisChangerView_test.py
@@ -6,11 +6,7 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 import unittest
 
-import os
-os.environ["QT_API"] = "pyqt"  # noqa E402
-
 from Muon.GUI.ElementalAnalysis.Plotting.AxisChanger.axis_changer_view import AxisChangerView
-
 from Muon.GUI.Common import mock_widget
 
 try:
diff --git a/scripts/test/Muon/PeriodicTablePresenter_test.py b/scripts/test/Muon/PeriodicTablePresenter_test.py
index 11bc54c7b41cfaa39f969f2cc2d077134ca900a1..97eb33ff8603937e7cf0a14dcdf919974d4c6f91 100644
--- a/scripts/test/Muon/PeriodicTablePresenter_test.py
+++ b/scripts/test/Muon/PeriodicTablePresenter_test.py
@@ -23,8 +23,12 @@ except ImportError:
 
 
 class PeriodicTablePresenterTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.qapp = mock_widget.mockQapp()
+
     def setUp(self):
-        self._qapp = mock_widget.mockQapp()
         self._model = mock.create_autospec(PeriodicTableModel)
         self.view = PeriodicTableView()
         self.presenter = PeriodicTablePresenter(
diff --git a/scripts/test/SANS/algorithm_detail/scale_helper_test.py b/scripts/test/SANS/algorithm_detail/scale_helper_test.py
index 530504cac91cfa82d3c5118f708fd5ba039706fc..dfc6c868c8132e89f94e6edd2ca76a77b697ecc3 100644
--- a/scripts/test/SANS/algorithm_detail/scale_helper_test.py
+++ b/scripts/test/SANS/algorithm_detail/scale_helper_test.py
@@ -6,8 +6,10 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
 import math
+
+from mantid.api import FrameworkManager
+
 from sans.test_helper.test_director import TestDirector
 from sans.algorithm_detail.scale_helpers import (DivideByVolumeFactory, DivideByVolumeISIS, NullDivideByVolume,
                                                  MultiplyByAbsoluteScaleFactory, MultiplyByAbsoluteScaleLOQ,
@@ -20,6 +22,11 @@ from sans.test_helper.file_information_mock import SANSFileInformationMock
 
 
 class ScaleHelperTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _get_workspace(width=1.0, height=1.0, thickness=1.0, shape=1):
         sample_name = "CreateSampleWorkspace"
diff --git a/scripts/test/SANS/algorithm_detail/strip_end_nans_test.py b/scripts/test/SANS/algorithm_detail/strip_end_nans_test.py
index 9cff3b537e54eed0c5000a8e9c2cffde6d07c413..0b6ae862834a8dda8402e6dc9fa56f89fad1bbb5 100644
--- a/scripts/test/SANS/algorithm_detail/strip_end_nans_test.py
+++ b/scripts/test/SANS/algorithm_detail/strip_end_nans_test.py
@@ -6,12 +6,17 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
-from mantid.api import AlgorithmManager
+
+from mantid.api import AlgorithmManager, FrameworkManager
 from sans.algorithm_detail.strip_end_nans_and_infs import strip_end_nans
 
 
 class StripEndNansTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     def _do_test(self, data_x, data_y):
         # Arrange
         alg_ws = AlgorithmManager.createUnmanaged("CreateWorkspace")
diff --git a/scripts/test/SANS/common/general_functions_test.py b/scripts/test/SANS/common/general_functions_test.py
index 434f9242e26295adadd79184f00c2796c1e0e1cd..a50282648ca696f4a607e704c6ac0b0defd47af6 100644
--- a/scripts/test/SANS/common/general_functions_test.py
+++ b/scripts/test/SANS/common/general_functions_test.py
@@ -7,7 +7,7 @@
 from __future__ import (absolute_import, division, print_function)
 import unittest
 from mantid.kernel import (V3D, Quat)
-from mantid.api import AnalysisDataService
+from mantid.api import AnalysisDataService, FrameworkManager
 from sans.common.general_functions import (quaternion_to_angle_and_axis, create_unmanaged_algorithm, add_to_sample_log,
                                            get_standard_output_workspace_name, sanitise_instrument_name,
                                            get_reduced_can_workspace_from_ads, write_hash_into_reduced_can_workspace,
@@ -22,6 +22,11 @@ from sans.state.data import StateData
 
 
 class SANSFunctionsTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _prepare_workspaces(number_of_workspaces, tagged_workspace_names=None, state=None, reduction_mode=None):
         create_name = "CreateSampleWorkspace"
diff --git a/scripts/test/SANS/common/log_tagger_test.py b/scripts/test/SANS/common/log_tagger_test.py
index 01b123df2b77f047e2cfbce41b8ab4e10b7c2934..6e1e6b0ec3e5a0032e539c0a4fdf643f4b5aab5c 100644
--- a/scripts/test/SANS/common/log_tagger_test.py
+++ b/scripts/test/SANS/common/log_tagger_test.py
@@ -6,12 +6,17 @@
 # SPDX - License - Identifier: GPL - 3.0 +
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
-from mantid.api import AlgorithmManager
+
+from mantid.api import AlgorithmManager, FrameworkManager
 from sans.common.log_tagger import (has_tag, set_tag, get_tag, has_hash, set_hash, get_hash_value)
 
 
 class SANSLogTaggerTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        FrameworkManager.Instance()
+
     @staticmethod
     def _provide_sample_workspace():
         alg = AlgorithmManager.createUnmanaged("CreateSampleWorkspace")
diff --git a/scripts/test/pythonTSVTest.py b/scripts/test/pythonTSVTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..53a5666c1a6759205e04887f57eb6d70d40d40fd
--- /dev/null
+++ b/scripts/test/pythonTSVTest.py
@@ -0,0 +1,148 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+import unittest
+
+from mantidqtpython import MantidQt
+import pythonTSV
+
+Name = "test"
+
+"""
+Returns a TSV
+to read from the input TSV
+"""
+def load_TSV(TSV):
+    string = TSV.outputLines()
+    return MantidQt.API.TSVSerialiser(string)
+
+"""
+Returns a TSV on the line Name
+"""
+def get_loaded_data(TSV,value):
+    load = load_TSV(TSV)
+    load.selectLine(Name)
+    return load
+
+# dummy class
+class Class(object):
+    def __init__(self):
+        self.a = "a"
+
+class PythonTSVTest(unittest.TestCase):
+
+    def test_saveDouble(self):
+        value = 1.1
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        pythonTSV.saveToTSV(TSV,value)
+        load =get_loaded_data(TSV,value)
+        self.assertEquals(value, load.readDouble())
+
+    def test_saveInt(self):
+        value = 1
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        pythonTSV.saveToTSV(TSV,value)
+        load =get_loaded_data(TSV,value)
+        self.assertEquals(value, load.readInt())
+
+    def test_saveString(self):
+        value = "string"
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        pythonTSV.saveToTSV(TSV,value)
+        load =get_loaded_data(TSV,value)
+        self.assertEquals(value, load.readString())
+ 
+    def test_saveBool(self):
+        value = False
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        pythonTSV.saveToTSV(TSV,value)
+        load =get_loaded_data(TSV,value)
+        self.assertEquals(value, load.readBool())
+
+    def test_saveClassFails(self):
+        value = Class()
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        with self.assertRaises(TypeError):
+             pythonTSV.saveToTSV(TSV,value)
+
+    def test_readDouble(self):
+        value = 1.1
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        TSV.storeDouble(value)
+        load =load_TSV(TSV)
+        self.assertEquals(value, pythonTSV.loadFromTSV(load,Name,3.3))
+
+
+    def test_readInt(self):
+        value = 1
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        TSV.storeInt(value)
+        load =load_TSV(TSV)
+        self.assertEquals(value, pythonTSV.loadFromTSV(load,Name,3))
+
+    def test_saveString(self):
+        value = "string"
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        TSV.storeString(value)
+        load =load_TSV(TSV)
+        self.assertEquals(value, pythonTSV.loadFromTSV(load,Name,"test"))
+
+    def test_saveBool(self):
+        value = False
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        TSV.storeBool(value)
+        load =load_TSV(TSV)
+        self.assertEquals(value, pythonTSV.loadFromTSV(load,Name,True))
+
+ 
+    def test_saveClassFails(self):
+        value = Class()
+        TSV = MantidQt.API.TSVSerialiser()
+        TSV.writeLine(Name)
+        TSV.storeString("doesn't matter what is stored")
+        load =load_TSV(TSV)
+        with self.assertRaises(TypeError):
+            pythonTSV.loadFromTSV(load,Name,value)
+
+    def test_makeLineNameSafeSpaces(self):
+        badName = "spaces fail"
+        newName = pythonTSV.makeLineNameSafe(badName)
+        self.assertEquals(newName,"SpacesFail")
+
+    def test_makeLineNameSafeUnderscores(self):
+        badName = "underscores_fail"
+        newName = pythonTSV.makeLineNameSafe(badName)
+        self.assertEquals(newName,"UnderscoresFail")
+
+    def test_makeLineNameSafeDashes(self):
+        badName = "dashes-fail"
+        newName = pythonTSV.makeLineNameSafe(badName)
+        self.assertEquals(newName,"DashesFail")
+
+    def test_writeLine(self):
+        badName = "bad name_example-here"
+        TSV = MantidQt.API.TSVSerialiser()
+        pythonTSV.writeLine(TSV, badName)
+        pi = 3.14159
+        TSV.storeDouble(pi)
+        load = load_TSV(TSV)
+        safeName = pythonTSV.makeLineNameSafe(badName)
+        load.selectLine(safeName)
+        self.assertEquals(pi, load.readDouble())
+        
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/tools/Pylint/run_pylint.py b/tools/Pylint/run_pylint.py
index 8b2bf451b7577eae9c9ba91dd238e55bb4e07241..3e41a68b2110dcc837c5ad2785f18d035e452c26 100644
--- a/tools/Pylint/run_pylint.py
+++ b/tools/Pylint/run_pylint.py
@@ -153,7 +153,7 @@ def parse_arguments(argv):
                       help="If provided, use the given format type "
                            "[default=%s]." % DEFAULT_PYLINT_FORMAT)
     parser.add_option("-m", "--mantidpath", dest="mantidpath", metavar="MANTIDPATH",
-                      help="If provided, use this as the MANTIDPATH, overriding"
+                      help="If provided, add this to the PYTHONPATH, overriding"
                            "anything that is currently set.")
     parser.add_option("-n", "--nofail", action="store_true",dest="nofail",
                       help="If specified, then script will always return an exit status of 0.")
@@ -209,8 +209,7 @@ def setup_environment(mantidpath):
 def setup_mantidpath(mantidpath):
     """
     Setup the environment ready for the subprocess call.
-    Inserts the given path at the front of the PYTHONPATH and
-    sets the MANTIDPATH variable
+    Inserts the given path at the front of the PYTHONPATH
 
     Args:
       mantidpath (str): A string that points to a directory containing
@@ -221,7 +220,6 @@ def setup_mantidpath(mantidpath):
         raise ValueError("Unable to find mantid python module in '%s'"
                          % mantidpath)
 
-    os.environ["MANTIDPATH"] = mantidpath
     cur_pypath = os.environ.get("PYTHONPATH", "")
     # for subprocesses
     os.environ["PYTHONPATH"] = mantidpath + os.pathsep + cur_pypath