Repository: biolab/orange3

Issue:
Create Instances duplicates attribute names
**What's wrong?**

Variable "Source Id" is added even if the attribute with the same name already exists.

**How can we reproduce the problem?** 

Put two Create Instances widgets one after another.

**What's your environment?**

N/A


Discussion:

Resolving patch:
diff --git a/Orange/widgets/data/owcreateinstance.py b/Orange/widgets/data/owcreateinstance.py
--- a/Orange/widgets/data/owcreateinstance.py
+++ b/Orange/widgets/data/owcreateinstance.py
@@ -16,6 +16,7 @@
 
 from Orange.data import DiscreteVariable, ContinuousVariable, \
     TimeVariable, Table, StringVariable, Variable, Domain
+from Orange.data.util import get_unique_names
 from Orange.widgets import gui
 from Orange.widgets.utils.itemmodels import TableModel
 from Orange.widgets.settings import Setting
@@ -646,12 +647,21 @@ def _create_data_from_values(self) -> Table:
                 data[:, var_name] = value
         return data
 
-    def _append_to_data(self, data: Table) -> Table:
+    def _append_to_data(self, instance: Table) -> Table:
         assert self.data
-        assert len(data) == 1
+        assert len(instance) == 1
+        source_label = "__source_widget"
 
-        var = DiscreteVariable("Source ID", values=(self.data.name, data.name))
-        data = Table.concatenate([self.data, data], axis=0)
+        data = Table.concatenate([self.data, instance], axis=0)
+        for var in self.data.domain.variables + self.data.domain.metas:
+            if var.attributes.get(source_label) == OWCreateInstance:
+                with data.unlocked():
+                    data.get_column_view(var)[0][-1] = 1
+                return data
+
+        name = get_unique_names(self.data.domain, "Source ID")
+        var = DiscreteVariable(name, values=(self.data.name, instance.name))
+        var.attributes[source_label] = OWCreateInstance
         domain = Domain(data.domain.attributes, data.domain.class_vars,
                         data.domain.metas + (var,))
         data = data.transform(domain)


Test patch:
diff --git a/Orange/widgets/data/tests/test_owcreateinstance.py b/Orange/widgets/data/tests/test_owcreateinstance.py
--- a/Orange/widgets/data/tests/test_owcreateinstance.py
+++ b/Orange/widgets/data/tests/test_owcreateinstance.py
@@ -54,6 +54,8 @@ def test_output_append_data(self):
         self.assertIn("Source ID", [m.name for m in output.domain.metas])
         self.assertTupleEqual(output.domain.metas[0].values,
                               ("iris", "created"))
+        self.assertDictEqual(output.domain.metas[0].attributes,
+                             {"__source_widget": OWCreateInstance})
 
     def _get_init_buttons(self, widget=None):
         if not widget:
@@ -213,6 +215,47 @@ def test_sparse(self):
         self.send_signal(self.widget.Inputs.data, data)
         self.send_signal(self.widget.Inputs.reference, data)
 
+    def test_cascade_widgets(self):
+        self.send_signal(self.widget.Inputs.data, self.data)
+        output = self.get_output(self.widget.Outputs.data)
+
+        widget = self.create_widget(OWCreateInstance)
+        self.send_signal(widget.Inputs.data, output, widget=widget)
+        output = self.get_output(widget.Outputs.data, widget=widget)
+        self.assertEqual(len(output), 152)
+        self.assertEqual(len(output.domain.metas), 1)
+        self.assertEqual(output.domain.metas[0].name, "Source ID")
+        self.assertTrue(all(output.metas[:150, 0] == 0))
+        self.assertTrue(all(output.metas[150:, 0] == 1))
+
+    def test_cascade_widgets_attributes(self):
+        data = self.data.copy()
+        data.domain.attributes[0].attributes = \
+            {"__source_widget": OWCreateInstance}
+        self.send_signal(self.widget.Inputs.data, data)
+        output = self.get_output(self.widget.Outputs.data)
+        self.assertEqual(len(output), 151)
+        self.assertEqual(len(output.domain.variables), 5)
+        self.assertEqual(len(output.domain.metas), 0)
+
+    def test_cascade_widgets_class_vars(self):
+        data = self.data.copy()
+        data.domain.class_var.attributes = \
+            {"__source_widget": OWCreateInstance}
+        self.send_signal(self.widget.Inputs.data, data)
+        output = self.get_output(self.widget.Outputs.data)
+        self.assertEqual(len(output), 151)
+        self.assertEqual(len(output.domain.variables), 5)
+        self.assertEqual(len(output.domain.metas), 0)
+
+        domain = Domain(data.domain.variables[:3], data.domain.variables[3:])
+        data = data.transform(domain)
+        self.send_signal(self.widget.Inputs.data, data)
+        output = self.get_output(self.widget.Outputs.data)
+        self.assertEqual(len(output), 151)
+        self.assertEqual(len(output.domain.variables), 5)
+        self.assertEqual(len(output.domain.metas), 0)
+
 
 class TestDiscreteVariableEditor(GuiTest):
     @classmethod