def test_workspace_selection_changed_multiple_selected_empty_options_success(self):
     slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
     slice_widget_presenter.register_master(self.main_presenter)
     workspace = "a"
     self.main_presenter.get_selected_workspaces = mock.Mock(return_value=[workspace,workspace])
     slice_widget_presenter.workspace_selection_changed()
     assert(self.slice_view.clear_input_fields.called)
 def test_notify_presenter_clears_error(self):
     presenter = SliceWidgetPresenter(self.slice_view)
     presenter.register_master(self.main_presenter)
     self.slice_view.clear_displayed_error = mock.Mock()
     # This unit test will verify that notifying cut presenter will cause the error to be cleared on the view.
     # The actual subsequent procedure will fail, however this irrelevant to this. Hence the try, except blocks
     for command in [x for x in dir(Command) if x[0] != "_"]:
         try:
             presenter.notify(command)
         except ValueError:
             pass
         self.slice_view.clear_displayed_error.assert_called()
         self.slice_view.reset_mock()
예제 #3
0
    def test_workspace_selection_changed(self, is_sliceable_mock,
                                         get_axis_range_mock,
                                         get_available_axes_mock,
                                         get_ws_handle_mock,
                                         get_ws_handle_mock2):

        slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
        slice_widget_presenter.register_master(self.main_presenter)
        workspace = 'workspace'
        self.main_presenter.get_selected_workspaces = mock.Mock(
            return_value=[workspace])
        ws_mock = mock.Mock()
        get_ws_handle_mock.return_value = ws_mock
        get_ws_handle_mock2.return_value = ws_mock
        is_sliceable_mock.return_value = True
        dims = ['dim1', 'dim2']
        get_available_axes_mock.return_value = dims
        get_axis_range_mock.return_value = (0, 1, 0.1)
        slice_widget_presenter.workspace_selection_changed()
        assert (self.slice_view.populate_slice_x_options.called)
        assert (self.slice_view.populate_slice_y_options.called)
        assert (get_available_axes_mock.called)
        assert (get_axis_range_mock.called)
        # Test error handling
        get_axis_range_mock.side_effect = KeyError
        slice_widget_presenter.workspace_selection_changed()
        assert (self.slice_view.clear_input_fields.called)
예제 #4
0
    def test_plot_slice_successful(self):
        slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
        slice_widget_presenter.register_master(self.main_presenter)
        slice_widget_presenter.set_slice_plotter_presenter(
            self.slice_plotter_presenter)
        x = Axis('x', '0', '10', '1')
        y = Axis('y', '2', '8', '3')
        intensity_start = '7'
        intensity_end = '8'
        norm_to_one = False
        colourmap = 'colormap'
        selected_workspace = 'workspace1'
        self.main_presenter.get_selected_workspaces.return_value = [
            selected_workspace
        ]
        self.slice_view.get_slice_x_axis.return_value = x.units
        self.slice_view.get_slice_x_start.return_value = x.start
        self.slice_view.get_slice_x_end.return_value = x.end
        self.slice_view.get_slice_x_step.return_value = x.step
        self.slice_view.get_slice_y_axis.return_value = y.units
        self.slice_view.get_slice_y_start.return_value = y.start
        self.slice_view.get_slice_y_end.return_value = y.end
        self.slice_view.get_slice_y_step.return_value = y.step
        self.slice_view.get_slice_intensity_start.return_value = intensity_start
        self.slice_view.get_slice_intensity_end.return_value = intensity_end
        self.slice_view.get_slice_is_norm_to_one.return_value = norm_to_one
        self.slice_view.get_slice_colourmap.return_value = colourmap
        plot_info = ("plot_data", "boundaries", "colormap", "norm")
        self.slice_plotter_presenter.plot_slice = mock.Mock(
            return_value=plot_info)
        self.slice_plotter_presenter.validate_intensity = mock.Mock(
            return_value=(7.0, 8.0))
        slice_widget_presenter.notify(Command.DisplaySlice)

        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.slice_view.get_slice_x_axis.assert_called_once_with()
        self.slice_view.get_slice_x_start.assert_called_once_with()
        self.slice_view.get_slice_x_end.assert_called_once_with()
        self.slice_view.get_slice_x_step.assert_called_once_with()
        self.slice_view.get_slice_y_axis.assert_called_once_with()
        self.slice_view.get_slice_y_start.assert_called_once_with()
        self.slice_view.get_slice_y_end.assert_called_once_with()
        self.slice_view.get_slice_y_step.assert_called_once_with()
        self.slice_view.get_slice_intensity_start.assert_called_once_with()
        self.slice_view.get_slice_intensity_end.assert_called_once_with()
        self.slice_view.get_slice_is_norm_to_one.assert_called_once_with()
        self.slice_view.get_slice_colourmap.assert_called_once_with()
        self.slice_plotter_presenter.validate_intensity.assert_called_once_with(
            '7', '8')
        self.slice_plotter_presenter.plot_slice.assert_called_with(
            selected_workspace, Axis('x', 0, 10, 1), Axis('y', 2, 8, 3),
            float(intensity_start), float(intensity_end), norm_to_one,
            colourmap)
