def test_start_calibration_worker(self, task): instrument, cer = ("test_ins", "test_cer") old_pending = CalibrationInfo(sample_path=None, instrument=None) self.presenter.pending_calibration = old_pending expected_pending = CalibrationInfo(sample_path=cer, instrument=instrument) self.presenter.instrument = instrument self.presenter.start_calibration_worker(cer, False, None) self.check_calibration_equal(self.presenter.pending_calibration, expected_pending)
def test_validate_while_searching(self, create_error): self.presenter.current_calibration = CalibrationInfo(sample_path="Fake/Path", instrument="ENGINX") self.view.is_searching.return_value = True self.assertEqual(False, self.presenter._validate()) self.assertEqual(1, create_error.call_count)
def test_set_current_calibration(self): self.presenter.calibration_notifier = MagicMock() pending = CalibrationInfo(sample_path="test/set/path/2", instrument="TEST_INS") pendcpy = CalibrationInfo(sample_path="test/set/path/2", instrument="TEST_INS") self.presenter.pending_calibration = pending current = CalibrationInfo(sample_path="old/cera", instrument="ENGINX") blank = CalibrationInfo() self.presenter.current_calibration = current self.presenter.set_current_calibration() self.check_calibration_equal(self.presenter.current_calibration, pendcpy) self.check_calibration_equal(self.presenter.pending_calibration, blank) self.assertEqual(self.presenter.calibration_notifier.notify_subscribers.call_count, 1)
def __init__(self, model, view): self.model = model self.view = view self.worker = None self.calibration_notifier = self.CalibrationNotifier(self) self.current_calibration = CalibrationInfo() self.pending_calibration = CalibrationInfo() self.connect_view_signals() # Main Window State Variables self.instrument = "ENGINX" self.rb_num = None # Cropping Options self.cropping_widget = CroppingPresenter(parent=self.view, view=self.view.get_cropping_widget()) self.show_cropping(False)
def test_validate_with_invalid_calibration(self, create_error): self.presenter.current_calibration = CalibrationInfo(sample_path=None, instrument=None) self.view.is_searching.return_value = False self.presenter._validate() create_error.assert_called_with( self.presenter.view, "Create or Load a calibration via the Calibration tab before focusing.")
def __init__(self, model, view): self.model = model self.view = view self.worker = None self.calibration_observer = CalibrationObserver(self) # Observable Setup self.focus_run_notifier = GenericObservable() # Connect view signals to local methods. self.view.set_on_focus_clicked(self.on_focus_clicked) self.view.set_enable_controls_connection(self.set_focus_controls_enabled) # Variables from other GUI tabs. self.current_calibration = CalibrationInfo() self.instrument = "ENGINX" self.rb_num = None last_van_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_vanadium_run") if last_van_path: self.view.set_van_file_text_with_search(last_van_path)
def test_calibrate_clicked_load_invalid_path(self, path, setting): self.presenter.calibration_notifier = MagicMock() self.view.get_new_checked.return_value = False self.view.get_load_checked.return_value = True path.return_value = False current = CalibrationInfo(sample_path="old/cera", instrument="ENGINX") self.presenter.current_calibration = current self.presenter.on_calibrate_clicked() self.assertEqual(self.presenter.current_calibration, current) self.assertEqual(self.presenter.calibration_notifier.notify_subscribers.call_count, 0)
def test_worker_started_with_correct_params_custom_crop(self, worker, setting): self.presenter.current_calibration = CalibrationInfo(sample_path="Fake/Path", instrument="ENGINX") self.view.get_focus_filenames.return_value = "305738" self.view.get_vanadium_filename.return_value = "307521" self.presenter.current_calibration.set_roi_info(None, None, "2-45") self.view.get_plot_output.return_value = True self.view.is_searching.return_value = False rp_dict_cropped = {'Cropped': 'Custom_spectra_grouping'} self.presenter.on_focus_clicked() worker.assert_called_with("305738", "307521", True, None, rp_dict_cropped) self.assertEqual(1, setting.call_count)
def test_worker_started_with_correct_params(self, worker, setting): self.presenter.current_calibration = CalibrationInfo(sample_path="Fake/Path", instrument="ENGINX") self.view.get_focus_filenames.return_value = "305738" self.view.get_vanadium_filename.return_value = "307521" # testing south bank roi info is correctly propagated self.presenter.current_calibration.set_roi_info('2', None, None) self.view.get_plot_output.return_value = True self.view.is_searching.return_value = False self.presenter.on_focus_clicked() grp_dict_south = {'bank_2': 'SouthBank_grouping'} worker.assert_called_with("305738", "307521", True, None, grp_dict_south) self.assertEqual(1, setting.call_count)
def test_calibrate_clicked_load_valid_path(self, path, setting): self.presenter.calibration_notifier = MagicMock() self.view.get_new_checked.return_value = False self.view.get_load_checked.return_value = True path.return_value = True instrument, cer, grp_ws, roi, banks = ("test_ins", "test_cer", "test_grpws", "test_roi", ['test']) self.model.load_existing_calibration_files.return_value = instrument, cer, grp_ws, roi, banks current = CalibrationInfo(sample_path="old/cera", instrument="ENGINX") new = CalibrationInfo(sample_path=cer, instrument=instrument) new.set_roi_info_load(banks, grp_ws, roi) self.presenter.current_calibration = current self.presenter.on_calibrate_clicked() self.assertEqual(self.presenter.current_calibration.get_sample(), new.get_sample()) self.assertEqual(self.presenter.current_calibration.get_instrument(), new.get_instrument()) self.assertEqual(self.presenter.calibration_notifier.notify_subscribers.call_count, 1)
class FocusPresenter(object): def __init__(self, model, view): self.model = model self.view = view self.worker = None self.calibration_observer = CalibrationObserver(self) # Observable Setup self.focus_run_notifier = GenericObservable() # Connect view signals to local methods. self.view.set_on_focus_clicked(self.on_focus_clicked) self.view.set_enable_controls_connection(self.set_focus_controls_enabled) # Variables from other GUI tabs. self.current_calibration = CalibrationInfo() self.instrument = "ENGINX" self.rb_num = None last_van_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_vanadium_run") if last_van_path: self.view.set_van_file_text_with_search(last_van_path) def add_focus_subscriber(self, obs): self.focus_run_notifier.add_subscriber(obs) def on_focus_clicked(self): if not self._validate(): return regions_dict = self.current_calibration.create_focus_roi_dictionary() focus_paths = self.view.get_focus_filenames() van_path = self.view.get_vanadium_filename() if self._number_of_files_warning(focus_paths): self.start_focus_worker(focus_paths, van_path, self.view.get_plot_output(), self.rb_num, regions_dict) van_run = self.view.get_vanadium_run() set_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_vanadium_run", van_run) def start_focus_worker(self, focus_paths: list, van_path: str, plot_output: bool, rb_num: str, regions_dict: dict) -> None: """ Focus data in a separate thread to stop the main GUI from hanging. :param focus_paths: List of paths to the files containing the data to focus. :param plot_output: True if the output should be plotted. :param rb_num: The RB Number from the main window (often an experiment id) :param regions_dict: Dictionary containing the regions to focus over, mapping region_name -> grouping_ws_name """ self.worker = AsyncTask(self.model.focus_run, (focus_paths, van_path, plot_output, self.instrument, rb_num, regions_dict), error_cb=self._on_worker_error, finished_cb=self._on_worker_success) self.set_focus_controls_enabled(False) self.worker.start() def _on_worker_success(self): self.emit_enable_button_signal() self.focus_run_notifier.notify_subscribers(self.model.get_last_focused_files()) def set_instrument_override(self, instrument): instrument = INSTRUMENT_DICT[instrument] self.view.set_instrument_override(instrument) self.instrument = instrument def set_rb_num(self, rb_num): self.rb_num = rb_num def _validate(self): """ Ensure that the worker is ready to be started. :return: True if the worker can be started safely. """ if self.view.is_searching(): create_error_message(self.view, "Mantid is searching for data files. Please wait.") return False if not self.view.get_focus_valid(): create_error_message(self.view, "Check run numbers/path is valid.") return False if not self.view.get_vanadium_valid(): create_error_message(self.view, "Check vanadium run number/path is valid.") return False if not self.current_calibration.is_valid(): create_error_message( self.view, "Create or Load a calibration via the Calibration tab before focusing.") return False if self.current_calibration.get_instrument() != self.instrument: create_error_message( self.view, "Please make sure the selected instrument matches instrument for the current calibration.\n" "The instrument for the current calibration is: " + self.current_calibration.get_instrument()) return False return True def _number_of_files_warning(self, paths): if len(paths) > 10: # Just a guess on the warning for now. May change in future. response = QMessageBox.warning( self.view, 'Engineering Diffraction - Warning', 'You are attempting to focus {} workspaces. This may take some time.\n\n Would you like to continue?' .format(len(paths)), QMessageBox.Ok | QMessageBox.Cancel) return response == QMessageBox.Ok else: return True def _on_worker_error(self, error_info): logger.error(str(error_info)) self.emit_enable_button_signal() def set_focus_controls_enabled(self, enabled): self.view.set_focus_button_enabled(enabled) self.view.set_plot_output_enabled(enabled) def emit_enable_button_signal(self): self.view.sig_enable_controls.emit(True) def update_calibration(self, calibration): """ Update the current calibration following an call from a CalibrationNotifier :param calibration: The new current calibration. """ self.current_calibration = calibration region_text = calibration.get_roi_text() self.view.set_region_display_text(region_text)
class CalibrationPresenter(object): def __init__(self, model, view): self.model = model self.view = view self.worker = None self.calibration_notifier = self.CalibrationNotifier(self) self.current_calibration = CalibrationInfo() self.pending_calibration = CalibrationInfo() self.connect_view_signals() # Main Window State Variables self.instrument = "ENGINX" self.rb_num = None # Cropping Options self.cropping_widget = CroppingPresenter(parent=self.view, view=self.view.get_cropping_widget()) self.show_cropping(False) def connect_view_signals(self): self.view.set_on_calibrate_clicked(self.on_calibrate_clicked) self.view.set_enable_controls_connection(self.set_calibrate_controls_enabled) self.view.set_update_field_connection(self.set_field_value) self.view.set_on_radio_new_toggled(self.set_create_new_enabled) self.view.set_on_radio_existing_toggled(self.set_load_existing_enabled) self.view.set_on_check_cropping_state_changed(self.show_cropping) def on_calibrate_clicked(self): plot_output = self.view.get_plot_output() if self.view.get_new_checked() and self._validate(): sample_file = self.view.get_sample_filename() if self.view.get_crop_checked(): self.start_cropped_calibration_worker(sample_file, plot_output, self.rb_num) else: self.start_calibration_worker(sample_file,plot_output, self.rb_num) elif self.view.get_load_checked(): if not self.validate_path(): logger.notice("Invalid calibration path") return filename = self.view.get_path_filename() try: instrument, sample_file, grp_ws_name, roi_text, banks = \ self.model.load_existing_calibration_files(filename) except: return self.pending_calibration.set_calibration(sample_file, instrument) self.pending_calibration.set_roi_info_load(banks, grp_ws_name, roi_text) self.set_current_calibration() set_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_calibration_path", filename) def start_calibration_worker(self, sample_path, plot_output, rb_num, bank=None, calfile=None, spectrum_numbers=None): """ Calibrate the data in a separate thread so as to not freeze the GUI. :param sample_path: Path to sample data file. :param plot_output: Whether to plot the output. :param rb_num: The current RB number set in the GUI. :param bank: Optional parameter to crop by bank. :param calfile: Custom calibration file the user can supply for the calibration region of interest. :param spectrum_numbers: Optional parameter to crop by spectrum number. """ self.worker = AsyncTask(self.model.create_new_calibration, (sample_path,), { "plot_output": plot_output, "instrument": self.instrument, "rb_num": rb_num, "bank": bank, "calfile": calfile, "spectrum_numbers": spectrum_numbers }, error_cb=self._on_error, success_cb=self._on_success) self.pending_calibration.set_calibration(sample_path, self.instrument) self.pending_calibration.set_roi_info(bank, calfile, spectrum_numbers) self.set_calibrate_controls_enabled(False) self.worker.start() def start_cropped_calibration_worker(self, sample_path, plot_output, rb_num): if self.cropping_widget.get_custom_calfile_enabled(): calfile = self.cropping_widget.get_custom_calfile() self.start_calibration_worker(sample_path, plot_output, rb_num, calfile=calfile) elif self.cropping_widget.get_custom_spectra_enabled(): spec_nums = self.cropping_widget.get_custom_spectra() self.start_calibration_worker(sample_path, plot_output, rb_num, spectrum_numbers=spec_nums) else: bank = str(self.cropping_widget.get_bank()) self.start_calibration_worker(sample_path, plot_output, rb_num, bank=bank) def set_current_calibration(self, success_info=None): if success_info: logger.information("Thread executed in " + str(success_info.elapsed_time) + " seconds.") self.current_calibration = deepcopy(self.pending_calibration) self.calibration_notifier.notify_subscribers(self.current_calibration) self.pending_calibration.clear() def load_last_calibration(self) -> None: """ Loads the most recently created or loaded calibration into the interface instance. To be used on interface startup. """ last_cal_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_calibration_path") if last_cal_path: self.view.set_load_checked(True) self.view.set_file_text_with_search(last_cal_path) def set_field_value(self): self.view.set_sample_text(self.current_calibration.get_sample()) def set_instrument_override(self, instrument): instrument = INSTRUMENT_DICT[instrument] self.view.set_instrument_override(instrument) self.instrument = instrument def set_rb_num(self, rb_num): self.rb_num = rb_num def _validate(self): # Do nothing if run numbers are invalid or view is searching. if self.view.is_searching(): create_error_message(self.view, "Mantid is searching for data files. Please wait.") return False if not self.view.get_sample_valid(): create_error_message(self.view, "Check run numbers/path is valid.") return False if self.view.get_crop_checked(): if self.cropping_widget.get_custom_calfile_enabled() and not self.cropping_widget.is_calfile_valid(): create_error_message(self.view, "Check custom calfile path is valid.") return False if self.cropping_widget.get_custom_spectra_enabled() and not self.cropping_widget.is_spectra_valid(): create_error_message(self.view, "Check custom spectra are valid.") return False return True def validate_path(self): return self.view.get_path_valid() def emit_enable_button_signal(self): self.view.sig_enable_controls.emit(True) def set_calibrate_controls_enabled(self, enabled): self.view.set_calibrate_button_enabled(enabled) def _on_error(self, error_info): logger.error(str(error_info)) self.emit_enable_button_signal() def _on_success(self, success_info): self.set_current_calibration(success_info) self.emit_enable_button_signal() def set_create_new_enabled(self, enabled): self.view.set_sample_enabled(enabled) if enabled: self.set_calibrate_button_text("Calibrate") self.view.set_check_plot_output_enabled(True) self.view.set_check_cropping_enabled(True) self.find_files() def set_load_existing_enabled(self, enabled): self.view.set_path_enabled(enabled) if enabled: self.set_calibrate_button_text("Load") self.view.set_check_plot_output_enabled(False) self.view.set_check_cropping_enabled(False) self.view.set_check_cropping_checked(False) def set_calibrate_button_text(self, text): self.view.set_calibrate_button_text(text) def find_files(self): self.view.find_sample_files() def show_cropping(self, show): self.view.set_cropping_widget_visibility(show) # ----------------------- # Observers / Observables # ----------------------- class CalibrationNotifier(Observable): def __init__(self, outer): Observable.__init__(self) self.outer = outer def notify_subscribers(self, *args, **kwargs): Observable.notify_subscribers(self, *args)
def setUp(self): self.test_dir = tempfile.mkdtemp() self.model = model.FocusModel() self.current_calibration = CalibrationInfo( sample_path="this_is_mocked_out_too", instrument="ENGINX")