diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt index fe0655675f91b6948921ffcf5e23375d1d1e97a0..5a6bcd5defe7a0d504161a5a7eb98b32dfb16b07 100644 --- a/Framework/CMakeLists.txt +++ b/Framework/CMakeLists.txt @@ -212,12 +212,11 @@ foreach(_bundle ${BUNDLES}) # Also ship mingw libraries for Inelastic fortran code. We need to do a # better job here and build things + file(GLOB MINGW_DLLS "${THIRD_PARTY_DIR}/bin/mingw/*.dll") if(WITH_PYTHON3) - install(FILES "${THIRD_PARTY_DIR}/bin/libquadmath-0.dll" "${THIRD_PARTY_DIR}/bin/libgcc_s_seh-1.dll" - DESTINATION ${_bundle}scripts/Inelastic) - else() - file(GLOB MINGW_DLLS "${THIRD_PARTY_DIR}/bin/mingw/*.dll") install(FILES ${MINGW_DLLS} DESTINATION ${_bundle}scripts/Inelastic) + else() + install(FILES ${MINGW_DLLS} DESTINATION ${_bundle}scripts/Inelastic/cp27) endif() else() install(DIRECTORY ../scripts/ diff --git a/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp b/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp index 04487b0b3f10dae8f707ec633aa0d27ab0ed9b9f..bab4eb01270f0e17ad3fdc8edb7725a0aea4fee3 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp @@ -362,10 +362,7 @@ void addRowFromDict(ITableWorkspace &self, const dict &rowItems) { // Wrong type of data for one of the columns if (PyErr_ExceptionMatches(PyExc_TypeError)) { std::ostringstream msg; - msg << "Wrong datatype <"; - msg << std::string( - extract<std::string>(value.attr("__class__").attr("__name__"))); - msg << "> for column <" << col->name() << "> "; + msg << "Wrong datatype for column <" << col->name() << "> "; msg << "(expected <" << col->type() << ">)"; PyErr_SetString(PyExc_TypeError, msg.str().c_str()); } @@ -410,10 +407,7 @@ void addRowFromSequence(ITableWorkspace &self, const object &rowItems) { // Wrong type of data for one of the columns if (PyErr_ExceptionMatches(PyExc_TypeError)) { std::ostringstream msg; - msg << "Wrong datatype <"; - msg << std::string( - extract<std::string>(value.attr("__class__").attr("__name__"))); - msg << "> for column <" << col->name() << "> "; + msg << "Wrong datatype for column <" << col->name() << "> "; msg << "(expected <" << col->type() << ">)"; PyErr_SetString(PyExc_TypeError, msg.str().c_str()); } diff --git a/Framework/PythonInterface/mantid/plots/scales.py b/Framework/PythonInterface/mantid/plots/scales.py index a2a08bc74f08bf7c13fbf2ddd0cd4df754213bc9..2c7167d7dcf0345bed11b5ed9c37207f5d641ebf 100644 --- a/Framework/PythonInterface/mantid/plots/scales.py +++ b/Framework/PythonInterface/mantid/plots/scales.py @@ -10,6 +10,7 @@ Defines a set of custom axis scales """ from __future__ import (absolute_import, division, unicode_literals) +from mantid.plots.utility import mpl_version_info from matplotlib.scale import ScaleBase from matplotlib.ticker import (AutoLocator, NullFormatter, NullLocator, ScalarFormatter) @@ -24,7 +25,7 @@ class PowerScale(ScaleBase): # commands name = 'power' - def __init__(self, _, **kwargs): + def __init__(self, _axis, **kwargs): """ Any keyword arguments passed to ``set_xscale`` and ``set_yscale`` will be passed along to the scale's @@ -32,7 +33,10 @@ class PowerScale(ScaleBase): gamma: The power used to scale the data. """ - super(PowerScale, self).__init__() + if mpl_version_info() > (3,): + super(PowerScale, self).__init__(_axis) + else: + super(PowerScale, self).__init__() gamma = kwargs.pop("gamma", None) if gamma is None: raise ValueError("power scale must specify gamma value") diff --git a/Framework/PythonInterface/test/python/mantid/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/CMakeLists.txt index 98adea1df09bb6b82a968233c497eaf156157358..aa8120c4a53c35c25e52cb456f049920feb5baa8 100644 --- a/Framework/PythonInterface/test/python/mantid/CMakeLists.txt +++ b/Framework/PythonInterface/test/python/mantid/CMakeLists.txt @@ -14,7 +14,9 @@ set(TEST_PY_FILES SimpleAPIRenameWorkspaceTest.py FitFunctionsTest.py) -if(MAKE_VATES) +# ParaView is unused and will be removed in the future. Effort to fix Python tests +# is not worth it +if(MAKE_VATES AND NOT MSVC) list(APPEND TEST_PY_FILES PVPythonTest.py) endif() diff --git a/Framework/PythonInterface/test/python/mantid/api/ITableWorkspaceTest.py b/Framework/PythonInterface/test/python/mantid/api/ITableWorkspaceTest.py index 001c44338f51fb759d2995db96f939160c27df85..ed52b2e82b08c813e9f52204cee5823454e2d8c8 100644 --- a/Framework/PythonInterface/test/python/mantid/api/ITableWorkspaceTest.py +++ b/Framework/PythonInterface/test/python/mantid/api/ITableWorkspaceTest.py @@ -35,8 +35,8 @@ class ITableWorkspaceTest(unittest.TestCase): self.assertEqual(type(column_names), list) def test_cell_access_returns_variables_as_native_python_types(self): - self.assertAlmostEquals(self._test_ws.cell('r_gd_prtn_chrg',0), 10.040912628173828, 15) - self.assertAlmostEquals(self._test_ws.cell(0, 7), 10.040912628173828, 15) + self.assertAlmostEqual(self._test_ws.cell('r_gd_prtn_chrg',0), 10.040912628173828, 15) + self.assertAlmostEqual(self._test_ws.cell(0, 7), 10.040912628173828, 15) self.assertEqual(self._test_ws.cell('r_goodfrm', 0), 9229) self.assertEqual(self._test_ws.cell(0, 9), 9229) diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py index 80883ff430b2ed527af5a5851055fb781a316b63..fecdc8673d2dd89186ba2f9dd36dd68a5ecf1a15 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py @@ -220,8 +220,10 @@ class ComputeCalibrationCoefVanTest(unittest.TestCase): Bcoef = 3.0*integral*1e+20*hbar*hbar/(2.0*mvan*k*389.0) dwf = np.exp( -1.0*Bcoef*(4.0*np.pi*np.sin(0.5*np.radians(15.0))/4.0)**2) - self.assertEqual(100./dwf, wsoutput.readY(1)[0]) - self.assertEqual(10./dwf, wsoutput.readE(1)[0]) + self.assertAlmostEqual(100./dwf, wsoutput.readY(1)[0], + places=12) + self.assertAlmostEqual(10./dwf, wsoutput.readE(1)[0], + places=12) if __name__ == "__main__": diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/BayesStretchTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/BayesStretchTest.py index 7fb7061cb96a9ecf3476c244fde8b38df2df13ca..0c589f528f4c96bc21cbac71ba29efe9d3ac47a3 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/BayesStretchTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/BayesStretchTest.py @@ -105,22 +105,23 @@ if platform.system() == "Windows": # Test values of contour contour_ws_0 = contour.getItem(0) - self.assertEqual(round(contour_ws_0.dataY(13)[11],49), 2.8026e-45) - self.assertEqual(round(contour_ws_0.dataY(14)[11],47), 7.41147e-42) - self.assertEqual(round(contour_ws_0.dataY(15)[11],49), 1.26117e-44) - self.assertEqual(round(contour_ws_0.dataY(15)[12],46), 2.49389e-41) + tol_places = 10 + self.assertAlmostEqual(contour_ws_0.dataY(13)[11], 0., places=tol_places) + self.assertAlmostEqual(contour_ws_0.dataY(14)[11], 0., places=tol_places) + self.assertAlmostEqual(contour_ws_0.dataY(15)[11], 0., places=tol_places) + self.assertAlmostEqual(contour_ws_0.dataY(15)[12], 0., places=tol_places) # Test values of fit_group fit_ws_sigma = fit_group.getItem(0) - self.assertEqual(round(fit_ws_sigma.dataY(0)[13],49), 2.8026e-45) - self.assertEqual(round(fit_ws_sigma.dataY(0)[14],46), 7.4115e-42) - self.assertEqual(round(fit_ws_sigma.dataY(0)[48],39), 9.87282e-34) - self.assertEqual(round(fit_ws_sigma.dataY(0)[49],45), 1.74277e-40) + self.assertAlmostEqual(fit_ws_sigma.dataY(0)[13], 0., places=tol_places) + self.assertAlmostEqual(fit_ws_sigma.dataY(0)[14], 0., places=tol_places) + self.assertAlmostEqual(fit_ws_sigma.dataY(0)[48], 0., places=tol_places) + self.assertAlmostEqual(fit_ws_sigma.dataY(0)[49], 0., places=tol_places) fit_ws_beta = fit_group.getItem(1) - self.assertEqual(round(fit_ws_beta.dataY(0)[11],47), 7.16204e-42) - self.assertEqual(round(fit_ws_beta.dataY(0)[12],33), 1.3059e-29) - self.assertEqual(round(fit_ws_beta.dataY(0)[21],33), 1.15045e-28) - self.assertEqual(round(fit_ws_beta.dataY(0)[22],49), 8.96831e-44) + self.assertAlmostEqual(fit_ws_beta.dataY(0)[11], 0., places=tol_places) + self.assertAlmostEqual(fit_ws_beta.dataY(0)[12], 0., places=tol_places) + self.assertAlmostEqual(fit_ws_beta.dataY(0)[21], 0., places=tol_places) + self.assertAlmostEqual(fit_ws_beta.dataY(0)[22], 0., places=tol_places) if __name__=="__main__": diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/IndirectReplaceFitResultTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/IndirectReplaceFitResultTest.py index a35c2c2264db3081fe036214ccc9724a112d5107..fca9d06b0df78b49cd68d0ab2f9bb7b39f441b0d 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/IndirectReplaceFitResultTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/IndirectReplaceFitResultTest.py @@ -10,7 +10,7 @@ import unittest from mantid.simpleapi import (CompareWorkspaces, ConvolutionFitSequential, ConvolutionFitSimultaneous, LoadNexus, IndirectReplaceFitResult, RenameWorkspace) from mantid.api import (AnalysisDataService, MatrixWorkspace, WorkspaceGroup) -import platform +from mantid.buildconfig import GSL_VERSION def get_ads_workspace(workspace_name): @@ -36,7 +36,7 @@ def get_sequential_input_string(workspace_name, number_of_histograms): def current_os_has_gslv2(): """ Check whether the current OS is using GSLv2 """ - return platform.linux_distribution()[0].lower() == 'ubuntu' or platform.mac_ver()[0] != '' + return int(GSL_VERSION[0]) >= 2 class IndirectReplaceFitResultTest(unittest.TestCase): diff --git a/MantidPlot/test/MantidPlotMatplotlibTest.py b/MantidPlot/test/MantidPlotMatplotlibTest.py index b97c04de399a28b9d6a5249c070711e0cca8341c..960ae0399ed94e44c731819c4ced70ee0753298e 100644 --- a/MantidPlot/test/MantidPlotMatplotlibTest.py +++ b/MantidPlot/test/MantidPlotMatplotlibTest.py @@ -24,6 +24,24 @@ try: except ImportError: HAVE_MPL = False + +def bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, + mux=0.0, muy=0.0, sigmaxy=0.0): + """ + Bivariate Gaussian distribution for equal shape *X*, *Y*. + See `bivariate normal + <http://mathworld.wolfram.com/BivariateNormalDistribution.html>`_ + at mathworld. + """ + Xmu = X-mux + Ymu = Y-muy + + rho = sigmaxy/(sigmax*sigmay) + z = Xmu**2/sigmax**2 + Ymu**2/sigmay**2 - 2*rho*Xmu*Ymu/(sigmax*sigmay) + denom = 2*np.pi*sigmax*sigmay*np.sqrt(1-rho**2) + return np.exp(-z/(2*(1-rho**2))) / denom + + class MantidPlotMatplotlibTest(unittest.TestCase): def setUp(self): @@ -44,8 +62,8 @@ class MantidPlotMatplotlibTest(unittest.TestCase): delta = 0.025 x = y = np.arange(-3.0, 3.0, delta) X, Y = np.meshgrid(x, y) - Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) - Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) + Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) + Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) Z = Z2 - Z1 # difference of Gaussians im = plt.imshow(Z, interpolation='bilinear', cmap=cm.RdYlGn, diff --git a/MantidPlot/test/MantidPlotProjectSerialiseTest.py b/MantidPlot/test/MantidPlotProjectSerialiseTest.py index 12c9a4b1f1bf67934fda68fedd29cc5e060502eb..ce2ec3f486412099d926aa98be9e8e56f582375f 100644 --- a/MantidPlot/test/MantidPlotProjectSerialiseTest.py +++ b/MantidPlot/test/MantidPlotProjectSerialiseTest.py @@ -7,6 +7,8 @@ """ Test of basic project saving and loading """ +import io + import mantidplottests from mantidplottests import * import shutil @@ -388,7 +390,7 @@ def get_project_file_contents(folder_name): project_name = os.path.basename(folder_name) + '.mantid' project_file = os.path.join(folder_name, project_name) - with open(project_file, 'r') as file_handle: + with io.open(project_file, 'r', encoding='utf-8') as file_handle: contents = file_handle.read() return contents diff --git a/Testing/SystemTests/tests/analysis/PVPythonTest.py b/Testing/SystemTests/tests/analysis/PVPythonTest.py index accba6e60e6d7b83c08a9c3b18f317b051c70efe..a6e3ed184729da5110102cce9df31afb1fddc537 100644 --- a/Testing/SystemTests/tests/analysis/PVPythonTest.py +++ b/Testing/SystemTests/tests/analysis/PVPythonTest.py @@ -5,11 +5,15 @@ # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + #pylint: disable=W0232,R0903 +import sys import systemtesting class PVPythonTest(systemtesting.MantidSystemTest): + def skipTests(self): + return sys.platform == 'win32' + def runTest(self): # Make Vates/ParaView a soft requirement rather than failing on module import # when determining what tests to run. diff --git a/Testing/SystemTests/tests/analysis/SXDAnalysis.py b/Testing/SystemTests/tests/analysis/SXDAnalysis.py index e4540228de4f55ac58850dda4c480360c81f18a2..8b53ea9fad284b1d01b0386d86843e786d2a867b 100644 --- a/Testing/SystemTests/tests/analysis/SXDAnalysis.py +++ b/Testing/SystemTests/tests/analysis/SXDAnalysis.py @@ -18,15 +18,11 @@ class SXDAnalysis(systemtesting.MantidSystemTest): def runTest(self): ws = Load(Filename='SXD23767.raw', LoadMonitors='Exclude') - #AddSampleLog(Workspace=ws,LogName='NUM_THREADS',LogText='0',LogType='Number') - from time import clock # A lower SplitThreshold, with a reasonable bound on the recursion depth, helps find weaker peaks at higher Q. - start = clock() QLab = ConvertToDiffractionMDWorkspace(InputWorkspace=ws, OutputDimensions='Q (lab frame)', SplitThreshold=50, LorentzCorrection='1',MaxRecursionDepth='13', Extents='-15,15,-15,15,-15,15',OneEventPerBin='0') - print(" ConvertToMD runs for: ",clock()-start,' sec') # NaCl has a relatively small unit cell, so the distance between peaks is relatively large. Setting the PeakDistanceThreshold # higher avoids finding high count regions on the sides of strong peaks as separate peaks. diff --git a/buildconfig/CMake/Bootstrap.cmake b/buildconfig/CMake/Bootstrap.cmake index 393fa287038e230648ad2b0e0385030a8d8b2db0..d3c010845623cf793daa8d4b5c21500896782100 100644 --- a/buildconfig/CMake/Bootstrap.cmake +++ b/buildconfig/CMake/Bootstrap.cmake @@ -17,7 +17,7 @@ if(MSVC) set(THIRD_PARTY_GIT_URL "https://github.com/mantidproject/thirdparty-msvc2015.git" ) - set(THIRD_PARTY_GIT_SHA1 a7bd18f35c8d67e68c3a965a07057efa266fc7d7) + set(THIRD_PARTY_GIT_SHA1 dfaaaa4dbb5c90127e6b3e540710a29856227447) set(THIRD_PARTY_DIR ${EXTERNAL_ROOT}/src/ThirdParty) # Generates a script to do the clone/update in tmp set(_project_name ThirdParty) diff --git a/buildconfig/CMake/FindPyQt.py b/buildconfig/CMake/FindPyQt.py index b25705f7c35b731171dd2c48885f807338bed77c..8cdde6b118710c799b7cfd85d9e73a4387ee9ccd 100644 --- a/buildconfig/CMake/FindPyQt.py +++ b/buildconfig/CMake/FindPyQt.py @@ -32,7 +32,10 @@ class PyQtConfig(object): # default case where installation paths have not been changed in PyQt's # configuration process. if sys.platform == 'win32': - self.sip_dir = os.path.join(sys.prefix, 'sip', name) + if sys.version_info > (3,): + self.sip_dir = os.path.join(sys.prefix, 'share', 'sip', name) + else: + self.sip_dir = os.path.join(sys.prefix, 'sip', name) elif sys.platform == 'darwin': # hardcoded to homebrew Cellar cellar_prefix = '/usr/local/opt' diff --git a/buildconfig/CMake/MSVCSetup.cmake b/buildconfig/CMake/MSVCSetup.cmake index 42e7b1735be2a0305989acc1c8eaf9833a296353..3286a3d322361578820e1cc997ceede4d4ebe1bd 100644 --- a/buildconfig/CMake/MSVCSetup.cmake +++ b/buildconfig/CMake/MSVCSetup.cmake @@ -116,7 +116,11 @@ configure_file ( ${WINDOWS_BUILDCONFIG}/pycharm.bat.in ${PROJECT_BINARY_DIR}/pyc ########################################################################### set ( PACKAGING_DIR ${PROJECT_SOURCE_DIR}/buildconfig/CMake/Packaging ) # build version -set ( MANTIDPYTHON_PREAMBLE "call %~dp0..\\..\\thirdpartypaths.bat\nset PATH=%_BIN_DIR%;%_BIN_DIR%\\PVPlugins\\PVPlugins;%PATH%" ) +if(WITH_PYTHON3) + set ( MANTIDPYTHON_PREAMBLE "set PYTHONHOME=${MSVC_PYTHON_EXECUTABLE_DIR}\nset PATH=%_BIN_DIR%;%_BIN_DIR%\\PVPlugins\\PVPlugins;%PATH%" ) +else() + set ( MANTIDPYTHON_PREAMBLE "call %~dp0..\\..\\thirdpartypaths.bat\nset PATH=%_BIN_DIR%;%_BIN_DIR%\\PVPlugins\\PVPlugins;%PATH%" ) +endif() if ( MAKE_VATES ) set ( PARAVIEW_PYTHON_PATHS ";${ParaView_DIR}/bin/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>;${ParaView_DIR}/lib/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>;${ParaView_DIR}/lib/site-packages;${ParaView_DIR}/lib/site-packages/vtk" ) diff --git a/buildconfig/CMake/Packaging/mantidpython.bat.in b/buildconfig/CMake/Packaging/mantidpython.bat.in index 4a3d510d80548fdf90430ee2447d0907a7a15c65..a3f8e560dcda00d94cec0651bd0420dbaf142966 100644 --- a/buildconfig/CMake/Packaging/mantidpython.bat.in +++ b/buildconfig/CMake/Packaging/mantidpython.bat.in @@ -14,7 +14,11 @@ set _BIN_DIR=%_SCRIPT_DIR:~,-1% :: Set paths for dependencies, including Python @MANTIDPYTHON_PREAMBLE@ -set PYTHONPATH=%_BIN_DIR%;%PYTHONPATH%@PARAVIEW_PYTHON_PATHS@ +if exist "%PYTHONHOME%\Lib\site-packages\PyQt4\sip.pyd" ( + set _sip_dir=%PYTHONHOME%\Lib\site-packages\PyQt4 +) + +set PYTHONPATH=%_BIN_DIR%;%_sip_dir%;%PYTHONPATH%@PARAVIEW_PYTHON_PATHS@ :: Python drivers set _PYTHON_EXE=%PYTHONHOME%\python.exe diff --git a/qt/applications/workbench/workbench/plotting/test/test_globalfiguremanager.py b/qt/applications/workbench/workbench/plotting/test/test_globalfiguremanager.py index bcc501286c05617573302b14585de963eb9426c5..3aa9b0dc451250d4053cd70519b840110eb3193e 100644 --- a/qt/applications/workbench/workbench/plotting/test/test_globalfiguremanager.py +++ b/qt/applications/workbench/workbench/plotting/test/test_globalfiguremanager.py @@ -1,24 +1,23 @@ import unittest -from mantid.py3compat import mock -from mock import call, patch +from mantid.py3compat.mock import Mock, call, patch from workbench.plotting.globalfiguremanager import FigureAction, GlobalFigureManager, GlobalFigureManagerObserver from workbench.plotting.observabledictionary import DictionaryAction class MockGlobalFigureManager: def __init__(self): - self.notify_observers = mock.Mock() + self.notify_observers = Mock() self.mock_figs = {} - self.figs = mock.Mock() - self.figs.keys = mock.Mock(return_value=self.mock_figs) + self.figs = Mock() + self.figs.keys = Mock(return_value=self.mock_figs) class MockCanvas: def __init__(self): - self.mpl_disconnect = mock.Mock() + self.mpl_disconnect = Mock() self.figure = None - self.draw_idle = mock.Mock() + self.draw_idle = Mock() class MockFigureManager: @@ -26,7 +25,7 @@ class MockFigureManager: self.num = num self.canvas = MockCanvas() self._cidgcf = -1231231 - self.destroy = mock.Mock() + self.destroy = Mock() class TestGlobalFigureManagerObserver(unittest.TestCase): @@ -90,7 +89,7 @@ class TestGlobalFigureManager(unittest.TestCase): def add_manager(self, num=0): mock_manager = MockFigureManager(num) - mock_fig = mock.Mock() + mock_fig = Mock() mock_manager.canvas.figure = mock_fig GlobalFigureManager.set_active(mock_manager) return mock_manager, mock_fig @@ -169,7 +168,7 @@ class TestGlobalFigureManager(unittest.TestCase): num = 0 self.add_manager(num) - other_mock_fig = mock.Mock() + other_mock_fig = Mock() other_mock_manager = MockFigureManager(num + 1) other_mock_manager.canvas.figure = other_mock_fig GlobalFigureManager.set_active(other_mock_manager) @@ -259,8 +258,8 @@ class TestGlobalFigureManager(unittest.TestCase): self.assertEqual({0: 4, 1: 3, 2: 2, 3: 1}, last_active_values) def test_add_observer(self): - good_observer = mock.Mock() - good_observer.notify = mock.Mock() + good_observer = Mock() + good_observer.notify = Mock() self.assertTrue(1, len(GlobalFigureManager.observers)) def test_fail_adding_bad_observer(self): @@ -275,8 +274,8 @@ class TestGlobalFigureManager(unittest.TestCase): num = 10 mock_observers = [] for i in range(num): - good_observer = mock.Mock() - good_observer.notify = mock.Mock() + good_observer = Mock() + good_observer.notify = Mock() GlobalFigureManager.add_observer(good_observer) mock_observers.append(good_observer) diff --git a/qt/applications/workbench/workbench/widgets/settings/general/presenter.py b/qt/applications/workbench/workbench/widgets/settings/general/presenter.py index 553d1d6c3f9030ae1a4cefa63936353d947a388b..49b8fd41e10d7f7f2431e3f8d325051bbda0cd3a 100644 --- a/qt/applications/workbench/workbench/widgets/settings/general/presenter.py +++ b/qt/applications/workbench/workbench/widgets/settings/general/presenter.py @@ -102,8 +102,8 @@ class GeneralSettings(object): ConfigService.setString(self.USE_NOTIFICATIONS, "On" if bool(state) else "Off") def load_current_setting_values(self): - self.view.prompt_save_on_close.setChecked(CONF.get(self.PROMPT_SAVE_ON_CLOSE)) - self.view.prompt_save_editor_modified.setChecked(CONF.get(self.PROMPT_SAVE_EDITOR_MODIFIED)) + self.view.prompt_save_on_close.setChecked(bool(CONF.get(self.PROMPT_SAVE_ON_CLOSE))) + self.view.prompt_save_editor_modified.setChecked(bool(CONF.get(self.PROMPT_SAVE_EDITOR_MODIFIED))) # compare lower-case, because MantidPlot will save it as lower case, # but Python will have the bool's first letter capitalised diff --git a/qt/applications/workbench/workbench/widgets/settings/general/test/test_general_settings.py b/qt/applications/workbench/workbench/widgets/settings/general/test/test_general_settings.py index 0175665a486f91ce2cf373f3902223b7e86c36b8..f133f51536fc58104230ea5258645759944dee43 100644 --- a/qt/applications/workbench/workbench/widgets/settings/general/test/test_general_settings.py +++ b/qt/applications/workbench/workbench/widgets/settings/general/test/test_general_settings.py @@ -157,18 +157,18 @@ class GeneralSettingsTest(unittest.TestCase): # load current setting is called automatically in the constructor GeneralSettings(None) - # calls().__int__() are the calls to int() on the retrieved value from ConfigService.getString - # In python 3.8 it falls back to __index__() if __int__() is not defined - if sys.version_info < (3, 8): + # calls().__bool__() are the calls to bool() on the retrieved value from ConfigService.getString + # In python 3 it __bool__ is called otherwise __nonzero__ is used + if sys.version_info < (3,): mock_CONF.get.assert_has_calls([call(GeneralSettings.PROMPT_SAVE_ON_CLOSE), - call().__int__(), + call().__nonzero__(), call(GeneralSettings.PROMPT_SAVE_EDITOR_MODIFIED), - call().__int__()]) + call().__nonzero__()]) else: mock_CONF.get.assert_has_calls([call(GeneralSettings.PROMPT_SAVE_ON_CLOSE), - call().__index__(), + call().__bool__(), call(GeneralSettings.PROMPT_SAVE_EDITOR_MODIFIED), - call().__index__()]) + call().__bool__()]) mock_ConfigService.getString.assert_has_calls([call(GeneralSettings.PR_RECOVERY_ENABLED), call(GeneralSettings.PR_TIME_BETWEEN_RECOVERY), diff --git a/qt/python/mantidqt/project/test/test_workspacesaver.py b/qt/python/mantidqt/project/test/test_workspacesaver.py index 7f6a9110c5c36c8aa4107a0b97b4f5bc731bd28b..472c6e4014b9302b422732a4a0d74091606e8107 100644 --- a/qt/python/mantidqt/project/test/test_workspacesaver.py +++ b/qt/python/mantidqt/project/test/test_workspacesaver.py @@ -13,11 +13,11 @@ from os import listdir from os.path import isdir from shutil import rmtree import tempfile -import mock from mantid.api import AnalysisDataService as ADS, IMDEventWorkspace # noqa from mantid.dataobjects import MDHistoWorkspace, MaskWorkspace # noqa from mantidqt.project import workspacesaver +from mantid.py3compat import mock from mantid.simpleapi import (CreateSampleWorkspace, CreateMDHistoWorkspace, LoadMD, LoadMask, MaskDetectors, # noqa ExtractMask, GroupWorkspaces) # noqa diff --git a/qt/python/mantidqt/widgets/test/test_functionbrowser.py b/qt/python/mantidqt/widgets/test/test_functionbrowser.py index 3edf044c99b130284fc7e1b67f7339dcfafdb638..35586e6f2491cbcbff3436b7a2c8dec03cd8b87f 100644 --- a/qt/python/mantidqt/widgets/test/test_functionbrowser.py +++ b/qt/python/mantidqt/widgets/test/test_functionbrowser.py @@ -1,5 +1,4 @@ from __future__ import (absolute_import, division, print_function) -from mock import MagicMock, call import unittest from qtpy.QtWidgets import QApplication @@ -8,6 +7,7 @@ from qtpy.QtTest import QTest from mantid import FrameworkManager, FunctionFactory from mantid.fitfunctions import FunctionWrapper +from mantid.py3compat.mock import MagicMock, call from mantidqt.utils.qt.testing.gui_window_test import (GuiWindowTest, not_on_windows, get_child, click_on) from mantidqt.widgets.functionbrowser import FunctionBrowser diff --git a/qt/python/mantidqt/widgets/test/test_jupyterconsole.py b/qt/python/mantidqt/widgets/test/test_jupyterconsole.py index 03ccaa0caa94152b35aa5298a9a474121f9aa621..0a18ef49a8980bcd763bc614780f96577525048e 100644 --- a/qt/python/mantidqt/widgets/test/test_jupyterconsole.py +++ b/qt/python/mantidqt/widgets/test/test_jupyterconsole.py @@ -10,8 +10,11 @@ from __future__ import (absolute_import) # system imports -# import readline before QApplication starts to avoid segfault with IPython 5 and Python 3 -import readline # noqa +# import readline (if available) before QApplication starts to avoid segfault with IPython 5 and Python 3 +try: + import readline # noqa +except ImportError: + pass import unittest # third-party library imports diff --git a/qt/widgets/common/src/QtJSONUtils.cpp b/qt/widgets/common/src/QtJSONUtils.cpp index 5636be0513d5dfe71690e9bacee37db04e74096b..1b88c0a9c231433fe91d5393001afc27210bf3a7 100644 --- a/qt/widgets/common/src/QtJSONUtils.cpp +++ b/qt/widgets/common/src/QtJSONUtils.cpp @@ -18,8 +18,8 @@ #include <QTextStream> #endif -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) namespace { +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) // Code in anonymous namespace taken from stack overflow // https://stackoverflow.com/questions/4169988/easiest-way-to-parse-json-in-qt-4-7 // from user2243820 on 1st August 2019 @@ -111,8 +111,23 @@ public: return decodeInner(object); } }; -} // namespace #endif + +void writeData(const QString &filename, const QByteArray &data) { + QFile jsonFile(filename); + + if (!jsonFile.open(QFile::WriteOnly)) { + throw std::invalid_argument("Could not open file at " + + filename.toStdString()); + } + + if (jsonFile.write(data) == -1) { + throw std::runtime_error("Failed to write data to " + + filename.toStdString()); + } +} + +} // namespace namespace MantidQt { namespace API { void saveJSONToFile(QString &filename, const QMap<QString, QVariant> &map) { @@ -125,22 +140,22 @@ void saveJSONToFile(QString &filename, const QMap<QString, QVariant> &map) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) JSON JSON; auto jsonString = JSON.encode(map); - QFile jsonFile(filename); - jsonFile.open(QFile::WriteOnly); + QByteArray jsonByteArray; - jsonFile.write(jsonByteArray.append(jsonString)); + writeData(filename, jsonByteArray.append(jsonString)); #else QJsonDocument jsonDocument(QJsonObject::fromVariantMap(map)); - QFile jsonFile(filename); - jsonFile.open(QFile::WriteOnly); - jsonFile.write(jsonDocument.toJson()); + writeData(filename, jsonDocument.toJson()); #endif } QMap<QString, QVariant> loadJSONFromFile(const QString &filename) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QFile jsonFile(filename); - jsonFile.open(QFile::ReadOnly); + if (!jsonFile.open(QFile::ReadOnly)) { + throw std::invalid_argument("Cannot open file at: " + + filename.toStdString()); + } QString jsonString(jsonFile.readAll()); return loadJSONFromString(jsonString); #else @@ -149,8 +164,9 @@ QMap<QString, QVariant> loadJSONFromFile(const QString &filename) { * implementation of this function, from user alanwsx and edited by BSMP. */ QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) { - throw std::runtime_error("Failed to open " + filename.toStdString()); + if (!file.open(QFile::ReadOnly)) { + throw std::invalid_argument("Cannot open file at: " + + filename.toStdString()); } // step 2 diff --git a/qt/widgets/common/test/QtJSONUtilsTest.h b/qt/widgets/common/test/QtJSONUtilsTest.h index abe9de9e1df4f95617eeb438d139336b293e29ce..751f8bb3d4405810d1ecffbfebcda1814dfc77d6 100644 --- a/qt/widgets/common/test/QtJSONUtilsTest.h +++ b/qt/widgets/common/test/QtJSONUtilsTest.h @@ -12,6 +12,7 @@ #include <cxxtest/TestSuite.h> +#include <Poco/TemporaryFile.h> #include <QFile> #include <QMap> #include <QString> @@ -30,7 +31,8 @@ public: static void destroySuite(QtJSONUtilsTest *suite) { delete suite; } void test_saveJSONToFile_and_loadJSONFromFile() { - QString filename("/tmp/tempFile.json"); + Poco::TemporaryFile tmpFile; + QString filename(tmpFile.path().data()); auto map1 = constructJSONMap(); MantidQt::API::saveJSONToFile(filename, map1); @@ -38,7 +40,6 @@ public: testMaps(map1, map2); QFile file(filename); - file.remove(); } void test_loadJSONFromString() { diff --git a/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colors.h b/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colors.h index e82ce0efa081ec547c4ddcc8bdf7dd6b9917bbf5..aacdaf040b1c403ca07566d57d633621084c5a75 100644 --- a/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colors.h +++ b/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colors.h @@ -28,7 +28,7 @@ namespace MplCpp { class MANTID_MPLCPP_DLL NormalizeBase : public Common::Python::InstanceHolder { public: /// Autoscale the limits to vmin, vmax, clamping any invalid values - std::tuple<double, double> autoscale(std::tuple<double, double> clim); + virtual std::tuple<double, double> autoscale(std::tuple<double, double> clim); /// Return an appropriate object to determine the tick locations /// The default returns None indicating that matplotlib should autoselect it @@ -90,6 +90,8 @@ class MANTID_MPLCPP_DLL PowerNorm : public NormalizeBase { public: PowerNorm(double gamma); PowerNorm(double gamma, double vmin, double vmax); + virtual std::tuple<double, double> + autoscale(std::tuple<double, double> clim) override; }; } // namespace MplCpp diff --git a/qt/widgets/mplcpp/src/Colors.cpp b/qt/widgets/mplcpp/src/Colors.cpp index 13d494334c040cec67d4e3aea80f95e5fa7ce0cf..6abba89dc631378ff7e562600043064ed2c00f16 100644 --- a/qt/widgets/mplcpp/src/Colors.cpp +++ b/qt/widgets/mplcpp/src/Colors.cpp @@ -7,7 +7,10 @@ #include "MantidQtWidgets/MplCpp/Colors.h" #include "MantidPythonInterface/core/ErrorHandling.h" #include "MantidPythonInterface/core/GlobalInterpreterLock.h" + #include <boost/optional.hpp> + +#include <algorithm> #include <tuple> using boost::none; @@ -205,6 +208,15 @@ PowerNorm::PowerNorm(double gamma) : NormalizeBase(createPowerNorm(gamma)) {} PowerNorm::PowerNorm(double gamma, double vmin, double vmax) : NormalizeBase(createPowerNorm(gamma, std::make_tuple(vmin, vmax))) {} +std::tuple<double, double> +PowerNorm::autoscale(std::tuple<double, double> clim) { + // Clipping was removed in matplotlib v3.2.0rc2 (Upstream PR #10234) so + // autoscale will now map [-x,y] -> [0,1] which causes weird color bar scales + // We now manually clamp min value to 0 so we map from [0,n]->[0,1] + std::get<0>(clim) = std::max(0., std::get<0>(clim)); + return NormalizeBase::autoscale(clim); +} + } // namespace MplCpp } // namespace Widgets } // namespace MantidQt diff --git a/scripts/Inelastic/Direct/CommonFunctions.py b/scripts/Inelastic/Direct/CommonFunctions.py index 77e7aef2b0a32590de5421aa15250df65bc9f28e..7b963db2e000bdf86a21239e7a6e022d55bec1c2 100644 --- a/scripts/Inelastic/Direct/CommonFunctions.py +++ b/scripts/Inelastic/Direct/CommonFunctions.py @@ -6,6 +6,15 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function, unicode_literals) +import sys + +# See https://www.python.org/dev/peps/pep-0479/#abstract and +# https://stackoverflow.com/a/51701040 +if sys.version_info >= (3,7): + NEW_STYLE_GENERATOR = True +else: + NEW_STYLE_GENERATOR = False + class switch(object): """ Helper class providing nice switch statement""" @@ -17,7 +26,10 @@ class switch(object): def __iter__(self): """Return the match method once, then stop""" yield self.match - raise StopIteration + if NEW_STYLE_GENERATOR: + return + else: + raise StopIteration def match(self, *args): """Indicate whether or not to enter a case suite""" diff --git a/scripts/Inelastic/QLdata_win64.cp38-win_amd64.pyd b/scripts/Inelastic/QLdata_win64.cp38-win_amd64.pyd index 68170025432c02fcf2e4375c7e8b808d121c18c0..31281bf2998411c215500aea09df9723c3b0c19e 100644 Binary files a/scripts/Inelastic/QLdata_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/QLdata_win64.cp38-win_amd64.pyd differ diff --git a/scripts/Inelastic/QLres_win64.cp38-win_amd64.pyd b/scripts/Inelastic/QLres_win64.cp38-win_amd64.pyd index a05effad32b68e5f8337836553e1ff9aea0ad4c7..2667721006f9fdef1b21288a0f177776395c1c4b 100644 Binary files a/scripts/Inelastic/QLres_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/QLres_win64.cp38-win_amd64.pyd differ diff --git a/scripts/Inelastic/QLse_win64.cp38-win_amd64.pyd b/scripts/Inelastic/QLse_win64.cp38-win_amd64.pyd index f26afeee8cf8c299bfdf934b0bc2a3a597c56b55..da481afd74ddb69fbabc1490c7c724bdb0e8b977 100644 Binary files a/scripts/Inelastic/QLse_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/QLse_win64.cp38-win_amd64.pyd differ diff --git a/scripts/Inelastic/Quest_win64.cp38-win_amd64.pyd b/scripts/Inelastic/Quest_win64.cp38-win_amd64.pyd index 7c02c7a842f4911c3279a8e0dbb9c929e4071d92..b7de0b197596593ae58159bb8eb8aa4156358813 100644 Binary files a/scripts/Inelastic/Quest_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/Quest_win64.cp38-win_amd64.pyd differ diff --git a/scripts/Inelastic/ResNorm_win64.cp38-win_amd64.pyd b/scripts/Inelastic/ResNorm_win64.cp38-win_amd64.pyd index 7daae32de8642e428ca5deecee245a8632d1e4b4..33ba44cd7170c691782ecbad3875776e463f4d16 100644 Binary files a/scripts/Inelastic/ResNorm_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/ResNorm_win64.cp38-win_amd64.pyd differ diff --git a/scripts/Inelastic/cylabs_win64.cp38-win_amd64.pyd b/scripts/Inelastic/cylabs_win64.cp38-win_amd64.pyd index 49f51382e30f7c123199b4f0509278381c81834a..c7a2193dbd2bce862e17c7fd99c519864d00fa6b 100644 Binary files a/scripts/Inelastic/cylabs_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/cylabs_win64.cp38-win_amd64.pyd differ diff --git a/scripts/Inelastic/muscat_win64.cp38-win_amd64.pyd b/scripts/Inelastic/muscat_win64.cp38-win_amd64.pyd index 7eeaf0122037daccf6b6212635df82bb91306d58..f37d545093334b912b49e6ab1601edece19e0601 100644 Binary files a/scripts/Inelastic/muscat_win64.cp38-win_amd64.pyd and b/scripts/Inelastic/muscat_win64.cp38-win_amd64.pyd differ diff --git a/scripts/MultiPlotting/subplot/subplot_context.py b/scripts/MultiPlotting/subplot/subplot_context.py index edec83fe136baf013c5e03604cb40a409aa46010..4304a3cfa1d146db46fef5d77545ad05ed12e2e6 100644 --- a/scripts/MultiPlotting/subplot/subplot_context.py +++ b/scripts/MultiPlotting/subplot/subplot_context.py @@ -104,7 +104,8 @@ class subplotContext(object): def replace_ws(self, ws): redraw_canvas = False - for key in self._ws.keys(): + # force copy of .keys() to avoid mutation while iterating + for key in list(self._ws.keys()): if key.name() == ws.name(): redraw_canvas = True self._ws[ws] = self._ws.pop(key) diff --git a/scripts/test/Muon/frequency_domain_context_test.py b/scripts/test/Muon/frequency_domain_context_test.py index 94c4e0abf36f8607f6841540f49187ba635a096f..47369c0accec8824c026e8cb57dcea0fe171a969 100644 --- a/scripts/test/Muon/frequency_domain_context_test.py +++ b/scripts/test/Muon/frequency_domain_context_test.py @@ -4,18 +4,16 @@ # NScD Oak Ridge National Laboratory, European Spallation Source # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + +from __future__ import (absolute_import, unicode_literals) + +import six import sys import unittest -import six from Muon.GUI.FrequencyDomainAnalysis.frequency_context import MaxEnt, FFT, FrequencyContext, FREQUENCY_EXTENSIONS +from mantid.py3compat import mock from mantid.simpleapi import CreateWorkspace, AnalysisDataService -if sys.version_info.major < 2: - from unittest import mock -else: - import mock - FFT_NAME_RE_2 = "FFT; Re MUSR62260; Group; fwd; Asymmmetry; FD_Re" FFT_NAME_RE_MOD = "FFT; Re MUSR62260; Group; fwd; Asymmmetry; FD_Mod" @@ -27,6 +25,7 @@ FFT_NAME_COMPLEX_MOD= "FFT; Re MUSR62260; Group; fwd; Asymmmetry; FD; Im MUSR622 PHASEQUAD_NAME_IM = "FFT; Re MUSR62261; PhaseQuad FD MUSR62260; PhaseTable FD; top; bkwd; Im MUSR62261; PhaseQuad FD MUSR62260; PhaseTable FD; top; bkwd_Mod" PHASEQUAD_NAME_RE = "FFT; Re MUSR62261; PhaseQuad FD MUSR62260; PhaseTable FD; top; bkwd_Mod" + class MuonFreqContextTest(unittest.TestCase): def setUp(self): self.ws_freq = "MUSR62260_raw_data FD; MaxEnt" diff --git a/scripts/test/Muon/muon_gui_context_test.py b/scripts/test/Muon/muon_gui_context_test.py index 12d32c8aa5c3a00e9fb7c9b3c3763e3975fbebff..c6188cba17283fa051d5cb0ed24907f0587ed4f3 100644 --- a/scripts/test/Muon/muon_gui_context_test.py +++ b/scripts/test/Muon/muon_gui_context_test.py @@ -4,18 +4,16 @@ # NScD Oak Ridge National Laboratory, European Spallation Source # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + +from __future__ import (absolute_import, unicode_literals) + import sys import unittest from Muon.GUI.Common.contexts.muon_gui_context import MuonGuiContext +from mantid.py3compat import mock from mantidqt.utils.observer_pattern import Observer from mantidqt.utils.qt.testing import start_qapplication -if sys.version_info.major < 2: - from unittest import mock -else: - import mock - @start_qapplication class MuonGUIContextTest(unittest.TestCase): def test_can_set_variables(self): diff --git a/scripts/test/SANS/common/file_information_test.py b/scripts/test/SANS/common/file_information_test.py index 5d876de5c0f5bf8dfdac060ba82e0b141cd58bac..16d7c7d1ef23a061bc33a45fea1277d2e8ca2a79 100644 --- a/scripts/test/SANS/common/file_information_test.py +++ b/scripts/test/SANS/common/file_information_test.py @@ -6,10 +6,10 @@ # SPDX - License - Identifier: GPL - 3.0 + from __future__ import (absolute_import, division, print_function) -import mock import unittest from mantid.kernel import DateAndTime +from mantid.py3compat import mock from sans.common.enums import SampleShape from sans.common.file_information import (SANSFileInformationFactory, FileType, SANSInstrument, get_instrument_paths_for_sans_file) diff --git a/scripts/test/SANS/gui_logic/table_model_test.py b/scripts/test/SANS/gui_logic/table_model_test.py index d0240662c8cddd6405317bb62f68c529146ce239..9f0ff43a58e8b18367fa67c83f85a7330f152c5a 100644 --- a/scripts/test/SANS/gui_logic/table_model_test.py +++ b/scripts/test/SANS/gui_logic/table_model_test.py @@ -7,10 +7,10 @@ from __future__ import (absolute_import, division, print_function) import unittest -from mock import patch, ANY from qtpy.QtCore import QCoreApplication from mantid.py3compat import mock +from mantid.py3compat.mock import patch, ANY from sans.common.enums import (RowState, SampleShape) from sans.gui_logic.models.basic_hint_strategy import BasicHintStrategy from sans.gui_logic.models.table_model import (TableModel, TableIndexModel, OptionsColumnModel, options_column_bool)