예제 #5
0
    def __init__(self, parent=None, *args, **kwargs):
        """This Widget provides basic control over displaying slices. This widget is NOT USABLE without a main window

        The main window must implement MainView"""
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'slice.ui', self)
        self.btnSliceDisplay.clicked.connect(self._btn_clicked)
        self.display_errors_to_statusbar = True
        self._presenter = SliceWidgetPresenter(self)
        # Each time the fields are populated, set a minimum step size
        self._minimumStep = {}
        self.lneSliceXStep.editingFinished.connect(
            lambda: self._step_edited('x', self.lneSliceXStep))
        self.lneSliceYStep.editingFinished.connect(
            lambda: self._step_edited('y', self.lneSliceYStep))
        self.enable_units_choice(False)
        self.cmbSliceXAxis.currentIndexChanged.connect(
            lambda ind: self._change_axes(1, ind))
        self.cmbSliceYAxis.currentIndexChanged.connect(
            lambda ind: self._change_axes(2, ind))
        self.set_validators()
예제 #6
0
 def test_workspace_selection_changed_multiple_selected_empty_options_success(
         self):
     slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
     slice_widget_presenter.register_master(self.main_presenter)
     workspace = "a"
     self.main_presenter.get_selected_workspaces = mock.Mock(
         return_value=[workspace, workspace])
     slice_widget_presenter.workspace_selection_changed()
     assert (self.slice_view.clear_input_fields.called)
    def test_plot_slice_successful(self):
        slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
        slice_widget_presenter.register_master(self.main_presenter)
        slice_widget_presenter.set_slice_plotter_presenter(self.slice_plotter_presenter)
        x = Axis('x', '0', '10' ,'1')
        y = Axis('y', '2', '8', '3')
        intensity_start = '7'
        intensity_end = '8'
        norm_to_one = False
        colourmap = 'colormap'
        selected_workspace = 'workspace1'
        self.main_presenter.get_selected_workspaces.return_value = [selected_workspace]
        self.slice_view.get_slice_x_axis.return_value = x.units
        self.slice_view.get_slice_x_start.return_value = x.start
        self.slice_view.get_slice_x_end.return_value = x.end
        self.slice_view.get_slice_x_step.return_value = x.step
        self.slice_view.get_slice_y_axis.return_value = y.units
        self.slice_view.get_slice_y_start.return_value = y.start
        self.slice_view.get_slice_y_end.return_value = y.end
        self.slice_view.get_slice_y_step.return_value = y.step
        self.slice_view.get_slice_intensity_start.return_value = intensity_start
        self.slice_view.get_slice_intensity_end.return_value = intensity_end
        self.slice_view.get_slice_is_norm_to_one.return_value = norm_to_one
        self.slice_view.get_slice_colourmap.return_value = colourmap
        self.slice_view.get_units.return_value = 'meV'
        plot_info = ("plot_data", "boundaries", "colormap", "norm")
        self.slice_plotter_presenter.plot_slice = mock.Mock(return_value=plot_info)
        self.slice_plotter_presenter.validate_intensity = mock.Mock(return_value=(7.0, 8.0))
        slice_widget_presenter.notify(Command.DisplaySlice)

        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.slice_view.get_slice_x_axis.assert_called_once_with()
        self.slice_view.get_slice_x_start.assert_called_once_with()
        self.slice_view.get_slice_x_end.assert_called_once_with()
        self.slice_view.get_slice_x_step.assert_called_once_with()
        self.slice_view.get_slice_y_axis.assert_called_once_with()
        self.slice_view.get_slice_y_start.assert_called_once_with()
        self.slice_view.get_slice_y_end.assert_called_once_with()
        self.slice_view.get_slice_y_step.assert_called_once_with()
        self.slice_view.get_slice_intensity_start.assert_called_once_with()
        self.slice_view.get_slice_intensity_end.assert_called_once_with()
        self.slice_view.get_slice_is_norm_to_one.assert_called_once_with()
        self.slice_view.get_slice_colourmap.assert_called_once_with()
        self.slice_plotter_presenter.validate_intensity.assert_called_once_with('7', '8')
        self.slice_plotter_presenter.plot_slice.assert_called_with(selected_workspace, Axis('x', 0, 10, 1),
                                                                   Axis('y', 2, 8, 3), float(intensity_start),
                                                                   float(intensity_end), norm_to_one, colourmap)
