diff --git a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Converters/PyObjectToString.h b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Converters/PyObjectToString.h
deleted file mode 100644
index 774cfcd81ce1860ef81b1ff9d3ddcc91832a4827..0000000000000000000000000000000000000000
--- a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Converters/PyObjectToString.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Mantid Repository : https://github.com/mantidproject/mantid
-//
-// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
-//     NScD Oak Ridge National Laboratory, European Spallation Source
-//     & Institut Laue - Langevin
-// SPDX - License - Identifier: GPL - 3.0 +
-#ifndef MANTID_PYTHONINERFACE_CONVERTERS_PYOBJECTTOSTRING_H_
-#define MANTID_PYTHONINERFACE_CONVERTERS_PYOBJECTTOSTRING_H_
-
-#include "MantidKernel/System.h"
-#include <boost/python/object.hpp>
-
-namespace Mantid {
-namespace PythonInterface {
-namespace Converters {
-
-/**
- * Convert a python object to a string or throw an exception. This will convert
- * unicode strings in python2 via utf8.
- */
-DLLExport std::string pyObjToStr(const boost::python::object &value);
-
-/// Return true if the supplied object can be converted to a string.
-DLLExport bool pyObjIsStr(const boost::python::object &value);
-
-} // namespace Converters
-} // namespace PythonInterface
-} // namespace Mantid
-
-#endif /* MANTID_PYTHONINERFACE_CONVERTERS_PYOBJECTTOSTRING_H_ */
diff --git a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/DataServiceExporter.h b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/DataServiceExporter.h
index 2a1a747e9833a3122dff107ca2f9defbfa460598..a500e91be5fce8defaf1483dfdf9079eb242d064 100644
--- a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/DataServiceExporter.h
+++ b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/DataServiceExporter.h
@@ -8,7 +8,6 @@
 #define MANTID_PYTHONINTERFACE_DATASERVICEEXPORTER_H_
 
 #include "MantidKernel/Exception.h"
-#include "MantidPythonInterface/kernel/Converters/PyObjectToString.h"
 #include "MantidPythonInterface/kernel/WeakPtr.h"
 
 #include <boost/python/class.hpp>
