Skip to content

Commit e452e4d

Browse files
authored
Merge pull request #3321 from janezd/context-migration-reject
Settings migration: Allow rejecting a context
2 parents 9b89000 + 2d9617b commit e452e4d

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed

Orange/widgets/settings.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
__all__ = ["Setting", "SettingsHandler", "SettingProvider",
5050
"ContextSetting", "ContextHandler",
5151
"DomainContextHandler", "PerfectDomainContextHandler",
52-
"ClassValuesContextHandler", "widget_settings_dir"]
52+
"ClassValuesContextHandler", "widget_settings_dir",
53+
"IncompatibleContext"]
5354

5455
_IMMUTABLES = (str, int, bytes, bool, float, tuple)
5556

@@ -624,8 +625,16 @@ def read_defaults_file(self, settings_file):
624625
self._migrate_contexts(self.global_contexts)
625626

626627
def _migrate_contexts(self, contexts):
627-
for context in contexts:
628-
self.widget_class.migrate_context(context, context.values.pop(VERSION_KEY, 0))
628+
i = 0
629+
while i < len(contexts):
630+
context = contexts[i]
631+
try:
632+
self.widget_class.migrate_context(
633+
context, context.values.pop(VERSION_KEY, 0))
634+
except IncompatibleContext:
635+
del contexts[i]
636+
else:
637+
i += 1
629638

630639
def write_defaults_file(self, settings_file):
631640
"""Call the inherited method, then add global context to the pickle."""

Orange/widgets/tests/test_context_handler.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from unittest.mock import Mock, patch, call
66
from Orange.widgets.settings import (
77
ContextHandler, ContextSetting, Context, Setting, SettingsPrinter,
8-
VERSION_KEY
8+
VERSION_KEY, IncompatibleContext
99
)
1010

1111
__author__ = 'anze'
@@ -111,6 +111,26 @@ def test_initialize_migrates_contexts(self):
111111
handler.initialize(widget, dict(context_settings=deepcopy(contexts)))
112112
migrate_context.assert_has_calls([call(c, c.values[VERSION_KEY]) for c in contexts])
113113

114+
def test_migrates_settings_removes_incompatible(self):
115+
handler = ContextHandler()
116+
handler.bind(SimpleWidget)
117+
118+
widget = SimpleWidget()
119+
120+
contexts = [Context(foo=i) for i in (13, 13, 0, 1, 13, 2, 13)]
121+
122+
def migrate_context(context, _):
123+
if context.foo == 13:
124+
raise IncompatibleContext()
125+
126+
with patch.object(SimpleWidget, "migrate_context", migrate_context):
127+
handler.initialize(widget, dict(context_settings=contexts))
128+
contexts = widget.context_settings
129+
self.assertEqual(len(contexts), 3)
130+
self.assertTrue(
131+
all(context.foo == i
132+
for i, context in enumerate(contexts)))
133+
114134
def test_fast_save(self):
115135
handler = ContextHandler()
116136
handler.bind(SimpleWidget)

doc/development/source/tutorial-settings.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,16 @@ using models. Function
316316
:obj:`Orange.widget.settings.migrate_str_to_variable(settings, names=None)`
317317
makes the necessary changes to the settings listed in `names`. `names` can be
318318
a list of setting names, a single string or `None`. In the latter case, all
319-
settings that may refer to variables (that is two-elements tuples constisting
319+
settings that may refer to variables (that is two-elements tuples consisting
320320
of a string and an int) are migrated.
321321

322+
What about situations in which some context settings become inapplicable due
323+
to some changes in the widget? For instance, a widget that used to accept any
324+
kind of variables is modified so that it requires a numeric variable?
325+
Context with categorical variables will match and be reused ... and crash the
326+
widget. In these (rare) cases, `migrate_context` must raise exception
327+
:obj:`Orange.widget.settings.IncompatibleContext` and the context will be
328+
removed.
329+
322330
So take some time, write the migrations and do not forget to bump the
323331
`settings_version` when you do breaking changes.

0 commit comments

Comments
 (0)