예제 #8
0
 def test_notify_presenter_clears_error(self):
     presenter = SliceWidgetPresenter(self.slice_view)
     presenter.register_master(self.main_presenter)
     self.slice_view.clear_displayed_error = mock.Mock()
     # This unit test will verify that notifying cut presenter will cause the error to be cleared on the view.
     # The actual subsequent procedure will fail, however this irrelevant to this. Hence the try, except blocks
     for command in [x for x in dir(Command) if x[0] != "_"]:
         try:
             presenter.notify(command)
         except ValueError:
             pass
         self.slice_view.clear_displayed_error.assert_called()
         self.slice_view.reset_mock()
예제 #9
0
    def __init__(self, parent=None, *args, **kwargs):
        """This Widget provides basic control over displaying slices. This widget is NOT USABLE without a main window

        The main window must implement MainView"""
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'slice.ui', self)
        self.btnSliceDisplay.clicked.connect(self._btn_clicked)
        self.display_errors_to_statusbar = True
        self._presenter = SliceWidgetPresenter(self)
        # Each time the fields are populated, set a minimum step size
        self._minimumStep = {}
        self.lneSliceXStep.editingFinished.connect(lambda: self._step_edited('x', self.lneSliceXStep))
        self.lneSliceYStep.editingFinished.connect(lambda: self._step_edited('y', self.lneSliceYStep))
        self.cmbSliceXAxis.currentIndexChanged.connect(lambda ind: self._change_axes(1, ind))
        self.cmbSliceYAxis.currentIndexChanged.connect(lambda ind: self._change_axes(2, ind))
        self.cmbSliceUnits.currentIndexChanged.connect(self._change_unit)
        self.set_validators()
        self._old_en = EnergyUnits('meV')
        self._en_default = 'meV'
 def test_register_master_success(self):
     slice_presenter = SliceWidgetPresenter(self.slice_view)
     slice_presenter.register_master(self.main_presenter)
     self.main_presenter.subscribe_to_workspace_selection_monitor.assert_called_once_with(slice_presenter)
