python.observation.field
Created on Thu May 26 20:30:00 2022
@author: philippe@loco-labs.io
The python.observation.field
module contains the Field
class.
Documentation is available in other pages :
- The Json Standard for Field is defined here
- The concept of 'indexed list' is described in this page.
- The non-regression tests are at this page
- The examples are :
1# -*- coding: utf-8 -*- 2""" 3Created on Thu May 26 20:30:00 2022 4 5@author: philippe@loco-labs.io 6 7The `python.observation.field` module contains the `Field` class. 8 9Documentation is available in other pages : 10 11- The Json Standard for Field is defined [here](https://github.com/loco-philippe/ 12Environmental-Sensing/tree/main/documentation/IlistJSON-Standard.pdf) 13- The concept of 'indexed list' is described in 14[this page](https://github.com/loco-philippe/Environmental-Sensing/wiki/Indexed-list). 15- The non-regression tests are at [this page](https://github.com/loco-philippe/ 16Environmental-Sensing/blob/main/python/Tests/test_iindex.py) 17- The [examples](https://github.com/loco-philippe/Environmental-Sensing/tree/main/ 18python/Examples/Field) are : 19 - [creation](https://github.com/loco-philippe/Environmental-Sensing/blob/main/ 20 python/Examples/Field/Field_creation.ipynb) 21 - [value](https://github.com/loco-philippe/Environmental-Sensing/blob/main/ 22 python/Examples/Field/Field_value.ipynb) 23 - [update](https://github.com/loco-philippe/Environmental-Sensing/blob/main/ 24 python/Examples/Field/Field_update.ipynb) 25 - [structure](https://github.com/loco-philippe/Environmental-Sensing/blob/main/ 26 python/Examples/Field/Field_structure.ipynb) 27 - [structure-analysis](https://github.com/loco-philippe/Environmental-Sensing/ 28 blob/main/python/Examples/Field/Field_structure-analysis.ipynb) 29 30--- 31""" 32# %% declarations 33from copy import copy, deepcopy 34from abc import ABC, abstractmethod 35 36from observation.esconstante import ES 37from observation.field_interface import FieldInterface, FieldError 38from observation.field_structure import FieldStructure 39from observation.util import util 40from json_ntv import Ntv, NtvList 41 42 43 44class Field(FieldStructure, FieldInterface, ABC): 45 # %% intro 46 ''' 47 An `Field` is a representation of an index list . 48 49 *Attributes (for dynamic attributes see @property methods)* : 50 51 - **name** : name of the Field 52 - **codec** : list of values for each key 53 - **keys** : list of code values 54 55 The methods defined in this class are : 56 57 *constructor (@classmethod)* 58 59 - `Field.bol` 60 - `Field.ntv` 61 - `Field.from_parent` 62 - `Field.from_ntv` 63 - `Field.merging` 64 65 *conversion abstract static methods (@abstractmethod, @staticmethod)* 66 67 - `Field.l_to_i` 68 - `Field.s_to_i` 69 - `Field.l_to_e` 70 - `Field.s_to_e` 71 - `Field.i_to_n` 72 - `Field.n_to_i` 73 - `Field.i_to_name` 74 75 *dynamic value (getters @property)* 76 77 - `Field.values` 78 - `Field.val` 79 - `Field.cod` 80 - `Field.codec` 81 - `Field.infos` 82 - `Field.keys` 83 84 *add - update methods (`observation.field_structure.FieldStructure`)* 85 86 - `Field.append` 87 - `Field.setcodecvalue` 88 - `Field.setcodeclist` 89 - `Field.setname` 90 - `Field.setkeys` 91 - `Field.setlistvalue` 92 - `Field.setvalue` 93 94 *transform methods (`observation.field_structure.FieldStructure`)* 95 96 - `Field.coupling` 97 - `Field.extendkeys` 98 - `Field.full` 99 - `Field.reindex` 100 - `Field.reorder` 101 - `Field.sort` 102 - `Field.tocoupled` 103 - `Field.tostdcodec` 104 105 *getters methods (`observation.field_structure.FieldStructure`)* 106 107 - `Field.couplinginfos` 108 - `Field.derkeys` 109 - `Field.getduplicates` 110 - `Field.iscrossed` 111 - `Field.iscoupled` 112 - `Field.isderived` 113 - `Field.islinked` 114 - `Field.isvalue` 115 - `Field.iskeysfromderkeys` 116 - `Field.keysfromderkeys` 117 - `Field.keytoval` 118 - `Field.loc` 119 - `Field.recordfromkeys` 120 - `Field.recordfromvalue` 121 - `Field.valtokey` 122 123 *export methods (`observation.field_interface.FieldInterface`)* 124 125 - `Field.json` 126 - `Field.to_obj` 127 - `Field.to_dict_obj` 128 - `Field.to_numpy` 129 - `Field.to_pandas` 130 - `Field.vlist` 131 - `Field.vName` 132 - `Field.vSimple` 133 ''' 134 135 def __init__(self, codec=None, name=None, keys=None, 136 lendefault=0, reindex=False, fast=False): 137 ''' 138 Field constructor. 139 140 *Parameters* 141 142 - **codec** : list (default None) - external different values of index (see data model) 143 - **keys** : list (default None) - key value of index (see data model) 144 - **name** : string (default None) - name of index (see data model) 145 - **lendefault** : integer (default 0) - default len if no keys is defined 146 - **reindex** : boolean (default True) - if True, default codec is apply 147 - **fast**: boolean (default False) - if True, codec is created without conversion''' 148 if isinstance(codec, Field): 149 self._keys = copy(codec._keys) 150 self._codec = deepcopy(codec._codec) 151 self.name = copy(codec.name) 152 return 153 if codec is None: 154 codec = [] 155 if not isinstance(codec, list): 156 codec = [codec] 157 codec = list(codec) 158 leng = lendefault 159 if codec and len(codec) > 0 and not leng: 160 leng = len(codec) 161 if not keys is None: 162 leng = len(keys) 163 if not name: 164 name = ES.defaultindex 165 if not (keys is None or isinstance(keys, list)): 166 raise FieldError("keys not list") 167 if keys is None and leng == 0: 168 keys = [] 169 elif keys is None: 170 keys = [(i*len(codec))//leng for i in range(leng)] 171 if not isinstance(codec, list): 172 raise FieldError("codec not list") 173 if codec == []: 174 keysset = util.tocodec(keys) 175 #codec = [Ntv.obj(key) for key in keysset] 176 codec = self.l_to_i(keysset, fast=True) 177 codec = self.l_to_i(codec, fast=fast) 178 self._keys = keys 179 self._codec = codec 180 self.name = name 181 if reindex: 182 self.reindex() 183 184 @classmethod 185 def bol(cls, leng, notdef=None, name=None, default=True): 186 ''' 187 Field constructor (boolean value). 188 189 *Parameters* 190 191 - **leng** : integer - length of the Field 192 - **notdef** : list (default None) - list of records without default value 193 - **default** : boolean (default True) - default value 194 - **name** : string (default None) - name of Field''' 195 values = [default] * leng 196 if notdef: 197 for item in notdef: 198 values[item] = not default 199 return cls.ntv({name: values}) 200 201 @classmethod 202 def from_parent(cls, codec, parent, name=None, reindex=False): 203 '''Generate an Field Object from specific codec and parent keys. 204 205 *Parameters* 206 207 - **codec** : list of objects 208 - **name** : string (default None) - name of index (see data model) 209 - **parent** : Field, parent of the new Field 210 - **reindex** : boolean (default True) - if True, default codec is apply 211 212 *Returns* : Field ''' 213 if isinstance(codec, Field): 214 return copy(codec) 215 return cls(codec=codec, name=name, keys=parent._keys, reindex=reindex) 216 217 @classmethod 218 def ntv(cls, ntv_value=None, extkeys=None, reindex=True, decode_str=False): 219 '''Generate an Field Object from a Ntv field object''' 220 return cls.from_ntv(ntv_value, extkeys=extkeys, reindex=reindex, decode_str=decode_str) 221 222 @classmethod 223 def from_ntv(cls, ntv_value=None, extkeys=None, reindex=True, decode_str=False, 224 add_type=True, lengkeys=None): 225 '''Generate an Field Object from a Ntv field object''' 226 if isinstance(ntv_value, cls): 227 return copy(ntv_value) 228 ntv = Ntv.obj(ntv_value, decode_str=decode_str) 229 #ntv = NtvList(ntv_value) 230 if ntv_value is None: 231 return cls() 232 name, typ, codec, parent, keys, coef, leng = cls.decode_ntv(ntv) 233 if parent and not extkeys: 234 return None 235 if coef: 236 keys = FieldInterface.keysfromcoef(coef, leng//coef, lengkeys) 237 elif extkeys and parent: 238 keys = cls.keysfromderkeys(extkeys, keys) 239 elif extkeys and not parent: 240 keys = extkeys 241 keys = list(range(len(codec))) if keys is None else keys 242 name = ntv.json_name(string=True) if add_type else name 243 return cls(codec=codec, name=name, keys=keys, reindex=reindex) 244 245 """@classmethod 246 def from_dict_obj(cls, bsd, typevalue=ES.def_clsName, reindex=False): 247 '''Generate an Field Object from a dict value''' 248 var = False 249 if not isinstance(bsd, dict): 250 raise FieldError('data is not a dict') 251 name = list(bsd.keys())[0] 252 bsdv = list(bsd.values())[0] 253 if not 'value' in bsdv: 254 raise FieldError('value is not present') 255 value = bsdv['value'] 256 if not isinstance(value, list): 257 value = [value] 258 if 'type' in bsdv and isinstance(bsdv['type'], str): 259 typevalue = bsdv['type'] 260 if 'var' in bsdv and isinstance(bsdv['var'], bool): 261 var = bsdv['var'] 262 codec = [util.castval(val['codec'], typevalue) for val in value] 263 pairs = [] 264 for i, rec in enumerate(value): 265 record = rec['record'] 266 if not isinstance(record, list): 267 record = [record] 268 for j in record: 269 pairs.append((j, i)) 270 if not pairs: 271 return (var, cls()) 272 keys = list(list(zip(*sorted(pairs)))[1]) 273 274 idx = cls(name=name, codec=codec, keys=keys, typevalue=None) 275 return (var, idx)""" 276 277 @classmethod 278 def merging(cls, listidx, name=None): 279 '''Create a new Field with values are tuples of listidx Field values 280 281 *Parameters* 282 283 - **listidx** : list of Field to be merged. 284 - **name** : string (default : None) - Name of the new Field 285 286 *Returns* : new Field''' 287 if not name: 288 name = str(list({idx.name for idx in listidx})) 289 values = util.transpose([idx.values for idx in listidx]) 290 return cls.ntv({name: values}) 291 292 293# %% abstract 294 @staticmethod 295 @abstractmethod 296 def l_to_i(lis): 297 ''' converting a list of external values to a list of internal values''' 298 pass 299 300 @staticmethod 301 @abstractmethod 302 def s_to_i(val): 303 '''converting an external value to an internal value''' 304 pass 305 306 @staticmethod 307 @abstractmethod 308 def n_to_i(ntv): 309 ''' converting a NTV value to an internal value''' 310 pass 311 312 @staticmethod 313 @abstractmethod 314 def l_to_e(lis): 315 ''' converting a list of internal values to a list of external values''' 316 pass 317 318 @staticmethod 319 @abstractmethod 320 def s_to_e(val): 321 '''converting an internal value to an external value''' 322 pass 323 324 @staticmethod 325 @abstractmethod 326 def i_to_n(val): 327 ''' converting an internal value to a NTV value''' 328 pass 329 330 @staticmethod 331 @abstractmethod 332 def i_to_name(val): 333 ''' return the name of the internal value''' 334 pass 335# %% special 336 337 def __repr__(self): 338 '''return classname and number of value''' 339 return self.__class__.__name__ + '[' + str(len(self)) + ']' 340 341 def __eq__(self, other): 342 ''' equal if class and values are equal''' 343 return self.__class__ .__name__ == other.__class__.__name__ and self.values == other.values 344 345 def __len__(self): 346 ''' len of values''' 347 return len(self._keys) 348 349 def __contains__(self, item): 350 ''' item of values''' 351 return item in self.values 352 353 def __getitem__(self, ind): 354 ''' return value item (value conversion)''' 355 if isinstance(ind, tuple): 356 return [copy(self.values[i]) for i in ind] 357 #return self.values[ind] 358 return copy(self.values[ind]) 359 360 def __setitem__(self, ind, value): 361 ''' modify values item''' 362 if ind < 0 or ind >= len(self): 363 raise FieldError("out of bounds") 364 self.setvalue(ind, value, extern=True) 365 366 def __delitem__(self, ind): 367 '''remove a record (value and key).''' 368 self._keys.pop(ind) 369 self.reindex() 370 371 def __hash__(self): 372 '''return hash(values)''' 373 return hash(tuple(self.values)) 374 375 def _hashe(self): 376 '''return hash(values)''' 377 return hash(tuple(self.values)) 378 379 def _hashi(self): 380 '''return hash(codec) + hash(keys)''' 381 return hash(tuple(self._codec)) + hash(tuple(self._keys)) 382 383 def __add__(self, other): 384 ''' Add other's values to self's values in a new Field''' 385 newiindex = self.__copy__() 386 newiindex.__iadd__(other) 387 return newiindex 388 389 def __iadd__(self, other): 390 ''' Add other's values to self's values''' 391 return self.add(other, solve=False) 392 393 def add(self, other, solve=True): 394 ''' Add other's values to self's values 395 396 *Parameters* 397 398 - **other** : Field object to add to self object 399 - **solve** : Boolean (default True) - If True, replace None other's codec value 400 with self codec value. 401 402 *Returns* : self ''' 403 if solve: 404 solved = copy(other) 405 for i in range(len(solved._codec)): 406 if not util.isNotNull(solved._codec[i]) and i in range(len(self._codec)): 407 solved._codec[i] = self._codec[i] 408 values = self.values + solved.values 409 else: 410 values = self.values + other.values 411 codec = util.tocodec(values) 412 if set(codec) != set(self._codec): 413 self._codec = codec 414 self._keys = util.tokeys(values, self._codec) 415 return self 416 417 def __copy__(self): 418 ''' Copy all the data ''' 419 return self.__class__(self) 420 421# %% property 422 @property 423 def cod(self): 424 '''return codec conversion to json value ''' 425 return self.l_to_e(self._codec) 426 #return [codec.to_obj() for codec in self._codec] 427 #return [codec.ntv_value for codec in self._codec] 428 #return self.to_ntv(codecval=True).ntv_value 429 #return self.to_obj(modecodec='optimize', codecval=True, encoded=False, listunic=True) 430 431 @property 432 def codec(self): 433 '''return codec ''' 434 return self._codec 435 436 @property 437 def infos(self): 438 '''return dict with lencodec, typecodec, ratecodec, mincodec, maxcodec''' 439 maxi = len(self) 440 mini = len(set(self._codec)) 441 xlen = len(self._codec) 442 rate = 0.0 443 if maxi == 0: 444 typecodec = 'null' 445 elif xlen == 1: 446 typecodec = 'unique' 447 elif mini == maxi: 448 typecodec = 'complete' 449 elif xlen == maxi: 450 typecodec = 'full' 451 else: 452 rate = (maxi - xlen) / (maxi - mini) 453 if xlen == mini: 454 typecodec = 'default' 455 else: 456 typecodec = 'mixed' 457 return {'lencodec': xlen, 'mincodec': mini, 'maxcodec': maxi, 458 'typecodec': typecodec, 'ratecodec': rate} 459 460 @property 461 def keys(self): 462 '''return keys ''' 463 return self._keys 464 465 @property 466 def values(self): 467 '''return values (see data model)''' 468 return [self._codec[key] for key in self._keys] 469 470 @property 471 def val(self): 472 '''return values conversion to string ''' 473 return [self.s_to_e(self._codec[key]) for key in self._keys] 474 #return [self._codec[key].to_obj() for key in self._keys] 475 #return self.to_obj(modecodec='full', codecval=True, encoded=False)
45class Field(FieldStructure, FieldInterface, ABC): 46 # %% intro 47 ''' 48 An `Field` is a representation of an index list . 49 50 *Attributes (for dynamic attributes see @property methods)* : 51 52 - **name** : name of the Field 53 - **codec** : list of values for each key 54 - **keys** : list of code values 55 56 The methods defined in this class are : 57 58 *constructor (@classmethod)* 59 60 - `Field.bol` 61 - `Field.ntv` 62 - `Field.from_parent` 63 - `Field.from_ntv` 64 - `Field.merging` 65 66 *conversion abstract static methods (@abstractmethod, @staticmethod)* 67 68 - `Field.l_to_i` 69 - `Field.s_to_i` 70 - `Field.l_to_e` 71 - `Field.s_to_e` 72 - `Field.i_to_n` 73 - `Field.n_to_i` 74 - `Field.i_to_name` 75 76 *dynamic value (getters @property)* 77 78 - `Field.values` 79 - `Field.val` 80 - `Field.cod` 81 - `Field.codec` 82 - `Field.infos` 83 - `Field.keys` 84 85 *add - update methods (`observation.field_structure.FieldStructure`)* 86 87 - `Field.append` 88 - `Field.setcodecvalue` 89 - `Field.setcodeclist` 90 - `Field.setname` 91 - `Field.setkeys` 92 - `Field.setlistvalue` 93 - `Field.setvalue` 94 95 *transform methods (`observation.field_structure.FieldStructure`)* 96 97 - `Field.coupling` 98 - `Field.extendkeys` 99 - `Field.full` 100 - `Field.reindex` 101 - `Field.reorder` 102 - `Field.sort` 103 - `Field.tocoupled` 104 - `Field.tostdcodec` 105 106 *getters methods (`observation.field_structure.FieldStructure`)* 107 108 - `Field.couplinginfos` 109 - `Field.derkeys` 110 - `Field.getduplicates` 111 - `Field.iscrossed` 112 - `Field.iscoupled` 113 - `Field.isderived` 114 - `Field.islinked` 115 - `Field.isvalue` 116 - `Field.iskeysfromderkeys` 117 - `Field.keysfromderkeys` 118 - `Field.keytoval` 119 - `Field.loc` 120 - `Field.recordfromkeys` 121 - `Field.recordfromvalue` 122 - `Field.valtokey` 123 124 *export methods (`observation.field_interface.FieldInterface`)* 125 126 - `Field.json` 127 - `Field.to_obj` 128 - `Field.to_dict_obj` 129 - `Field.to_numpy` 130 - `Field.to_pandas` 131 - `Field.vlist` 132 - `Field.vName` 133 - `Field.vSimple` 134 ''' 135 136 def __init__(self, codec=None, name=None, keys=None, 137 lendefault=0, reindex=False, fast=False): 138 ''' 139 Field constructor. 140 141 *Parameters* 142 143 - **codec** : list (default None) - external different values of index (see data model) 144 - **keys** : list (default None) - key value of index (see data model) 145 - **name** : string (default None) - name of index (see data model) 146 - **lendefault** : integer (default 0) - default len if no keys is defined 147 - **reindex** : boolean (default True) - if True, default codec is apply 148 - **fast**: boolean (default False) - if True, codec is created without conversion''' 149 if isinstance(codec, Field): 150 self._keys = copy(codec._keys) 151 self._codec = deepcopy(codec._codec) 152 self.name = copy(codec.name) 153 return 154 if codec is None: 155 codec = [] 156 if not isinstance(codec, list): 157 codec = [codec] 158 codec = list(codec) 159 leng = lendefault 160 if codec and len(codec) > 0 and not leng: 161 leng = len(codec) 162 if not keys is None: 163 leng = len(keys) 164 if not name: 165 name = ES.defaultindex 166 if not (keys is None or isinstance(keys, list)): 167 raise FieldError("keys not list") 168 if keys is None and leng == 0: 169 keys = [] 170 elif keys is None: 171 keys = [(i*len(codec))//leng for i in range(leng)] 172 if not isinstance(codec, list): 173 raise FieldError("codec not list") 174 if codec == []: 175 keysset = util.tocodec(keys) 176 #codec = [Ntv.obj(key) for key in keysset] 177 codec = self.l_to_i(keysset, fast=True) 178 codec = self.l_to_i(codec, fast=fast) 179 self._keys = keys 180 self._codec = codec 181 self.name = name 182 if reindex: 183 self.reindex() 184 185 @classmethod 186 def bol(cls, leng, notdef=None, name=None, default=True): 187 ''' 188 Field constructor (boolean value). 189 190 *Parameters* 191 192 - **leng** : integer - length of the Field 193 - **notdef** : list (default None) - list of records without default value 194 - **default** : boolean (default True) - default value 195 - **name** : string (default None) - name of Field''' 196 values = [default] * leng 197 if notdef: 198 for item in notdef: 199 values[item] = not default 200 return cls.ntv({name: values}) 201 202 @classmethod 203 def from_parent(cls, codec, parent, name=None, reindex=False): 204 '''Generate an Field Object from specific codec and parent keys. 205 206 *Parameters* 207 208 - **codec** : list of objects 209 - **name** : string (default None) - name of index (see data model) 210 - **parent** : Field, parent of the new Field 211 - **reindex** : boolean (default True) - if True, default codec is apply 212 213 *Returns* : Field ''' 214 if isinstance(codec, Field): 215 return copy(codec) 216 return cls(codec=codec, name=name, keys=parent._keys, reindex=reindex) 217 218 @classmethod 219 def ntv(cls, ntv_value=None, extkeys=None, reindex=True, decode_str=False): 220 '''Generate an Field Object from a Ntv field object''' 221 return cls.from_ntv(ntv_value, extkeys=extkeys, reindex=reindex, decode_str=decode_str) 222 223 @classmethod 224 def from_ntv(cls, ntv_value=None, extkeys=None, reindex=True, decode_str=False, 225 add_type=True, lengkeys=None): 226 '''Generate an Field Object from a Ntv field object''' 227 if isinstance(ntv_value, cls): 228 return copy(ntv_value) 229 ntv = Ntv.obj(ntv_value, decode_str=decode_str) 230 #ntv = NtvList(ntv_value) 231 if ntv_value is None: 232 return cls() 233 name, typ, codec, parent, keys, coef, leng = cls.decode_ntv(ntv) 234 if parent and not extkeys: 235 return None 236 if coef: 237 keys = FieldInterface.keysfromcoef(coef, leng//coef, lengkeys) 238 elif extkeys and parent: 239 keys = cls.keysfromderkeys(extkeys, keys) 240 elif extkeys and not parent: 241 keys = extkeys 242 keys = list(range(len(codec))) if keys is None else keys 243 name = ntv.json_name(string=True) if add_type else name 244 return cls(codec=codec, name=name, keys=keys, reindex=reindex) 245 246 """@classmethod 247 def from_dict_obj(cls, bsd, typevalue=ES.def_clsName, reindex=False): 248 '''Generate an Field Object from a dict value''' 249 var = False 250 if not isinstance(bsd, dict): 251 raise FieldError('data is not a dict') 252 name = list(bsd.keys())[0] 253 bsdv = list(bsd.values())[0] 254 if not 'value' in bsdv: 255 raise FieldError('value is not present') 256 value = bsdv['value'] 257 if not isinstance(value, list): 258 value = [value] 259 if 'type' in bsdv and isinstance(bsdv['type'], str): 260 typevalue = bsdv['type'] 261 if 'var' in bsdv and isinstance(bsdv['var'], bool): 262 var = bsdv['var'] 263 codec = [util.castval(val['codec'], typevalue) for val in value] 264 pairs = [] 265 for i, rec in enumerate(value): 266 record = rec['record'] 267 if not isinstance(record, list): 268 record = [record] 269 for j in record: 270 pairs.append((j, i)) 271 if not pairs: 272 return (var, cls()) 273 keys = list(list(zip(*sorted(pairs)))[1]) 274 275 idx = cls(name=name, codec=codec, keys=keys, typevalue=None) 276 return (var, idx)""" 277 278 @classmethod 279 def merging(cls, listidx, name=None): 280 '''Create a new Field with values are tuples of listidx Field values 281 282 *Parameters* 283 284 - **listidx** : list of Field to be merged. 285 - **name** : string (default : None) - Name of the new Field 286 287 *Returns* : new Field''' 288 if not name: 289 name = str(list({idx.name for idx in listidx})) 290 values = util.transpose([idx.values for idx in listidx]) 291 return cls.ntv({name: values}) 292 293 294# %% abstract 295 @staticmethod 296 @abstractmethod 297 def l_to_i(lis): 298 ''' converting a list of external values to a list of internal values''' 299 pass 300 301 @staticmethod 302 @abstractmethod 303 def s_to_i(val): 304 '''converting an external value to an internal value''' 305 pass 306 307 @staticmethod 308 @abstractmethod 309 def n_to_i(ntv): 310 ''' converting a NTV value to an internal value''' 311 pass 312 313 @staticmethod 314 @abstractmethod 315 def l_to_e(lis): 316 ''' converting a list of internal values to a list of external values''' 317 pass 318 319 @staticmethod 320 @abstractmethod 321 def s_to_e(val): 322 '''converting an internal value to an external value''' 323 pass 324 325 @staticmethod 326 @abstractmethod 327 def i_to_n(val): 328 ''' converting an internal value to a NTV value''' 329 pass 330 331 @staticmethod 332 @abstractmethod 333 def i_to_name(val): 334 ''' return the name of the internal value''' 335 pass 336# %% special 337 338 def __repr__(self): 339 '''return classname and number of value''' 340 return self.__class__.__name__ + '[' + str(len(self)) + ']' 341 342 def __eq__(self, other): 343 ''' equal if class and values are equal''' 344 return self.__class__ .__name__ == other.__class__.__name__ and self.values == other.values 345 346 def __len__(self): 347 ''' len of values''' 348 return len(self._keys) 349 350 def __contains__(self, item): 351 ''' item of values''' 352 return item in self.values 353 354 def __getitem__(self, ind): 355 ''' return value item (value conversion)''' 356 if isinstance(ind, tuple): 357 return [copy(self.values[i]) for i in ind] 358 #return self.values[ind] 359 return copy(self.values[ind]) 360 361 def __setitem__(self, ind, value): 362 ''' modify values item''' 363 if ind < 0 or ind >= len(self): 364 raise FieldError("out of bounds") 365 self.setvalue(ind, value, extern=True) 366 367 def __delitem__(self, ind): 368 '''remove a record (value and key).''' 369 self._keys.pop(ind) 370 self.reindex() 371 372 def __hash__(self): 373 '''return hash(values)''' 374 return hash(tuple(self.values)) 375 376 def _hashe(self): 377 '''return hash(values)''' 378 return hash(tuple(self.values)) 379 380 def _hashi(self): 381 '''return hash(codec) + hash(keys)''' 382 return hash(tuple(self._codec)) + hash(tuple(self._keys)) 383 384 def __add__(self, other): 385 ''' Add other's values to self's values in a new Field''' 386 newiindex = self.__copy__() 387 newiindex.__iadd__(other) 388 return newiindex 389 390 def __iadd__(self, other): 391 ''' Add other's values to self's values''' 392 return self.add(other, solve=False) 393 394 def add(self, other, solve=True): 395 ''' Add other's values to self's values 396 397 *Parameters* 398 399 - **other** : Field object to add to self object 400 - **solve** : Boolean (default True) - If True, replace None other's codec value 401 with self codec value. 402 403 *Returns* : self ''' 404 if solve: 405 solved = copy(other) 406 for i in range(len(solved._codec)): 407 if not util.isNotNull(solved._codec[i]) and i in range(len(self._codec)): 408 solved._codec[i] = self._codec[i] 409 values = self.values + solved.values 410 else: 411 values = self.values + other.values 412 codec = util.tocodec(values) 413 if set(codec) != set(self._codec): 414 self._codec = codec 415 self._keys = util.tokeys(values, self._codec) 416 return self 417 418 def __copy__(self): 419 ''' Copy all the data ''' 420 return self.__class__(self) 421 422# %% property 423 @property 424 def cod(self): 425 '''return codec conversion to json value ''' 426 return self.l_to_e(self._codec) 427 #return [codec.to_obj() for codec in self._codec] 428 #return [codec.ntv_value for codec in self._codec] 429 #return self.to_ntv(codecval=True).ntv_value 430 #return self.to_obj(modecodec='optimize', codecval=True, encoded=False, listunic=True) 431 432 @property 433 def codec(self): 434 '''return codec ''' 435 return self._codec 436 437 @property 438 def infos(self): 439 '''return dict with lencodec, typecodec, ratecodec, mincodec, maxcodec''' 440 maxi = len(self) 441 mini = len(set(self._codec)) 442 xlen = len(self._codec) 443 rate = 0.0 444 if maxi == 0: 445 typecodec = 'null' 446 elif xlen == 1: 447 typecodec = 'unique' 448 elif mini == maxi: 449 typecodec = 'complete' 450 elif xlen == maxi: 451 typecodec = 'full' 452 else: 453 rate = (maxi - xlen) / (maxi - mini) 454 if xlen == mini: 455 typecodec = 'default' 456 else: 457 typecodec = 'mixed' 458 return {'lencodec': xlen, 'mincodec': mini, 'maxcodec': maxi, 459 'typecodec': typecodec, 'ratecodec': rate} 460 461 @property 462 def keys(self): 463 '''return keys ''' 464 return self._keys 465 466 @property 467 def values(self): 468 '''return values (see data model)''' 469 return [self._codec[key] for key in self._keys] 470 471 @property 472 def val(self): 473 '''return values conversion to string ''' 474 return [self.s_to_e(self._codec[key]) for key in self._keys] 475 #return [self._codec[key].to_obj() for key in self._keys] 476 #return self.to_obj(modecodec='full', codecval=True, encoded=False)
An Field
is a representation of an index list .
Attributes (for dynamic attributes see @property methods) :
- name : name of the Field
- codec : list of values for each key
- keys : list of code values
The methods defined in this class are :
constructor (@classmethod)
conversion abstract static methods (@abstractmethod, @staticmethod)
dynamic value (getters @property)
add - update methods (observation.field_structure.FieldStructure
)
Field.append
Field.setcodecvalue
Field.setcodeclist
Field.setname
Field.setkeys
Field.setlistvalue
Field.setvalue
transform methods (observation.field_structure.FieldStructure
)
Field.coupling
Field.extendkeys
Field.full
Field.reindex
Field.reorder
Field.sort
Field.tocoupled
Field.tostdcodec
getters methods (observation.field_structure.FieldStructure
)
Field.couplinginfos
Field.derkeys
Field.getduplicates
Field.iscrossed
Field.iscoupled
Field.isderived
Field.islinked
Field.isvalue
Field.iskeysfromderkeys
Field.keysfromderkeys
Field.keytoval
Field.loc
Field.recordfromkeys
Field.recordfromvalue
Field.valtokey
export methods (observation.field_interface.FieldInterface
)
Field.json
Field.to_obj
Field.to_dict_obj
Field.to_numpy
Field.to_pandas
Field.vlist
Field.vName
Field.vSimple
136 def __init__(self, codec=None, name=None, keys=None, 137 lendefault=0, reindex=False, fast=False): 138 ''' 139 Field constructor. 140 141 *Parameters* 142 143 - **codec** : list (default None) - external different values of index (see data model) 144 - **keys** : list (default None) - key value of index (see data model) 145 - **name** : string (default None) - name of index (see data model) 146 - **lendefault** : integer (default 0) - default len if no keys is defined 147 - **reindex** : boolean (default True) - if True, default codec is apply 148 - **fast**: boolean (default False) - if True, codec is created without conversion''' 149 if isinstance(codec, Field): 150 self._keys = copy(codec._keys) 151 self._codec = deepcopy(codec._codec) 152 self.name = copy(codec.name) 153 return 154 if codec is None: 155 codec = [] 156 if not isinstance(codec, list): 157 codec = [codec] 158 codec = list(codec) 159 leng = lendefault 160 if codec and len(codec) > 0 and not leng: 161 leng = len(codec) 162 if not keys is None: 163 leng = len(keys) 164 if not name: 165 name = ES.defaultindex 166 if not (keys is None or isinstance(keys, list)): 167 raise FieldError("keys not list") 168 if keys is None and leng == 0: 169 keys = [] 170 elif keys is None: 171 keys = [(i*len(codec))//leng for i in range(leng)] 172 if not isinstance(codec, list): 173 raise FieldError("codec not list") 174 if codec == []: 175 keysset = util.tocodec(keys) 176 #codec = [Ntv.obj(key) for key in keysset] 177 codec = self.l_to_i(keysset, fast=True) 178 codec = self.l_to_i(codec, fast=fast) 179 self._keys = keys 180 self._codec = codec 181 self.name = name 182 if reindex: 183 self.reindex()
Field constructor.
Parameters
- codec : list (default None) - external different values of index (see data model)
- keys : list (default None) - key value of index (see data model)
- name : string (default None) - name of index (see data model)
- lendefault : integer (default 0) - default len if no keys is defined
- reindex : boolean (default True) - if True, default codec is apply
- fast: boolean (default False) - if True, codec is created without conversion
185 @classmethod 186 def bol(cls, leng, notdef=None, name=None, default=True): 187 ''' 188 Field constructor (boolean value). 189 190 *Parameters* 191 192 - **leng** : integer - length of the Field 193 - **notdef** : list (default None) - list of records without default value 194 - **default** : boolean (default True) - default value 195 - **name** : string (default None) - name of Field''' 196 values = [default] * leng 197 if notdef: 198 for item in notdef: 199 values[item] = not default 200 return cls.ntv({name: values})
Field constructor (boolean value).
Parameters
- leng : integer - length of the Field
- notdef : list (default None) - list of records without default value
- default : boolean (default True) - default value
- name : string (default None) - name of Field
202 @classmethod 203 def from_parent(cls, codec, parent, name=None, reindex=False): 204 '''Generate an Field Object from specific codec and parent keys. 205 206 *Parameters* 207 208 - **codec** : list of objects 209 - **name** : string (default None) - name of index (see data model) 210 - **parent** : Field, parent of the new Field 211 - **reindex** : boolean (default True) - if True, default codec is apply 212 213 *Returns* : Field ''' 214 if isinstance(codec, Field): 215 return copy(codec) 216 return cls(codec=codec, name=name, keys=parent._keys, reindex=reindex)
Generate an Field Object from specific codec and parent keys.
Parameters
- codec : list of objects
- name : string (default None) - name of index (see data model)
- parent : Field, parent of the new Field
- reindex : boolean (default True) - if True, default codec is apply
Returns : Field
218 @classmethod 219 def ntv(cls, ntv_value=None, extkeys=None, reindex=True, decode_str=False): 220 '''Generate an Field Object from a Ntv field object''' 221 return cls.from_ntv(ntv_value, extkeys=extkeys, reindex=reindex, decode_str=decode_str)
Generate an Field Object from a Ntv field object
223 @classmethod 224 def from_ntv(cls, ntv_value=None, extkeys=None, reindex=True, decode_str=False, 225 add_type=True, lengkeys=None): 226 '''Generate an Field Object from a Ntv field object''' 227 if isinstance(ntv_value, cls): 228 return copy(ntv_value) 229 ntv = Ntv.obj(ntv_value, decode_str=decode_str) 230 #ntv = NtvList(ntv_value) 231 if ntv_value is None: 232 return cls() 233 name, typ, codec, parent, keys, coef, leng = cls.decode_ntv(ntv) 234 if parent and not extkeys: 235 return None 236 if coef: 237 keys = FieldInterface.keysfromcoef(coef, leng//coef, lengkeys) 238 elif extkeys and parent: 239 keys = cls.keysfromderkeys(extkeys, keys) 240 elif extkeys and not parent: 241 keys = extkeys 242 keys = list(range(len(codec))) if keys is None else keys 243 name = ntv.json_name(string=True) if add_type else name 244 return cls(codec=codec, name=name, keys=keys, reindex=reindex)
Generate an Field Object from a Ntv field object
278 @classmethod 279 def merging(cls, listidx, name=None): 280 '''Create a new Field with values are tuples of listidx Field values 281 282 *Parameters* 283 284 - **listidx** : list of Field to be merged. 285 - **name** : string (default : None) - Name of the new Field 286 287 *Returns* : new Field''' 288 if not name: 289 name = str(list({idx.name for idx in listidx})) 290 values = util.transpose([idx.values for idx in listidx]) 291 return cls.ntv({name: values})
Create a new Field with values are tuples of listidx Field values
Parameters
- listidx : list of Field to be merged.
- name : string (default : None) - Name of the new Field
Returns : new Field
295 @staticmethod 296 @abstractmethod 297 def l_to_i(lis): 298 ''' converting a list of external values to a list of internal values''' 299 pass
converting a list of external values to a list of internal values
301 @staticmethod 302 @abstractmethod 303 def s_to_i(val): 304 '''converting an external value to an internal value''' 305 pass
converting an external value to an internal value
307 @staticmethod 308 @abstractmethod 309 def n_to_i(ntv): 310 ''' converting a NTV value to an internal value''' 311 pass
converting a NTV value to an internal value
313 @staticmethod 314 @abstractmethod 315 def l_to_e(lis): 316 ''' converting a list of internal values to a list of external values''' 317 pass
converting a list of internal values to a list of external values
319 @staticmethod 320 @abstractmethod 321 def s_to_e(val): 322 '''converting an internal value to an external value''' 323 pass
converting an internal value to an external value
325 @staticmethod 326 @abstractmethod 327 def i_to_n(val): 328 ''' converting an internal value to a NTV value''' 329 pass
converting an internal value to a NTV value
331 @staticmethod 332 @abstractmethod 333 def i_to_name(val): 334 ''' return the name of the internal value''' 335 pass
return the name of the internal value
394 def add(self, other, solve=True): 395 ''' Add other's values to self's values 396 397 *Parameters* 398 399 - **other** : Field object to add to self object 400 - **solve** : Boolean (default True) - If True, replace None other's codec value 401 with self codec value. 402 403 *Returns* : self ''' 404 if solve: 405 solved = copy(other) 406 for i in range(len(solved._codec)): 407 if not util.isNotNull(solved._codec[i]) and i in range(len(self._codec)): 408 solved._codec[i] = self._codec[i] 409 values = self.values + solved.values 410 else: 411 values = self.values + other.values 412 codec = util.tocodec(values) 413 if set(codec) != set(self._codec): 414 self._codec = codec 415 self._keys = util.tokeys(values, self._codec) 416 return self
Add other's values to self's values
Parameters
- other : Field object to add to self object
- solve : Boolean (default True) - If True, replace None other's codec value with self codec value.
Returns : self
Inherited Members
- observation.field_structure.FieldStructure
- append
- coupling
- couplinginfos
- derkeys
- extendkeys
- full
- getduplicates
- iscrossed
- iscoupled
- isderived
- iskeysfromderkeys
- islinked
- isvalue
- keytoval
- keysfromderkeys
- loc
- recordfromvalue
- recordfromkeys
- reindex
- reorder
- setcodecvalue
- setcodeclist
- set_keys
- set_codec
- setkeys
- setname
- setvalue
- setlistvalue
- sort
- tocoupled
- tostdcodec
- valtokey
- observation.field_interface.FieldInterface
- decode_ntv
- encode_coef
- keysfromcoef
- to_dict_obj
- to_numpy
- to_ntv
- to_pandas
- vlist
- vName