Repository: biolab/orange3

Issue:
OWBaseSql: Backend should be a setting
While the server is stored as a setting, the selected backend is not. This means saving a workflow that reads an mssql table and loading it, resets the backend to postgres and shows an error.


Discussion:

Resolving patch:
diff --git a/Orange/widgets/data/owsql.py b/Orange/widgets/data/owsql.py
--- a/Orange/widgets/data/owsql.py
+++ b/Orange/widgets/data/owsql.py
@@ -50,6 +50,7 @@ class Outputs:
 
     settings_version = 2
 
+    selected_backend = Setting(None)
     table = Setting(None)
     sql = Setting("")
     guess_values = Setting(True)
@@ -89,11 +90,19 @@ def _add_backend_controls(self):
         self.backendcombo = QComboBox(box)
         if self.backends:
             self.backendcombo.setModel(self.backends)
+            names = [backend.display_name for backend in self.backends]
+            if self.selected_backend and self.selected_backend in names:
+                self.backendcombo.setCurrentText(self.selected_backend)
         else:
             self.Error.no_backends()
             box.setEnabled(False)
+        self.backendcombo.currentTextChanged.connect(self.__backend_changed)
         box.layout().insertWidget(0, self.backendcombo)
 
+    def __backend_changed(self):
+        backend = self.get_backend()
+        self.selected_backend = backend.display_name if backend else None
+
     def _add_tables_controls(self):
         vbox = gui.vBox(self.controlArea, "Tables", addSpace=True)
         box = gui.vBox(vbox)


Test patch:
diff --git a/Orange/widgets/data/tests/test_owsql.py b/Orange/widgets/data/tests/test_owsql.py
--- a/Orange/widgets/data/tests/test_owsql.py
+++ b/Orange/widgets/data/tests/test_owsql.py
@@ -6,7 +6,7 @@
 
 from Orange.data import Table
 from Orange.widgets.data.owsql import OWSql
-from Orange.widgets.tests.base import WidgetTest
+from Orange.widgets.tests.base import WidgetTest, simulate
 from Orange.tests.sql.base import DataBaseTest as dbt
 
 
@@ -116,6 +116,33 @@ def test_restore_table(self, mock_backends, mock_sqltable, mock_table):
         widget = self.create_widget(OWSql, stored_settings=settings)
         self.assertEqual(widget.tablecombo.currentText(), "b")
 
+    @mock.patch("Orange.data.sql.backend.base.Backend.available_backends")
+    def test_selected_backend(self, mocked_backends: mock.Mock):
+        b1, b2 = mock.Mock(), mock.Mock()
+        b1.display_name = "B1"
+        b2.display_name = "B2"
+        mocked_backends.return_value = [b1, b2]
+
+        widget = self.create_widget(OWSql)
+        self.assertEqual(widget.backendcombo.currentText(), "B1")
+
+        simulate.combobox_activate_index(widget.backendcombo, 1)
+        self.assertEqual(widget.backendcombo.currentText(), "B2")
+
+        settings = widget.settingsHandler.pack_data(widget)
+        widget = self.create_widget(OWSql, stored_settings=settings)
+        self.assertEqual(widget.backendcombo.currentText(), "B2")
+
+        settings = widget.settingsHandler.pack_data(widget)
+        settings["selected_backend"] = "B3"
+        widget = self.create_widget(OWSql, stored_settings=settings)
+        self.assertEqual(widget.backendcombo.currentText(), "B1")
+
+        mocked_backends.return_value = []
+        settings = widget.settingsHandler.pack_data(widget)
+        widget = self.create_widget(OWSql, stored_settings=settings)
+        self.assertEqual(widget.backendcombo.currentText(), "")
+
 
 if __name__ == "__main__":
     unittest.main()