Skip to content

Commit 551e531

Browse files
authored
Merge pull request #2996 from astaric/fix-feature-constructor-settings-handler
[FIX] Feature constructor does not restore features when loading from saved workflow
2 parents b62d04f + 5076c1a commit 551e531

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

Orange/widgets/data/owfeatureconstructor.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,14 @@ def is_valid_item(self, setting, descriptor, attrs, metas):
317317
except Exception:
318318
return False
319319

320-
for name in freevars(exp_ast, []):
321-
if not (name in attrs or name in metas):
322-
return False
320+
available = dict(globals()["__GLOBALS"])
321+
for var in attrs:
322+
available[sanitized_name(var)] = None
323+
for var in metas:
324+
available[sanitized_name(var)] = None
325+
326+
if freevars(exp_ast, available):
327+
return False
323328
return True
324329

325330

Orange/widgets/data/tests/test_owfeatureconstructor.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
from Orange.data import (Table, Domain, StringVariable,
1111
ContinuousVariable, DiscreteVariable)
1212
from Orange.widgets.tests.base import WidgetTest
13+
from Orange.widgets.utils import vartype
1314
from Orange.widgets.utils.itemmodels import PyListModel
1415
from Orange.widgets.data.owfeatureconstructor import (
1516
DiscreteDescriptor, ContinuousDescriptor, StringDescriptor,
1617
construct_variables, OWFeatureConstructor,
17-
FeatureEditor, DiscreteFeatureEditor)
18+
FeatureEditor, DiscreteFeatureEditor, FeatureConstructorHandler)
1819

1920
from Orange.widgets.data.owfeatureconstructor import (
2021
freevars, validate_exp, FeatureFunc
@@ -269,3 +270,45 @@ class TestFeatureEditor(unittest.TestCase):
269270
def test_has_functions(self):
270271
self.assertIs(FeatureEditor.FUNCTIONS["abs"], abs)
271272
self.assertIs(FeatureEditor.FUNCTIONS["sqrt"], math.sqrt)
273+
274+
275+
class FeatureConstructorHandlerTests(unittest.TestCase):
276+
def test_handles_builtins_in_expression(self):
277+
self.assertTrue(
278+
FeatureConstructorHandler().is_valid_item(
279+
OWFeatureConstructor.descriptors,
280+
StringDescriptor("X", "str(A) + str(B)"),
281+
{"A": vartype(DiscreteVariable)},
282+
{"B": vartype(DiscreteVariable)}
283+
)
284+
)
285+
286+
# no variables is also ok
287+
self.assertTrue(
288+
FeatureConstructorHandler().is_valid_item(
289+
OWFeatureConstructor.descriptors,
290+
StringDescriptor("X", "str('foo')"),
291+
{},
292+
{}
293+
)
294+
)
295+
296+
# should fail on unknown variables
297+
self.assertFalse(
298+
FeatureConstructorHandler().is_valid_item(
299+
OWFeatureConstructor.descriptors,
300+
StringDescriptor("X", "str(X)"),
301+
{},
302+
{}
303+
)
304+
)
305+
306+
def test_handles_special_characters_in_var_names(self):
307+
self.assertTrue(
308+
FeatureConstructorHandler().is_valid_item(
309+
OWFeatureConstructor.descriptors,
310+
StringDescriptor("X", "A_2_f"),
311+
{"A.2 f": vartype(DiscreteVariable)},
312+
{}
313+
)
314+
)

0 commit comments

Comments
 (0)