Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Orange/widgets/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,10 +659,11 @@ def find_or_create_context(self, widget, *args):
of the context list."""

# First search the contexts that were already used in this widget instance
best_context, best_score = self.find_context(widget.context_settings, args)
best_context, best_score = self.find_context(widget.context_settings, args, move_up=True)
# If the exact data was used, reuse the context
if best_score == self.PERFECT_MATCH:
return best_context, False

# Otherwise check if a better match is available in global_contexts
best_context, best_score = self.find_context(self.global_contexts, args,
best_score, best_context)
Expand All @@ -675,7 +676,7 @@ def find_or_create_context(self, widget, *args):
self.add_context(widget.context_settings, context)
return context, best_context is None

def find_context(self, known_contexts, args, best_score=0, best_context=None):
def find_context(self, known_contexts, args, best_score=0, best_context=None, move_up=False):
"""Search the given list of contexts and return the context
which best matches the given args.

Expand All @@ -685,7 +686,8 @@ def find_context(self, known_contexts, args, best_score=0, best_context=None):
for i, context in enumerate(known_contexts):
score = self.match(context, *args)
if score == self.PERFECT_MATCH:
self.move_context_up(known_contexts, i)
if move_up:
self.move_context_up(known_contexts, i)
return context, score
if score > best_score: # NO_MATCH is not OK!
best_context, best_score = context, score
Expand Down Expand Up @@ -1035,6 +1037,8 @@ def is_valid_item(self, setting, item, attrs, metas):
Subclasses can override this method to checks data in alternative
representations.
"""
if not isinstance(item, tuple):
return True
return self._var_exists(setting, item, attrs, metas)


Expand Down
32 changes: 30 additions & 2 deletions Orange/widgets/tests/test_context_handler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from copy import copy
from unittest import TestCase
from unittest.mock import Mock
from Orange.widgets.settings import ContextHandler, Setting, ContextSetting
from Orange.widgets.settings import ContextHandler, Setting, ContextSetting, Context

__author__ = 'anze'

Expand All @@ -11,7 +12,7 @@ class SimpleWidget:
context_setting = ContextSetting(42)


class ContextHandlerTestCase(TestCase):
class TestContextHandler(TestCase):
def test_initialize(self):
handler = ContextHandler()
handler.provider = Mock()
Expand Down Expand Up @@ -40,3 +41,30 @@ def test_fast_save(self):
self.assertEqual(context.values['context_setting'], 55)
self.assertEqual(handler.known_settings['context_setting'].default,
SimpleWidget.context_setting.default)

def test_find_or_create_context(self):
widget = SimpleWidget()
handler = ContextHandler()
handler.match = lambda context, i: (context.i == i) * 2
handler.clone_context = lambda context, i: copy(context)

c1, c2, c3, c4, c5, c6, c7, c8, c9 = (Context(i=i)
for i in range(1, 10))

# finding a perfect match in global_contexts should copy it to
# the front of context_settings (and leave globals as-is)
widget.context_settings = [c2, c5]
handler.global_contexts = [c3, c7]
context, new = handler.find_or_create_context(widget, 7)
self.assertEqual(context.i, 7)
self.assertEqual([c.i for c in widget.context_settings], [7, 2, 5])
self.assertEqual([c.i for c in handler.global_contexts], [3, 7])

# finding a perfect match in context_settings should move it to
# the front of the list
widget.context_settings = [c2, c5]
handler.global_contexts = [c3, c7]
context, new = handler.find_or_create_context(widget, 5)
self.assertEqual(context.i, 5)
self.assertEqual([c.i for c in widget.context_settings], [5, 2])
self.assertEqual([c.i for c in handler.global_contexts], [3, 7])
22 changes: 21 additions & 1 deletion Orange/widgets/tests/test_domain_context_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Discrete = vartype(DiscreteVariable())


class DomainContextHandlerTestCase(TestCase):
class TestDomainContextHandler(TestCase):
def setUp(self):
self.domain = Domain(
attributes=[ContinuousVariable('c1'),
Expand Down Expand Up @@ -235,6 +235,26 @@ def test_open_context_with_no_match(self):
('c2', Continuous), ('d4', Discrete)))
self.assertEqual(context.values['text'], ('u', -2))

def test_filter_value(self):
setting = ContextSetting([])
setting.name = "value"

def test_filter(before_value, after_value):
data = dict(value=before_value)
self.handler.filter_value(setting, data, *self.args)
self.assertIn("value", data)
self.assertEqual(data["value"], after_value)

# filter list values
test_filter([], [])
# When list contains attributes asa tuple of (name, type),
# Attributes not present in domain should be filtered out
test_filter([("d1", Discrete), ("d1", Continuous),
("c1", Continuous), ("c1", Discrete)],
[("d1", Discrete), ("c1", Continuous)])
# All other values in list should remain
test_filter([0, [1, 2, 3], "abcd", 5.4], [0, [1, 2, 3], "abcd", 5.4])

def create_context(self, domain, values):
if not domain:
domain = Domain([])
Expand Down