2121from traceback import format_exception_only
2222from collections import namedtuple , OrderedDict
2323from itertools import chain , count , starmap
24- from typing import List , Dict , Any
24+ from typing import List , Dict , Any , Mapping
2525
2626import numpy as np
2727
3131 QPushButton , QMenu , QListView , QFrame , QLabel , QMessageBox )
3232from AnyQt .QtGui import QKeySequence
3333from AnyQt .QtCore import Qt , pyqtSignal as Signal , pyqtProperty as Property
34+
3435from orangewidget .utils .combobox import ComboBoxSearch
3536
3637import Orange
38+ from Orange .preprocess .transformation import MappingTransform
39+ from Orange .util import frompyfunc
3740from Orange .data import Variable , Table , Value , Instance
3841from Orange .data .util import get_unique_names
3942from Orange .widgets import gui
6366
6467StringDescriptor = namedtuple ("StringDescriptor" , ["name" , "expression" ])
6568
66- #warningIcon = gui.createAttributePixmap('!', QColor((202, 0, 32)))
6769
6870def make_variable (descriptor , compute_value ):
6971 if isinstance (descriptor , ContinuousDescriptor ):
@@ -1019,7 +1021,6 @@ def bind_variable(descriptor, env, data, use_values):
10191021
10201022 values = {}
10211023 cast = None
1022- nan = float ("nan" )
10231024
10241025 if isinstance (descriptor , DiscreteDescriptor ):
10251026 if not descriptor .values :
@@ -1028,29 +1029,62 @@ def bind_variable(descriptor, env, data, use_values):
10281029 values = sorted ({str (x ) for x in str_func (data )})
10291030 values = {name : i for i , name in enumerate (values )}
10301031 descriptor = descriptor ._replace (values = values )
1031-
1032- def cast (x ): # pylint: disable=function-redefined
1033- return values .get (x , nan )
1034-
1032+ cast = MappingTransformCast (values )
10351033 else :
10361034 values = [sanitized_name (v ) for v in descriptor .values ]
10371035 values = {name : i for i , name in enumerate (values )}
10381036
10391037 if isinstance (descriptor , DateTimeDescriptor ):
1040- parse = Orange .data .TimeVariable ("_" ).parse
1041-
1042- def cast (e ): # pylint: disable=function-redefined
1043- if isinstance (e , (int , float )):
1044- return e
1045- if e == "" or e is None :
1046- return np .nan
1047- return parse (e )
1038+ cast = DateTimeCast ()
10481039
10491040 func = FeatureFunc (descriptor .expression , source_vars , values , cast ,
10501041 use_values = use_values )
10511042 return descriptor , func
10521043
10531044
1045+ _parse_datetime = Orange .data .TimeVariable ("_" ).parse
1046+ _cast_datetime_num_types = (int , float )
1047+
1048+
1049+ def cast_datetime (e ):
1050+ if isinstance (e , _cast_datetime_num_types ):
1051+ return e
1052+ if e == "" or e is None :
1053+ return np .nan
1054+ return _parse_datetime (e )
1055+
1056+
1057+ _cast_datetime = frompyfunc (cast_datetime , 1 , 1 , dtype = float )
1058+
1059+
1060+ class DateTimeCast :
1061+ def __call__ (self , values ):
1062+ return _cast_datetime (values )
1063+
1064+ def __eq__ (self , other ):
1065+ return isinstance (other , DateTimeCast )
1066+
1067+ def __hash__ (self ):
1068+ return hash (cast_datetime )
1069+
1070+
1071+ class MappingTransformCast :
1072+ def __init__ (self , mapping : Mapping ):
1073+ self .t = MappingTransform (None , mapping )
1074+
1075+ def __reduce_ex__ (self , protocol ):
1076+ return type (self ), (self .t .mapping , )
1077+
1078+ def __call__ (self , values ):
1079+ return self .t .transform (values )
1080+
1081+ def __eq__ (self , other ):
1082+ return isinstance (other , MappingTransformCast ) and self .t == other .t
1083+
1084+ def __hash__ (self ):
1085+ return hash (self .t )
1086+
1087+
10541088def make_lambda (expression , args , env = None ):
10551089 # type: (ast.Expression, List[str], Dict[str, Any]) -> types.FunctionType
10561090 """
@@ -1217,8 +1251,7 @@ def __call_table(self, table):
12171251 else :
12181252 y = list (starmap (f , args ))
12191253 if self .cast is not None :
1220- cast = self .cast
1221- y = [cast (y_ ) for y_ in y ]
1254+ y = self .cast (y )
12221255 return y
12231256
12241257 def __call_instance (self , instance : Instance ):
@@ -1248,7 +1281,7 @@ def extract_column(self, table: Table, var: Variable):
12481281
12491282 def __reduce__ (self ):
12501283 return type (self ), (self .expression , self .args ,
1251- self .extra_env , self .cast )
1284+ self .extra_env , self .cast , self . use_values )
12521285
12531286 def __repr__ (self ):
12541287 return "{0.__name__}{1!r}" .format (* self .__reduce__ ())
0 commit comments