diff --git a/Orange/widgets/data/owcreateclass.py b/Orange/widgets/data/owcreateclass.py index ffefb558054..60ae07fe2f9 100644 --- a/Orange/widgets/data/owcreateclass.py +++ b/Orange/widgets/data/owcreateclass.py @@ -13,7 +13,7 @@ from Orange.statistics.util import bincount from Orange.preprocess.transformation import Transformation, Lookup from Orange.widgets import gui, widget -from Orange.widgets.settings import DomainContextHandler, ContextSetting +from Orange.widgets.settings import DomainContextHandler, ContextSetting, Setting from Orange.widgets.utils.itemmodels import DomainModel from Orange.widgets.utils.localization import pl from Orange.widgets.utils.widgetpreview import WidgetPreview @@ -229,12 +229,14 @@ class Outputs: buttons_area_orientation = Qt.Vertical settingsHandler = DomainContextHandler() - attribute = ContextSetting(None) - class_name = ContextSetting("class") - rules = ContextSetting({}) - match_beginning = ContextSetting(False) - case_sensitive = ContextSetting(False) - regular_expressions = ContextSetting(False) + attribute = ContextSetting(None, schema_only=True) + class_name = Setting("class", schema_only=True) + rules = Setting({}, schema_only=True) + match_beginning = Setting(False, schema_only=True) + case_sensitive = Setting(False, schema_only=True) + regular_expressions = Setting(False, schema_only=True) + + settings_version = 2 TRANSFORMERS = {StringVariable: ValueFromStringSubstring, DiscreteVariable: ValueFromDiscreteSubstring} @@ -270,15 +272,15 @@ def __init__(self): #: list of list of QLabel: pairs of labels with counts self.counts = [] - gui.lineEdit( + le = gui.lineEdit( self.controlArea, self, "class_name", orientation=Qt.Horizontal, box="New Class Name") + le.setStyleSheet("QLineEdit { padding-left: 4px; }") - variable_select_box = gui.vBox(self.controlArea, "Match by Substring") + variable_select_box = gui.vBox(self.controlArea, box="Source column and patterns") combo = gui.comboBox( - variable_select_box, self, "attribute", label="From column:", - orientation=Qt.Horizontal, searchable=True, + variable_select_box, self, "attribute", searchable=True, callback=self.update_rules, model=DomainModel(valid_types=(StringVariable, DiscreteVariable))) # Don't use setSizePolicy keyword argument here: it applies to box, @@ -328,8 +330,8 @@ def __init__(self): gui.button(self.buttonsArea, self, "Apply", callback=self.apply) - # TODO: Resizing upon changing the number of rules does not work self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) + self.update_dynamic_height(initial=True) @property def active_rules(self): @@ -347,11 +349,16 @@ def rules_to_edits(self): for edit, text in zip(editr, textr): edit.setText(text) + def update_dynamic_height(self, initial=False): + self.updateGeometry() + current_width = 350 if initial else self.width() + target_height = self.layout().sizeHint().height() + self.resize(current_width, target_height) + @Inputs.data def set_data(self, data): """Input data signal handler.""" self.closeContext() - self.rules = {} self.data = data model = self.controls.attribute.model() model.set_domain(data.domain if data is not None else None) @@ -693,6 +700,18 @@ def _count_part(): self.report_items("Output", [("Class name", self.class_name)]) self.report_raw(f"
    {output}
