def test_save_and_read_csv_without_name(tmpdir): original_fitting_data = FittingData(data=RAW_DATA) original_fitting_data.save_csv(tmpdir) loaded_fitting_data = FittingData.read_from_csv( Path(tmpdir / "fitting_data.csv")) assert_fitting_data_are_equal(original_fitting_data, loaded_fitting_data)
def case_unselect_one_record(): fitting_data = FittingData(COLUMNS) fitting_data.unselect_record(2) return ( fitting_data, [1] + list(range(3, NUMBER_OF_RECORDS + 1)), )
def test_set_cell_not_allowed_because_of_non_existing_row(): fitting_data = FittingData(COLUMNS) value = np.random.uniform(0, 10) column = np.random.choice(COLUMNS_NAMES) with pytest.raises(FittingDataSetError, match="^Record number 13 does not exists$"): fitting_data.set_cell(NUMBER_OF_RECORDS + 1, column, value)
def test_save_and_read_excel_without_name(tmpdir): original_fitting_data = FittingData(data=RAW_DATA) original_fitting_data.save_excel(tmpdir, sheet=SHEET_NAME) loaded_fitting_data = FittingData.read_from_excel( Path(tmpdir / "fitting_data.xlsx"), SHEET_NAME) assert_fitting_data_are_equal(original_fitting_data, loaded_fitting_data)
def test_set_header_with_same_header_does_not_change_anything(header_name): fitting_data = FittingData(COLUMNS) fitting_data.set_header(header_name, header_name) for header in COLUMNS_NAMES: assert fitting_data.data[header] == pytest.approx( COLUMNS[header] ), f'Header "{header}" has changed unexpectedly'
def case_select_multiple_records(): fitting_data = FittingData(COLUMNS) fitting_data.unselect_all_records() fitting_data.select_record(2) fitting_data.select_record(5) fitting_data.select_record(3) fitting_data.select_record(10) return fitting_data, [2, 3, 5, 10]
def test_set_cell_not_allowed_because_of_non_existing_column(): fitting_data = FittingData(COLUMNS) value = np.random.uniform(0, 10) with pytest.raises( FittingDataSetError, match='^Column name "I do not exist" does not exists$' ): fitting_data.set_cell(0, "I do not exist", value)
def test_header_cannot_already_exist(header_name): fitting_data = FittingData(COLUMNS) new_header = np.random.choice( [header for header in COLUMNS_NAMES if header != header_name] ) with pytest.raises( FittingDataSetError, match=f'^The column name:"{new_header}" is already used.$' ): fitting_data.set_header(header_name, new_header)
def case_select_all_records(): fitting_data = FittingData(COLUMNS) fitting_data.unselect_all_records() fitting_data.select_record(2) fitting_data.select_record(5) fitting_data.select_all_records() return fitting_data, list(range(1, NUMBER_OF_RECORDS + 1))
def case_unselect_multiple(): fitting_data = FittingData(COLUMNS) fitting_data.unselect_record(2) fitting_data.unselect_record(5) fitting_data.unselect_record(3) fitting_data.unselect_record(10) return fitting_data, [1, 4, 6, 7, 8, 9] + list(range(11, NUMBER_OF_RECORDS + 1))
def test_set_cell_not_allowed_because_of_non_float_value(): fitting_data = FittingData(COLUMNS) column = np.random.choice(COLUMNS_NAMES) record = np.random.randint(1, NUMBER_OF_RECORDS + 1) value = "I'm not a float" with pytest.raises( FittingDataSetError, match=( f'^The cell at record number:"{record}", column:"{column}"' f" has invalid syntax: I'm not a float.$" ), ): fitting_data.set_cell(record, column, value)
def test_x_larger_than_size(column): with pytest.raises( FittingDataColumnIndexError, match= "^No column number 11 in data. index should be between 1 and 10$", ): FittingData(COLUMNS, **{column: 11})
def case_fitting(case_path): with open(str(case_path), mode="r") as json_file: json_obj = json.load(json_file) func_name = json_obj["fit_function"] func = FittingFunctionsRegistry.load(func_name) fix = json_obj.get("fix", None) if fix is not None: for index, value in fix: func.fix(index, value) data_dict = json_obj["data"] data = FittingData( OrderedDict([ ("x", data_dict["x"]), ("xerr", data_dict["xerr"]), ("y", data_dict["y"]), ("yerr", data_dict["yerr"]), ])) a0 = json_obj.get("a0", None) result = fit(data=data, func=func, a0=a0) decimal = json_obj.get("decimal", 2) inp = dict(actual_result=result, a0=a0, func=func, delta=np.power(10.0, -decimal)) expected_result = json_obj["result"] return inp, expected_result
def test_x_zero_index(column): with pytest.raises( FittingDataColumnIndexError, match= "^No column number 0 in data. index should be between 1 and 10$", ): FittingData(COLUMNS, **{column: 0})
def read_csv(self, filepath): """ Read data from csv file. :param filepath: path of the csv file """ self.fitting_data = FittingData.read_from_csv(filepath)
def test_set_header_allowed(i): old_header = COLUMNS_NAMES[i] new_header = "new_header" fitting_data = FittingData(deepcopy(COLUMNS)) fitting_data.set_header(old_header, new_header) constant_headers = [header for header in COLUMNS_NAMES if header != old_header] for header in constant_headers: assert fitting_data.data[header] == pytest.approx( COLUMNS[header] ), f'Header "{header}" has changed unexpectedly' assert fitting_data.data[new_header] == pytest.approx( COLUMNS[old_header] ), f'Header "{new_header}" has changed unexpectedly' assert set(fitting_data.all_columns) == set( constant_headers + [new_header] ), "Did not update all columns"
def test_exception_risen_because_of_columns_length(): data = deepcopy(COLUMNS) data["a"] = data["a"][:-2] with pytest.raises( FittingDataColumnsLengthError, match="^All columns in FittingData should have the same length$", ): FittingData(data=data)
def case_jumbled_columns(): fitting_data = FittingData(COLUMNS, x_column=3, xerr_column=1, y_column="b", yerr_column=9) expected_columns = Columns(x="c", xerr="a", y="b", yerr="i") return fitting_data, expected_columns
def read_excel(self, filepath, sheet): """ Read data from excel file. :param filepath: path of the excel file :param sheet: sheet from which to read the data. """ self.fitting_data = FittingData.read_from_excel(filepath, sheet)
def test_set_cell_allowed(record_number, column_name): fitting_data = FittingData(deepcopy(COLUMNS)) value = np.random.uniform(0, 10) fitting_data.set_cell( record_number=record_number, column_name=column_name, value=value, ) for column in COLUMNS_NAMES: for i in range(NUMBER_OF_RECORDS): if column == column_name and i + 1 == record_number: assert fitting_data.data[column][i] == value, "New value was not set" else: assert ( fitting_data.data[column][i] == COLUMNS[column][i] ), "Data was change unexpectedly"
def test_set_selection_with_different_size(): fitting_data = FittingData(COLUMNS) def set_records_indices(): fitting_data.records_indices = [False, False, True] with pytest.raises( FittingDataColumnsSelectionError, match=f"^Should select {NUMBER_OF_RECORDS} records, only 3 selected.$", ): set_records_indices()
def test_set_selection_with_non_boolean_values(): fitting_data = FittingData(COLUMNS) def set_records_indices(): fitting_data.records_indices = [False, False, "dummy"] + [True] * ( NUMBER_OF_RECORDS - 3 ) with pytest.raises( FittingDataColumnsSelectionError, match="^When setting record indices, all values should be booleans.$", ): set_records_indices()
def __init__(self, fitting_data: FittingData, app: toga.App): """Initialize window.""" super().__init__(title="Choose Records", size=RECORD_WINDOW_SIZE) main_box = toga.Box(style=Pack(direction=COLUMN)) data_box = toga.Box() self.__checkboxes = [ toga.Switch( label="", is_on=fitting_data.is_selected(i), style=Pack(height=LINE_HEIGHT), ) for i in range(1, fitting_data.length + 1) ] data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label(text="Chosen", style=Pack(height=LINE_HEIGHT)) ] + self.__checkboxes, # noqa: W503 )) for header, column in fitting_data.data.items(): data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label(text=header, style=Pack(height=LINE_HEIGHT)) ] + [ # noqa: W503 toga.Label(text=element, style=Pack(height=LINE_HEIGHT)) for element in column ], )) main_box.add(data_box) main_box.add( LineBox(children=[ toga.Button(label="Save", on_press=self.save_action(fitting_data)) ], )) scroller = toga.ScrollContainer(content=main_box) self.content = scroller self.app = app
def function_cases(odr_mock, request): func, kwargs, model_extra_kwargs, fit_a0 = ( request.param["func"], request.param.get("kwargs", {}), request.param.get("model_extra_kwargs", {}), request.param.get("a0", a0), ) data = FittingData.random(fit_func=func) result = fit(data=data, func=func, a0=fit_a0, **kwargs) return dict( func=func, data=data, result=result, model_extra_kwargs=model_extra_kwargs, a0=fit_a0, mocks=odr_mock, )
def random_fitting_data(mocker, fitting_arguments, random_sigma_mock, random_error_mock): random_array_mock = mocker.patch("eddington.fitting_data.random_array") random_array_side_effect = [] if "a" not in fitting_arguments: random_array_side_effect.append(a) if "x" not in fitting_arguments: random_array_side_effect.append(x) random_array_mock.side_effect = random_array_side_effect return ( FittingData.random(dummy_func1, **fitting_arguments), dict( params=fitting_arguments, random_array=random_array_mock, random_sigma=random_sigma_mock, random_error=random_error_mock, ), )
def select_default_sheet(self): """ Automatically choose the first valid sheet. If it fails to find a valid sheet, resets the input file. """ for sheet in self.input_file_box.sheets_options: if sheet != NO_VALUE: try: self.data_columns_box.fitting_data = FittingData.read_from_excel( Path(self.input_file_box.file_path), sheet) self.input_file_box.selected_sheet = sheet return except FittingDataError: pass if self.data_columns_box.fitting_data is None: self.main_window.error_dialog( title="Input data error", message=("No sheet available with valid data.\n" "Please fix the file or load another one."), ) self.input_file_box.file_path = None
def test_header_cannot_be_set_to_be_empty(header_name): fitting_data = FittingData(COLUMNS) with pytest.raises( FittingDataSetError, match="^Cannot set new header to be empty$" ): fitting_data.set_header(header_name, "")
from eddington import FittingData from tests.fitting_data import ( COLUMNS, COLUMNS_NAMES, CONTENT, DEFAULT_SHEET, NUMBER_OF_RECORDS, ) DECIMAL = 5 DIRECTORY_PATH = Path("/path/to/directory") EPSILON = 1e-5 FIT_DATA = FittingData(COLUMNS) def assert_workbook_calls(workbook, sheet_name=DEFAULT_SHEET, name="fitting_data"): worksheet = workbook.active assert worksheet.title == sheet_name assert (worksheet.append.call_count == NUMBER_OF_RECORDS + 1), "worksheet append called unexpected number of times" assert worksheet.append.call_args_list[0] == call( COLUMNS_NAMES), "worksheet append called unexpected number of times" for i in range(NUMBER_OF_RECORDS): assert worksheet.append.call_args_list[i + 1][0][0] == pytest.approx( CONTENT[i], rel=EPSILON), "worksheet append called unexpected number of times"
def __init__(self, fitting_data: FittingData, font_size: FontSize, app: toga.App): """Initialize window.""" super().__init__(title="Choose Records", size=RECORD_WINDOW_SIZE) self.__fitting_data = fitting_data main_box = toga.Box(style=Pack(direction=COLUMN)) data_box = toga.Box() statistics_box = toga.Box() font_size_value = FontSize.get_font_size(font_size) self.__update_on_check = True self.__statistics_labels = { (column, parameter): toga.Label( text=to_relevant_precision_string( getattr(fitting_data.statistics(column), parameter, 0)), style=Pack(height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value), ) for column, parameter in itertools.product( fitting_data.all_columns, Statistics.parameters()) } self.__checkboxes = [ toga.Switch( label="", is_on=fitting_data.is_selected(i), on_toggle=self.select_records, style=Pack(height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value), ) for i in range(1, fitting_data.length + 1) ] self.__all_checkbox = toga.Switch( label="", is_on=self.are_all_selected(), on_toggle=self.select_all, style=Pack(height=TITLES_LINE_HEIGHT, font_size=font_size_value), ) self.__selected_records_label = toga.Label( text="", style=Pack(font_size=font_size_value, width=COLUMN_WIDTH, height=TITLES_LINE_HEIGHT), ) data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Box( style=Pack( height=TITLES_LINE_HEIGHT, font_size=font_size_value, ), children=[ self.__all_checkbox, self.__selected_records_label ], ), *self.__checkboxes, ], )) for header, column in fitting_data.data.items(): data_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label( text=header, style=Pack( height=TITLES_LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value, font_weight=BOLD, ), ), *[ toga.Label( text=to_relevant_precision_string(element), style=Pack( height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value, ), ) for element in column ], ], )) main_box.add(data_box) main_box.add(toga.Divider()) statistics_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ toga.Label( text=parameter.replace("_", " ").title(), style=Pack( height=LINE_HEIGHT, width=COLUMN_WIDTH, font_size=font_size_value, font_weight=BOLD, ), ) for parameter in Statistics.parameters() ], )) for header, column in fitting_data.data.items(): statistics_box.add( toga.Box( style=Pack( flex=1, direction=COLUMN, padding_left=SMALL_PADDING, padding_right=SMALL_PADDING, ), children=[ self.__statistics_labels[(header, parameter)] for parameter in Statistics.parameters() ], )) main_box.add(statistics_box) main_box.add( LineBox(children=[ toga.Button(label="Close", on_press=lambda _: self.close()) ], )) scroller = toga.ScrollContainer(content=main_box) self.content = scroller self.app = app self.update()
HAS_LEGEND = "has_legend" DOES_NOT_HAVE_LEGEND = "does_not_have_legend" EPSILON = 1e-5 FUNC = linear X = np.arange(1, 11) A1, A2, A3 = np.array([1, 1]), np.array([3, 2]), np.array([3.924356, 1.2345e-5]) A1_REPR, A2_REPR, A3_REPR = ( "[a[0]=1.000, a[1]=1.000]", "[a[0]=3.000, a[1]=2.000]", "[a[0]=3.924, a[1]=1.234e-05]", ) FIT_DATA = FittingData.random(FUNC, x=X, a=np.array([1, 2]), measurements=X.shape[0]) TITLE_NAME = "Title" @case(tags=[DOES_NOT_HAVE_LEGEND]) def case_no_args(mock_figure): x = np.arange(0.1, 10.9, step=0.0108) kwargs = dict(a=A1) plot_calls = [([x, FUNC(A1, x)], dict(label=A1_REPR))] return kwargs, plot_calls, mock_figure @case(tags=[DOES_NOT_HAVE_LEGEND]) def case_xmin(mock_figure):