예제 #11
0
class SliceWidget(SliceView, QWidget):
    error_occurred = Signal('QString')
    busy = Signal(bool)

    def __init__(self, parent=None, *args, **kwargs):
        """This Widget provides basic control over displaying slices. This widget is NOT USABLE without a main window

        The main window must implement MainView"""
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'slice.ui', self)
        self.btnSliceDisplay.clicked.connect(self._btn_clicked)
        self.display_errors_to_statusbar = True
        self._presenter = SliceWidgetPresenter(self)
        # Each time the fields are populated, set a minimum step size
        self._minimumStep = {}
        self.lneSliceXStep.editingFinished.connect(
            lambda: self._step_edited('x', self.lneSliceXStep))
        self.lneSliceYStep.editingFinished.connect(
            lambda: self._step_edited('y', self.lneSliceYStep))
        self.enable_units_choice(False)
        self.cmbSliceXAxis.currentIndexChanged.connect(
            lambda ind: self._change_axes(1, ind))
        self.cmbSliceYAxis.currentIndexChanged.connect(
            lambda ind: self._change_axes(2, ind))
        self.set_validators()

    def get_presenter(self):
        return self._presenter

    def _btn_clicked(self):
        if self._step_edited('x', self.lneSliceXStep) and self._step_edited(
                'y', self.lneSliceXStep):
            self._presenter.notify(Command.DisplaySlice)

    def _step_edited(self, idx, lineEdit):
        """Checks that user inputted step size is not too small."""
        if self._minimumStep:
            try:
                value = float(lineEdit.text())
            except ValueError:
                value = 0
                self._display_error(
                    'Invalid step parameter. Using default value.')
            if value == 0:
                lineEdit.setText(str(self._minimumStep[idx]))
                self._display_error('Setting step size to default.')
            elif value < (self._minimumStep[idx] / 100.):
                self._display_error('Step size too small!')
                return False
        return True

    def _change_axes(self, axis, idx):
        """Makes sure u1 and u2 are always different, and updates default limits/steps values."""
        curr_axis = axis - 1
        other_axis = axis % 2
        axes_handle = [self.cmbSliceXAxis, self.cmbSliceYAxis]
        num_items = axes_handle[other_axis].count()
        if num_items < 2:
            return
        axes = [
            self.cmbSliceXAxis.currentText(),
            self.cmbSliceYAxis.currentText()
        ]
        index = [
            self.cmbSliceXAxis.currentIndex(),
            self.cmbSliceYAxis.currentIndex()
        ]
        axes_set = [
            self.cmbSliceXAxis.setCurrentIndex,
            self.cmbSliceYAxis.setCurrentIndex
        ]
        if axes[curr_axis] == axes[other_axis]:
            new_index = (index[other_axis] + 1) % num_items
            axes_set[other_axis](new_index)
        self._presenter.populate_slice_params()

    def _display_error(self, error_string):
        self.error_occurred.emit(error_string)

    def enable_units_choice(self, enabled):
        if enabled:
            # TODO implement conversion from meV to cm-1
            pass
            #self.cmbSliceUnits.show()
            #self.label_16.show()
        else:
            self.cmbSliceUnits.hide()
            self.label_16.hide()

    def get_units(self):
        return self.cmbSliceUnits.currentText()

    def get_slice_x_axis(self):
        return str(self.cmbSliceXAxis.currentText())

    def get_slice_y_axis(self):
        return str(self.cmbSliceYAxis.currentText())

    def get_slice_is_norm_to_one(self):
        return self.rdoSliceNormToOne.isChecked()

    def get_slice_smoothing(self):
        return str(self.lneSliceSmoothing.text())

    def get_slice_x_start(self):
        return str(self.lneSliceXStart.text())

    def get_slice_x_end(self):
        return str(self.lneSliceXEnd.text())

    def get_slice_x_step(self):
        return str(self.lneSliceXStep.text())

    def get_slice_y_start(self):
        return str(self.lneSliceYStart.text())

    def get_slice_y_end(self):
        return str(self.lneSliceYEnd.text())

    def get_slice_y_step(self):
        return str(self.lneSliceYStep.text())

    def get_slice_colourmap(self):
        return str(self.cmbSliceColormap.currentText())

    def get_slice_intensity_start(self):
        return str(self.lneSliceIntensityStart.text())

    def get_slice_intensity_end(self):
        return str(self.lneSliceIntensityEnd.text())

    def populate_colormap_options(self, colormaps):
        self.cmbSliceColormap.clear()
        for colormap in colormaps:
            self.cmbSliceColormap.addItem(colormap)

    def populate_slice_x_options(self, options):
        self.cmbSliceXAxis.clear()
        for option in options:
            self.cmbSliceXAxis.addItem(option)

    def populate_slice_y_options(self, options):
        self.cmbSliceYAxis.clear()
        for option in options:
            self.cmbSliceYAxis.addItem(option)

    def error_select_one_workspace(self):
        self._display_error('Please select a workspace to slice')

    def error_invalid_x_params(self):
        self._display_error('Invalid parameters for the x axis of the slice')

    def error_invalid_intensity_params(self):
        self._display_error(
            'Invalid parameters for the intensity of the slice')

    def error_invalid_plot_parameters(self):
        self._display_error('Invalid parameters for the slice')

    def error_invalid_smoothing_params(self):
        self._display_error('Invalid value for smoothing')

    def error_invalid_y_units(self):
        self._display_error('Invalid selection of the y axis')

    def error_invalid_y_params(self):
        self._display_error('Invalid parameters for the y axis of the slice')

    def error_invalid_x_units(self):
        self._display_error('Invalid selection of the x axis')

    def error(self, string):
        self._display_error(string)

    def populate_slice_x_params(self, x_start, x_end, x_step):
        self.lneSliceXStart.setText(x_start)
        self.lneSliceXEnd.setText(x_end)
        self.lneSliceXStep.setText(x_step)
        if x_step:
            self._minimumStep['x'] = float(x_step)

    def populate_slice_y_params(self, y_start, y_end, y_step):
        self.lneSliceYStart.setText(y_start)
        self.lneSliceYEnd.setText(y_end)
        self.lneSliceYStep.setText(y_step)
        if y_step:
            self._minimumStep['y'] = float(y_step)

    def clear_input_fields(self):
        self.populate_slice_x_options([])
        self.populate_slice_y_options([])
        self.populate_slice_x_params("", "", "")
        self.populate_slice_y_params("", "", "")
        self.lneSliceIntensityStart.setText("")
        self.lneSliceIntensityEnd.setText("")
        self.rdoSliceNormToOne.setChecked(0)
        self._minimumStep = {}

    def disable(self):
        self.cmbSliceXAxis.setEnabled(False)
        self.cmbSliceYAxis.setEnabled(False)
        self.lneSliceXStart.setEnabled(False)
        self.lneSliceXEnd.setEnabled(False)
        self.lneSliceXStep.setEnabled(False)
        self.lneSliceYStart.setEnabled(False)
        self.lneSliceYEnd.setEnabled(False)
        self.lneSliceYStep.setEnabled(False)
        self.lneSliceIntensityStart.setEnabled(False)
        self.lneSliceIntensityEnd.setEnabled(False)
        self.rdoSliceNormToOne.setEnabled(False)
        self.btnSliceDisplay.setEnabled(False)
        self.cmbSliceColormap.setEnabled(False)

    def enable(self):
        self.cmbSliceXAxis.setEnabled(True)
        self.cmbSliceYAxis.setEnabled(True)
        self.lneSliceXStart.setEnabled(True)
        self.lneSliceXEnd.setEnabled(True)
        self.lneSliceXStep.setEnabled(True)
        self.lneSliceYStart.setEnabled(True)
        self.lneSliceYEnd.setEnabled(True)
        self.lneSliceYStep.setEnabled(True)
        self.lneSliceIntensityStart.setEnabled(True)
        self.lneSliceIntensityEnd.setEnabled(True)
        self.rdoSliceNormToOne.setEnabled(True)
        self.btnSliceDisplay.setEnabled(True)
        self.cmbSliceColormap.setEnabled(True)

    def set_validators(self):
        line_edits = [
            self.lneSliceXStart, self.lneSliceXEnd, self.lneSliceXStep,
            self.lneSliceYStart, self.lneSliceYEnd, self.lneSliceYStep,
            self.lneSliceIntensityStart, self.lneSliceIntensityEnd
        ]
        for line_edit in line_edits:
            line_edit.setValidator(QDoubleValidator())

    def clear_displayed_error(self):
        self._display_error("")
