Skip to content

Commit 2cd42a4

Browse files
authored
Merge pull request #2720 from janezd/vartypes-as-predicates
Variable: Allow using is_* as predicates
2 parents 645066a + e85f87c commit 2cd42a4

File tree

2 files changed

+47
-18
lines changed

2 files changed

+47
-18
lines changed

Orange/data/tests/test_variable.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,19 @@ def test_properties(self):
107107
self.assertTrue(a.is_string)
108108
self.assertFalse(a.is_primitive())
109109

110+
def test_properties_as_predicates(self):
111+
a = ContinuousVariable()
112+
self.assertTrue(Variable.is_continuous(a))
113+
self.assertFalse(Variable.is_discrete(a))
114+
self.assertFalse(Variable.is_string(a))
115+
self.assertTrue(Variable.is_primitive(a))
116+
117+
a = StringVariable()
118+
self.assertFalse(Variable.is_continuous(a))
119+
self.assertFalse(Variable.is_discrete(a))
120+
self.assertTrue(Variable.is_string(a))
121+
self.assertFalse(Variable.is_primitive(a))
122+
110123
def test_strange_eq(self):
111124
a = ContinuousVariable()
112125
b = ContinuousVariable()

Orange/data/variable.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -349,28 +349,13 @@ def _clear_all_caches():
349349
cls._clear_cache()
350350

351351
@classmethod
352-
def is_primitive(cls):
352+
def is_primitive(cls, var=None):
353353
"""
354354
`True` if the variable's values are stored as floats.
355355
Non-primitive variables can appear in the data only as meta attributes.
356356
"""
357-
return issubclass(cls, (DiscreteVariable, ContinuousVariable))
358-
359-
@property
360-
def is_discrete(self):
361-
return isinstance(self, DiscreteVariable)
362-
363-
@property
364-
def is_continuous(self):
365-
return isinstance(self, ContinuousVariable)
366-
367-
@property
368-
def is_string(self):
369-
return isinstance(self, StringVariable)
370-
371-
@property
372-
def is_time(self):
373-
return isinstance(self, TimeVariable)
357+
to_check = cls if var is None else type(var)
358+
return issubclass(to_check, (DiscreteVariable, ContinuousVariable))
374359

375360
def repr_val(self, val):
376361
"""
@@ -1026,3 +1011,34 @@ def to_val(self, s):
10261011
return self.parse(s)
10271012
else:
10281013
return super().to_val(s)
1014+
1015+
1016+
class _TypeIndicatorDescriptor:
1017+
"""
1018+
Descriptor that can be used on classes and on instances.
1019+
1020+
On an instance, the descriptor is used as a property of a variable,
1021+
e.g. `var.is_discrete`.
1022+
1023+
As a class attribute, the descriptor returns a predicate that can
1024+
be called as `Variable.is_discrete(var)` or, for a more common use,
1025+
`filter(Variable.is_discrete, domain)`.
1026+
"""
1027+
def __init__(self, atype):
1028+
def __check_type(instance):
1029+
return isinstance(instance, atype)
1030+
1031+
self.check_type = __check_type
1032+
1033+
def __get__(self, instance, owner):
1034+
if instance is not None:
1035+
return self.check_type(instance)
1036+
else:
1037+
return self.check_type
1038+
1039+
# These properties of Variable require its subclasses, hence they have to
1040+
# inserted into the class later.
1041+
Variable.is_discrete = _TypeIndicatorDescriptor(DiscreteVariable)
1042+
Variable.is_continuous = _TypeIndicatorDescriptor(ContinuousVariable)
1043+
Variable.is_string = _TypeIndicatorDescriptor(StringVariable)
1044+
Variable.is_time = _TypeIndicatorDescriptor(TimeVariable)

0 commit comments

Comments
 (0)