def test_data_collection_combo_helper(): callback = MagicMock() state = ExampleState() state.add_callback('combo', callback) dc = DataCollection([]) helper = DataCollectionComboHelper(state, 'combo', dc) # noqa data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') assert callback.call_count == 0 dc.append(data1) assert callback.call_count == 1 assert selection_choices(state, 'combo') == "data1" data1.label = 'mydata1' assert selection_choices(state, 'combo') == "mydata1" assert callback.call_count == 2 dc.remove(data1) assert callback.call_count == 3 assert selection_choices(state, 'combo') == ""
def test_component_id_combo_helper(): state = ExampleState() dc = DataCollection([]) helper = ComponentIDComboHelper(state, 'combo', dc) assert selection_choices(state, 'combo') == "" data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) helper.append_data(data1) assert selection_choices(state, 'combo') == "x:y" data2 = Data(a=[1, 2, 3], b=['a', 'b', 'c'], label='data2') dc.append(data2) helper.append_data(data2) assert selection_choices(state, 'combo') == "data1:x:y:data2:a:b" helper.categorical = False assert selection_choices(state, 'combo') == "data1:x:y:data2:a" helper.numeric = False assert selection_choices(state, 'combo') == "data1:data2" helper.categorical = True helper.numeric = True helper.visible = False assert selection_choices( state, 'combo' ) == "data1:x:Pixel Axis 0 [x]:World 0:y:data2:a:Pixel Axis 0 [x]:World 0:b" helper.visible = True dc.remove(data2) assert selection_choices(state, 'combo') == "x:y" # TODO: check that renaming a component updates the combo # data1.id['x'].label = 'z' # assert selection_choices(state, 'combo') == "z:y" helper.remove_data(data1) assert selection_choices(state, 'combo') == ""
def test_component_id_combo_helper(): combo = QtWidgets.QComboBox() dc = DataCollection([]) helper = ComponentIDComboHelper(combo, dc) assert combo_as_string(combo) == "" data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) helper.append_data(data1) assert combo_as_string(combo) == "x:y" data2 = Data(a=[1, 2, 3], b=['a', 'b', 'c'], label='data2') dc.append(data2) helper.append_data(data2) assert combo_as_string(combo) == "data1:x:y:data2:a:b" helper.categorical = False assert combo_as_string(combo) == "data1:x:y:data2:a" helper.numeric = False assert combo_as_string(combo) == "data1:data2" helper.categorical = True helper.numeric = True helper.visible = False assert combo_as_string( combo ) == "data1:Pixel Axis 0 [x]:World 0:x:y:data2:Pixel Axis 0 [x]:World 0:a:b" helper.visible = True dc.remove(data2) assert combo_as_string(combo) == "x:y" # TODO: check that renaming a component updates the combo # data1.id['x'].label = 'z' # assert combo_as_string(combo) == "z:y" helper.remove_data(data1) assert combo_as_string(combo) == ""
def test_close_on_last_layer_remove(self): # regression test for 391 d1 = Data(x=np.random.random((2,) * self.ndim)) d2 = Data(y=np.random.random((2,) * self.ndim)) dc = DataCollection([d1, d2]) app = GlueApplication(dc) with patch.object(self.widget_cls, 'close') as close: w = app.new_data_viewer(self.widget_cls, data=d1) w.add_data(d2) dc.remove(d1) dc.remove(d2) assert close.call_count >= 1
def test_component_id_combo_helper(): combo = QtWidgets.QComboBox() dc = DataCollection([]) helper = ComponentIDComboHelper(combo, dc) assert _items_as_string(combo) == "" data1 = Data(x=[1,2,3], y=[2,3,4], label='data1') dc.append(data1) helper.append_data(data1) assert _items_as_string(combo) == "x:y" data2 = Data(a=[1,2,3], b=['a','b','c'], label='data2') dc.append(data2) helper.append_data(data2) assert _items_as_string(combo) == "data1:x:y:data2:a:b" helper.categorical = False assert _items_as_string(combo) == "data1:x:y:data2:a" helper.numeric = False assert _items_as_string(combo) == "data1:data2" helper.categorical = True helper.numeric = True helper.visible = False assert _items_as_string(combo) == "data1:Pixel Axis 0 [x]:World 0:x:y:data2:Pixel Axis 0 [x]:World 0:a:b" helper.visible = True dc.remove(data2) assert _items_as_string(combo) == "x:y" # TODO: check that renaming a component updates the combo # data1.id['x'].label = 'z' # assert _items_as_string(combo) == "z:y" helper.remove_data(data1) assert _items_as_string(combo) == ""
def test_close_on_last_layer_remove(self): # regression test for 391 d1 = Data(x=np.random.random((2,) * self.ndim)) d2 = Data(y=np.random.random((2,) * self.ndim)) dc = DataCollection([d1, d2]) app = GlueApplication(dc) w = app.new_data_viewer(self.widget_cls, data=d1) w.add_data(d2) process_events() assert len(app.viewers[0]) == 1 dc.remove(d1) process_events() assert len(app.viewers[0]) == 1 dc.remove(d2) process_events() assert len(app.viewers[0]) == 0 app.close()
def test_close_on_last_layer_remove(self): # regression test for 391 d1 = Data(x=np.random.random((2, ) * self.ndim)) d2 = Data(y=np.random.random((2, ) * self.ndim)) dc = DataCollection([d1, d2]) app = GlueApplication(dc) w = app.new_data_viewer(self.widget_cls, data=d1) w.add_data(d2) process_events() assert len(app.viewers[0]) == 1 dc.remove(d1) process_events() assert len(app.viewers[0]) == 1 dc.remove(d2) process_events() assert len(app.viewers[0]) == 0 app.close()
def test_data_collection_combo_helper(): combo = QtWidgets.QComboBox() dc = DataCollection([]) helper = DataCollectionComboHelper(combo, dc) data1 = Data(x=[1,2,3], y=[2,3,4], label='data1') dc.append(data1) assert _items_as_string(combo) == "data1" data1.label = 'mydata1' assert _items_as_string(combo) == "mydata1" dc.remove(data1) assert _items_as_string(combo) == ""
def test_data_collection_combo_helper(): combo = QtWidgets.QComboBox() dc = DataCollection([]) helper = DataCollectionComboHelper(combo, dc) data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) assert combo_as_string(combo) == "data1" data1.label = 'mydata1' assert combo_as_string(combo) == "mydata1" dc.remove(data1) assert combo_as_string(combo) == ""
def test_data_collection_combo_helper(): state = ExampleState() dc = DataCollection([]) helper = DataCollectionComboHelper(state, 'combo', dc) # noqa data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) assert selection_choices(state, 'combo') == "data1" data1.label = 'mydata1' assert selection_choices(state, 'combo') == "mydata1" dc.remove(data1) assert selection_choices(state, 'combo') == ""
def test_manual_data_combo_helper(initialize_data_collection): # The case with initialize_data_collection=False is a regression test for a # bug which meant that when a ManualDataComboHelper was initialized without # a data collection, it did not change when a data object added later has a # label changed. callback = MagicMock() state = ExampleState() state.add_callback('combo', callback) dc = DataCollection([]) if initialize_data_collection: helper = ManualDataComboHelper(state, 'combo', dc) else: helper = ManualDataComboHelper(state, 'combo') data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) assert callback.call_count == 0 assert selection_choices(state, 'combo') == "" helper.append_data(data1) assert callback.call_count == 1 assert selection_choices(state, 'combo') == "data1" data1.label = 'mydata1' assert selection_choices(state, 'combo') == "mydata1" assert callback.call_count == 2 if initialize_data_collection: dc.remove(data1) assert selection_choices(state, 'combo') == "" assert callback.call_count == 3
def test_close_on_last_layer_remove(self): # regression test for 391 # Note: processEvents is needed for things to work correctly with PySide2 qtapp = get_qapp() d1 = Data(x=np.random.random((2,) * self.ndim)) d2 = Data(y=np.random.random((2,) * self.ndim)) dc = DataCollection([d1, d2]) app = GlueApplication(dc) w = app.new_data_viewer(self.widget_cls, data=d1) w.add_data(d2) qtapp.processEvents() assert len(app.viewers[0]) == 1 dc.remove(d1) qtapp.processEvents() assert len(app.viewers[0]) == 1 dc.remove(d2) qtapp.processEvents() assert len(app.viewers[0]) == 0 app.close()
def test_close_on_last_layer_remove(self): # regression test for 391 # Note: processEvents is needed for things to work correctly with PySide2 qtapp = get_qapp() d1 = Data(x=np.random.random((2, ) * self.ndim)) d2 = Data(y=np.random.random((2, ) * self.ndim)) dc = DataCollection([d1, d2]) app = GlueApplication(dc) w = app.new_data_viewer(self.widget_cls, data=d1) w.add_data(d2) qtapp.processEvents() assert len(app.viewers[0]) == 1 dc.remove(d1) qtapp.processEvents() assert len(app.viewers[0]) == 1 dc.remove(d2) qtapp.processEvents() assert len(app.viewers[0]) == 0 app.close()
def test_manual_data_combo_helper(): combo = QtGui.QComboBox() dc = DataCollection([]) helper = ManualDataComboHelper(combo, dc) data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) assert _items_as_string(combo) == "" helper.append(data1) assert _items_as_string(combo) == "data1" data1.label = 'mydata1' assert _items_as_string(combo) == "mydata1" dc.remove(data1) assert _items_as_string(combo) == ""
class TestLinkEditor: def setup_method(self, method): self.data1 = Data(x=[1, 2, 3], y=[2, 3, 4], z=[6, 5, 4], label='data1') self.data2 = Data(a=[2, 3, 4], b=[4, 5, 4], c=[3, 4, 1], label='data2') self.data3 = Data(i=[5, 4, 3], j=[2, 2, 1], label='data3') self.data_collection = DataCollection([self.data1, self.data2, self.data3]) def test_defaults(self): # Make sure the dialog opens and closes and check default settings. dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.state.data1 is None assert link_widget.state.data2 is None assert not link_widget.button_add_link.isEnabled() assert not link_widget.button_remove_link.isEnabled() link_widget.state.data1 = self.data2 assert not link_widget.button_add_link.isEnabled() assert not link_widget.button_remove_link.isEnabled() link_widget.state.data2 = self.data1 assert link_widget.button_add_link.isEnabled() assert link_widget.button_remove_link.isEnabled() dialog.accept() assert len(self.data_collection.external_links) == 0 def test_defaults_two(self): # Make sure the dialog opens and closes and check default settings. With # two datasets, the datasets should be selected by default. self.data_collection.remove(self.data3) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 assert link_widget.button_add_link.isEnabled() assert link_widget.button_remove_link.isEnabled() dialog.accept() assert len(self.data_collection.external_links) == 0 def test_ui_behavior(self): # This is a bit more detailed test that checks that things update # correctly as we change various settings dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 add_identity_link = get_action(link_widget, 'identity') add_lengths_volume_link = get_action(link_widget, 'lengths_to_volume') # At this point, there should be no links in the main list widget # and nothing on the right. assert link_widget.listsel_current_link.count() == 0 assert link_widget.link_details.text() == '' assert link_widget.link_io.itemAt(0) is None # Let's add an identity link add_identity_link.trigger() # Ensure that all events get processed process_events() # Now there should be one link in the main list and content in the # right hand panel. assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'a' # Let's change the current components for the link link_widget.state.current_link.x = self.data1.id['y'] link_widget.state.current_link.y = self.data2.id['b'] # and make sure the UI gets updated assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'b' # We now add another link of a different type add_lengths_volume_link.trigger() # Ensure that all events get processed process_events() # and make sure the UI has updated assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Convert between linear measurements and volume' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(3, 1).widget().currentText() == 'z' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'a' # Now switch back to the first link link_widget.state.current_link = type(link_widget.state).current_link.get_choices(link_widget.state)[0] # and make sure the UI updates and has preserved the correct settings assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'b' # Next up, we try changing the data link_widget.state.data1 = self.data3 # At this point there should be no links in the list assert link_widget.listsel_current_link.count() == 0 assert link_widget.link_details.text() == '' assert link_widget.link_io.itemAt(0) is None # Add another identity link add_identity_link.trigger() # Ensure that all events get processed process_events() # Now there should be one link in the main list assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'i' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'a' # Switch back to the original data link_widget.state.data1 = self.data1 # And check the output is as before assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'b' # Let's now remove this link link_widget.button_remove_link.click() # Ensure that all events get processed process_events() # We should now see the lengths/volume link assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Convert between linear measurements and volume' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(3, 1).widget().currentText() == 'z' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'a' dialog.accept() links = self.data_collection.external_links assert len(links) == 2 assert isinstance(links[0], ComponentLink) assert links[0].get_from_ids()[0] is self.data1.id['x'] assert links[0].get_from_ids()[1] is self.data1.id['y'] assert links[0].get_from_ids()[2] is self.data1.id['z'] assert links[0].get_to_id() is self.data2.id['a'] assert isinstance(links[1], ComponentLink) assert links[1].get_from_ids()[0] is self.data3.id['i'] assert links[1].get_to_id() is self.data2.id['a'] def test_graph(self): dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget add_identity_link = get_action(link_widget, 'identity') graph = link_widget.graph_widget def click(node_or_edge): # We now simulate a selection - since we can't deterministically # figure out the exact pixel coordinates to use, we patch # 'find_object' to return the object we want to select. with patch.object(graph, 'find_object', return_value=node_or_edge): graph.mousePressEvent(None) def hover(node_or_edge): # Same as for select, we patch find_object with patch.object(graph, 'find_object', return_value=node_or_edge): graph.mouseMoveEvent(None) # To start with, no data should be selected assert link_widget.state.data1 is None assert link_widget.state.data2 is None # and the graph should have three nodes and no edges assert len(graph.nodes) == 3 assert len(graph.edges) == 0 click(graph.nodes[0]) # Check that this has caused one dataset to be selected assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is None # Click on the same node again and this should deselect the data # (but only once we move off from the node) click(graph.nodes[0]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is None hover(None) assert link_widget.state.data1 is None assert link_widget.state.data2 is None # Select it again click(graph.nodes[0]) # and now select another node too click(graph.nodes[1]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 assert len(graph.nodes) == 3 assert len(graph.edges) == 0 add_identity_link.trigger() assert len(graph.nodes) == 3 assert len(graph.edges) == 1 # Unselect and select another node click(graph.nodes[1]) click(graph.nodes[2]) # and check the data selections have been updated assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data3 # Deselect it and move off click(graph.nodes[2]) hover(None) # and the second dataset should now once again be None assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is None # Now change the data manually link_widget.state.data1 = self.data2 link_widget.state.data2 = self.data3 # and check that if we select the edge the datasets change back click(graph.edges[0]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 # Unselect and hover over nothing click(graph.edges[0]) hover(None) assert link_widget.state.data1 is None assert link_widget.state.data2 is None # Hover over the edge and the datasets should change back hover(graph.edges[0]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 # And check that clicking outside of nodes/edges deselects everything click(None) assert link_widget.state.data1 is None assert link_widget.state.data2 is None # Select a node, select another, then make sure that selecting a third # one will deselect the two original ones click(graph.nodes[0]) click(graph.nodes[1]) click(graph.nodes[2]) assert link_widget.state.data1 is self.data3 assert link_widget.state.data2 is None dialog.accept() def test_preexisting_links(self): # Check that things work properly if there are pre-existing links link1 = ComponentLink([self.data1.id['x']], self.data2.id['c']) def add(x, y): return x + y def double(x): return x * 2 def halve(x): return x / 2 link2 = ComponentLink([self.data2.id['a'], self.data2.id['b']], self.data3.id['j'], using=add) link3 = ComponentLink([self.data3.id['i']], self.data2.id['c'], using=double, inverse=halve) self.data_collection.add_link(link1) self.data_collection.add_link(link2) self.data_collection.add_link(link3) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == '' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'c' link_widget.state.data1 = self.data3 assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == '' assert non_empty_rows_count(get_link_io(link_widget)) == 6 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'a' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'b' assert get_link_io(link_widget).itemAtPosition(5, 1).widget().currentText() == 'j' link_widget.state.current_link = type(link_widget.state).current_link.get_choices(link_widget.state)[1] assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == '' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'i' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'c' dialog.accept() links = self.data_collection.external_links assert len(links) == 3 assert isinstance(links[0], ComponentLink) assert links[0].get_from_ids()[0] is self.data1.id['x'] assert links[0].get_to_id() is self.data2.id['c'] assert links[0].get_using() is identity assert isinstance(links[1], ComponentLink) assert links[1].get_from_ids()[0] is self.data2.id['a'] assert links[1].get_from_ids()[1] is self.data2.id['b'] assert links[1].get_to_id() is self.data3.id['j'] assert links[1].get_using() is add assert isinstance(links[2], ComponentLink) assert links[2].get_from_ids()[0] is self.data3.id['i'] assert links[2].get_to_id() is self.data2.id['c'] assert links[2].get_using() is double assert links[2].get_inverse() is halve def test_add_helper(self): dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 add_coordinate_link = get_action(link_widget, 'ICRS <-> Galactic') # Add a coordinate link add_coordinate_link.trigger() # Ensure that all events get processed process_events() assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link ICRS and Galactic coordinates' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(5, 1).widget().currentText() == 'a' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'b' dialog.accept() links = self.data_collection.external_links assert len(links) == 1 assert isinstance(links[0], ICRS_to_Galactic) assert links[0].cids1[0] is self.data1.id['x'] assert links[0].cids1[1] is self.data1.id['y'] assert links[0].cids2[0] is self.data2.id['a'] assert links[0].cids2[1] is self.data2.id['b'] def test_preexisting_helper(self): link1 = Galactic_to_FK5(cids1=[self.data1.id['x'], self.data1.id['y']], cids2=[self.data2.id['c'], self.data2.id['b']]) self.data_collection.add_link(link1) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.listsel_current_link.count() == 0 link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link Galactic and FK5 (J2000) Equatorial coordinates' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(5, 1).widget().currentText() == 'c' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'b' dialog.accept() links = self.data_collection.external_links assert len(links) == 1 assert isinstance(links[0], Galactic_to_FK5) assert links[0].cids1[0] is self.data1.id['x'] assert links[0].cids1[1] is self.data1.id['y'] assert links[0].cids2[0] is self.data2.id['c'] assert links[0].cids2[1] is self.data2.id['b'] def test_cancel(self): # Make sure that changes aren't saved if dialog is cancelled # This is a bit more detailed test that checks that things update # correctly as we change various settings link1 = ComponentLink([self.data1.id['x']], self.data2.id['c']) self.data_collection.add_link(link1) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 link_widget.state.current_link.x = self.data1.id['y'] assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' add_identity_link = get_action(link_widget, 'identity') add_identity_link.trigger() assert link_widget.listsel_current_link.count() == 2 dialog.reject() links = self.data_collection.external_links assert len(links) == 1 assert isinstance(links[0], ComponentLink) assert links[0].get_from_ids()[0] is self.data1.id['x'] assert links[0].get_to_id() is self.data2.id['c'] def test_functional_link_collection(self): # Test that if we use a @link_helper in 'legacy' mode, i.e. with only # input labels, both datasets are available from the combos in the # link editor dialog. Also test the new-style @link_helper. def deg_arcsec(degree, arcsecond): return [ComponentLink([degree], arcsecond, using=lambda d: d * 3600), ComponentLink([arcsecond], degree, using=lambda a: a / 3600)] # Old-style link helper helper1 = functional_link_collection(deg_arcsec, description='Legacy link', labels1=['deg', 'arcsec'], labels2=[]) link1 = helper1(cids1=[self.data1.id['x'], self.data2.id['c']]) self.data_collection.add_link(link1) # New-style link helper helper2 = functional_link_collection(deg_arcsec, description='New-style link', labels1=['deg'], labels2=['arcsec']) link2 = helper2(cids1=[self.data1.id['x']], cids2=[self.data2.id['c']]) self.data_collection.add_link(link2) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.listsel_current_link.count() == 0 link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Legacy link' assert non_empty_rows_count(get_link_io(link_widget)) == 4 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'c' link_widget.state.current_link = type(link_widget.state).current_link.get_choices(link_widget.state)[1] assert link_widget.link_details.text() == 'New-style link' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'c' dialog.accept() links = self.data_collection.external_links assert len(links) == 2 assert isinstance(links[0], helper1) assert links[0].cids1[0] is self.data1.id['x'] assert links[0].cids1[1] is self.data2.id['c'] assert isinstance(links[1], helper2) assert links[1].cids1[0] is self.data1.id['x'] assert links[1].cids2[0] is self.data2.id['c'] def test_same_data(self): # Test that we can't set the same data twice dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.state.data1 == self.data1 assert link_widget.state.data2 == self.data2 link_widget.state.data1 = self.data2 assert link_widget.state.data1 == self.data2 assert link_widget.state.data2 == self.data1 link_widget.state.data2 = self.data2 assert link_widget.state.data1 == self.data1 assert link_widget.state.data2 == self.data2
def test_component_id_combo_helper(): state = ExampleState() dc = DataCollection([]) helper = ComponentIDComboHelper(state, 'combo', dc) assert selection_choices(state, 'combo') == "" data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) helper.append_data(data1) assert selection_choices(state, 'combo') == "x:y" data2 = Data(a=[1, 2, 3], b=['a', 'b', 'c'], label='data2') dc.append(data2) helper.append_data(data2) assert selection_choices(state, 'combo') == "data1:x:y:data2:a:b" helper.categorical = False assert selection_choices(state, 'combo') == "data1:x:y:data2:a" helper.numeric = False assert selection_choices(state, 'combo') == "data1:data2" helper.categorical = True helper.numeric = True helper.pixel_coord = True assert selection_choices( state, 'combo' ) == "data1:main:x:y:coord:Pixel Axis 0 [x]:data2:main:a:b:coord:Pixel Axis 0 [x]" helper.world_coord = True assert selection_choices( state, 'combo' ) == "data1:main:x:y:coord:Pixel Axis 0 [x]:World 0:data2:main:a:b:coord:Pixel Axis 0 [x]:World 0" helper.pixel_coord = False assert selection_choices( state, 'combo') == "data1:main:x:y:coord:World 0:data2:main:a:b:coord:World 0" helper.world_coord = False dc.remove(data2) assert selection_choices(state, 'combo') == "x:y" data1['z'] = data1.id['x'] + 1 assert selection_choices(state, 'combo') == "main:x:y:derived:z" helper.derived = False assert selection_choices(state, 'combo') == "x:y" data1.id['x'].label = 'z' assert selection_choices(state, 'combo') == "z:y" helper.remove_data(data1) assert selection_choices(state, 'combo') == ""
def test_component_id_combo_helper(): state = ExampleState() dc = DataCollection([]) helper = ComponentIDComboHelper(state, 'combo', dc) assert selection_choices(state, 'combo') == "" data1 = Data(x=[1, 2, 3], y=[2, 3, 4], label='data1') dc.append(data1) helper.append_data(data1) assert selection_choices(state, 'combo') == "x:y" data2 = Data(a=[1, 2, 3], b=['a', 'b', 'c'], label='data2') dc.append(data2) helper.append_data(data2) assert selection_choices(state, 'combo') == "data1:x:y:data2:a:b" helper.categorical = False assert selection_choices(state, 'combo') == "data1:x:y:data2:a" helper.numeric = False assert selection_choices(state, 'combo') == "data1:data2" helper.categorical = True helper.numeric = True helper.pixel_coord = True assert selection_choices(state, 'combo') == "data1:main:x:y:coord:Pixel Axis 0 [x]:data2:main:a:b:coord:Pixel Axis 0 [x]" helper.world_coord = True assert selection_choices(state, 'combo') == "data1:main:x:y:coord:Pixel Axis 0 [x]:World 0:data2:main:a:b:coord:Pixel Axis 0 [x]:World 0" helper.pixel_coord = False assert selection_choices(state, 'combo') == "data1:main:x:y:coord:World 0:data2:main:a:b:coord:World 0" helper.world_coord = False dc.remove(data2) assert selection_choices(state, 'combo') == "x:y" data1['z'] = data1.id['x'] + 1 assert selection_choices(state, 'combo') == "main:x:y:derived:z" helper.derived = False assert selection_choices(state, 'combo') == "x:y" data1.id['x'].label = 'z' assert selection_choices(state, 'combo') == "z:y" helper.remove_data(data1) assert selection_choices(state, 'combo') == ""
class TestDendroClient(): def setup_method(self, method): self.data = Data(parent=[4, 4, 5, 5, 5, -1], height=[5, 4, 3, 2, 1, 0], label='dendro') self.dc = DataCollection([self.data]) self.hub = self.dc.hub self.client = DendroClient(self.dc, figure=FIGURE) EditSubsetMode().data_collection = self.dc def add_subset_via_hub(self): self.connect() self.client.add_layer(self.data) s = self.data.new_subset() return s def connect(self): self.client.register_to_hub(self.hub) self.dc.register_to_hub(self.hub) def click(self, x, y): roi = PointROI(x=x, y=y) self.client.apply_roi(roi) def test_data_present_after_adding(self): assert self.data not in self.client self.client.add_layer(self.data) assert self.data in self.client def test_add_data_adds_subsets(self): s1 = self.data.new_subset() self.client.add_layer(self.data) assert s1 in self.client def test_remove_data(self): self.client.add_layer(self.data) self.client.remove_layer(self.data) assert self.data not in self.client def test_remove_data_removes_subsets(self): s = self.data.new_subset() self.client.add_layer(self.data) self.client.remove_layer(self.data) assert s not in self.client def test_add_subset_hub(self): s = self.add_subset_via_hub() assert s in self.client def test_new_subset_autoadd(self): self.connect() self.client.add_layer(self.data) s = self.data.new_subset() assert s in self.client def test_remove_subset_hub(self): s = self.add_subset_via_hub() s.delete() assert s not in self.client def test_subset_sync(self): s = self.add_subset_via_hub() self.client._update_layer = MagicMock() s.style.color = 'blue' self.client._update_layer.assert_called_once_with(s) def test_data_sync(self): self.connect() self.client.add_layer(self.data) self.client._update_layer = MagicMock() self.data.style.color = 'blue' self.client._update_layer.assert_called_once_with(self.data) def test_data_remove(self): s = self.add_subset_via_hub() self.dc.remove(self.data) assert self.data not in self.dc assert self.data not in self.client assert s not in self.client def test_log(self): self.client.ylog = True assert self.client.axes.get_yscale() == 'log' def test_1d_data_required(self): d = Data(x=[[1, 2], [2, 3]]) self.dc.append(d) self.client.add_layer(d) assert d not in self.client def test_apply_roi(self): self.client.add_layer(self.data) self.client.select_substruct = False self.click(0, 4) s = self.data.subsets[0] assert_array_equal(s.to_index_list(), [1]) self.click(0, 3) assert_array_equal(s.to_index_list(), [1]) self.click(0, 0) assert_array_equal(s.to_index_list(), [4]) self.click(.75, 4) assert_array_equal(s.to_index_list(), [0]) self.click(0, 10) assert_array_equal(s.to_index_list(), []) def test_apply_roi_children_select(self): self.client.select_substruct = True self.client.add_layer(self.data) self.click(.5, .5) s = self.data.subsets[0] assert_array_equal(s.to_index_list(), [0, 1, 4]) def test_attribute_change_triggers_relayout(self): self.client.add_layer(self.data) l = self.client._layout self.client.height_attr = self.data.id['parent'] assert self.client._layout is not l l = self.client._layout self.client.parent_attr = self.data.id['height'] assert self.client._layout is not l l = self.client._layout self.client.order_attr = self.data.id['parent'] assert self.client._layout is not l
class TestLinkEditor: def setup_method(self, method): self.data1 = Data(x=[1, 2, 3], y=[2, 3, 4], z=[6, 5, 4], label='data1') self.data2 = Data(a=[2, 3, 4], b=[4, 5, 4], c=[3, 4, 1], label='data2') self.data3 = Data(i=[5, 4, 3], j=[2, 2, 1], label='data3') self.data_collection = DataCollection([self.data1, self.data2, self.data3]) def test_defaults(self): # Make sure the dialog opens and closes and check default settings. dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.state.data1 is None assert link_widget.state.data2 is None assert not link_widget.button_add_link.isEnabled() assert not link_widget.button_remove_link.isEnabled() link_widget.state.data1 = self.data2 assert not link_widget.button_add_link.isEnabled() assert not link_widget.button_remove_link.isEnabled() link_widget.state.data2 = self.data1 assert link_widget.button_add_link.isEnabled() assert link_widget.button_remove_link.isEnabled() dialog.accept() assert len(self.data_collection.external_links) == 0 def test_defaults_two(self): # Make sure the dialog opens and closes and check default settings. With # two datasets, the datasets should be selected by default. self.data_collection.remove(self.data3) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 assert link_widget.button_add_link.isEnabled() assert link_widget.button_remove_link.isEnabled() dialog.accept() assert len(self.data_collection.external_links) == 0 def test_ui_behavior(self): # This is a bit more detailed test that checks that things update # correctly as we change various settings app = get_qapp() dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 add_identity_link = get_action(link_widget, 'identity') add_lengths_volume_link = get_action(link_widget, 'lengths_to_volume') # At this point, there should be no links in the main list widget # and nothing on the right. assert link_widget.listsel_current_link.count() == 0 assert link_widget.link_details.text() == '' assert link_widget.link_io.itemAt(0) is None # Let's add an identity link add_identity_link.trigger() # Ensure that all events get processed app.processEvents() # Now there should be one link in the main list and content in the # right hand panel. assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'a' # Let's change the current components for the link link_widget.state.current_link.x = self.data1.id['y'] link_widget.state.current_link.y = self.data2.id['b'] # and make sure the UI gets updated assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'b' # We now add another link of a different type add_lengths_volume_link.trigger() # Ensure that all events get processed app.processEvents() # and make sure the UI has updated assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Convert between linear measurements and volume' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(3, 1).widget().currentText() == 'z' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'a' # Now switch back to the first link link_widget.state.current_link = type(link_widget.state).current_link.get_choices(link_widget.state)[0] # and make sure the UI updates and has preserved the correct settings assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'b' # Next up, we try changing the data link_widget.state.data1 = self.data3 # At this point there should be no links in the list assert link_widget.listsel_current_link.count() == 0 assert link_widget.link_details.text() == '' assert link_widget.link_io.itemAt(0) is None # Add another identity link add_identity_link.trigger() # Ensure that all events get processed app.processEvents() # Now there should be one link in the main list assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'i' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'a' # Switch back to the original data link_widget.state.data1 = self.data1 # And check the output is as before assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Link conceptually identical components' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'b' # Let's now remove this link link_widget.button_remove_link.click() # Ensure that all events get processed app.processEvents() # We should now see the lengths/volume link assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Convert between linear measurements and volume' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(3, 1).widget().currentText() == 'z' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'a' dialog.accept() links = self.data_collection.external_links assert len(links) == 2 assert isinstance(links[0], ComponentLink) assert links[0].get_from_ids()[0] is self.data1.id['x'] assert links[0].get_from_ids()[1] is self.data1.id['y'] assert links[0].get_from_ids()[2] is self.data1.id['z'] assert links[0].get_to_id() is self.data2.id['a'] assert isinstance(links[1], ComponentLink) assert links[1].get_from_ids()[0] is self.data3.id['i'] assert links[1].get_to_id() is self.data2.id['a'] def test_graph(self): dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget add_identity_link = get_action(link_widget, 'identity') graph = link_widget.graph_widget def click(node_or_edge): # We now simulate a selection - since we can't deterministically # figure out the exact pixel coordinates to use, we patch # 'find_object' to return the object we want to select. with patch.object(graph, 'find_object', return_value=node_or_edge): graph.mousePressEvent(None) def hover(node_or_edge): # Same as for select, we patch find_object with patch.object(graph, 'find_object', return_value=node_or_edge): graph.mouseMoveEvent(None) # To start with, no data should be selected assert link_widget.state.data1 is None assert link_widget.state.data2 is None # and the graph should have three nodes and no edges assert len(graph.nodes) == 3 assert len(graph.edges) == 0 click(graph.nodes[0]) # Check that this has caused one dataset to be selected assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is None # Click on the same node again and this should deselect the data # (but only once we move off from the node) click(graph.nodes[0]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is None hover(None) assert link_widget.state.data1 is None assert link_widget.state.data2 is None # Select it again click(graph.nodes[0]) # and now select another node too click(graph.nodes[1]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 assert len(graph.nodes) == 3 assert len(graph.edges) == 0 add_identity_link.trigger() assert len(graph.nodes) == 3 assert len(graph.edges) == 1 # Unselect and select another node click(graph.nodes[1]) click(graph.nodes[2]) # and check the data selections have been updated assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data3 # Deselect it and move off click(graph.nodes[2]) hover(None) # and the second dataset should now once again be None assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is None # Now change the data manually link_widget.state.data1 = self.data2 link_widget.state.data2 = self.data3 # and check that if we select the edge the datasets change back click(graph.edges[0]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 # Unselect and hover over nothing click(graph.edges[0]) hover(None) assert link_widget.state.data1 is None assert link_widget.state.data2 is None # Hover over the edge and the datasets should change back hover(graph.edges[0]) assert link_widget.state.data1 is self.data1 assert link_widget.state.data2 is self.data2 # And check that clicking outside of nodes/edges deselects everything click(None) assert link_widget.state.data1 is None assert link_widget.state.data2 is None # Select a node, select another, then make sure that selecting a third # one will deselect the two original ones click(graph.nodes[0]) click(graph.nodes[1]) click(graph.nodes[2]) assert link_widget.state.data1 is self.data3 assert link_widget.state.data2 is None dialog.accept() def test_preexisting_links(self): # Check that things work properly if there are pre-existing links app = get_qapp() link1 = ComponentLink([self.data1.id['x']], self.data2.id['c']) def add(x, y): return x + y def double(x): return x * 2 def halve(x): return x / 2 link2 = ComponentLink([self.data2.id['a'], self.data2.id['b']], self.data3.id['j'], using=add) link3 = ComponentLink([self.data3.id['i']], self.data2.id['c'], using=double, inverse=halve) self.data_collection.add_link(link1) self.data_collection.add_link(link2) self.data_collection.add_link(link3) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == '' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'c' link_widget.state.data1 = self.data3 assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == '' assert non_empty_rows_count(get_link_io(link_widget)) == 6 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'a' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'b' assert get_link_io(link_widget).itemAtPosition(5, 1).widget().currentText() == 'j' link_widget.state.current_link = type(link_widget.state).current_link.get_choices(link_widget.state)[1] assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == '' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'i' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'c' dialog.accept() links = self.data_collection.external_links assert len(links) == 3 assert isinstance(links[0], ComponentLink) assert links[0].get_from_ids()[0] is self.data1.id['x'] assert links[0].get_to_id() is self.data2.id['c'] assert links[0].get_using() is identity assert isinstance(links[1], ComponentLink) assert links[1].get_from_ids()[0] is self.data2.id['a'] assert links[1].get_from_ids()[1] is self.data2.id['b'] assert links[1].get_to_id() is self.data3.id['j'] assert links[1].get_using() is add assert isinstance(links[2], ComponentLink) assert links[2].get_from_ids()[0] is self.data3.id['i'] assert links[2].get_to_id() is self.data2.id['c'] assert links[2].get_using() is double assert links[2].get_inverse() is halve def test_add_helper(self): app = get_qapp() dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 add_coordinate_link = get_action(link_widget, 'ICRS <-> Galactic') # Add a coordinate link add_coordinate_link.trigger() # Ensure that all events get processed app.processEvents() assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link ICRS and Galactic coordinates' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(5, 1).widget().currentText() == 'a' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'b' dialog.accept() links = self.data_collection.external_links assert len(links) == 1 assert isinstance(links[0], ICRS_to_Galactic) assert links[0].cids1[0] is self.data1.id['x'] assert links[0].cids1[1] is self.data1.id['y'] assert links[0].cids2[0] is self.data2.id['a'] assert links[0].cids2[1] is self.data2.id['b'] def test_preexisting_helper(self): app = get_qapp() link1 = Galactic_to_FK5(cids1=[self.data1.id['x'], self.data1.id['y']], cids2=[self.data2.id['c'], self.data2.id['b']]) self.data_collection.add_link(link1) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.listsel_current_link.count() == 0 link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.listsel_current_link.count() == 1 assert link_widget.link_details.text() == 'Link Galactic and FK5 (J2000) Equatorial coordinates' assert non_empty_rows_count(get_link_io(link_widget)) == 7 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'y' assert get_link_io(link_widget).itemAtPosition(5, 1).widget().currentText() == 'c' assert get_link_io(link_widget).itemAtPosition(6, 1).widget().currentText() == 'b' dialog.accept() links = self.data_collection.external_links assert len(links) == 1 assert isinstance(links[0], Galactic_to_FK5) assert links[0].cids1[0] is self.data1.id['x'] assert links[0].cids1[1] is self.data1.id['y'] assert links[0].cids2[0] is self.data2.id['c'] assert links[0].cids2[1] is self.data2.id['b'] def test_cancel(self): # Make sure that changes aren't saved if dialog is cancelled # This is a bit more detailed test that checks that things update # correctly as we change various settings app = get_qapp() link1 = ComponentLink([self.data1.id['x']], self.data2.id['c']) self.data_collection.add_link(link1) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 link_widget.state.current_link.x = self.data1.id['y'] assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'y' add_identity_link = get_action(link_widget, 'identity') add_identity_link.trigger() assert link_widget.listsel_current_link.count() == 2 dialog.reject() links = self.data_collection.external_links assert len(links) == 1 assert isinstance(links[0], ComponentLink) assert links[0].get_from_ids()[0] is self.data1.id['x'] assert links[0].get_to_id() is self.data2.id['c'] def test_functional_link_collection(self): # Test that if we use a @link_helper in 'legacy' mode, i.e. with only # input labels, both datasets are available from the combos in the # link editor dialog. Also test the new-style @link_helper. app = get_qapp() def deg_arcsec(degree, arcsecond): return [ComponentLink([degree], arcsecond, using=lambda d: d * 3600), ComponentLink([arcsecond], degree, using=lambda a: a / 3600)] # Old-style link helper helper1 = functional_link_collection(deg_arcsec, description='Legacy link', labels1=['deg', 'arcsec'], labels2=[]) link1 = helper1(cids1=[self.data1.id['x'], self.data2.id['c']]) self.data_collection.add_link(link1) # New-style link helper helper2 = functional_link_collection(deg_arcsec, description='New-style link', labels1=['deg'], labels2=['arcsec']) link2 = helper2(cids1=[self.data1.id['x']], cids2=[self.data2.id['c']]) self.data_collection.add_link(link2) dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget assert link_widget.listsel_current_link.count() == 0 link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.listsel_current_link.count() == 2 assert link_widget.link_details.text() == 'Legacy link' assert non_empty_rows_count(get_link_io(link_widget)) == 4 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(2, 1).widget().currentText() == 'c' link_widget.state.current_link = type(link_widget.state).current_link.get_choices(link_widget.state)[1] assert link_widget.link_details.text() == 'New-style link' assert non_empty_rows_count(get_link_io(link_widget)) == 5 assert get_link_io(link_widget).itemAtPosition(1, 1).widget().currentText() == 'x' assert get_link_io(link_widget).itemAtPosition(4, 1).widget().currentText() == 'c' dialog.accept() links = self.data_collection.external_links assert len(links) == 2 assert isinstance(links[0], helper1) assert links[0].cids1[0] is self.data1.id['x'] assert links[0].cids1[1] is self.data2.id['c'] assert isinstance(links[1], helper2) assert links[1].cids1[0] is self.data1.id['x'] assert links[1].cids2[0] is self.data2.id['c'] def test_same_data(self): # Test that we can't set the same data twice app = get_qapp() dialog = LinkEditor(self.data_collection) dialog.show() link_widget = dialog.link_widget link_widget.state.data1 = self.data1 link_widget.state.data2 = self.data2 assert link_widget.state.data1 == self.data1 assert link_widget.state.data2 == self.data2 link_widget.state.data1 = self.data2 assert link_widget.state.data1 == self.data2 assert link_widget.state.data2 == self.data1 link_widget.state.data2 = self.data2 assert link_widget.state.data1 == self.data1 assert link_widget.state.data2 == self.data2