") + @classmethod + def migrate_settings(cls, settings, version): + if version < 2: + contexts = settings.pop("context_settings", []) + if contexts: + print(contexts[0].values) + print(settings) + settings.update( + {name: contexts[0].values[name][0] + for name in ("class_name", "rules", "match_beginning", + "case_sensitive")}) + if __name__ == "__main__": # pragma: no cover WidgetPreview(OWCreateClass).run(Table("zoo")) diff --git a/Orange/widgets/data/tests/test_owcreateclass.py b/Orange/widgets/data/tests/test_owcreateclass.py index f265011820e..a63a1dfe30a 100644 --- a/Orange/widgets/data/tests/test_owcreateclass.py +++ b/Orange/widgets/data/tests/test_owcreateclass.py @@ -5,6 +5,7 @@ import numpy as np +from orangewidget.settings import Context from Orange.data import Table, StringVariable, DiscreteVariable, Domain from Orange.widgets.data.owcreateclass import ( OWCreateClass, @@ -503,7 +504,7 @@ def _check_thal(self): np.testing.assert_equal(classes[fixed], 1) self.assertTrue(np.all(np.isnan(classes[~(reversable | fixed)]))) - def test_flow_and_context_handling(self): + def test_flow(self): widget = self.widget self.send_signal(self.widget.Inputs.data, self.heart) self._test_default_rules() @@ -545,27 +546,6 @@ def test_flow_and_context_handling(self): self._set_attr(thal) self._check_thal() - prev_rules = widget.rules - self.send_signal(self.widget.Inputs.data, self.zoo) - self.assertIsNot(widget.rules, prev_rules) - - self.send_signal(self.widget.Inputs.data, self.heart) - self._check_thal() - - # Check that sending None as data does not ruin the context, and that - # the empty context does not match the true one later - self.send_signal(self.widget.Inputs.data, None) - self.assertIsNot(widget.rules, prev_rules) - - self.send_signal(self.widget.Inputs.data, self.heart) - self._check_thal() - - self.send_signal(self.widget.Inputs.data, self.no_attributes) - self.assertIsNot(widget.rules, prev_rules) - - self.send_signal(self.widget.Inputs.data, self.heart) - self._check_thal() - def test_add_remove_lines(self): widget = self.widget self.send_signal(self.widget.Inputs.data, self.heart) @@ -690,6 +670,32 @@ def test_same_class(self): self.get_output(widget2.Outputs.data, widget=widget2).domain.class_var ) + def test_migrate_settings_1_2(self): + settings = {"__version__": 1, "context_settings": [Context( + values= { + 'attribute': ('type', 101), + 'case_sensitive': (True, -2), + 'class_name': ('class', -2), + 'match_beginning': (True, -2), + 'regular_expressions': (False, -2), + 'rules': ({'type': [['cam', 'am'], ['cer', 'er'], ['', '']], + 'eggs': [['de', 'e1'], ['', '']]}, + -2), + '__version__': 1}, + attributes = {'hair': 1, 'feathers': 1, 'eggs': 1, 'type': 1}, + metas = {'name': 3})]} + w = self.create_widget(OWCreateClass, stored_settings=settings) + self.send_signal(w.Inputs.data, self.zoo, widget=w) + self.assertEqual(w.active_rules, [['cam', 'am'], ['cer', 'er'], ['', '']]) + self.assertEqual(w.class_name, "class") + self.assertTrue(w.case_sensitive) + self.assertTrue(w.match_beginning) + self.assertFalse(w.regular_expressions) + + w.attribute = self.zoo.domain["eggs"] + self.assertEqual(w.active_rules, [['de', 'e1'], ['', '']]) + + if __name__ == "__main__": unittest.main() diff --git a/i18n/si/msgs.jaml b/i18n/si/msgs.jaml index 6fc02647808..c6ea8843085 100644 --- a/i18n/si/msgs.jaml +++ b/i18n/si/msgs.jaml @@ -4820,9 +4820,9 @@ widgets/data/owcreateclass.py: def `__init__`: class_name: false New Class Name: Ime novega razreda - Match by Substring: Vzorci in razredi + 'QLineEdit { padding-left: 4px; }': false + Source column and patterns: Izvorni stolpec in vzorci attribute: false - From column:: Iz stolpca: Name: Ime Substring: Vzorec Count: Primerov @@ -4873,6 +4873,12 @@ widgets/data/owcreateclass.py: Output: Izhod Class name: Ime razreda
    {output}
: false + def `migrate_settings`: + context_settings: false + class_name: false + rules: false + match_beginning: false + case_sensitive: false __main__: false zoo: false widgets/data/owcreateinstance.py: