Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Feature constructor did not restore features when loading from saved workflow #2996

Merged
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
11 changes: 8 additions & 3 deletions Orange/widgets/data/owfeatureconstructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,14 @@ def is_valid_item(self, setting, descriptor, attrs, metas):
except Exception:
return False

for name in freevars(exp_ast, []):
if not (name in attrs or name in metas):
return False
available = dict(globals()["__GLOBALS"])
for var in attrs:
available[sanitized_name(var)] = None
for var in metas:
available[sanitized_name(var)] = None

if freevars(exp_ast, available):
return False
return True


Expand Down
45 changes: 44 additions & 1 deletion Orange/widgets/data/tests/test_owfeatureconstructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
from Orange.data import (Table, Domain, StringVariable,
ContinuousVariable, DiscreteVariable)
from Orange.widgets.tests.base import WidgetTest
from Orange.widgets.utils import vartype
from Orange.widgets.utils.itemmodels import PyListModel
from Orange.widgets.data.owfeatureconstructor import (
DiscreteDescriptor, ContinuousDescriptor, StringDescriptor,
construct_variables, OWFeatureConstructor,
FeatureEditor, DiscreteFeatureEditor)
FeatureEditor, DiscreteFeatureEditor, FeatureConstructorHandler)

from Orange.widgets.data.owfeatureconstructor import (
freevars, validate_exp, FeatureFunc
Expand Down Expand Up @@ -269,3 +270,45 @@ class TestFeatureEditor(unittest.TestCase):
def test_has_functions(self):
self.assertIs(FeatureEditor.FUNCTIONS["abs"], abs)
self.assertIs(FeatureEditor.FUNCTIONS["sqrt"], math.sqrt)


class FeatureConstructorHandlerTests(unittest.TestCase):
def test_handles_builtins_in_expression(self):
self.assertTrue(
FeatureConstructorHandler().is_valid_item(
OWFeatureConstructor.descriptors,
StringDescriptor("X", "str(A) + str(B)"),
{"A": vartype(DiscreteVariable)},
{"B": vartype(DiscreteVariable)}
)
)

# no variables is also ok
self.assertTrue(
FeatureConstructorHandler().is_valid_item(
OWFeatureConstructor.descriptors,
StringDescriptor("X", "str('foo')"),
{},
{}
)
)

# should fail on unknown variables
self.assertFalse(
FeatureConstructorHandler().is_valid_item(
OWFeatureConstructor.descriptors,
StringDescriptor("X", "str(X)"),
{},
{}
)
)

def test_handles_special_characters_in_var_names(self):
self.assertTrue(
FeatureConstructorHandler().is_valid_item(
OWFeatureConstructor.descriptors,
StringDescriptor("X", "A_2_f"),
{"A.2 f": vartype(DiscreteVariable)},
{}
)
)