예제 #12
0
 def test_plot_slice_error_handling(self):
     slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
     slice_widget_presenter.register_master(self.main_presenter)
     slice_widget_presenter.set_slice_plotter_presenter(
         self.slice_plotter_presenter)
     x = Axis('x', '0', '10', '1')
     y = Axis('y', '2', '8', '3')
     intensity_start = '7'
     intensity_end = '8'
     norm_to_one = False
     smoothing = '10'
     colourmap = 'colormap'
     selected_workspace = 'workspace1'
     self.slice_view.get_slice_x_axis.return_value = x.units
     self.slice_view.get_slice_x_start.return_value = x.start
     self.slice_view.get_slice_x_end.return_value = x.end
     self.slice_view.get_slice_x_step.return_value = x.step
     self.slice_view.get_slice_y_axis.return_value = y.units
     self.slice_view.get_slice_y_start.return_value = y.start
     self.slice_view.get_slice_y_end.return_value = y.end
     self.slice_view.get_slice_y_step.return_value = y.step
     self.slice_view.get_slice_intensity_start.return_value = intensity_start
     self.slice_view.get_slice_intensity_end.return_value = intensity_end
     self.slice_view.get_slice_is_norm_to_one.return_value = norm_to_one
     self.slice_view.get_slice_smoothing.return_value = smoothing
     self.slice_view.get_slice_colourmap.return_value = colourmap
     plot_info = ("plot_data", "boundaries", "colormap", "norm")
     self.slice_plotter_presenter.plot_slice = mock.Mock(
         return_value=plot_info)
     self.slice_plotter_presenter.validate_intensity = mock.Mock(
         return_value=(7.0, 8.0))
     # Test empty workspace, multiple workspaces
     self.main_presenter.get_selected_workspaces.return_value = []
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_select_one_workspace.called
     self.main_presenter.get_selected_workspaces.return_value = [
         selected_workspace, selected_workspace
     ]
     self.slice_view.error_select_one_workspace.reset_mock()
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_select_one_workspace.called
     # Test invalid axes
     self.main_presenter.get_selected_workspaces.return_value = [
         selected_workspace
     ]
     self.slice_view.get_slice_y_axis.return_value = x.units
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_invalid_plot_parameters.called
     # Simulate matplotlib error
     self.slice_plotter_presenter.plot_slice = mock.Mock(
         side_effect=ValueError(
             'minvalue must be less than or equal to maxvalue'))
     self.slice_view.get_slice_y_axis.return_value = y.units
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_invalid_intensity_params.called
     self.slice_plotter_presenter.plot_slice = mock.Mock(
         side_effect=ValueError('something bad'))
     self.assertRaises(ValueError, slice_widget_presenter.notify,
                       Command.DisplaySlice)
 def test_set_energy_default(self):
     slice_presenter = SliceWidgetPresenter(self.slice_view)
     slice_presenter.set_energy_default("meV")
     self.slice_view.set_units.assert_called_once()
     self.slice_view.set_energy_default.assert_called_once()
예제 #14
0
 def test_register_master_invalid_master_fail(self):
     slice_presenter = SliceWidgetPresenter(self.slice_view)
     with self.assertRaises(AssertionError):
         slice_presenter.register_master(3)
예제 #15
0
 def test_register_master_success(self):
     slice_presenter = SliceWidgetPresenter(self.slice_view)
     slice_presenter.register_master(self.main_presenter)
     self.main_presenter.subscribe_to_workspace_selection_monitor.assert_called_once_with(
         slice_presenter)
예제 #16
0
 def test_notify_presenter_unknown_command_raise_exception_failure(self):
     slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
     slice_widget_presenter.register_master(self.main_presenter)
     unknown_command = -1
     with self.assertRaises(ValueError):
         slice_widget_presenter.notify(unknown_command)
예제 #17
0
 def test_constructor_invalid_slice_view_failure(self):
     with self.assertRaises(TypeError):
         SliceWidgetPresenter(self.slice_plotter_presenter)
 def test_register_master_invalid_master_fail(self):
     slice_presenter = SliceWidgetPresenter(self.slice_view)
     with self.assertRaises(AssertionError):
         slice_presenter.register_master(3)
