def test_GIVEN_instrument_containing_component_WHEN_generating_json_THEN_file_is_written_containing_components( ): file = io.StringIO(newline=None) wrapper = NexusWrapper("test.nxs") data = Instrument(wrapper, NX_CLASS_DEFINITIONS) component_name = "pinhole" component_nx_class = "NXpinhole" dataset_name = "depends_on" dataset_value = "something_else" component = data.create_component(component_name, component_nx_class, "") component.set_field(dataset_name, value=dataset_value, dtype=str) write_nexus_structure_to_json(data, file) output_file_dict = json.loads(file.getvalue()) component = output_file_dict["children"][0]["children"][0]["children"][0] assert component["name"].lstrip("/entry/instrument/") == component_name assert (component["children"][0]["name"].lstrip( f"/entry/instrument/{component_name}/") == dataset_name) assert component["children"][0]["type"] == "dataset" assert component["children"][0]["values"] == dataset_value assert component["children"][0]["dataset"]["type"] == "string"
def test_GIVEN_component_with_cylindrical_shape_information_WHEN_duplicating_component_THEN_shape_information_is_stored_in_nexus_file( nexus_wrapper, ): instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) first_component_name = "component1" first_component_nx_class = "NXdetector" description = "desc" first_component = instrument.create_component(first_component_name, first_component_nx_class, description) axis_direction = QVector3D(1, 0, 0) height = 2 radius = 3 units = "cm" first_component.set_cylinder_shape(axis_direction=axis_direction, height=height, radius=radius, units=units) tree_model = ComponentTreeModel(instrument) first_component_index = tree_model.index(0, 0, QModelIndex()) tree_model.duplicate_node(first_component_index) assert tree_model.rowCount(QModelIndex()) == 3 second_component_index = tree_model.index(2, 0, QModelIndex()) second_component = second_component_index.internalPointer() second_shape, _ = second_component.shape assert second_shape.axis_direction == axis_direction assert second_shape.height == height assert second_shape.units == units
def test_GIVEN_instrument_with_component_WHEN_component_is_removed_THEN_components_list_does_not_contain_component( ): wrapper = NexusWrapper("test_components_list") instrument = Instrument(wrapper, NX_CLASS_DEFINITIONS) component_type = "NXcrystal" name = "test_crystal" description = "shiny" test_component = instrument.create_component(name, component_type, description) # Test component should be in list check_if_component_is_in_component_list(component_type, description, instrument, name, expect_component_present=True) instrument.remove_component(test_component) # Test component should no longer be in list check_if_component_is_in_component_list(component_type, description, instrument, name, expect_component_present=False)
def test_UI_GIVEN_new_values_are_provided_WHEN_save_changes_is_called_THEN_transformation_changed_signal_is_called_to_update_3d_view( qtbot, ): wrapper = NexusWrapper() instrument = Instrument(wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 1 y = 2 z = 3 angle = 90 transform = component.add_rotation(angle=angle, axis=QVector3D(x, y, z)) view = EditRotation(parent=None, transformation=transform, instrument=instrument) instrument.nexus.transformation_changed = Mock() qtbot.addWidget(view) new_x = 4 view.transformation_frame.x_spinbox.setValue(new_x) view.saveChanges() instrument.nexus.transformation_changed.emit.assert_called_once() assert transform.vector == QVector3D(new_x, y, z)
def test_UI_GIVEN_link_as_rotation_magnitude_WHEN_creating_rotation_view_THEN_ui_is_filled_correctly( qtbot, ): wrapper = NexusWrapper(filename="asdfgsdfh") instrument = Instrument(wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 0 y = 0 z = 0 path = "/entry" transform = component.add_rotation(QVector3D(x, y, z), 0, name="test") link = wrapper.instrument["asdfgh"] = h5py.SoftLink(path) transform.dataset = link view = EditRotation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) assert view.transformation_frame.x_spinbox.value() == x assert view.transformation_frame.y_spinbox.value() == y assert view.transformation_frame.z_spinbox.value() == z assert view.transformation_frame.value_spinbox.value() == 0.0 assert view.transformation_frame.magnitude_widget.field_type == FieldType.link assert view.transformation_frame.magnitude_widget.value.path == path
def test_UI_GIVEN_vector_updated_WHEN_saving_view_changes_THEN_model_is_updated(qtbot): wrapper = NexusWrapper() instrument = Instrument(wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 1 y = 2 z = 3 angle = 90 transform = component.add_rotation(angle=angle, axis=QVector3D(x, y, z)) view = EditRotation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) new_x = 4 new_y = 5 new_z = 6 view.transformation_frame.x_spinbox.setValue(new_x) view.transformation_frame.y_spinbox.setValue(new_y) view.transformation_frame.z_spinbox.setValue(new_z) view.saveChanges() assert transform.vector == QVector3D(new_x, new_y, new_z)
def test_UI_GIVEN_array_dataset_as_magnitude_WHEN_creating_translation_THEN_ui_is_filled_correctly( qtbot, file # noqa:F811 ): wrapper = NexusWrapper() instrument = Instrument(wrapper, {}) component = instrument.create_component("test", "NXaperture", "") array = np.array([1, 2, 3, 4]) x = 1 y = 0 z = 0 transform = component.add_translation(QVector3D(x, y, z), name="test") transform.dataset = file.create_dataset("test", data=array) view = EditTranslation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) assert view.transformation_frame.x_spinbox.value() == x assert view.transformation_frame.y_spinbox.value() == y assert view.transformation_frame.z_spinbox.value() == z assert np.allclose(view.transformation.dataset[...], array) assert ( view.transformation_frame.magnitude_widget.field_type == FieldType.array_dataset )
def test_UI_GIVEN_scalar_angle_WHEN_creating_rotation_view_THEN_ui_is_filled_correctly( qtbot, ): wrapper = NexusWrapper() instrument = Instrument(wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 1 y = 2 z = 3 angle = 90 transform = component.add_rotation(angle=angle, axis=QVector3D(x, y, z)) view = EditRotation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) assert view.transformation_frame.x_spinbox.value() == x assert view.transformation_frame.y_spinbox.value() == y assert view.transformation_frame.z_spinbox.value() == z assert view.transformation_frame.value_spinbox.value() == angle assert view.transformation_frame.magnitude_widget.value[()] == angle assert ( view.transformation_frame.magnitude_widget.field_type == FieldType.scalar_dataset )
def test_remove_component(nexus_wrapper): instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) under_test = ComponentTreeModel(instrument) instrument.create_component("Some name", "some class", "desc") component_index = under_test.index(0, 0, QModelIndex()) assert under_test.rowCount(QModelIndex()) == 1 under_test.remove_node(component_index) assert under_test.rowCount(QModelIndex()) == 0
def test_remove_transformation(nexus_wrapper): instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) under_test = ComponentTreeModel(instrument) instrument.create_component("Some name", "some class", "desc") component_index = under_test.index(0, 0, QModelIndex()) under_test.add_rotation(component_index) transformation_list_index = under_test.index(1, 0, component_index) transformation_index = under_test.index(0, 0, transformation_list_index) assert under_test.rowCount(transformation_list_index) == 1 under_test.remove_node(transformation_index) assert under_test.rowCount(transformation_list_index) == 0
def test_remove_component_with_transformation(nexus_wrapper): instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) under_test = ComponentTreeModel(instrument) instrument.create_component("Some name", "some class", "desc") component_index = under_test.index(0, 0, QModelIndex()) under_test.add_rotation(component_index) assert under_test.rowCount(QModelIndex()) == 1 under_test.remove_node(component_index) assert under_test.rowCount(QModelIndex()) == 0, ( "Expected component to be successfully deleted because it has " "a transformation that only has it as a dependent")
def test_remove_link(): wrapper = NexusWrapper("test_remove_link") instrument = Instrument(wrapper, NX_CLASS_DEFINITIONS) under_test = ComponentTreeModel(instrument) instrument.create_component("Some name", "some class", "desc") component_index = under_test.index(0, 0, QModelIndex()) under_test.add_link(component_index) transformation_list_index = under_test.index(1, 0, component_index) transformation_index = under_test.index(0, 0, transformation_list_index) assert under_test.rowCount(transformation_list_index) == 1 assert len(transformation_list_index.internalPointer()) == 0 under_test.remove_node(transformation_index) assert under_test.rowCount(transformation_list_index) == 0
def test_GIVEN_component_WHEN_adding_component_THEN_components_list_contains_added_component( nexus_wrapper, ): instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) component_type = "NXcrystal" name = "test_crystal" description = "shiny" instrument.create_component(name, component_type, description) check_if_component_is_in_component_list(component_type, description, instrument, name, expect_component_present=True)
def test_GIVEN_stream_group_that_has_ev42_advanced_option_WHEN_filling_in_existing_field_widget_THEN_ev42_group_box_is_shown( file, qtbot): group = file.create_group("stream2") group.attrs["NX_class"] = "NCstream" vlen_str = h5py.special_dtype(vlen=str) group.create_dataset("writer_module", dtype=vlen_str, data="ev42") group.create_dataset("topic", dtype=vlen_str, data="topic1") group.create_dataset("source", dtype=vlen_str, data="source1") group.create_dataset(ADC_PULSE_DEBUG, dtype=bool, data=True) wrapper = NexusWrapper() wrapper.load_file(file, file) instrument = Instrument(wrapper, {}) widget = FieldWidget(instrument=instrument) qtbot.addWidget(widget) update_existing_stream_field(group, widget) # this would usually be done outside of the update_existing_stream_field widget.name = get_name_of_node(group) assert widget.streams_widget.ev42_advanced_group_box.isEnabled() generated_group = widget.streams_widget.get_stream_group() assert generated_group["writer_module"][()] == group["writer_module"][()] assert generated_group["topic"][()] == group["topic"][()] assert generated_group["source"][()] == group["source"][()] assert generated_group[ADC_PULSE_DEBUG][()] == group[ADC_PULSE_DEBUG][()]
def test_dependents_list_is_created_by_instrument(file, nexus_wrapper): """ The dependents list for transforms is stored in the "dependent_of" attribute, which is not part of the NeXus standard, we therefore cannot rely on it being present and correct in a file we load. This test makes sure that instrument generates this information in the wrapped NeXus file it is given. """ # Create minimal test file with some transformations but no "dependent_of" attributes entry_group = file.create_group("entry") entry_group.attrs["NX_class"] = "NXentry" instrument_group = entry_group.create_group("instrument") instrument_group.attrs["NX_class"] = "NXinstrument" transforms_group = instrument_group.create_group("transformations") transforms_group.attrs["NX_class"] = "NXtransformations" transform_1 = transforms_group.create_dataset("transform_1", data=42) transform_2 = transforms_group.create_dataset("transform_2", data=42) transform_3 = transforms_group.create_dataset("transform_3", data=42) transform_4 = transforms_group.create_dataset("transform_4", data=42) transform_2.attrs["depends_on"] = transform_1.name transform_3.attrs["depends_on"] = transform_2.name transform_4.attrs["depends_on"] = transform_2.name nexus_wrapper.load_file(entry_group, file) Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) transform_1_loaded = Transformation(nexus_wrapper, transform_1) assert ( len(transform_1_loaded.dependents) == 1 ), "Expected transform 1 to have a registered dependent (transform 2)" transform_2_loaded = Transformation(nexus_wrapper, transform_2) assert ( len(transform_2_loaded.dependents) == 2 ), "Expected transform 2 to have 2 registered dependents (transforms 3 and 4)"
def test_GIVEN_stream_group_that_has_f142_advanced_option_WHEN_filling_in_existing_field_widget_THEN_f142_group_box_is_shown( file, qtbot, nexus_wrapper): group = file.create_group("stream1") group.attrs["NX_class"] = "NCstream" vlen_str = h5py.special_dtype(vlen=str) group.create_dataset("writer_module", dtype=vlen_str, data="f142") group.create_dataset("type", dtype=vlen_str, data="byte") group.create_dataset("topic", dtype=vlen_str, data="topic1") group.create_dataset("source", dtype=vlen_str, data="source1") group.create_dataset(NEXUS_INDICES_INDEX_EVERY_MB, dtype=int, data=1) wrapper = nexus_wrapper wrapper.load_file(file, file) instrument = Instrument(wrapper, {}) widget = FieldWidget(instrument=instrument) qtbot.addWidget(widget) update_existing_stream_field(group, widget) # this would usually be done outside of the update_existing_stream_field widget.name = get_name_of_node(group) assert widget.streams_widget.f142_advanced_group_box.isEnabled() generated_group = widget.streams_widget.get_stream_group() assert generated_group["writer_module"][()] == group["writer_module"][()] assert generated_group["topic"][()] == group["topic"][()] assert generated_group["type"][()] == group["type"][()] assert generated_group["source"][()] == group["source"][()] assert (generated_group[NEXUS_INDICES_INDEX_EVERY_MB][( )] == group[NEXUS_INDICES_INDEX_EVERY_MB][()])
def test_dependee_of_contains_both_components_when_generating_dependee_of_chain_with_mixture_of_absolute_and_relative_paths( file, # noqa: F811 ): entry_group = file.create_group("entry") entry_group.attrs["NX_class"] = "NXentry" instrument_group = entry_group.create_group("instrument") instrument_group.attrs["NX_class"] = "NXinstrument" component_a = instrument_group.create_group("a") component_a.attrs["NX_class"] = "NXaperture" transforms_group = component_a.create_group("Transforms1") transform_1 = transforms_group.create_dataset("transform1", data=1.0) # Relative path to transform component_a.create_dataset("depends_on", data="Transforms1/transform1") component_b = instrument_group.create_group("b") component_b.attrs["NX_class"] = "NXaperture" # Absolute path to transform component_b.create_dataset( "depends_on", data="/entry/instrument/a/Transforms1/transform1") nexus_wrapper = NexusWrapper("test_dependent_transforms_1") nexus_wrapper.load_file(entry_group, file) Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) transform_1_loaded = Transformation(nexus_wrapper, transform_1) # Check both relative and absolute are in dependee_of list assert component_a.name in transform_1_loaded.dataset.attrs[ "NCdependee_of"] assert component_b.name in transform_1_loaded.dataset.attrs[ "NCdependee_of"]
def test_GIVEN_component_with_off_shape_information_WHEN_duplicating_component_THEN_shape_information_is_stored_in_nexus_file( ): wrapper = NexusWrapper("test_duplicate_off_shape") instrument = Instrument(wrapper, NX_CLASS_DEFINITIONS) first_component_name = "component1" first_component_nx_class = "NXdetector" description = "desc" first_component = instrument.create_component(first_component_name, first_component_nx_class, description) vertices = [ QVector3D(-0.5, -0.5, 0.5), QVector3D(0.5, -0.5, 0.5), QVector3D(-0.5, 0.5, 0.5), QVector3D(0.5, 0.5, 0.5), QVector3D(-0.5, 0.5, -0.5), QVector3D(0.5, 0.5, -0.5), QVector3D(-0.5, -0.5, -0.5), QVector3D(0.5, -0.5, -0.5), ] faces = [ [0, 1, 3, 2], [2, 3, 5, 4], [4, 5, 7, 6], [6, 7, 1, 0], [1, 7, 5, 3], [6, 0, 2, 4], ] first_component.set_off_shape( OFFGeometryNoNexus(vertices=vertices, faces=faces)) tree_model = ComponentTreeModel(instrument) first_component_index = tree_model.index(0, 0, QModelIndex()) tree_model.duplicate_node(first_component_index) assert tree_model.rowCount(QModelIndex()) == 3 second_component_index = tree_model.index(2, 0, QModelIndex()) second_component = second_component_index.internalPointer() second_shape, _ = second_component.shape assert second_shape.vertices == vertices assert second_shape.faces == faces
def test_duplicate_component(): data_under_test = Instrument( NexusWrapper("test_component_model_duplicate"), NX_CLASS_DEFINITIONS) under_test = ComponentTreeModel(data_under_test) assert under_test.rowCount(QModelIndex()) == 1 # Sample under_test.add_component(get_component()) component_index = under_test.index(0, 0, QModelIndex()) under_test.duplicate_node(component_index) assert under_test.rowCount(QModelIndex()) == 3
def test_UI_GIVEN_stream_group_as_angle_WHEN_creating_rotation_THEN_ui_is_filled_correctly( qtbot, file, nexus_wrapper): instrument = Instrument(nexus_wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 0 y = 0 z = 0 transform = component.add_rotation(QVector3D(x, y, z), 0, name="test") stream_group = file.create_group("stream_group") stream_group.attrs["NX_class"] = "NCstream" topic = "test_topic" writer_module = "ev42" source = "source1" stream_group.create_dataset("topic", dtype=h5py.special_dtype(vlen=str), data=topic) stream_group.create_dataset("writer_module", data=writer_module) stream_group.create_dataset("source", data=source) transform.dataset = stream_group view = EditRotation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) assert view.transformation_frame.x_spinbox.value() == x assert view.transformation_frame.y_spinbox.value() == y assert view.transformation_frame.z_spinbox.value() == z assert view.transformation_frame.value_spinbox.value() == 0.0 assert (view.transformation_frame.magnitude_widget.field_type == FieldType.kafka_stream) assert view.transformation_frame.magnitude_widget.value["topic"][( )] == topic assert (view.transformation_frame.magnitude_widget.value["writer_module"][( )] == writer_module) assert view.transformation_frame.magnitude_widget.value["source"][( )] == source
def test_UI_GIVEN_scalar_vector_WHEN_creating_translation_view_THEN_ui_is_filled_correctly( qtbot, nexus_wrapper): instrument = Instrument(nexus_wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 1 y = 0 z = 0 transform = component.add_translation(QVector3D(x, y, z), name="test") view = EditTranslation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) assert view.transformation_frame.x_spinbox.value() == x assert view.transformation_frame.y_spinbox.value() == y assert view.transformation_frame.z_spinbox.value() == z assert view.transformation_frame.value_spinbox.value() == 1 assert view.transformation_frame.magnitude_widget.value[()] == 1 assert (view.transformation_frame.magnitude_widget.field_type == FieldType.scalar_dataset)
def test_UI_GIVEN_view_loses_focus_WHEN_transformation_view_exists_THEN_spinboxes_are_disabled( qtbot, ): wrapper = NexusWrapper() instrument = Instrument(wrapper, {}) component = instrument.create_component("test", "NXaperture", "") x = 1 y = 2 z = 3 angle = 90 transform = component.add_rotation(angle=angle, axis=QVector3D(x, y, z)) view = EditRotation(parent=None, transformation=transform, instrument=instrument) qtbot.addWidget(view) view.disable() assert not view.transformation_frame.x_spinbox.isEnabled() assert not view.transformation_frame.y_spinbox.isEnabled() assert not view.transformation_frame.z_spinbox.isEnabled() assert not view.transformation_frame.name_line_edit.isEnabled()
def test_duplicate_transform_fail(): data_under_test = Instrument( NexusWrapper("test_component_model_duplicate_fail"), NX_CLASS_DEFINITIONS) under_test = ComponentTreeModel(data_under_test) under_test.add_component(get_component()) component_index = under_test.index(0, 0, QModelIndex()) under_test.add_rotation(component_index) transformation_list_index = under_test.index(1, 0, component_index) transformation_index = under_test.index(0, 0, transformation_list_index) try: under_test.duplicate_node(transformation_index) except (NotImplementedError, AttributeError): return # Success assert False # Failure
def test_ui_field_GIVEN_field_has_units_filled_in_ui_WHEN_getting_field_group_THEN_units_are_stored_in_attrs( qtbot, ): nexus_wrapper = NexusWrapper("test_ui_fields_units") instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) listwidget = QListWidget() field = FieldWidget(["test"], listwidget, instrument=instrument) field_name = "test" field.name = field_name field.value_line_edit.setText("1") qtbot.addWidget(field) units = "m" field.units = units group = field.value assert "units" in group.attrs assert group.attrs["units"] == units
def test_dependent_is_created_by_instrument_if_depends_on_is_relative( file, nexus_wrapper): entry_group = file.create_group("entry") entry_group.attrs["NX_class"] = "NXentry" monitor_group = entry_group.create_group("monitor1") monitor_group.attrs["NX_class"] = "NXmonitor" monitor_group.create_dataset("depends_on", data=b"transformations/translation1") transformations_group = monitor_group.create_group("transformations") transformations_group.attrs["NX_class"] = "NXtransformations" transform_1 = transformations_group.create_dataset("translation1", data=1) nexus_wrapper.load_file(entry_group, file) Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) transform_1_loaded = Transformation(nexus_wrapper, transform_1) assert transform_1_loaded.dataset.attrs["NCdependee_of"][ 0] == "/entry/monitor1"
def instrument(nexus_wrapper) -> Instrument: return Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS)
def test_GIVEN_nothing_WHEN_getting_components_list_THEN_list_contains_sample_and_no_components( nexus_wrapper, ): instrument = Instrument(nexus_wrapper, NX_CLASS_DEFINITIONS) assert len(instrument.get_component_list()) == 1
from PySide2.QtGui import QIcon from PySide2.QtWidgets import QApplication, QMainWindow from PySide2 import QtCore from nexus_constructor.component.component_type import ( make_dictionary_of_class_definitions, ) from nexus_constructor.main_window import MainWindow from nexus_constructor.nexus.nexus_wrapper import NexusWrapper from nexus_constructor.instrument import Instrument import os import argparse if __name__ == "__main__": parser = argparse.ArgumentParser(description="Nexus Constructor") if "help" in parser.parse_args(): exit(0) logging.basicConfig(level=logging.INFO) QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) app = QApplication(sys.argv) app.setWindowIcon(QIcon(os.path.join("ui", "icon.png"))) window = QMainWindow() nexus_wrapper = NexusWrapper() definitions_dir = os.path.abspath(os.path.join(os.getcwd(), "definitions")) _, nx_component_classes = make_dictionary_of_class_definitions( definitions_dir) instrument = Instrument(nexus_wrapper, nx_component_classes) ui = MainWindow(instrument, nx_component_classes) ui.setupUi(window) window.showMaximized() sys.exit(app.exec_())
def test_GIVEN_nothing_WHEN_getting_components_list_THEN_list_contains_sample_and_no_components( ): wrapper = NexusWrapper("component_list_with_sample") instrument = Instrument(wrapper, NX_CLASS_DEFINITIONS) assert len(instrument.get_component_list()) == 1