@@ -94,15 +93,9 @@ template <typename SvcType, typename SvcPtrType> struct DataServiceExporter {
    * @param name The name to assign to this in the service
    * @param item A boost.python wrapped SvcHeldType object
    */
-  static void addItem(SvcType &self, const boost::python::object &name,
+  static void addItem(SvcType &self, const std::string &name,
                       const boost::python::object &item) {
-    std::string namestr;
-    try {
-      namestr = PythonInterface::Converters::pyObjToStr(name);
-    } catch (std::invalid_argument &) {
-      throw std::invalid_argument("Failed to convert name to a string");
-    }
-    self.add(namestr, extractCppValue(item));
+    self.add(name, extractCppValue(item));
   }
 
   /**
@@ -112,15 +105,9 @@ template <typename SvcType, typename SvcPtrType> struct DataServiceExporter {
    * @param name The name to assign to this in the service
    * @param item A boost.python wrapped SvcHeldType object
    */
-  static void addOrReplaceItem(SvcType &self, const boost::python::object &name,
+  static void addOrReplaceItem(SvcType &self, const std::string &name,
                                const boost::python::object &item) {
-    std::string namestr;
-    try {
-      namestr = PythonInterface::Converters::pyObjToStr(name);
-    } catch (std::invalid_argument &) {
-      throw std::invalid_argument("Failed to convert name to a string");
-    }
-    self.addOrReplace(namestr, extractCppValue(item));
+    self.addOrReplace(name, extractCppValue(item));
   }
 
   /**
@@ -153,23 +140,15 @@ template <typename SvcType, typename SvcPtrType> struct DataServiceExporter {
    * @return A shared_ptr to the named object. If the name does not exist it
    * sets a KeyError error indicator.
    */
-  static WeakPtr retrieveOrKeyError(SvcType &self,
-                                    const boost::python::object &name) {
+  static WeakPtr retrieveOrKeyError(SvcType &self, const std::string &name) {
     using namespace Mantid::Kernel;
 
-    std::string namestr;
-    try {
-      namestr = PythonInterface::Converters::pyObjToStr(name);
-    } catch (std::invalid_argument &) {
-      throw std::invalid_argument("Failed to convert name to a string");
-    }
-
     SvcPtrType item;
     try {
-      item = self.retrieve(namestr);
+      item = self.retrieve(name);
     } catch (Exception::NotFoundError &) {
       // Translate into a Python KeyError
-      std::string err = "'" + namestr + "' does not exist.";
+      std::string err = "'" + name + "' does not exist.";
       PyErr_SetString(PyExc_KeyError, err.c_str());
       throw boost::python::error_already_set();
     }
diff --git a/Framework/PythonInterface/mantid/kernel/CMakeLists.txt b/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
index 3525553a96359bd64cda42dc425d49de3a02a24b..592357caa7ef4dee0d6de64dd7f16082e75f533d 100644
--- a/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
@@ -75,7 +75,6 @@ set ( SRC_FILES
   src/Converters/NDArrayToVector.cpp
   src/Converters/NumpyFunctions.cpp
   src/Converters/PyObjectToMatrix.cpp
-  src/Converters/PyObjectToString.cpp
   src/Converters/PyObjectToV3D.cpp
   src/Converters/PyObjectToVMD.cpp
   src/Registry/MappingTypeHandler.cpp
@@ -95,7 +94,6 @@ set ( INC_FILES
   ${HEADER_DIR}/kernel/Converters/NumpyFunctions.h
   ${HEADER_DIR}/kernel/Converters/NDArrayToVector.h
   ${HEADER_DIR}/kernel/Converters/PyObjectToMatrix.h
-  ${HEADER_DIR}/kernel/Converters/PyObjectToString.h
   ${HEADER_DIR}/kernel/Converters/PyObjectToV3D.h
   ${HEADER_DIR}/kernel/Converters/PyObjectToVMD.h
   ${HEADER_DIR}/kernel/Converters/PySequenceToVector.h
diff --git a/Framework/PythonInterface/mantid/kernel/src/Converters/PyObjectToString.cpp b/Framework/PythonInterface/mantid/kernel/src/Converters/PyObjectToString.cpp
deleted file mode 100644
index cd5b2e15d6bca01686c99f08c691ec5b19eb0ce2..0000000000000000000000000000000000000000
--- a/Framework/PythonInterface/mantid/kernel/src/Converters/PyObjectToString.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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 +
-#include "MantidPythonInterface/kernel/Converters/PyObjectToString.h"
-#include <boost/python/extract.hpp>
-#include <boost/python/str.hpp>
-
-using namespace boost;
-
-namespace Mantid {
-namespace PythonInterface {
-namespace Converters {
-
-std::string pyObjToStr(const python::object &value) {
-  python::extract<std::string> extractor(value);
-
-  std::string valuestr;
-  if (extractor.check()) {
-    valuestr = extractor();
-#if PY_VERSION_HEX < 0x03000000
-  } else if (PyUnicode_Check(value.ptr())) {
-    valuestr =
-        python::extract<std::string>(python::str(value).encode("utf-8"))();
-#endif
-  } else {
-    throw std::invalid_argument("Failed to convert python object a string");
-  }
-  return valuestr;
-}
-
-bool pyObjIsStr(const boost::python::object &value) {
-  python::extract<std::string> extractor(value);
-  if (extractor.check()) {
-    return true;
-#if PY_VERSION_HEX < 0x03000000
-  } else if (PyUnicode_Check(value.ptr())) {
-    return true;
-#endif
-  }
-
-  return false;
-}
-
-} // namespace Converters
-} // namespace PythonInterface
-} // namespace Mantid
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/ConfigService.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/ConfigService.cpp
index 451445db7934b39dc8134b13ea0c63ef69759634..8f76fdf8942a5839068f21d69075fdebfe61cd40 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/ConfigService.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/ConfigService.cpp
@@ -8,7 +8,6 @@
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/InstrumentInfo.h"
 #include "MantidKernel/WarningSuppressions.h"
-#include "MantidPythonInterface/kernel/Converters/PyObjectToString.h"
 #include "MantidPythonInterface/kernel/Converters/PySequenceToVector.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include "MantidPythonInterface/kernel/StlExportDefinitions.h"
@@ -23,82 +22,47 @@ using Mantid::Kernel::ConfigServiceImpl;
 using Mantid::Kernel::FacilityInfo;
 using Mantid::Kernel::InstrumentInfo;
 using Mantid::PythonInterface::Converters::PySequenceToVector;
-using Mantid::PythonInterface::Converters::pyObjIsStr;
-using Mantid::PythonInterface::Converters::pyObjToStr;
 
 using namespace boost::python;
 
+using ExtractStdString = boost::python::extract<std::string>;
+
 GET_POINTER_SPECIALIZATION(ConfigServiceImpl)
 
 namespace {
 /// Set directories from a python list
 void setDataSearchDirs(ConfigServiceImpl &self, const object &paths) {
-  if (pyObjIsStr(paths)) {
-    self.setDataSearchDirs(pyObjToStr(paths));
+  ExtractStdString singleString(paths);
+  if (singleString.check()) {
+    self.setDataSearchDirs(singleString());
   } else {
     self.setDataSearchDirs(PySequenceToVector<std::string>(paths)());
   }
 }
 
 /// Forward call from __getitem__ to getString with use_cache_true
-std::string getStringUsingCache(ConfigServiceImpl &self, const object &key) {
-  return self.getString(pyObjToStr(key), true);
-}
-
-bool hasProperty(ConfigServiceImpl &self, const object &name) {
-  return self.hasProperty(pyObjToStr(name));
-}
-
-const FacilityInfo &getFacility(ConfigServiceImpl &self, const object &name) {
-  return self.getFacility(pyObjToStr(name));
-}
-
-void setFacility(ConfigServiceImpl &self, const object &name) {
-  return self.setFacility(pyObjToStr(name));
-}
-
-void updateFacilities(ConfigServiceImpl &self, const object &filename) {
-  return self.updateFacilities(pyObjToStr(filename));
+std::string getStringUsingCache(ConfigServiceImpl &self,
+                                const std::string &key) {
+  return self.getString(key, true);
 }
 
 const InstrumentInfo &getInstrument(ConfigServiceImpl &self,
                                     const object &name = object()) {
-  if (name.ptr() == Py_None)
+  if (name.is_none())
     return self.getInstrument();
   else
-    return self.getInstrument(pyObjToStr(name));
-}
-
-std::string getString(ConfigServiceImpl &self, const object &name,
-                      bool use_cache = true) {
-  return self.getString(pyObjToStr(name), use_cache);
-}
-
-void setString(ConfigServiceImpl &self, const object &key,
-               const object &value) {
-  self.setString(pyObjToStr(key), pyObjToStr(value));
-}
-
-void appendDataSearchDir(ConfigServiceImpl &self, const object &path) {
-  self.appendDataSearchDir(pyObjToStr(path));
-}
-
-void appendDataSearchSubDir(ConfigServiceImpl &self, const object &subdir) {
-  self.appendDataSearchSubDir(pyObjToStr(subdir));
-}
-
-void saveConfig(ConfigServiceImpl &self, const object &filename) {
-  self.saveConfig(pyObjToStr(filename));
+    return self.getInstrument(ExtractStdString(name)());
 }
 
 GNU_DIAG_OFF("unused-local-typedef")
 // Ignore -Wconversion warnings coming from boost::python
 // Seen with GCC 7.1.1 and Boost 1.63.0
 GNU_DIAG_OFF("conversion")
-/// Overload generator for getInstrument
+// Overload generator for getInstrument
 BOOST_PYTHON_FUNCTION_OVERLOADS(getInstrument_Overload, getInstrument, 1, 2)
-/// Overload generator for getString
-BOOST_PYTHON_FUNCTION_OVERLOADS(getString_Overload, getString, 2, 3)
+// Overload generator for getString
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getStringOverload,
+                                       ConfigServiceImpl::getString, 1, 2)
 
 GNU_DIAG_ON("conversion")
 GNU_DIAG_ON("unused-local-typedef")
@@ -138,13 +102,18 @@ void export_ConfigService() {
                ConfigServiceImpl::getFacility,
            arg("self"), return_value_policy<reference_existing_object>(),
            "Returns the default facility")
-      .def("getFacility", &getFacility, (arg("self"), arg("facilityName")),
+      .def("getFacility",
+           (const FacilityInfo &(
+               ConfigServiceImpl::*)(const std::string &)const) &
+               ConfigServiceImpl::getFacility,
+           (arg("self"), arg("facilityName")),
            return_value_policy<reference_existing_object>(),
            "Returns the named facility. Raises an RuntimeError if it does not "
            "exist")
-      .def("setFacility", &setFacility, (arg("self"), arg("facilityName")),
+      .def("setFacility", &ConfigServiceImpl::setFacility,
+           (arg("self"), arg("facilityName")),
            "Sets the current facility to the given name")
-      .def("updateFacilities", &updateFacilities,
+      .def("updateFacilities", &ConfigServiceImpl::updateFacilities,
            (arg("self"), arg("fileName")),
            "Loads facility information from a provided file")
       .def("getInstrument", &getInstrument,
@@ -153,22 +122,24 @@ void export_ConfigService() {
                "default.instrument is returned",
                (arg("self"), arg("instrumentName") = boost::python::object()))
                [return_value_policy<copy_const_reference>()])
-      .def("getString", &getString,
-           getString_Overload(
-               "Returns the named key's value. If use_cache = "
-               "true [default] then relative paths->absolute",
-               (arg("self"), arg("key"), arg("use_cache") = true)))
-      .def("setString", &setString, (arg("self"), arg("key"), arg("value")),
+      .def(
+          "getString", &ConfigServiceImpl::getString,
+          getStringOverload("Returns the named key's value. If use_cache = "
+                            "true [default] then relative paths->absolute",
+                            (arg("self"), arg("key"), arg("use_cache") = true)))
+      .def("setString", &ConfigServiceImpl::setString,
+           (arg("self"), arg("key"), arg("value")),
            "Set the given property name. "
            "If it does not exist it is added to the current configuration")
-      .def("hasProperty", &hasProperty, (arg("self"), arg("rootName")))
+      .def("hasProperty", &ConfigServiceImpl::hasProperty,
+           (arg("self"), arg("rootName")))
       .def("getDataSearchDirs", &ConfigServiceImpl::getDataSearchDirs,
            arg("self"), return_value_policy<copy_const_reference>(),
            "Return the current list of data search paths")
-      .def("appendDataSearchDir", &appendDataSearchDir,
+      .def("appendDataSearchDir", &ConfigServiceImpl::appendDataSearchDir,
            (arg("self"), arg("path")),
            "Append a directory to the current list of data search paths")
-      .def("appendDataSearchSubDir", &appendDataSearchSubDir,
+      .def("appendDataSearchSubDir", &ConfigServiceImpl::appendDataSearchSubDir,
            (arg("self"), arg("subdir")),
            "Appends a sub-directory to each data search directory "
            "and appends the new paths back to datasearch directories")
@@ -176,7 +147,8 @@ void export_ConfigService() {
            (arg("self"), arg("searchDirs")),
            "Set the datasearch.directories property from a list of strings or "
            "a single ';' separated string.")
-      .def("saveConfig", &saveConfig, (arg("self"), arg("filename")),
+      .def("saveConfig", &ConfigServiceImpl::saveConfig,
+           (arg("self"), arg("filename")),
            "Saves the keys that have changed from their default to the given "
            "filename")
       .def("setLogLevel", &ConfigServiceImpl::setLogLevel,
@@ -187,8 +159,10 @@ void export_ConfigService() {
 
       // Treat this as a dictionary
       .def("__getitem__", &getStringUsingCache, (arg("self"), arg("key")))
-      .def("__setitem__", &setString, (arg("self"), arg("key"), arg("value")))
-      .def("__contains__", &hasProperty, (arg("self"), arg("key")))
+      .def("__setitem__", &ConfigServiceImpl::setString,
+           (arg("self"), arg("key"), arg("value")))
+      .def("__contains__", &ConfigServiceImpl::hasProperty,
+           (arg("self"), arg("key")))
       .def("Instance", &ConfigService::Instance,
            return_value_policy<reference_existing_object>(),
            "Returns a reference to the ConfigService")
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
index 299ed42ab1a4e10ecc89456628d62061141aaf36..7a5e51c61bd0c12ec7cf1bd99e3e6929ed2918ad 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
@@ -6,7 +6,6 @@
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "MantidKernel/IPropertyManager.h"
 #include "MantidKernel/IPropertySettings.h"
-#include "MantidPythonInterface/kernel/Converters/PyObjectToString.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include "MantidPythonInterface/kernel/Registry/PropertyValueHandler.h"
 #include "MantidPythonInterface/kernel/Registry/PropertyWithValueFactory.h"
@@ -24,8 +23,8 @@
 
 using namespace Mantid::Kernel;
 namespace Registry = Mantid::PythonInterface::Registry;
-namespace Converters = Mantid::PythonInterface::Converters;
 using namespace boost::python;
+using ExtractStdString = extract<std::string>;
 
 GET_POINTER_SPECIALIZATION(IPropertyManager)
 
@@ -38,30 +37,18 @@ namespace {
  * @param name :: The name of the property
  * @param value :: The value of the property as a bpl object
  */
-void setProperty(IPropertyManager &self, const boost::python::object &name,
+void setProperty(IPropertyManager &self, const std::string &name,
                  const boost::python::object &value) {
-  std::string namestr;
-  try {
-    namestr = Converters::pyObjToStr(name);
-  } catch (std::invalid_argument &) {
-    throw std::invalid_argument("Failed to convert property name to a string");
-  }
-
-  extract<std::string> valuecpp(value);
+  ExtractStdString valuecpp(value);
   if (valuecpp.check()) {
-    self.setPropertyValue(namestr, valuecpp());
-#if PY_VERSION_HEX < 0x03000000
-  } else if (PyUnicode_Check(value.ptr())) {
-    self.setPropertyValue(namestr,
-                          extract<std::string>(str(value).encode("utf-8"))());
-#endif
+    self.setPropertyValue(name, valuecpp());
   } else {
     try {
-      Property *p = self.getProperty(namestr);
+      Property *p = self.getProperty(name);
       const auto &entry = Registry::TypeRegistry::retrieve(*(p->type_info()));
-      entry.set(&self, namestr, value);
+      entry.set(&self, name, value);
     } catch (std::invalid_argument &e) {
-      throw std::invalid_argument("When converting parameter \"" + namestr +
+      throw std::invalid_argument("When converting parameter \"" + name +
                                   "\": " + e.what());
     }
   }
@@ -77,7 +64,7 @@ void setProperties(IPropertyManager &self, const boost::python::dict &kwargs) {
   auto begin = stl_input_iterator<object>(objectItems);
   auto end = stl_input_iterator<object>();
   for (auto it = begin; it != end; ++it) {
-    setProperty(self, (*it)[0], (*it)[1]);
+    setProperty(self, ExtractStdString((*it)[0])(), (*it)[1]);
   }
 }
 
@@ -88,11 +75,10 @@ void setProperties(IPropertyManager &self, const boost::python::dict &kwargs) {
  * @param name :: The name of the property
  * @param value :: The value of the property as a bpl object
  */
-void declareProperty(IPropertyManager &self, const boost::python::object &name,
+void declareProperty(IPropertyManager &self, const std::string &name,
                      boost::python::object value) {
-  std::string nameStr = Converters::pyObjToStr(name);
   auto p = std::unique_ptr<Property>(
-      Registry::PropertyWithValueFactory::create(nameStr, value, 0));
+      Registry::PropertyWithValueFactory::create(name, value, 0));
   self.declareProperty(std::move(p));
 }
 
@@ -104,11 +90,9 @@ void declareProperty(IPropertyManager &self, const boost::python::object &name,
  * @param name :: The name of the property
  * @param value :: The value of the property as a bpl object
  */
-void declareOrSetProperty(IPropertyManager &self,
-                          const boost::python::object &name,
+void declareOrSetProperty(IPropertyManager &self, const std::string &name,
                           boost::python::object value) {
-  std::string nameStr = Converters::pyObjToStr(name);
-  bool propExists = self.existsProperty(nameStr);
+  bool propExists = self.existsProperty(name);
   if (propExists) {
     setProperty(self, name, value);
   } else {
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/Logger.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/Logger.cpp
index 064e67dfbca5834361ea7643f362f41a60a029de..10e43a9f636189c0097241577aacba5fb24869ea 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/Logger.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/Logger.cpp
@@ -5,7 +5,6 @@
 //     & Institut Laue - Langevin
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "MantidKernel/Logger.h"
-#include "MantidPythonInterface/kernel/Converters/PyObjectToString.h"
 #include <boost/make_shared.hpp>
 #include <boost/python/class.hpp>
 #include <boost/python/make_constructor.hpp>
@@ -14,7 +13,7 @@
 
 using Mantid::Kernel::Logger;
 using namespace boost::python;
-namespace Converters = Mantid::PythonInterface::Converters;
+using LoggerMsgFunction = void (Logger::*)(const std::string &);
 
 namespace {
 /**
@@ -28,32 +27,8 @@ boost::shared_ptr<Logger> getLogger(const std::string &name) {
   return boost::make_shared<Logger>(name);
 }
 
-boost::shared_ptr<Logger> create(const boost::python::object &name) {
-  return boost::make_shared<Logger>(Converters::pyObjToStr(name));
-}
-
-void fatal(Logger *self, const boost::python::object &message) {
-  self->fatal(Converters::pyObjToStr(message));
-}
-
-void error(Logger *self, const boost::python::object &message) {
-  self->error(Converters::pyObjToStr(message));
-}
-
-void warning(Logger *self, const boost::python::object &message) {
-  self->warning(Converters::pyObjToStr(message));
-}
-
-void notice(Logger *self, const boost::python::object &message) {
-  self->notice(Converters::pyObjToStr(message));
-}
-
-void information(Logger *self, const boost::python::object &message) {
-  self->information(Converters::pyObjToStr(message));
-}
-
-void debug(Logger *self, const boost::python::object &message) {
-  self->debug(Converters::pyObjToStr(message));
+boost::shared_ptr<Logger> create(const std::string &name) {
+  return boost::make_shared<Logger>(name);
 }
 } // namespace
 
@@ -64,27 +39,33 @@ void export_Logger() {
       "Logger", init<std::string>((arg("self"), arg("name"))))
       .def("__init__",
            make_constructor(&create, default_call_policies(), args("name")))
-      .def("fatal", &fatal, (arg("self"), arg("message")),
+      .def("fatal", (LoggerMsgFunction)&Logger::fatal,
+           (arg("self"), arg("message")),
            "Send a message at fatal priority: "
            "An unrecoverable error has occured and the application will "
            "terminate")
-      .def("error", &error, (arg("self"), arg("message")),
+      .def("error", (LoggerMsgFunction)&Logger::error,
+           (arg("self"), arg("message")),
            "Send a message at error priority: "
            "An error has occured but the framework is able to handle it and "
            "continue")
-      .def("warning", &warning, (arg("self"), arg("message")),
+      .def("warning", (LoggerMsgFunction)&Logger::warning,
+           (arg("self"), arg("message")),
            "Send a message at warning priority: "
            "Something was wrong but the framework was able to continue despite "
            "the problem.")
-      .def("notice", &notice, (arg("self"), arg("message")),
+      .def("notice", (LoggerMsgFunction)&Logger::notice,
+           (arg("self"), arg("message")),
            "Sends a message at notice priority: "
            "Really important information that should be displayed to the user, "
            "this should be minimal. The default logging level is set here "
            "unless it is altered.")
-      .def("information", &information, (arg("self"), arg("message")),
+      .def("information", (LoggerMsgFunction)&Logger::information,
+           (arg("self"), arg("message")),
            "Send a message at information priority: "
            "Useful but not vital information to be relayed back to the user.")
-      .def("debug", &debug, (arg("self"), arg("message")),
+      .def("debug", (LoggerMsgFunction)&Logger::debug,
+           (arg("self"), arg("message")),
            "Send a message at debug priority:"
            ". Anything that may be useful to understand what the code has been "
            "doing for debugging purposes.")
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp
index 7bfa57ce02af5ac8214c5dc54c105772c04cadb2..f29a7668252e02da1151e3306ed2dd2ad8e05e0f 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/UsageService.cpp
@@ -5,30 +5,16 @@
 //     & Institut Laue - Langevin
 // SPDX - License - Identifier: GPL - 3.0 +
 #include "MantidKernel/UsageService.h"
-#include "MantidPythonInterface/kernel/Converters/PyObjectToString.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include <boost/python/class.hpp>
 #include <boost/python/reference_existing_object.hpp>
 
 using Mantid::Kernel::UsageService;
 using Mantid::Kernel::UsageServiceImpl;
-using Mantid::PythonInterface::Converters::pyObjToStr;
 using namespace boost::python;
 
 GET_POINTER_SPECIALIZATION(UsageServiceImpl)
 
-namespace {
-void setApplication(UsageServiceImpl *self, const object &name) {
-  self->setApplication(pyObjToStr(name));
-}
-
-void registerFeatureUsage(UsageServiceImpl *self, const object &type,
-                          const object &name, const bool internal) {
-  self->registerFeatureUsage(pyObjToStr(type), pyObjToStr(name), internal);
-}
-
-} // anonymous namespace
-
 void export_UsageService() {
 
   class_<UsageServiceImpl, boost::noncopyable>("UsageServiceImpl", no_init)
@@ -47,13 +33,14 @@ void export_UsageService() {
       .def("setInterval", &UsageServiceImpl::setEnabled,
            (arg("self"), arg("seconds")),
            "Sets the interval that the timer checks for tasks.")
-      .def("setApplication", &setApplication, (arg("self"), arg("name")),
+      .def("setApplication", &UsageServiceImpl::setApplication,
+           (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("registerStartup", &UsageServiceImpl::registerStartup, arg("self"),
            "Registers the startup of Mantid.")
-      .def("registerFeatureUsage", &registerFeatureUsage,
+      .def("registerFeatureUsage", &UsageServiceImpl::registerFeatureUsage,
            (arg("self"), arg("type"), arg("name"), arg("internal")),
            "Registers the use of a feature in Mantid.")
       .def("Instance", &UsageService::Instance,
diff --git a/Framework/PythonInterface/mantid/kernel/src/kernel.cpp.in b/Framework/PythonInterface/mantid/kernel/src/kernel.cpp.in
index bf2e1a8e1eeac7154f6fdeaae73d20308bfc2460..5dd67ec43bd340fd98c56994d26d92516f53993f 100644
--- a/Framework/PythonInterface/mantid/kernel/src/kernel.cpp.in
+++ b/Framework/PythonInterface/mantid/kernel/src/kernel.cpp.in
@@ -5,36 +5,70 @@
 //     & Institut Laue - Langevin
 // SPDX - License - Identifier: GPL - 3.0 +
 /*****************************************************************************************/
-/********** PLEASE NOTE! THIS FILE WAS AUTO-GENERATED FROM CMAKE.  ***********************/
-/********** Source = kernel.cpp.in *******************************************************/
+/********** PLEASE NOTE! THIS FILE WAS AUTO-GENERATED FROM CMAKE.
+ * ***********************/
+/********** Source = kernel.cpp.in
+ * *******************************************************/
 /*****************************************************************************************/
-#include <boost/python/module.hpp>
-#include <boost/python/docstring_options.hpp>
 #include <boost/python/def.hpp>
+#include <boost/python/docstring_options.hpp>
+#include <boost/python/module.hpp>
+#include <boost/python/type_id.hpp>
 
 #include "MantidKernel/MantidVersion.h"
 #include "MantidPythonInterface/core/NDArray.h"
-#include "MantidPythonInterface/kernel/kernel.h"
 #include "MantidPythonInterface/kernel/Registry/TypeRegistry.h"
+#include "MantidPythonInterface/kernel/kernel.h"
 
-// See http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
+// See
+// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
 #define PY_ARRAY_UNIQUE_SYMBOL KERNEL_ARRAY_API
 #include <numpy/arrayobject.h>
 
 // See comment in kernel.h
 #ifdef _WIN32
-void kernel_dll_import_numpy_capi_for_unittest() {
-  _import_array();
-}
+void kernel_dll_import_numpy_capi_for_unittest() { _import_array(); }
 #endif
 
 using boost::python::def;
+using boost::python::type_id;
+namespace converter = boost::python::converter;
 
 // Forward declare
 @EXPORT_DECLARE@
 
-BOOST_PYTHON_MODULE(_kernel)
-{
+#if PY_VERSION_HEX < 0x03000000
+    /**
+     * Adds a from_python converter to converter unicode strings to std::string
+     * by encoding them in utf-8 if possible. Adapted from
+     * https://www.boost.org/doc/libs/1_68_0/libs/python/doc/html/faq/how_can_i_automatically_convert_.html
+     */
+struct from_unicode_py2 {
+  from_unicode_py2() {
+    converter::registry::push_back(&convertible, &construct,
+                                   type_id<std::string>());
+  }
+  static void *convertible(PyObject *obj_ptr) {
+    return (PyUnicode_Check(obj_ptr)) ? obj_ptr : 0;
+  }
+  static void construct(PyObject *obj_ptr,
+                        converter::rvalue_from_python_stage1_data *data) {
+    PyObject *pyutf8 = PyUnicode_AsUTF8String(obj_ptr);
+    if (pyutf8 == 0)
+      boost::python::throw_error_already_set();
+    const char *value = PyString_AsString(pyutf8);
+    if (value == 0)
+      boost::python::throw_error_already_set();
+    Py_DECREF(pyutf8);
+    using rvalue_from_python_std_string = converter::rvalue_from_python_storage<std::string>;
+    void *storage = reinterpret_cast<rvalue_from_python_std_string*>(data)->storage.bytes;
+    new (storage) std::string(value);
+    data->convertible = storage;
+  }
+};
+#endif
+
+BOOST_PYTHON_MODULE(_kernel) {
   // Doc string options - User defined, python arguments, C++ call signatures
   boost::python::docstring_options docstrings(true, true, false);
   // Import numpy for the core DLL
@@ -57,8 +91,12 @@ BOOST_PYTHON_MODULE(_kernel)
   def("paper_citation", &Mantid::Kernel::MantidVersion::paperCitation,
       "Returns The citation for the Mantid paper");
 
+#if PY_VERSION_HEX < 0x03000000
+  // accept unicode strings wherever we see std::string (as long as they can be
+  // encoded in utf8)
+  from_unicode_py2();
+#endif
   Mantid::PythonInterface::Registry::TypeRegistry::registerBuiltins();
 
-
-@EXPORT_FUNCTIONS@
+  @EXPORT_FUNCTIONS@
 }
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/ConfigServiceTest.py b/Framework/PythonInterface/test/python/mantid/kernel/ConfigServiceTest.py
index 4149da46745b32f65bb5c14cff597a19baf80371..adca7f8fa8426fe75d3b0fda2cb9e054fc54a791 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/ConfigServiceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/ConfigServiceTest.py
@@ -13,6 +13,7 @@ import unittest
 
 from mantid.kernel import (ConfigService, ConfigServiceImpl, config,
                            std_vector_str, FacilityInfo, InstrumentInfo)
+import six
 
 class ConfigServiceTest(unittest.TestCase):
 
@@ -86,19 +87,36 @@ class ConfigServiceTest(unittest.TestCase):
         self.assertEquals(type(paths), std_vector_str)
         self.assert_(len(paths) > 0)
 
-    def test_setting_paths_via_single_string(self):
+    def test_setting_paths(self):
+        def do_test(paths):
+            config.setDataSearchDirs(paths)
+            newpaths = config.getDataSearchDirs()
+            # Clean up here do that if the assert fails
+            # it doesn't bring all the other tests down
+            self._clean_up_test_areas()
+            self.assertEqual(len(newpaths), 2)
+            self.assertTrue('tmp' in newpaths[0])
+            self.assertTrue('tmp_2' in newpaths[1])
+
         new_path_list = self._setup_test_areas()
-        path_str = ';'.join(new_path_list)
-        config.setDataSearchDirs(path_str)
-        paths = config.getDataSearchDirs()
-        # Clean up here do that if the assert fails
-        # it doesn't bring all the other tests down
-        self._clean_up_test_areas()
-
-        self.assertTrue(len(paths), 2)
-        self.assertTrue('tmp' in paths[0])
-        self.assertTrue('tmp_2' in paths[1])
-        self._clean_up_test_areas()
+        # test with list
+        do_test(new_path_list)
+
+        # reset test areas or the directories don't exist to be added
+        new_path_list = self._setup_test_areas()
+        # test with single string
+        do_test(';'.join(new_path_list))
+
+
+    def test_appending_paths(self):
+        new_path_list = self._setup_test_areas()
+        try:
+            config.appendDataSearchDir(six.text_type(new_path_list[0]))
+            updated_paths = config.getDataSearchDirs()
+        finally:
+            self._clean_up_test_areas()
+
+        self.assertEqual(4, len(updated_paths))
 
     def test_setting_log_channel_levels(self):
         testhelpers.assertRaisesNothing(self, config.setLogLevel, 4, True)
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py b/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py
index 0a40891da9a9861fb30054193019d27eed8dc56f..51bfa4ea937864757880efb081e6bd5450bb8886 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py
@@ -4,9 +4,10 @@
 #     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)
+from __future__ import (absolute_import, division, print_function, unicode_literals)
 
 import unittest
+
 from mantid.kernel import PropertyManager, PropertyManagerDataService
 
 class PropertyManagerDataServiceTest(unittest.TestCase):
diff --git a/docs/source/release/v3.14.0/framework.rst b/docs/source/release/v3.14.0/framework.rst
index b86aab3f45f78d3bf7d95913868a89b14140ff19..31971ef23f9b1ddc24980dba41f1b95425e1038b 100644
--- a/docs/source/release/v3.14.0/framework.rst
+++ b/docs/source/release/v3.14.0/framework.rst
@@ -14,16 +14,16 @@ Logging
 
 - We have changed the logging in Mantid to stop writing the high level version of the log to a file.  This had been causing numerous problems including inconsistent behaviour with multiple instances of Mantid, performance problems when logging at detailed levels, and excessive network usage in some scenarios.  This does not change the rest of the logging that you see in the message display in Mantidplot or the console window. A warning message will appear if configuration for the removed components of logging is found.
 
-  - Associated with this we have also simplified the python methods used to control logging.
+- Associated with this we have also simplified the python methods used to control logging.
 
-    .. code-block:: python
+.. code-block:: python
 
-	  	# The two methods
-	  	ConfigService.SetConsoleLogLevel(int)
-	  	ConfigService.SetFileLogLevel(int)
+   # The two methods
+   ConfigService.SetConsoleLogLevel(int)
+   ConfigService.SetFileLogLevel(int)
 
-	  	# Have been replaced by
-	  	ConfigService.SetLogLevel(int)
+   # Have been replaced by
+   ConfigService.SetLogLevel(int)
 
 Nexus Geometry Loading
 ----------------------
@@ -78,6 +78,7 @@ Python
 New
 ###
 
+- All python methods accepting basic strings now also accept unicode strings.
 - New python validator type: :class:`~mantid.geometry.OrientedLattice` checks whether a workspace has an oriented lattice object attached.
 - We have been making major performance improvements to geometry access in Mantid over the last few releases. We are now exposing these features via Python to give our users direct access to the same benefits as part of their scripts. The newly exposed objects are now available via workspaces and include:
 
diff --git a/qt/python/mantidqt/widgets/codeeditor/errorformatter.py b/qt/python/mantidqt/widgets/codeeditor/errorformatter.py
index 506a26233ebd36f94cf3ac084cf03b7ee8e0e84f..059cd7979bac8233998597cce0630f639d787e10 100644
--- a/qt/python/mantidqt/widgets/codeeditor/errorformatter.py
+++ b/qt/python/mantidqt/widgets/codeeditor/errorformatter.py
@@ -12,6 +12,9 @@ from __future__ import (absolute_import, unicode_literals)
 # std imports
 import traceback
 
+# third-party imports
+import six
+
 
 class ErrorFormatter(object):
     """Formats errors to strings"""
@@ -30,4 +33,10 @@ class ErrorFormatter(object):
         lines = traceback.format_exception_only(exc_type, exc_value)
         if stack is not None:
             lines.extend(traceback.format_list(stack))
+
+        if six.PY2:
+            # traceback always returns a list of ascii string objects
+            # encoded as utf-8 we want unicode to be consistent
+            # with using unicode_literals across the codebase
+            lines = map(lambda x: x.decode('utf-8') , lines)
         return ''.join(lines)
diff --git a/qt/python/mantidqt/widgets/codeeditor/test/test_errorformatter.py b/qt/python/mantidqt/widgets/codeeditor/test/test_errorformatter.py
index 323a16e471819f3463092447435d96f5afc0033f..53e3352705187ef881d0a5f5fa67acc5b96ecb12 100644
--- a/qt/python/mantidqt/widgets/codeeditor/test/test_errorformatter.py
+++ b/qt/python/mantidqt/widgets/codeeditor/test/test_errorformatter.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # Mantid Repository : https://github.com/mantidproject/mantid
 #
 # Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory UKRI,
@@ -13,6 +14,9 @@ import sys
 import traceback
 import unittest
 
+# third-party imports
+import six
+
 # local imports
 from mantidqt.widgets.codeeditor.errorformatter import ErrorFormatter
 
@@ -67,6 +71,24 @@ foo()
         for produced, expected in zip(error_lines, expected_lines):
             self.assertRegexpMatches(produced, expected)
 
+    def test_errors_containing_unicode_produce_expected_value_in_python2(self):
+        if not six.PY2:
+            # everything is already unicode in python > 2
+            return
+        try:
+            exec("é =")
+        except SyntaxError:
+            exc_type, exc_value = sys.exc_info()[:2]
+            formatter = ErrorFormatter()
+            error = formatter.format(exc_type, exc_value, None)
+
+        expected = """  File "<string>", line 1
+    é =
+    ^
+SyntaxError: invalid syntax
+"""
+        self.assertEqual(expected, error)
+
 
 if __name__ == "__main__":
     unittest.main()