def test_GIVEN_nexus_file_with_linked_transformation_but_without_dependee_of_attr_WHEN_opening_nexus_file_THEN_components_linked_contain_dependee_of_attribute( ): nexus_wrapper = NexusWrapper(str(uuid1())) transform_name = "transform_1" transform = create_transform(nexus_wrapper, transform_name) component1_name = "test_component1" component2_name = "test_component2" component1 = add_component_to_file(nexus_wrapper, component_name=component1_name) component2 = add_component_to_file(nexus_wrapper, component_name=component2_name) component1.depends_on = transform component2.depends_on = transform del transform._dataset.attrs[CommonAttrs.DEPENDEE_OF] nexus_wrapper.load_nexus_file(nexus_wrapper.nexus_file) new_transform_group = nexus_wrapper.nexus_file[transform_name] assert CommonAttrs.DEPENDEE_OF in new_transform_group.attrs assert len(new_transform_group.attrs[CommonAttrs.DEPENDEE_OF]) == 2 assert (new_transform_group.attrs[CommonAttrs.DEPENDEE_OF][0] == "/" + component1_name) assert (new_transform_group.attrs[CommonAttrs.DEPENDEE_OF][1] == "/" + component2_name)
def test_transform_dependents_depends_on_are_updated_when_transformation_name_is_changed( ): nexus_wrapper = NexusWrapper(str(uuid1())) test_name = "slartibartfast" test_value = 42 test_vector = QVector3D(1.0, 0.0, 0.0) test_type = "Translation" transform_dataset = _add_transform_to_file(nexus_wrapper, test_name, test_value, test_vector, test_type) component = nexus_wrapper.create_nx_group("test", "NXaperture", nexus_wrapper.nexus_file) component.create_dataset("depends_on", data=transform_dataset.name) transform = Transformation(nexus_wrapper, transform_dataset) transform.register_dependent(Component(nexus_wrapper, component)) new_name = test_name + "1" transform.name = new_name assert transform.name == new_name assert str(component["depends_on"][()], encoding="UTF-8") == transform.dataset.name
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_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_GIVEN_no_entry_or_instrument_in_file_WHEN_finding_entry_THEN_default_entry_and_instrument_are_created( file, ): wrapper = NexusWrapper(filename="test_nw5") wrapper.find_entries_in_file(file) assert isinstance(wrapper.entry, h5py.Group) assert isinstance(wrapper.instrument, h5py.Group)
def test_GIVEN_multiple_entry_groups_in_file_WHEN_finding_entry_THEN_signal_is_emitted_with_entry_options( ): with InMemoryFile("test_file") as file: entry = file.create_group("entry") # Test with byte string as well as python string. entry.attrs["NX_class"] = b"NXentry" inst_group = entry.create_group("instrument") inst_group.attrs["NX_class"] = "NXinstrument" entry2 = file.create_group("entry2") entry2.attrs["NX_class"] = "NXentry" inst_group2 = entry2.create_group("instrument2") inst_group2.attrs["NX_class"] = "NXinstrument" wrapper = NexusWrapper(filename="test_nw7") wrapper.show_entries_dialog = Mock() wrapper.show_entries_dialog.emit = Mock() wrapper.find_entries_in_file(file) expected_entry_dict = {entry.name: entry, entry2.name: entry2} assert wrapper.show_entries_dialog.emit.called_once_with( expected_entry_dict, file)
def test_validate_group_reports_problem_when_group_does_not_have_expected_nx_class( ): nexus_wrapper = NexusWrapper() group = nexus_wrapper.create_nx_group("test_group", "NXsomething", nexus_wrapper.nexus_file) problems = validate_group(group, "NXtest", ()) assert ( len(problems) > 0 ), "Expected there to be a reported problem because group does not have expected NX_class"
def test_validate_group_does_not_report_problem_when_group_has_expected_nx_class( ): nexus_wrapper = NexusWrapper() nexus_class = "NXtest" group = nexus_wrapper.create_nx_group("test_group", nexus_class, nexus_wrapper.nexus_file) problems = validate_group(group, nexus_class, ()) assert ( len(problems) == 0 ), "Expected there to be no reported problem because group has expected NX_class"
def create_component(nexus_wrapper: NexusWrapper, component_group: h5py.Group) -> Component: if (nexus_wrapper.get_attribute_value( component_group, CommonAttrs.NX_CLASS) == CHOPPER_CLASS_NAME): return Component(nexus_wrapper, component_group, ChopperShape(nexus_wrapper, component_group)) if (nexus_wrapper.get_attribute_value( component_group, CommonAttrs.NX_CLASS) in PIXEL_COMPONENT_TYPES and "pixel_shape" in component_group): return Component(nexus_wrapper, component_group, PixelShape(nexus_wrapper, component_group)) return Component(nexus_wrapper, component_group)
def test_GIVEN_group_with_bytes_attribute_WHEN_getting_attribute_value_THEN_returns_value_as_str( ): wrapper = NexusWrapper(filename="test_attr_as_str") test_group = wrapper.nexus_file.create_group("test_group") attr_value = b"test_attr_value" attr_name = "test_attr" test_group.attrs[attr_name] = attr_value attr_value_as_str = attr_value.decode("utf-8") assert wrapper.get_attribute_value(test_group, attr_name) == attr_value_as_str
def record_vertices_in_file(nexus_wrapper: nx.NexusWrapper, group: h5py.Group, new_vertices: List[QVector3D]): """ Record vertex data in file :param nexus_wrapper: Wrapper for the file the data will be stored in :param group: The shape group node :param new_vertices: The new vertices data, list of cartesian coords for each vertex """ vertices = [qvector3d_to_numpy_array(vertex) for vertex in new_vertices] vertices_node = nexus_wrapper.set_field_value(group, CommonAttrs.VERTICES, vertices) nexus_wrapper.set_attribute_value(vertices_node, CommonAttrs.UNITS, "m")
def test_validate_dataset_reports_problem_when_expected_dataset_is_not_present( ): nexus_wrapper = NexusWrapper() nexus_wrapper.set_field_value(nexus_wrapper.nexus_file, "a_dataset", 0) dataset_name = "test_dataset" validator = ValidateDataset(dataset_name) problems = [] validator.check(nexus_wrapper.nexus_file, problems) assert ( len(problems) > 0 ), "Expected there to be a reported problem because dataset is not present"
def test_validate_dataset_reports_problem_when_expected_attribute_is_not_present( ): nexus_wrapper = NexusWrapper() dataset_name = "test_dataset" nexus_wrapper.set_field_value(nexus_wrapper.nexus_file, dataset_name, 0) validator = ValidateDataset(dataset_name, attributes={"test_attribute": None}) problems = [] validator.check(nexus_wrapper.nexus_file, problems) assert ( len(problems) > 0 ), "Expected there to be a reported problem because attribute is not present"
def test_GIVEN_variable_length_string_type_dataset_WHEN_getting_value_THEN_returned_as_str( ): wrapper = NexusWrapper(filename="test_read_vlen_str_dataset") dataset_name = "vlen_str_dataset" string_data = b"This is a string" wrapper.nexus_file.create_dataset(dataset_name, dtype=h5py.special_dtype(vlen=str), data=string_data) assert wrapper.get_field_value(wrapper.nexus_file, dataset_name) == string_data.decode("utf8") assert isinstance( wrapper.get_field_value(wrapper.nexus_file, dataset_name), str)
def record_faces_in_file(nexus_wrapper: nx.NexusWrapper, group: h5py.Group, new_faces: List[List[int]]): """ Record face data in file :param nexus_wrapper: Wrapper for the file the data will be stored in :param group: The shape group node :param new_faces: The new face data, list of list for each face with indices of vertices in face """ winding_order = [index for new_face in new_faces for index in new_face] nexus_wrapper.set_field_value(group, "winding_order", winding_order) faces_length = [0] faces_length.extend([len(new_face) for new_face in new_faces[:-1]]) faces_start_indices = np.cumsum(faces_length) nexus_wrapper.set_field_value(group, "faces", faces_start_indices)
def test_GIVEN_entry_group_with_one_instrument_group_WHEN_getting_instrument_group_from_entry_THEN_group_is_returned( file, ): entry = file.create_group("entry") entry.attrs["NX_class"] = "NXentry" inst_group = entry.create_group("instrument") inst_group.attrs["NX_class"] = "NXinstrument" wrapper = NexusWrapper(filename="test_nw") wrapper.load_file(entry, file) assert wrapper.instrument == inst_group assert wrapper.entry == entry assert wrapper.nexus_file == file
def test_GIVEN_single_entry_group_with_instrument_group_WHEN_finding_entry_THEN_file_is_loaded_correctly( file, ): entry = file.create_group("entry") entry.attrs["NX_class"] = "NXentry" inst_group = entry.create_group("instrument") inst_group.attrs["NX_class"] = "NXinstrument" wrapper = NexusWrapper(filename="test_nw5") wrapper.find_entries_in_file(file) assert wrapper.nexus_file == file assert wrapper.entry == entry assert wrapper.instrument == inst_group
def test_can_set_transform_properties(): nexus_wrapper = NexusWrapper(str(uuid1())) initial_name = "slartibartfast" transform = create_transform(nexus_wrapper, initial_name) test_name = "beeblebrox" test_value = 34.0 test_vector = QVector3D(0.0, 0.0, 1.0) test_type = "Rotation" transform.name = test_name transform.value = test_value transform.vector = test_vector transform.type = test_type assert ( transform.name == test_name ), "Expected the transform name to match what was in the NeXus file" assert ( transform.value == test_value ), "Expected the transform value to match what was in the NeXus file" assert ( transform.vector == test_vector ), "Expected the transform vector to match what was in the NeXus file" assert ( transform.type == test_type ), "Expected the transform type to match what was in the NeXus file"
def test_validate_dataset_does_not_report_problem_when_dataset_has_expected_shape( ): nexus_wrapper = NexusWrapper() dataset_name = "test_dataset" dataset_value = np.array(list(range(12))) dataset_shape = (3, 4) dataset_value = np.reshape(dataset_value, dataset_shape) nexus_wrapper.set_field_value(nexus_wrapper.nexus_file, dataset_name, dataset_value) validator = ValidateDataset(dataset_name, shape=dataset_shape) problems = [] validator.check(nexus_wrapper.nexus_file, problems) assert ( len(problems) == 0 ), "Expected there to be no reported problem because dataset has expected shape"
def test_can_get_transform_properties(): nexus_wrapper = NexusWrapper(str(uuid1())) test_name = "slartibartfast" test_value = 42 test_vector = QVector3D(1.0, 0.0, 0.0) test_type = "Translation" transform_dataset = _add_transform_to_file(nexus_wrapper, test_name, test_value, test_vector, test_type) transform = Transformation(nexus_wrapper, transform_dataset) assert ( transform.name == test_name ), "Expected the transform name to match what was in the NeXus file" assert ( transform.ui_value == test_value ), "Expected the transform value to match what was in the NeXus file" assert ( transform.vector == test_vector ), "Expected the transform vector to match what was in the NeXus file" assert ( transform.type == test_type ), "Expected the transform type to match what was in the NeXus file"
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_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_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 create_transformation(trans_type: TransformationType): file = NexusWrapper(str(uuid.uuid4())) ds = file.nexus_file.create_dataset("transform", data=8) t = Transformation(file, ds) t.type = trans_type t.vector = QVector3D(1, 0, 0) return t
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_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_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_can_get_rotation_as_4_by_4_matrix(): nexus_wrapper = NexusWrapper(str(uuid1())) test_value = 45.0 # degrees test_vector = QVector3D(0.0, 1.0, 0.0) # around y-axis test_type = "Rotation" dataset = _add_transform_to_file(nexus_wrapper, "test_transform", test_value, test_vector, test_type) transformation = Transformation(nexus_wrapper, dataset) test_matrix = transformation.qmatrix # for a rotation around the y-axis: test_value_radians = np.deg2rad(test_value) expected_matrix = np.array(( np.cos(-test_value_radians), 0, np.sin(-test_value_radians), 0, 0, 1, 0, 0, -np.sin(-test_value_radians), 0, np.cos(-test_value_radians), 0, 0, 0, 0, 1, )) assert np.allclose(expected_matrix, np.array(test_matrix.data()), atol=1.0e-7)
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_GIVEN_component_with_cylindrical_shape_information_WHEN_duplicating_component_THEN_shape_information_is_stored_in_nexus_file( ): wrapper = NexusWrapper("test_duplicate_cyl_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) 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