def test_rename_item(self): project = self.toolbox.project() source_name = "source" destination_name = "destination" add_view(project, source_name) add_view(project, destination_name) source_item = project.get_item("source") project.add_connection( Connection(source_name, "left", destination_name, "right")) while project.is_busy(): # Make sure we process all pending signals related to changes in DAG. # Otherwise me may rename the item while the old name is still in use. QApplication.processEvents() project.rename_item("source", "renamed source", "") self.assertTrue(bool(project.get_item("renamed source"))) self.assertEqual(source_item.name, "renamed source") self.assertEqual( project.connections, [Connection("renamed source", "left", destination_name, "right")]) dags = project.dag_handler.dags() self.assertEqual(len(dags), 1) self.assertEqual(project.dag_handler.node_successors(dags[0]), { "destination": [], "renamed source": ["destination"] }) self.assertEqual(source_item.get_icon().name(), "renamed source") self.assertEqual( os.path.split(source_item.data_dir)[1], shorten("renamed source"))
def test_remove_connection(self): """Tests issue #1310""" # Make two DC's connected to a tool and provide a resource from both to Tool. # Remove one connection, and test that the other one still provides the resource to Tool project = self.toolbox.project() add_dc(project, "dc1") add_dc(project, "dc2") add_tool(project, "t") dc1 = project.get_item("dc1") dc2 = project.get_item("dc2") t = project.get_item("t") a = Path(self._temp_dir.name, "a.txt") a.touch() b = Path(self._temp_dir.name, "b.txt") b.touch() dc1.add_data_files([a]) dc2.add_data_files([b]) project.add_connection(Connection("dc1", "right", "t", "left")) project.add_connection(Connection("dc2", "right", "t", "left")) self.assertEqual(t._input_file_model.rowCount(), 2) # There should 2 files in Available resources connection = project.find_connection("dc2", "t") project.remove_connection(connection) self.assertEqual(t._input_file_model.rowCount(), 1) # There should 1 resource left
def test_serialization_without_filters(self): connection = Connection("source", "bottom", "destination", "top") connection_dict = connection.to_dict() restored = Connection.from_dict(connection_dict) self.assertEqual(restored.source, "source") self.assertEqual(restored.source_position, "bottom") self.assertEqual(restored.destination, "destination") self.assertEqual(restored.destination_position, "top") self.assertFalse(restored.has_filters())
def test_serialization_with_filters(self): filters = {"label": {"scenario_filter": {13: True}}} connection = Connection("source", "bottom", "destination", "top", filters) connection_dict = connection.to_dict() restored = Connection.from_dict(connection_dict) self.assertEqual(restored.source, "source") self.assertEqual(restored.source_position, "bottom") self.assertEqual(restored.destination, "destination") self.assertEqual(restored.destination_position, "top") self.assertTrue(restored.has_filters()) self.assertEqual(restored.resource_filters, filters)
def redo(self): if self._replaced_connection_dict is None: success = self._project.add_connection( Connection.from_dict(self._connection_dict)) if not success: self.setObsolete(True) else: self._project.replace_connection( Connection.from_dict(self._replaced_connection_dict), Connection.from_dict(self._connection_dict)) action = "add" if self._replaced_connection_dict is None else "replace" self.setText(f"{action} {self._connection_name}")
def test_replace_connection(self): project = self.toolbox.project() dc1_name = "DC 1" add_dc(project, dc1_name) dc2_name = "DC 2" add_dc(project, dc2_name) project.add_connection(Connection(dc1_name, "left", dc2_name, "right")) project.replace_connection( Connection(dc1_name, "left", dc2_name, "right"), Connection(dc1_name, "top", dc2_name, "bottom")) self.assertEqual(project.connections_for_item(dc1_name), [Connection(dc1_name, "top", dc2_name, "bottom")]) self.assertEqual(project.connections_for_item(dc2_name), [Connection(dc1_name, "top", dc2_name, "bottom")]) dag = project.dag_handler.dag_with_node(dc1_name) self.assertEqual(project.dag_handler.node_successors(dag), { dc1_name: [dc2_name], dc2_name: [] })
def test_fetch_tools(self): connection = Connection("source", "bottom", "destination", "top") url = "sqlite:///" + os.path.join(self._temp_dir.name, "db.sqlite") db_map = DiffDatabaseMapping(url, create=True) import_tools(db_map, ("tool",)) db_map.commit_session("Add test data.") db_map.connection.close() resources = [database_resource("source", url)] connection.receive_resources_from_source(resources) self.assertFalse(connection.has_filters()) connection.fetch_database_items() self.assertTrue(connection.has_filters()) self.assertEqual(connection.resource_filters, {resources[0].label: {"tool_filter": {1: False}}})
def undo(self): if self._replaced_connection_dict is None: connection = self._project.find_connection(self._source_name, self._destination_name) self._project.remove_connection(connection) else: connection = self._project.find_connection(self._source_name, self._destination_name) self._project.replace_connection( connection, Connection.from_dict(self._replaced_connection_dict))
def test_execute_selected_item_within_single_dag(self): data_store, data_store_executable = self._make_item(self.add_ds) data_connection, data_connection_executable = self._make_item( self.add_dc) view, view_executable = self._make_item(self.add_view) self.toolbox.project().add_connection( Connection(data_store.name, "right", data_connection.name, "left")) self.toolbox.project().add_connection( Connection(data_connection.name, "bottom", view.name, "top")) self.toolbox.project().set_item_selected(data_connection) with mock.patch("spine_engine.spine_engine.SpineEngine._make_item" ) as mock_make_item: mock_make_item.side_effect = lambda name, *args: { data_store.name: data_store_executable, data_connection.name: data_connection_executable, view.name: view_executable, }[name] self.toolbox.project().execute_selected() self._wait_for_execution_finished() self.assertFalse(data_store_executable.execute_called) self.assertTrue(data_connection_executable.execute_called) self.assertFalse(view_executable.execute_called)
def test_outgoing_and_incoming_links(self): source_icon = ProjectItemIcon(self._toolbox, "", QColor(Qt.gray), QColor(Qt.green)) target_icon = ProjectItemIcon(self._toolbox, "", QColor(Qt.gray), QColor(Qt.green)) connection = Connection("source item", "bottom", "destination item", "bottom") link = Link(self._toolbox, source_icon.conn_button("bottom"), target_icon.conn_button("bottom"), connection) link.src_connector.links.append(link) link.dst_connector.links.append(link) self.assertEqual(source_icon.outgoing_links(), [link]) self.assertEqual(target_icon.incoming_links(), [link])
def test_add_connection_updates_resources(self): project = self.toolbox.project() dc_name = "DC" add_dc(project, dc_name) tool_name = "Tool" add_tool(project, tool_name) dc = project.get_item(dc_name) data_file = Path(self._temp_dir.name, "a.txt") data_file.touch() dc.add_data_files([data_file]) tool = project.get_item(tool_name) self.assertEqual(tool._input_file_model.rowCount(), 0) project.add_connection(Connection(dc_name, "left", tool_name, "right")) self.assertEqual(tool._input_file_model.rowCount(), 1)
def test_add_connection_updates_dag_handler(self): project = self.toolbox.project() dc_name = "DC" add_dc(project, dc_name) importer_name = "Importer" add_importer(project, importer_name) project.add_connection( Connection(dc_name, "right", importer_name, "left")) self.assertEqual(len(project.connections), 1) dag = project.dag_handler.dag_with_node(dc_name) self.assertEqual(project.dag_handler.node_successors(dag), { dc_name: [importer_name], importer_name: [] })
def remove_links(self, links): """Pushes a RemoveConnectionsCommand to the Toolbox undo stack. Args: links (list of Link): links to remove """ connections = list() for link in links: source = link.src_connector destination = link.dst_connector connections.append( Connection(source.parent_name(), source.position, destination.parent_name(), destination.position)) self._toolbox.undo_stack.push( RemoveConnectionsCommand(self._toolbox.project(), connections))
def test_rename_item(self): project = self.toolbox.project() source_name = "source" destination_name = "destination" add_view(project, source_name) add_view(project, destination_name) source_item = project.get_item("source") project.add_connection( Connection(source_name, "left", destination_name, "right")) project.rename_item("source", "renamed source", "") self.assertTrue(bool(project.get_item("renamed source"))) self.assertEqual(source_item.name, "renamed source") self.assertEqual( project.connections, [Connection("renamed source", "left", destination_name, "right")]) dags = project.dag_handler.dags() self.assertEqual(len(dags), 1) self.assertEqual(project.dag_handler.node_successors(dags[0]), { "destination": [], "renamed source": ["destination"] }) self.assertEqual(source_item.get_icon().name(), "renamed source") self.assertEqual( os.path.split(source_item.data_dir)[1], shorten("renamed source"))
def test_replace_resource_from_source(self): filters = {"database": {"scenario_filter": {13: False}}} connection = Connection("source", "bottom", "destination", "top", filters) original = database_resource("source", "sqlite:///db.sqlite", label="database") connection.receive_resources_from_source([original]) self.assertEqual(connection.database_resources, {original}) modified = database_resource("source", "sqlite:///db2.sqlite", label="new database") connection.replace_resource_from_source(original, modified) self.assertEqual(connection.database_resources, {modified}) self.assertEqual(connection.resource_filters, {"new database": {"scenario_filter": {13: False}}})
def test_modifying_connected_item_updates_resources(self): project = self.toolbox.project() dc_name = "DC" add_dc(project, dc_name) tool_name = "Tool" add_tool(project, tool_name) tool = project.get_item(tool_name) project.add_connection(Connection(dc_name, "left", tool_name, "right")) self.assertEqual(tool._input_file_model.rowCount(), 0) dc = project.get_item(dc_name) data_file = Path(self._temp_dir.name, "a.txt") data_file.touch() dc.add_data_files([data_file]) while dc.data_model.rowCount() == 0: QApplication.processEvents( ) # DC's file system watcher updates DC here self.assertEqual(tool._input_file_model.rowCount(), 1)
def test_remove_item_by_name_removes_incoming_connections(self): project = self.toolbox.project() view1_name = "View 1" add_view(project, view1_name) view2_name = "View 2" add_view(project, view2_name) project.add_connection( Connection(view1_name, "top", view2_name, "bottom")) view = self.toolbox.project_item_model.get_item(view1_name) self.assertEqual(view1_name, view.name) view = self.toolbox.project_item_model.get_item(view2_name) self.assertEqual(view2_name, view.name) self.assertEqual(len(project.connections), 1) project.remove_item_by_name(view2_name) self.assertEqual(self.toolbox.project_item_model.n_items(), 1) self.assertEqual(len(project.connections), 0) view = self.toolbox.project_item_model.get_item(view1_name) self.assertEqual(view1_name, view.name) self.assertTrue(project.dag_handler.node_is_isolated(view1_name))
def setUp(self): self._temp_dir = TemporaryDirectory() with patch("spinetoolbox.ui_main.SpineDBManager.thread", new_callable=PropertyMock) as mock_thread: mock_thread.return_value = QApplication.instance().thread() self._toolbox = create_toolboxui_with_project(self._temp_dir.name) type(self._toolbox.db_mngr).thread = PropertyMock( return_value=QApplication.instance().thread()) source_item_icon = ProjectItemIcon(self._toolbox, "", QColor(Qt.gray), QColor(Qt.green)) source_item_icon.update_name_item("source icon") destination_item_icon = ProjectItemIcon(self._toolbox, "", QColor(Qt.gray), QColor(Qt.green)) destination_item_icon.update_name_item("destination icon") connection = Connection("source icon", "right", "destination icon", "left") self._link = Link(self._toolbox, source_item_icon.conn_button(), destination_item_icon.conn_button(), connection)
def make_link(self, src_connector, dst_connector, connection=None): """Constructs a Link between given connectors. Args: src_connector (ConnectorButton): Source connector button dst_connector (ConnectorButton): Destination connector button connection (Connection, optional): Underlying connection Returns: Link: new link """ if connection is None: connection = Connection( src_connector.project_item().name, src_connector.position, dst_connector.project_item().name, dst_connector.position, ) return Link(self._toolbox, src_connector, dst_connector, connection)
def __init__(self, project, source_name, source_position, destination_name, destination_position): """Command to add connection between project items. Args: project (SpineToolboxProject): project source_name (str): source item's name source_position (str): link's position on source item's icon destination_name (str): destination item's name destination_position (str): link's position on destination item's icon """ super().__init__() self._project = project self._source_name = source_name self._destination_name = destination_name self._connection_dict = Connection(source_name, source_position, destination_name, destination_position).to_dict() replaced_connection = self._project.find_connection( source_name, destination_name) self._replaced_connection_dict = replaced_connection.to_dict( ) if replaced_connection is not None else None self._connection_name = f"link from {source_name} to {destination_name}"
def test_connections_for_item(self): project = self.toolbox.project() dc1_name = "My first DC" add_dc(project, dc1_name) dc2_name = "My second DC" add_dc(project, dc2_name) dc3_name = "My third and last DC" add_dc(project, dc3_name) project.add_connection(Connection(dc1_name, "bottom", dc2_name, "top")) project.add_connection(Connection(dc2_name, "top", dc3_name, "bottom")) self.assertEqual(project.connections_for_item(dc1_name), [Connection(dc1_name, "bottom", dc2_name, "top")]) self.assertEqual( project.connections_for_item(dc2_name), [ Connection(dc1_name, "bottom", dc2_name, "top"), Connection(dc2_name, "top", dc3_name, "bottom") ], ) self.assertEqual(project.connections_for_item(dc3_name), [Connection(dc2_name, "top", dc3_name, "bottom")])
def undo(self): for connection_dict in self._connections_dict.values(): self._project.add_connection(Connection.from_dict(connection_dict))
def test_set_online(self): filters = {"label": {"scenario_filter": {13: False}}} connection = Connection("source", "bottom", "destination", "top", filters) connection.set_online("label", "scenario_filter", {13: True}) self.assertEqual(connection.resource_filters, {"label": {"scenario_filter": {13: True}}})
def undo(self): self._project.make_and_add_project_items(self._items_dict, verbosity=False) for connection_dict in self._connection_dicts: self._project.add_connection(Connection.from_dict(connection_dict))