예제 #19
0
 def test_constructor_success(self):
     self.slice_plotter_presenter = SliceWidgetPresenter(self.slice_view)
 def test_notify_presenter_unknown_command_raise_exception_failure(self):
     slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
     slice_widget_presenter.register_master(self.main_presenter)
     unknown_command = -1
     with self.assertRaises(ValueError):
         slice_widget_presenter.notify(unknown_command)
    def test_workspace_selection_changed(self, is_sliceable_mock, get_axis_range_mock, get_available_axes_mock,
                                         get_ws_handle_mock, get_ws_handle_mock2):

        slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
        slice_widget_presenter.register_master(self.main_presenter)
        workspace = 'workspace'
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=[workspace])
        ws_mock = mock.Mock()
        get_ws_handle_mock.return_value = ws_mock
        get_ws_handle_mock2.return_value = ws_mock
        is_sliceable_mock.return_value = True
        dims = ['dim1', 'dim2']
        get_available_axes_mock.return_value = dims
        get_axis_range_mock.return_value = (0, 1, 0.1)
        self.slice_view.get_units = mock.Mock(side_effect=['meV', 'cm-1', 'cm-1'])
        slice_widget_presenter.workspace_selection_changed()
        assert (self.slice_view.get_slice_x_axis.call_count == 1)
        assert (self.slice_view.populate_slice_x_options.called)
        assert (self.slice_view.populate_slice_y_options.called)
        assert (get_available_axes_mock.called)
        assert (get_axis_range_mock.called)
        # Test energy unit conversion is different for second call
        slice_widget_presenter.workspace_selection_changed()
        self.slice_view.get_slice_x_axis.assert_called()
        self.slice_view.get_slice_x_axis.return_value = 'DeltaE'
        slice_widget_presenter.workspace_selection_changed()
        assert (self.slice_view.get_slice_x_axis.call_count == 5)
        # Test error handling
        get_axis_range_mock.side_effect = KeyError
        slice_widget_presenter.workspace_selection_changed()
        assert (self.slice_view.clear_input_fields.called)
