Skip to content

Commit d9fcfed

Browse files
authored
Merge pull request #1854 from ales-erjavec/fixes/select-rows-enum-use
[FIX] Select Rows filter enum
2 parents d098ccb + 6b001f6 commit d9fcfed

File tree

3 files changed

+148
-30
lines changed

3 files changed

+148
-30
lines changed

.ci_tools/appveyor/step-test.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ try {
5757

5858
# Widget tests
5959
python -m pip install `
60-
--extra-index-url "$Env:STAGING_INDEX" `
60+
--index-url "$Env:STAGING_INDEX" `
6161
PyQt5
6262

6363
echo "Running widget tests with PyQt5"

Orange/widgets/data/owselectrows.py

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import enum
2+
13
from collections import OrderedDict
24
from itertools import chain
35

@@ -14,6 +16,7 @@
1416
from Orange.data import (ContinuousVariable, DiscreteVariable, StringVariable,
1517
Table, TimeVariable)
1618
import Orange.data.filter as data_filter
19+
from Orange.data.filter import FilterContinuous, FilterString
1720
from Orange.data.domain import filter_visible
1821
from Orange.data.sql.table import SqlTable
1922
from Orange.preprocess import Remove
@@ -32,6 +35,13 @@ def is_valid_item(self, setting, condition, attrs, metas):
3235
return varname in attrs or varname in metas
3336

3437

38+
class FilterDiscreteType(enum.Enum):
39+
Equal = "Equal"
40+
NotEqual = "NotEqual"
41+
In = "In"
42+
IsDefined = "IsDefined"
43+
44+
3545
class OWSelectRows(widget.OWWidget):
3646
name = "Select Rows"
3747
id = "Orange.widgets.data.file"
@@ -51,20 +61,43 @@ class OWSelectRows(widget.OWWidget):
5161
purge_classes = Setting(True)
5262
auto_commit = Setting(True)
5363

54-
operator_names = {
55-
ContinuousVariable: ["equals", "is not",
56-
"is below", "is at most",
57-
"is greater than", "is at least",
58-
"is between", "is outside",
59-
"is defined"],
60-
DiscreteVariable: ["is", "is not", "is one of", "is defined"],
61-
StringVariable: ["equals", "is not",
62-
"is before", "is equal or before",
63-
"is after", "is equal or after",
64-
"is between", "is outside", "contains",
65-
"begins with", "ends with",
66-
"is defined"]}
67-
operator_names[TimeVariable] = operator_names[ContinuousVariable]
64+
Operators = {
65+
ContinuousVariable: [
66+
(FilterContinuous.Equal, "equals"),
67+
(FilterContinuous.NotEqual, "is not"),
68+
(FilterContinuous.Less, "is below"),
69+
(FilterContinuous.LessEqual, "is at most"),
70+
(FilterContinuous.Greater,"is greater than"),
71+
(FilterContinuous.GreaterEqual, "is at least"),
72+
(FilterContinuous.Between, "is between"),
73+
(FilterContinuous.Outside, "is outside"),
74+
(FilterContinuous.IsDefined, "is defined"),
75+
],
76+
DiscreteVariable: [
77+
(FilterDiscreteType.Equal, "is"),
78+
(FilterDiscreteType.NotEqual, "is not"),
79+
(FilterDiscreteType.In, "is one of"),
80+
(FilterDiscreteType.IsDefined, "is defined")
81+
],
82+
StringVariable: [
83+
(FilterString.Equal, "equals"),
84+
(FilterString.NotEqual, "is not"),
85+
(FilterString.Less, "is before"),
86+
(FilterString.LessEqual, "is equal or before"),
87+
(FilterString.Greater, "is after"),
88+
(FilterString.GreaterEqual, "is equal or after"),
89+
(FilterString.Between, "is between"),
90+
(FilterString.Outside, "is outside"),
91+
(FilterString.Contains, "contains"),
92+
(FilterString.StartsWith, "begins with"),
93+
(FilterString.EndsWith, "ends with"),
94+
(FilterString.IsDefined, "is defined"),
95+
]
96+
}
97+
Operators[TimeVariable] = Operators[ContinuousVariable]
98+
99+
operator_names = {vtype: [name for _, name in filters]
100+
for vtype, filters in Operators.items()}
68101

69102
def __init__(self):
70103
super().__init__()
@@ -199,8 +232,8 @@ def set_new_operators(self, attr_combo, adding_all,
199232
var = self.data.domain[attr_combo.currentText()]
200233
oper_combo.addItems(self.operator_names[type(var)])
201234
oper_combo.setCurrentIndex(selected_index or 0)
202-
self.set_new_values(oper_combo, adding_all, selected_values)
203235
self.cond_list.setCellWidget(oper_combo.row, 1, oper_combo)
236+
self.set_new_values(oper_combo, adding_all, selected_values)
204237
oper_combo.currentIndexChanged.connect(
205238
lambda _: self.set_new_values(oper_combo, False))
206239

@@ -338,14 +371,17 @@ def set_data(self, data):
338371
except Exception:
339372
pass
340373

341-
if not self.conditions and len(data.domain.variables):
374+
variables = list(filter_visible(chain(data.domain.variables,
375+
data.domain.metas)))
376+
varnames = [v.name for v in variables]
377+
if self.conditions:
378+
for attr, cond_type, cond_value in self.conditions:
379+
if attr in varnames:
380+
self.add_row(varnames.index(attr), cond_type, cond_value)
381+
elif variables:
342382
self.add_row()
383+
343384
self.update_info(data, self.data_in_variables, "In: ")
344-
for attr, cond_type, cond_value in self.conditions:
345-
attrs = [a.name for a in
346-
filter_visible(chain(data.domain.variables, data.domain.metas))]
347-
if attr in attrs:
348-
self.add_row(attrs.index(attr), cond_type, cond_value)
349385
self.unconditional_commit()
350386

351387
def conditions_changed(self):
@@ -372,10 +408,11 @@ def commit(self):
372408
if self.data:
373409
domain = self.data.domain
374410
conditions = []
375-
for attr_name, oper, values in self.conditions:
411+
for attr_name, oper_idx, values in self.conditions:
376412
attr_index = domain.index(attr_name)
377413
attr = domain[attr_index]
378-
414+
operators = self.Operators[type(attr)]
415+
opertype, _ = operators[oper_idx]
379416
if attr.is_continuous:
380417
if any(not v for v in values):
381418
continue
@@ -389,23 +426,23 @@ def commit(self):
389426
return
390427

391428
filter = data_filter.FilterContinuous(
392-
attr_index, oper, *[float(v) for v in values])
429+
attr_index, opertype, *[float(v) for v in values])
393430
elif attr.is_string:
394431
filter = data_filter.FilterString(
395-
attr_index, oper, *[str(v) for v in values])
432+
attr_index, opertype, *[str(v) for v in values])
396433
else:
397-
if oper == 3:
434+
if opertype == FilterDiscreteType.IsDefined:
398435
f_values = None
399436
else:
400437
if not values or not values[0]:
401438
continue
402439
values = [attr.values[i-1] for i in values]
403-
if oper == 0:
440+
if opertype == FilterDiscreteType.Equal:
404441
f_values = {values[0]}
405-
elif oper == 1:
442+
elif opertype == FilterDiscreteType.NotEqual:
406443
f_values = set(attr.values)
407444
f_values.remove(values[0])
408-
elif oper == 2:
445+
elif opertype == FilterDiscreteType.In:
409446
f_values = set(values)
410447
else:
411448
raise ValueError("invalid operand")
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Test methods with long descriptive names can omit docstrings
2+
# pylint: disable=missing-docstring
3+
from Orange.data import (
4+
Table, ContinuousVariable, StringVariable, DiscreteVariable)
5+
from Orange.widgets.data.owselectrows import OWSelectRows, FilterDiscreteType
6+
from Orange.widgets.tests.base import WidgetTest
7+
8+
from Orange.data.filter import FilterContinuous, FilterString
9+
10+
CFValues = {
11+
FilterContinuous.Equal: ["5.4"],
12+
FilterContinuous.NotEqual: ["5.4"],
13+
FilterContinuous.Less: ["5.4"],
14+
FilterContinuous.LessEqual: ["5.4"],
15+
FilterContinuous.Greater: ["5.4"],
16+
FilterContinuous.GreaterEqual: ["5.4"],
17+
FilterContinuous.Between: ["5.4", "6.0"],
18+
FilterContinuous.Outside: ["5.4", "6.0"],
19+
FilterContinuous.IsDefined: [],
20+
}
21+
22+
23+
SFValues = {
24+
FilterString.Equal: ["aardwark"],
25+
FilterString.NotEqual: ["aardwark"],
26+
FilterString.Less: ["aardwark"],
27+
FilterString.LessEqual: ["aardwark"],
28+
FilterString.Greater: ["aardwark"],
29+
FilterString.GreaterEqual: ["aardwark"],
30+
FilterString.Between: ["aardwark", "cat"],
31+
FilterString.Outside: ["aardwark"],
32+
FilterString.Contains: ["aa"],
33+
FilterString.StartsWith: ["aa"],
34+
FilterString.EndsWith: ["ark"],
35+
FilterString.IsDefined: []
36+
}
37+
38+
DFValues = {
39+
FilterDiscreteType.Equal: [0],
40+
FilterDiscreteType.NotEqual: [0],
41+
FilterDiscreteType.In: [0, 1],
42+
FilterDiscreteType.IsDefined: [],
43+
}
44+
45+
46+
class TestOWSelectRows(WidgetTest):
47+
def setUp(self):
48+
self.widget = self.create_widget(OWSelectRows) # type: OWSelectRows
49+
50+
def test_filter_cont(self):
51+
iris = Table("iris")[::5]
52+
self.widget.auto_commit = True
53+
self.widget.set_data(iris)
54+
55+
for i, (op, _) in enumerate(OWSelectRows.Operators[ContinuousVariable]):
56+
self.widget.remove_all()
57+
self.widget.add_row(0, i, CFValues[op])
58+
self.widget.conditions_changed()
59+
self.widget.unconditional_commit()
60+
61+
def test_filter_str(self):
62+
zoo = Table("zoo")[::5]
63+
self.widget.auto_commit = False
64+
self.widget.set_data(zoo)
65+
var_idx = len(zoo.domain)
66+
for i, (op, _) in enumerate(OWSelectRows.Operators[StringVariable]):
67+
self.widget.remove_all()
68+
self.widget.add_row(var_idx, i, SFValues[op])
69+
self.widget.conditions_changed()
70+
self.widget.unconditional_commit()
71+
72+
def test_filter_disc(self):
73+
lenses = Table("lenses")
74+
self.widget.auto_commit = False
75+
self.widget.set_data(lenses)
76+
77+
for i, (op, _) in enumerate(OWSelectRows.Operators[DiscreteVariable]):
78+
self.widget.remove_all()
79+
self.widget.add_row(0, i, DFValues[op])
80+
self.widget.conditions_changed()
81+
self.widget.unconditional_commit()

0 commit comments

Comments
 (0)