예제 #22
0
class SliceWidget(SliceView, QWidget):
    error_occurred = Signal('QString')
    busy = Signal(bool)

    def __init__(self, parent=None, *args, **kwargs):
        """This Widget provides basic control over displaying slices. This widget is NOT USABLE without a main window

        The main window must implement MainView"""
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'slice.ui', self)
        self.btnSliceDisplay.clicked.connect(self._btn_clicked)
        self.display_errors_to_statusbar = True
        self._presenter = SliceWidgetPresenter(self)
        # Each time the fields are populated, set a minimum step size
        self._minimumStep = {}
        self.lneSliceXStep.editingFinished.connect(lambda: self._step_edited('x', self.lneSliceXStep))
        self.lneSliceYStep.editingFinished.connect(lambda: self._step_edited('y', self.lneSliceYStep))
        self.cmbSliceXAxis.currentIndexChanged.connect(lambda ind: self._change_axes(1, ind))
        self.cmbSliceYAxis.currentIndexChanged.connect(lambda ind: self._change_axes(2, ind))
        self.cmbSliceUnits.currentIndexChanged.connect(self._change_unit)
        self.set_validators()
        self._old_en = EnergyUnits('meV')
        self._en_default = 'meV'

    def get_presenter(self):
        return self._presenter

    def _btn_clicked(self):
        if self._step_edited('x', self.lneSliceXStep) and self._step_edited('y', self.lneSliceXStep):
            self._presenter.notify(Command.DisplaySlice)

    def _step_edited(self, idx, lineEdit):
        """Checks that user inputted step size is not too small."""
        if self._minimumStep:
            try:
                value = float(lineEdit.text())
            except ValueError:
                value = 0
                self._display_error('Invalid step parameter. Using default value.')
            if value == 0:
                lineEdit.setText(str(self._minimumStep[idx]))
                self._display_error('Setting step size to default.')
            elif value < (self._minimumStep[idx] / 100.):
                self._display_error('Step size too small!')
                return False
        return True

    def _change_axes(self, axis, idx):
        """Makes sure u1 and u2 are always different, and updates default limits/steps values."""
        curr_axis = axis - 1
        other_axis = axis % 2
        axes_handle = [self.cmbSliceXAxis, self.cmbSliceYAxis]
        num_items = axes_handle[other_axis].count()
        if num_items < 2:
            return
        axes = [self.cmbSliceXAxis.currentText(), self.cmbSliceYAxis.currentText()]
        index = [self.cmbSliceXAxis.currentIndex(), self.cmbSliceYAxis.currentIndex()]
        axes_set = [self.cmbSliceXAxis.setCurrentIndex, self.cmbSliceYAxis.setCurrentIndex]
        if axes[curr_axis] == axes[other_axis]:
            new_index = (index[other_axis] + 1) % num_items
            axes_set[other_axis](new_index)
        self._presenter.populate_slice_params()

    def _change_unit(self):
        new_unit = self.get_units()
        if self._old_en.factor_to(new_unit) != 1.:
            if 'DeltaE' in self.get_slice_x_axis():
                x_start, x_end, x_step = self.get_slice_x_start(), self.get_slice_x_end(), self.get_slice_x_step()
                x_start, x_end, x_step = self._old_en.convert_to(new_unit, x_start, x_end, x_step)
                self.populate_slice_x_params(x_start, x_end, x_step)
            elif 'DeltaE' in self.get_slice_y_axis():
                y_start, y_end, y_step = self.get_slice_y_start(), self.get_slice_y_end(), self.get_slice_y_step()
                y_start, y_end, y_step = self._old_en.convert_to(new_unit, y_start, y_end, y_step)
                self.populate_slice_y_params(y_start, y_end, y_step)
        self._old_en = EnergyUnits(new_unit)

    def _display_error(self, error_string):
        self.error_occurred.emit(error_string)

    def get_units(self):
        return self.cmbSliceUnits.currentText()

    def set_units(self, en_unit):
        self.cmbSliceUnits.setCurrentIndex(EnergyUnits.get_index(en_unit))

    def get_slice_x_axis(self):
        return str(self.cmbSliceXAxis.currentText())

    def get_slice_y_axis(self):
        return str(self.cmbSliceYAxis.currentText())

    def get_slice_is_norm_to_one(self):
        return self.rdoSliceNormToOne.isChecked()

    def get_slice_smoothing(self):
        return str(self.lneSliceSmoothing.text())

    def get_slice_x_start(self):
        return str(self.lneSliceXStart.text())

    def get_slice_x_end(self):
        return str(self.lneSliceXEnd.text())

    def get_slice_x_step(self):
        return str(self.lneSliceXStep.text())

    def get_slice_y_start(self):
        return str(self.lneSliceYStart.text())

    def get_slice_y_end(self):
        return str(self.lneSliceYEnd.text())

    def get_slice_y_step(self):
        return str(self.lneSliceYStep.text())

    def get_slice_colourmap(self):
        return str(self.cmbSliceColormap.currentText())

    def get_slice_intensity_start(self):
        return str(self.lneSliceIntensityStart.text())

    def get_slice_intensity_end(self):
        return str(self.lneSliceIntensityEnd.text())

    def populate_colormap_options(self, colormaps):
        self.cmbSliceColormap.clear()
        for colormap in colormaps:
            self.cmbSliceColormap.addItem(colormap)

    def populate_slice_x_options(self, options):
        self.cmbSliceXAxis.clear()
        for option in options:
            self.cmbSliceXAxis.addItem(option)

    def populate_slice_y_options(self, options):
        self.cmbSliceYAxis.clear()
        for option in options:
            self.cmbSliceYAxis.addItem(option)

    def error_select_one_workspace(self):
        self._display_error('Please select a workspace to slice')

    def error_invalid_x_params(self):
        self._display_error('Invalid parameters for the x axis of the slice')

    def error_invalid_intensity_params(self):
        self._display_error('Invalid parameters for the intensity of the slice')

    def error_invalid_plot_parameters(self):
        self._display_error('Invalid parameters for the slice')

    def error_invalid_smoothing_params(self):
        self._display_error('Invalid value for smoothing')

    def error_invalid_y_units(self):
        self._display_error('Invalid selection of the y axis')

    def error_invalid_y_params(self):
        self._display_error('Invalid parameters for the y axis of the slice')

    def error_invalid_x_units(self):
        self._display_error('Invalid selection of the x axis')

    def error(self, string):
        self._display_error(string)

    def populate_slice_x_params(self, x_start, x_end, x_step):
        self.lneSliceXStart.setText(x_start)
        self.lneSliceXEnd.setText(x_end)
        self.lneSliceXStep.setText(x_step)
        if x_step:
            self._minimumStep['x'] = float(x_step)

    def populate_slice_y_params(self, y_start, y_end, y_step):
        self.lneSliceYStart.setText(y_start)
        self.lneSliceYEnd.setText(y_end)
        self.lneSliceYStep.setText(y_step)
        if y_step:
            self._minimumStep['y'] = float(y_step)

    def clear_input_fields(self):
        self.populate_slice_x_options([])
        self.populate_slice_y_options([])
        self.populate_slice_x_params("", "", "")
        self.populate_slice_y_params("", "", "")
        self.lneSliceIntensityStart.setText("")
        self.lneSliceIntensityEnd.setText("")
        self.rdoSliceNormToOne.setChecked(0)
        self.cmbSliceUnits.setCurrentIndex(EnergyUnits.get_index(self._en_default))
        self._minimumStep = {}

    def disable(self):
        self.cmbSliceXAxis.setEnabled(False)
        self.cmbSliceYAxis.setEnabled(False)
        self.lneSliceXStart.setEnabled(False)
        self.lneSliceXEnd.setEnabled(False)
        self.lneSliceXStep.setEnabled(False)
        self.lneSliceYStart.setEnabled(False)
        self.lneSliceYEnd.setEnabled(False)
        self.lneSliceYStep.setEnabled(False)
        self.lneSliceIntensityStart.setEnabled(False)
        self.lneSliceIntensityEnd.setEnabled(False)
        self.rdoSliceNormToOne.setEnabled(False)
        self.btnSliceDisplay.setEnabled(False)
        self.cmbSliceColormap.setEnabled(False)
        self.cmbSliceUnits.setEnabled(False)

    def enable(self):
        self.cmbSliceXAxis.setEnabled(True)
        self.cmbSliceYAxis.setEnabled(True)
        self.lneSliceXStart.setEnabled(True)
        self.lneSliceXEnd.setEnabled(True)
        self.lneSliceXStep.setEnabled(True)
        self.lneSliceYStart.setEnabled(True)
        self.lneSliceYEnd.setEnabled(True)
        self.lneSliceYStep.setEnabled(True)
        self.lneSliceIntensityStart.setEnabled(True)
        self.lneSliceIntensityEnd.setEnabled(True)
        self.rdoSliceNormToOne.setEnabled(True)
        self.btnSliceDisplay.setEnabled(True)
        self.cmbSliceColormap.setEnabled(True)
        self.cmbSliceUnits.setEnabled(True)

    def set_validators(self):
        line_edits = [self.lneSliceXStart, self.lneSliceXEnd, self.lneSliceXStep, self.lneSliceYStart,
                      self.lneSliceYEnd, self.lneSliceYStep, self.lneSliceIntensityStart, self.lneSliceIntensityEnd]
        for line_edit in line_edits:
            line_edit.setValidator(QDoubleValidator())

    def set_energy_default(self, en_default):
        self._en_default = en_default

    def clear_displayed_error(self):
        self._display_error("")
 def test_plot_slice_error_handling(self):
     slice_widget_presenter = SliceWidgetPresenter(self.slice_view)
     slice_widget_presenter.register_master(self.main_presenter)
     slice_widget_presenter.set_slice_plotter_presenter(self.slice_plotter_presenter)
     x = Axis('x', '0', '10', '1')
     y = Axis('y', '2', '8', '3')
     intensity_start = '7'
     intensity_end = '8'
     norm_to_one = False
     smoothing = '10'
     colourmap = 'colormap'
     selected_workspace = 'workspace1'
     self.slice_view.get_slice_x_axis.return_value = x.units
     self.slice_view.get_slice_x_start.return_value = x.start
     self.slice_view.get_slice_x_end.return_value = x.end
     self.slice_view.get_slice_x_step.return_value = x.step
     self.slice_view.get_slice_y_axis.return_value = y.units
     self.slice_view.get_slice_y_start.return_value = y.start
     self.slice_view.get_slice_y_end.return_value = y.end
     self.slice_view.get_slice_y_step.return_value = y.step
     self.slice_view.get_slice_intensity_start.return_value = intensity_start
     self.slice_view.get_slice_intensity_end.return_value = intensity_end
     self.slice_view.get_slice_is_norm_to_one.return_value = norm_to_one
     self.slice_view.get_slice_smoothing.return_value = smoothing
     self.slice_view.get_slice_colourmap.return_value = colourmap
     self.slice_view.get_units.return_value = 'meV'
     plot_info = ("plot_data", "boundaries", "colormap", "norm")
     self.slice_plotter_presenter.plot_slice = mock.Mock(return_value=plot_info)
     self.slice_plotter_presenter.validate_intensity = mock.Mock(return_value=(7.0, 8.0))
     # Test empty workspace, multiple workspaces
     self.main_presenter.get_selected_workspaces.return_value = []
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_select_one_workspace.called
     self.main_presenter.get_selected_workspaces.return_value = [selected_workspace, selected_workspace]
     self.slice_view.error_select_one_workspace.reset_mock()
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_select_one_workspace.called
     # Test invalid axes
     self.main_presenter.get_selected_workspaces.return_value = [selected_workspace]
     self.slice_view.get_slice_y_axis.return_value = x.units
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_invalid_plot_parameters.called
     # Simulate matplotlib error
     self.slice_plotter_presenter.plot_slice = mock.Mock(
         side_effect=ValueError('minvalue must be less than or equal to maxvalue'))
     self.slice_view.get_slice_y_axis.return_value = y.units
     slice_widget_presenter.notify(Command.DisplaySlice)
     assert self.slice_view.error_invalid_intensity_params.called
     self.slice_plotter_presenter.plot_slice = mock.Mock(side_effect=ValueError('something bad'))
     self.assertRaises(ValueError, slice_widget_presenter.notify, Command.DisplaySlice)