NTV.json_ntv.ntv
@author: Philippe@loco-labs.io
The ntv
module is part of the NTV.json_ntv
package (specification document).
It contains the classes NtvSingle
, NtvList
, Ntv
(abstract) for NTV entities.
For more information, see the user guide or the github repository.
1# -*- coding: utf-8 -*- 2""" 3@author: Philippe@loco-labs.io 4 5The `ntv` module is part of the `NTV.json_ntv` package ([specification document]( 6https://loco-philippe.github.io/ES/JSON%20semantic%20format%20(JSON-NTV).htm)). 7 8It contains the classes `NtvSingle`, `NtvList`, `Ntv`(abstract) for NTV entities. 9 10For more information, see the 11[user guide](https://loco-philippe.github.io/NTV/documentation/user_guide.html) 12or the [github repository](https://github.com/loco-philippe/NTV). 13 14""" 15import copy 16from abc import ABC, abstractmethod 17from numbers import Number 18import json 19 20from json_ntv.namespace import Datatype, Namespace, str_type, relative_type, agreg_type 21from json_ntv.ntv_util import NtvError, NtvJsonEncoder, NtvConnector, NtvTree, NtvUtil 22from json_ntv.ntv_patch import NtvPointer 23 24NAME = 'N' 25TYPE = 'T' 26VALUE = 'V' 27ENTITY = 'E' 28NTVSINGLE = 'S' 29NTVLIST = 'L' 30 31class Ntv(ABC, NtvUtil): 32 ''' The Ntv class is an abstract class used by `NtvSingle`and `NtvList` classes. 33 34 *Attributes :* 35 - **ntv_name** : String - name of the NTV entity 36 - **ntv_type**: Datatype or Namespace - type of the entity 37 - **ntv_value**: value of the entity 38 39 *Internal attributes :* 40 - **parent**: parent NtvList entity 41 - **is_json**: True if ntv_value is a json_value 42 43 *dynamic values (@property)* 44 - `json_array` (abstract method) 45 - `type_str` 46 - `code_ntv` 47 - `max_len` 48 - `name` 49 - `tree` 50 - `val` 51 52 The methods defined in this class are : 53 54 *Ntv constructor (staticmethod)* 55 - `fast` 56 - `obj` 57 - `from_obj` 58 - `from_att` 59 60 *NTV conversion (instance methods)* 61 - `alike` 62 - `to_json_ntv` 63 - `to_obj_ntv` 64 65 *export - conversion (instance methods)* 66 - `expand` 67 - `to_fast` 68 - `to_name` 69 - `to_obj` 70 - `to_repr` 71 - `to_mermaid` 72 - `to_tuple` 73 - `to_ntvsingle` 74 - `to_ntvlist` 75 - `notype` 76 77 *tree methods (instance methods)* 78 - `childs` 79 - `pointer` 80 - `replace` 81 - `remove` 82 - `append` (NtvList only) 83 - `insert` (NtvList only) 84 85 *other instance methods* 86 - `from_value` 87 - `json_name` 88 - `set_name` 89 - `set_type` 90 - `set_value` 91 - `obj_value` (abstract method) 92 93 *utility methods* 94 - `decode_json` *(staticmethod)* 95 - `obj_ntv` *(staticmethod)* 96 ''' 97 98 def __init__(self, ntv_value, ntv_name, ntv_type): 99 '''Ntv constructor. 100 101 *Parameters* 102 103 - **ntv_value**: Json entity - value of the entity 104 - **ntv_name** : String (default None) - name of the NTV entity 105 - **ntv_type**: String or Datatype or Namespace (default None) - type of the entity 106 ''' 107 if ntv_type.__class__.__name__ in ['Datatype', 'Namespace']: 108 self.ntv_type = ntv_type 109 elif ntv_type and ntv_type[-1] != '.': 110 self.ntv_type = Datatype.add(ntv_type) 111 elif ntv_type and ntv_type[-1] == '.': 112 self.ntv_type = Namespace.add(ntv_type) 113 else: 114 self.ntv_type = None 115 if not isinstance(ntv_name, str): 116 ntv_name = '' 117 self.ntv_name = ntv_name 118 self.ntv_value = ntv_value 119 self.is_json = NtvConnector.is_json(ntv_value) 120 self.parent = None 121 122 @staticmethod 123 def fast(data, no_typ=False, typ_auto=False): 124 ''' return an Ntv entity from data without conversion. 125 126 *Parameters* : see `obj` method''' 127 return Ntv.obj(data, no_typ=no_typ, typ_auto=typ_auto, fast=True) 128 129 @staticmethod 130 def obj(data, no_typ=False, decode_str=False, typ_auto=False, fast=False): 131 ''' return an Ntv entity from data. 132 133 *Parameters* 134 135 - **Data** can be : 136 - a tuple with value, name, typ and cat (see `from_att` method) 137 - a value to decode (see `from_obj`method) 138 - **no_typ** : boolean (default False) - if True, NtvList is with None type 139 - **type_auto**: boolean (default False) - if True, default type for NtvList 140 is the ntv_type of the first Ntv in the ntv_value 141 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 142 - **decode_str**: boolean (default False) - if True, string are loaded in json data''' 143 #print('obj : ', Namespace.namespaces(), '\n') 144 145 if isinstance(data, tuple): 146 return Ntv.from_att(*data, decode_str=decode_str, fast=fast) 147 # if isinstance(data, str) and data.lstrip() and data.lstrip()[0] in '{[': 148 if isinstance(data, str): 149 try: 150 data = json.loads(data) 151 except json.JSONDecodeError: 152 pass 153 return Ntv.from_obj(data, no_typ=no_typ, decode_str=decode_str, 154 typ_auto=typ_auto, fast=fast) 155 156 @staticmethod 157 def from_att(value, name, typ, cat, decode_str=False, fast=False): 158 ''' return an Ntv entity. 159 160 *Parameters* 161 162 - **value**: Ntv entity or value to convert in an Ntv entity 163 - **name** : string - name of the Ntv entity 164 - **typ** : string or NtvType - type of the NTV entity 165 - **cat**: string - NTV category ('single', 'list') 166 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 167 - **decode_str**: boolean (default False) - if True, string are loaded as json data''' 168 169 value = Ntv._from_value(value, decode_str) 170 if value.__class__.__name__ in ['NtvSingle', 'NtvList']: 171 return value 172 if isinstance(value, list) and cat == 'list': 173 return NtvList(value, name, typ, fast=fast) 174 if cat == 'single': 175 return NtvSingle(value, name, typ, fast=fast) 176 return Ntv.from_obj(value, def_type=typ, fast=fast) 177 178 @staticmethod 179 def from_obj(value, def_type=None, def_sep=None, no_typ=False, decode_str=False, 180 typ_auto=False, fast=False): 181 ''' return an Ntv entity from an object value. 182 183 *Parameters* 184 185 - **value**: Ntv value to convert in an Ntv entity 186 - **no_typ** : boolean (default None) - if True, NtvList is with None type 187 - **def_type** : Datatype or Namespace (default None) - default type of the value 188 - **def_sep**: ':', '::' or None (default None) - default separator of the value 189 - **decode_str**: boolean (default False) - if True, string are loaded as json data 190 - **type_auto**: boolean (default False) - if True, default type for NtvList 191 is the ntv_type of the first Ntv in the ntv_value 192 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion''' 193 value = Ntv._from_value(value, decode_str) 194 if value.__class__.__name__ in ['NtvSingle', 'NtvList']: 195 return value 196 ntv_value, ntv_name, str_typ, sep, is_json = Ntv.decode_json(value) 197 sep = def_sep if not sep else sep 198 sep = None if str_typ and str_typ[-1] == '.' and sep == ':' else sep 199 if isinstance(ntv_value, (list, dict)) and sep in (None, '::'): 200 return Ntv._create_ntvlist(str_typ, def_type, sep, ntv_value, 201 typ_auto, no_typ, ntv_name, fast) 202 if sep == ':' or (sep is None and isinstance(ntv_value, dict)): 203 ntv_type = agreg_type(str_typ, def_type, False) 204 return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast) 205 if sep is None and not isinstance(ntv_value, dict): 206 #is_single_json = isinstance(value, (int, str, float, bool)) 207 is_single_json = isinstance(ntv_value, (int, str, float, bool)) 208 ntv_type = agreg_type(str_typ, def_type, is_single_json) 209 return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast) 210 raise NtvError('separator ":" is not compatible with value') 211 212 def __len__(self): 213 ''' len of ntv_value''' 214 if isinstance(self.ntv_value, list): 215 return len(self.ntv_value) 216 return 1 217 218 def __str__(self): 219 '''return string format''' 220 return self.to_obj(encoded=True) 221 222 def __repr__(self): 223 '''return classname and code''' 224 #return json.dumps(self.to_repr(False, False, False, 10), cls=NtvJsonEncoder) 225 return self.reduce(obj=False, level=3, maxi=6).to_obj(encoded=True) 226 227 def __contains__(self, item): 228 ''' item of Ntv entities''' 229 if isinstance(self.val, list): 230 return item in self.ntv_value 231 return item == self.ntv_value 232 233 def __iter__(self): 234 ''' iterator for Ntv entities''' 235 if isinstance(self, NtvSingle): 236 return iter([self.val]) 237 return iter(self.val) 238 239 def __getitem__(self, selec): 240 ''' return ntv_value item with selec: 241 - String beginning with "/" : json-pointer, 242 - string : name of the ntv, 243 - list : recursive selector 244 - tuple : list of name or index ''' 245 if selec is None or selec == [] or selec == () or selec == '': 246 return self 247 if isinstance(selec, (list, tuple)) and len(selec) == 1: 248 selec = selec[0] 249 if isinstance(selec, str) and len(selec) > 1 and selec[0] == '/': 250 selec = list(NtvPointer(selec)) 251 elif isinstance(selec, NtvPointer): 252 selec = list(selec) 253 if (selec == 0 or selec == self.ntv_name) and isinstance(self, NtvSingle): 254 return self.ntv_value 255 if isinstance(self, NtvSingle): 256 raise NtvError('item not present') 257 if isinstance(selec, tuple): 258 return [self[i] for i in selec] 259 if isinstance(selec, str) and isinstance(self, NtvList): 260 ind = [ntv.ntv_name for ntv in self.ntv_value].index(selec) 261 return self.ntv_value[ind] 262 if isinstance(selec, list) and isinstance(self, NtvList): 263 return self[selec[0]][selec[1:]] 264 return self.ntv_value[selec] 265 266 def __lt__(self, other): 267 ''' return a comparison between two ntv_value''' 268 # order: number > string > None 269 res = Ntv.lower(self, other) 270 if res is None: 271 res = None if len(self) == len(other) else len(self) < len(other) 272 res = self.to_obj(encoded=True) < other.to_obj(encoded=True) if res is None else res 273 return res 274 275 @staticmethod 276 def lower(val1, val2): 277 ''' compare two ntv_value and return True if val1 < val2, False if val1 > val2 and 278 None in the other cases''' 279 res = None 280 for v1, v2 in zip(Ntv.obj(val1).tree.leaf_nodes, Ntv.obj(val2).tree.leaf_nodes): 281 if v1.val is None: 282 res = True 283 elif isinstance(v1.val, (dict, list)): 284 res = Ntv.lower(v1.val, v2) 285 elif isinstance(v2.val, (dict, list)): 286 res = Ntv.lower(v1, v2.val) 287 elif isinstance(v1.val, Number): 288 if isinstance(v2.val, Number): 289 res = None if v1.val == v2.val else v1.val < v2.val 290 else: 291 res = False 292 elif isinstance(v1.val, str): 293 if isinstance(v2.val, Number): 294 res = True 295 elif isinstance(v2.val, str): 296 res = None if v1.val == v2.val else v1.val < v2.val 297 else: 298 res = False 299 if not res is None: 300 break 301 return res 302 303 def childs(self, obj=False, nam=False, typ=False): 304 ''' return a list of child Ntv entities or child data 305 306 *parameters* 307 308 - **obj**: boolean (default False) - return json-value 309 - **nam**: boolean (default False) - return name (with or without type) 310 - **typ**: boolean (default False) - return type (with or without name) 311 ''' 312 if isinstance(self, NtvSingle): 313 return [] 314 if not (obj or nam or typ): 315 return self.val 316 if obj: 317 return [ntv.to_obj() for ntv in self.val] 318 return [(ntv.name if nam else '') + (' - ' if nam and typ else '') + 319 (ntv.type_str if typ else '') for ntv in self.val] 320 321 def pointer(self, index=False, item_idx=None): 322 '''return a nested list of pointer from root 323 324 *Parameters* 325 326 - **index**: Boolean (default False) - use index instead of name 327 - **item_idx**: Integer (default None) - index value for the pointer 328 (useful with duplicate data)''' 329 if not self.parent: 330 return NtvPointer([]) 331 idx = item_idx if item_idx else self.parent.ntv_value.index(self) 332 num = index or (self.ntv_name == "" and self.parent.json_array) 333 pointer = self.parent.pointer(index) 334 pointer.append(idx if num else self.ntv_name) 335 return pointer 336 337 @property 338 def code_ntv(self): 339 '''return a string with the NTV code composed with 1 to 3 letters: 340 - 'l' (NtvList), 's' (NtvSingle / json_value) or 'o' (NtvSingle / obj_value) 341 - 'N' if ntv_name is present else none 342 - 'T' if ntv_type is present else none''' 343 dic = {'NtvList': 'l', 'NtvSingle': 's'} 344 code = dic[self.__class__.__name__] 345 if isinstance(self, NtvSingle) and not self.is_json: 346 code = 'o' 347 if self.ntv_name: 348 code += 'N' 349 if self.ntv_type and self.ntv_type.long_name != 'json': 350 code += 'T' 351 return code 352 353 @property 354 def max_len(self): 355 '''return the highest len of Ntv entity included''' 356 maxi = len(self) 357 if isinstance(self.ntv_value, (list, set)): 358 maxi = max(maxi, max(ntv.max_len for ntv in self.ntv_value)) 359 return maxi 360 361 @property 362 def name(self): 363 '''return the ntv_name of the entity''' 364 return self.ntv_name 365 366 @property 367 def type_str(self): 368 '''return a string with the value of the NtvType of the entity''' 369 if not self.ntv_type: 370 return '' 371 return self.ntv_type.long_name 372 373 @property 374 def val(self): 375 '''return the ntv_value of the entity''' 376 return self.ntv_value 377 378 def alike(self, ntv_value): 379 ''' return a Ntv entity with same name and type. 380 381 *Parameters* 382 383 - **ntv_value**: list of ntv values''' 384 return self.__class__(ntv_value, self.ntv_name, self.ntv_type) 385 386 def from_value(self): 387 '''return a Ntv entity from ntv_value''' 388 if isinstance(self.ntv_value, list): 389 return NtvList(self.ntv_value) 390 return Ntv.from_obj(self.ntv_value) 391 392 def json_name(self, def_type=None, string=False, explicit=False): 393 '''return the JSON name of the NTV entity (json-ntv format) 394 395 *Parameters* 396 397 - **def_typ** : Datatype or Namespace (default None) - type of the parent entity 398 - **string** : boolean (default False) - If True, return a string else a tuple 399 - **explicit** : boolean (default False) - If True, type is always included''' 400 if def_type is None: 401 def_type = '' 402 elif isinstance(def_type, (Datatype, Namespace)): 403 def_type = def_type.long_name 404 json_name = self.ntv_name if self.ntv_name else '' 405 json_type = relative_type( 406 def_type, self.type_str) if self.ntv_type else '' 407 implicit = isinstance(self, NtvSingle) and (json_type == 'json' 408 and (not def_type or def_type == 'json' or def_type[-1] == '.') 409 or not NtvConnector.is_json_class(self.val)) 410 if implicit and not explicit: 411 json_type = '' 412 json_sep = self._obj_sep(json_name, json_type, def_type) 413 if string: 414 return json_name + json_sep + json_type 415 return [json_name, json_sep, json_type] 416 417 def to_ntvsingle(self, name=None, typ=None, def_type=None, **kwargs): 418 '''convert NtvList entity to NtvSingle entity 419 420 *Parameters* 421 422 - **ntv_name** : String (default None) - name of the NTV entity 423 - **ntv_type**: String (default None) - type of the entity 424 - **value**: value of the entity 425 - **fast**: boolean (default False) - Ntv is created with a list of json values 426 without control 427 ''' 428 return NtvSingle(self.obj_value(def_type=def_type, **kwargs), 429 self.name if self.name else name, 430 self.type_str if self.type_str else typ) 431 432 def to_ntvlist(self, def_type=None, def_sep=None, no_typ=False, decode_str=False, 433 typ_auto=False, fast=False): 434 '''convert NtvSingle entity to NtvList entity 435 436 *Parameters* 437 438 - **value**: Ntv value to convert in an Ntv entity 439 - **no_typ** : boolean (default None) - if True, NtvList is with 'json' type 440 - **def_type** : Datatype or Namespace (default None) - default type of the value 441 - **def_sep**: ':', '::' or None (default None) - default separator of the value 442 - **decode_str**: boolean (default False) - if True, string are loaded as json data 443 - **type_auto**: boolean (default False) - if True, default type for NtvList 444 is the ntv_type of the first Ntv in the ntv_value 445 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 446 ''' 447 ntv = Ntv.from_obj(self.ntv_value, def_type, def_sep, no_typ, decode_str, 448 typ_auto, fast) 449 if ntv.__class__.__name__ == 'NtvSingle': 450 return NtvList([self]) 451 if self.ntv_name: 452 ntv.set_name(self.ntv_name) 453 return ntv 454 455 def notype(self): 456 '''convert NTV entity in a NV entity (with ntv_type is 'json' or None')''' 457 no_type = copy.copy(self) 458 for ntv in NtvTree(no_type).leaf_nodes: 459 ntv.set_type('json') 460 for ntv in NtvTree(no_type).inner_nodes: 461 ntv.set_type() 462 return no_type 463 464 def reduce(self, obj=True, maxi=6, level=3): 465 '''reduce the length and the level of the entity 466 467 *Parameters* 468 469 - **obj**: boolean (default True) - If True return jsonNTV else NTV entity 470 - **maxi**: integer (default 6) - Number of returned entities in an NtvList 471 - **level**: integer (default 6) - returned entities in an NtvList at this level is None 472 473 *return* 474 475 - **NTV entity** or **jsonNTV** 476 ''' 477 ntv = copy.copy(self) 478 cont = Ntv.obj('___') if self.json_array else Ntv.obj({'___':''}) 479 if isinstance(self, NtvSingle): 480 return ntv 481 if level == 0: 482 #ntv.ntv_value = [NtvSingle('___',ntv_type=ntv.type_str)] 483 ntv.ntv_value = [Ntv.obj('___',no_typ=True)] 484 #ntv.ntv_value = [Ntv.obj('___',typ_auto=True)] 485 if len(self) <= maxi: 486 ntv.ntv_value = [child.reduce(False, maxi, level-1) for child in ntv] 487 return ntv 488 mid = maxi // 2 489 cont.set_type(ntv.type_str) 490 start = [child.reduce(False, maxi, level-1) for child in ntv[:mid]] 491 #middle = [NtvSingle('...',ntv_type=ntv.type_str)] 492 middle = [cont] 493 end = [child.reduce(False, maxi, level-1) for child in ntv[-mid:]] 494 ntv.ntv_value = start + middle + end 495 if obj: 496 return ntv.to_obj() 497 return ntv 498 499 def set_name(self, name='', nodes='simple'): 500 '''set new names to the entity 501 502 *Parameters* 503 504 - **name**: list or string (default '') - New name values 505 - **nodes**: string (default 'simple') - nodes to be changed 506 'simple': current entity 507 'leaves': NtvSingle entities 508 'inner': NtvList entities 509 'all': all entities ''' 510 name = '' if name is None else name 511 match nodes: 512 case 'simple': 513 self.ntv_name = str(name) 514 case 'leaves': 515 if not isinstance(name, list): 516 name = [str(name)] * NtvTree(self).breadth 517 for nam, ntv in zip(name, NtvTree(self).leaf_nodes): 518 ntv.ntv_name = nam 519 case 'inner': 520 if not isinstance(name, list): 521 name = [str(name)] * len(NtvTree(self).inner_nodes) 522 for nam, ntv in zip(name, NtvTree(self).inner_nodes): 523 ntv.ntv_name = nam 524 case 'all': 525 if not isinstance(name, list): 526 name = [str(name)] * NtvTree(self).size 527 for nam, ntv in zip(name, NtvTree(self).nodes): 528 ntv.ntv_name = nam 529 case _: 530 raise NtvError('the nodes option is not valid') 531 532 def set_type(self, typ=None): 533 '''set a new type to the entity 534 535 *Parameters* 536 537 - **typ**: string, Datatype, Namespace (default None)''' 538 if typ and not isinstance(typ, (str, Datatype, Namespace)): 539 raise NtvError('the type is not a valid type') 540 self.ntv_type = str_type(typ, self.__class__.__name__ == 'NtvSingle') 541 542 def set_value(self, value=None, fast=False): 543 '''set new ntv_value of a single entity or of a list of entities included 544 545 *Parameters* 546 547 - **value**: list or single value 548 - **fast** : boolean (default False) - if True, value is not converted''' 549 if isinstance(self, NtvSingle): 550 self.ntv_value = NtvSingle(value, ntv_type=self.ntv_type, 551 fast=fast).val 552 return 553 if not isinstance(value, list): 554 value = [value] * NtvTree(self).breadth 555 ntv_val = NtvList(value, fast=fast) 556 for val, ntv in zip(ntv_val, NtvTree(self).leaf_nodes): 557 ntv.ntv_value = val.val 558 return 559 560 def to_mermaid(self, title='', disp=False, row=False, leaves=False): 561 '''return a mermaid flowchart. 562 563 *Parameters* 564 565 - **title**: String (default '') - title of the flowchart 566 - **disp**: Boolean (default False) - if true, return a display else return 567 a mermaid text diagram 568 - **row**: Boolean (default False) - if True, add the node row 569 - **leaves**: Boolean (default False) - if True, add the leaf row 570 ''' 571 option = {'title': title, 'disp': disp, 'row': row, 'leaves': leaves} 572 if disp: 573 Ntv.obj({':$mermaid': self.to_obj()}).to_obj( 574 format='obj', **option) 575 return None 576 return Ntv.obj({':$mermaid': self.to_obj()}).to_obj(format='obj', **option) 577 578 def expand(self, full=True, entity=True): 579 '''return a json representation of the triplet (name, type, value) 580 581 582 *Parameters* 583 584 - **full**: Boolean (default True) - If False only members with non empty values are present 585 - **entity**: Boolean (default True) - If True, member with entity name is added 586 ''' 587 exp = {ENTITY: self.__class__.__name__} if entity else {} 588 if isinstance(self, NtvList) and full: 589 return exp | {NAME: self.name, TYPE: self.type_str, 590 VALUE: [ntv.expand(full) for ntv in self.val]} 591 if isinstance(self, NtvSingle) and full: 592 return exp | {NAME: self.name, TYPE: self.type_str, VALUE: self.val} 593 exp |= {} if not self.name else {NAME: self.name} 594 if not self.type_str in ['json', ''] : 595 exp[TYPE] = self.type_str 596 if isinstance(self, NtvList): 597 exp[VALUE] = [ntv.expand(full) for ntv in self.val] 598 else: 599 exp[VALUE] = self.val 600 return exp 601 602 def to_repr(self, nam=True, typ=True, val=True, jsn=False, maxi=10): 603 '''return a simple json representation of the Ntv entity. 604 605 *Parameters* 606 607 - **nam**: Boolean(default True) - if true, the names are included 608 - **typ**: Boolean(default True) - if true, the types are included 609 - **val**: Boolean(default True) - if true, the values are included 610 - **jsn**: Boolean(default False) - if false, the 'json' type is not included 611 - **maxi**: Integer (default 10) - number of values to include for NtvList 612 entities. If maxi < 1 all the values are included. 613 ''' 614 ntv = self.code_ntv 615 if nam and typ: 616 ntv = ntv[0] 617 if self.ntv_name and nam: 618 ntv += '-' + self.ntv_name 619 if self.ntv_type and typ and (jsn or self.ntv_type.long_name != 'json'): 620 ntv += '-' + self.ntv_type.long_name 621 clas = self.__class__.__name__ 622 clas_val = self.ntv_value.__class__.__name__ 623 if clas == 'NtvSingle' and clas_val != 'NtvSingle': 624 if val: 625 if ntv: 626 ntv += '-' 627 ntv += json.dumps(self.ntv_value, cls=NtvJsonEncoder) 628 return ntv 629 if clas == 'NtvSingle' and clas_val == 'NtvSingle': 630 return {ntv: self.ntv_value.to_repr(nam, typ, val, jsn, maxi)} 631 if clas == 'NtvList': 632 maxv = len(self.ntv_value) if maxi < 1 else maxi 633 return {ntv: [ntvi.to_repr(nam, typ, val, jsn, maxi) 634 for ntvi in self.ntv_value[:maxv]]} 635 raise NtvError('the ntv entity is not consistent') 636 637 def to_name(self, default=''): 638 '''return the name of the NTV entity 639 640 *Parameters* 641 642 - **default**: string (default ''): returned value if name is not present ''' 643 if self.ntv_name == '': 644 return default 645 return self.ntv_name 646 647 def to_fast(self, def_type=None, **kwargs): 648 '''return the JSON representation of the NTV entity (json-ntv format) 649 without value conversion. 650 651 *Parameters* 652 653 - **def_type** : Datatype or Namespace (default None) - default type to apply 654 to the NTV entity 655 - **encoded** : boolean (default False) - choice for return format 656 (string/bytes if True, dict/list/tuple else) 657 - **format** : string (default 'json')- choice for return format 658 (json, cbor, obj) 659 - **simpleval** : boolean (default False) - if True, only value (without 660 name and type) is included 661 - **name** : boolean (default true) - if False, name is not included 662 - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList 663 - **maxi**: Integer (default -1) - number of values to include for NtvList 664 entities. If maxi < 1 all the values are included. 665 ''' 666 option = kwargs | {'fast': True} 667 return self.to_obj(def_type=def_type, **option) 668 669 def to_obj(self, def_type=None, **kwargs): 670 '''return the JSON representation of the NTV entity (json-ntv format). 671 672 *Parameters* 673 674 - **def_type** : Datatype or Namespace (default None) - default type to apply 675 to the NTV entity 676 - **encoded** : boolean (default False) - choice for return format 677 (string/bytes if True, dict/list/tuple else) 678 - **format** : string (default 'json')- choice for return format 679 (json, cbor, obj) 680 - **simpleval** : boolean (default False) - if True, only value (without 681 name and type) is included 682 - **name** : boolean (default true) - if False, name is not included 683 - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList 684 - **fast** : boolean (default False) - if True, json is created without conversion 685 - **maxi**: Integer (default -1) - number of values to include for NtvList 686 entities. If maxi < 1 all the values are included. 687 ''' 688 option = {'encoded': False, 'format': 'json', 'fast': False, 'maxi': -1, 689 'simpleval': False, 'name': True, 'json_array': False} | kwargs 690 value = self.obj_value(def_type=def_type, **option) 691 obj_name = self.json_name(def_type) 692 if not option['name']: 693 obj_name[0] = '' 694 if option['simpleval']: 695 name = '' 696 elif option['format'] in ('cbor', 'obj') and not NtvConnector.is_json_class(value): 697 name = obj_name[0] 698 else: 699 name = obj_name[0] + obj_name[1] + obj_name[2] 700 value = [value] if not name and isinstance(value, dict) and len(value) == 1 else value 701 json_obj = {name: value} if name else value 702 if option['encoded'] and option['format'] == 'json': 703 return json.dumps(json_obj, cls=NtvJsonEncoder) 704 if option['encoded'] and option['format'] == 'cbor': 705 return NtvConnector.connector()['CborConnec'].to_obj_ntv(json_obj) 706 return json_obj 707 708 @staticmethod 709 def obj_ntv(value, name='', typ='', single=False): 710 '''return a json-ntv representation without using Ntv structure. 711 712 *Parameters* 713 714 - **value** : ntv-value of the json-ntv 715 - **name** : string (default '') - ntv-name of the json-ntv 716 - **typ** : string (default '') - ntv_type of the json-ntv 717 - **single** : boolean (default False) - if True, value is a single object 718 else value is a set of objetcs. 719 ''' 720 value = {} if not value else value 721 name = '' if not name else name 722 typ = '' if not typ else typ 723 ntv_list = isinstance(value, (list, dict)) 724 if not single and not ntv_list: 725 raise NtvError('value is not compatible with not single NTV data') 726 sep = ':' if single else '::' 727 sep = '' if not typ and (not single or single and not ntv_list) else sep 728 name += sep + typ 729 value = [value] if not name and isinstance(value, dict) and len(value) == 1 else value 730 return {name: value} if name else value 731 732 def to_json_ntv(self): 733 ''' create a copy where ntv-value of the self-tree nodes is converted 734 in json-value''' 735 ntv = copy.copy(self) 736 for leaf in ntv.tree.leaf_nodes: 737 if isinstance(leaf.ntv_value, (NtvSingle, NtvList)): 738 leaf.ntv_value = leaf.ntv_value.to_obj() 739 leaf.ntv_type = Datatype('ntv') 740 elif not leaf.is_json: 741 leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.cast( 742 leaf.ntv_value, leaf.ntv_name, leaf.type_str) 743 leaf.ntv_type = Datatype.add(type_str) 744 leaf.is_json = True 745 return ntv 746 747 def to_obj_ntv(self, **kwargs): 748 ''' create a copy where ntv-value of the self-tree nodes is converted 749 in object-value 750 751 *Parameters* 752 753 - **kwargs** : parameters used in NtvConnector class (specific for each Connector)''' 754 ntv = copy.copy(self) 755 for leaf in ntv.tree.leaf_nodes: 756 if (leaf.is_json and leaf.type_str in set(NtvConnector.dic_type.values()) 757 or leaf.ntv_type is None): 758 leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.uncast( 759 leaf, **kwargs) 760 leaf.ntv_type = Datatype.add(type_str) if type_str else None 761 leaf.is_json = NtvConnector.is_json(leaf.ntv_value) 762 return ntv 763 764 def to_tuple(self, maxi=10): 765 '''return a nested tuple representation of the NTV entity 766 (NtvList/NtvSingle, ntv_name, ntv_type, ntv_value). 767 768 *Parameters* 769 770 - **maxi**: Integer (default 10) - number of values to include for NtvList 771 entities. If maxi < 1 all the values are included. 772 ''' 773 clas = self.__class__.__name__ 774 val = self.ntv_value 775 name = self.ntv_name 776 typ = None 777 if self.ntv_type: 778 typ = self.ntv_type.long_name 779 if isinstance(self, NtvSingle) and not isinstance(val, NtvSingle): 780 return (clas, name, typ, val) 781 if isinstance(self, NtvSingle) and isinstance(val, NtvSingle): 782 return (clas, name, typ, val.to_tuple(maxi=maxi)) 783 if isinstance(self, NtvList): 784 maxv = len(self.ntv_value) if maxi < 1 else maxi 785 return (clas, name, typ, [ntv.to_tuple(maxi=maxi) for ntv in val[:maxv]]) 786 raise NtvError('the ntv entity is not consistent') 787 788 def remove(self, first=True, index=None): 789 '''remove self from its parent entity. 790 791 *parameters* 792 793 - **first** : boolean (default True) - if True only the first instance 794 else all 795 - **index** : integer (default None) - index of self in its parent 796 ''' 797 parent = self.parent 798 if not parent: 799 return 800 idx = parent.ntv_value.index(self) if index is None else index 801 if not parent[idx] == self: 802 raise NtvError('the entity is not present at the index') 803 del parent.ntv_value[idx] 804 if not first and index is None: 805 while self in parent: 806 idx = parent.ntv_value.index(self) 807 del parent.ntv_value[idx] 808 if not self in parent: 809 self.parent = None 810 return 811 812 def replace(self, ntv): 813 '''replace self by ntv in the tree''' 814 parent = self.parent 815 if parent: 816 idx = parent.ntv_value.index(self) 817 parent.insert(idx, ntv) 818 del parent[idx+1] 819 if not self in parent: 820 self.parent=None 821 else: 822 self = ntv 823 824 @property 825 def tree(self): 826 '''return a tree with included entities (NtvTree object)''' 827 return NtvTree(self) 828 829 @abstractmethod 830 def obj_value(self): 831 '''return the ntv_value with different formats defined by kwargs (abstract method)''' 832 833 @property 834 @abstractmethod 835 def json_array(self): 836 ''' return the json_array dynamic attribute (abstract method)''' 837 838 @abstractmethod 839 def _obj_sep(self, json_type, def_type): 840 ''' return separator to include in json_name (abstract method)''' 841 842 @staticmethod 843 def _from_value(value, decode_str=False): 844 '''return a decoded value 845 846 *Parameters* 847 848 - **decode_str**: boolean (default False) - if True, string are loaded as json data 849 ''' 850 if isinstance(value, bytes): 851 value = Ntv.from_obj({'$cbor': value}).ntv_value 852 elif decode_str and isinstance(value, str) and value.lstrip() and\ 853 value.lstrip()[0] in '"-{[0123456789tfn': 854 try: 855 value = json.loads(value) 856 except json.JSONDecodeError: 857 pass 858 return value 859 860 @staticmethod 861 def decode_json(json_value): 862 '''return (value, name, type, separator, isjson) of a json object''' 863 if isinstance(json_value, dict) and len(json_value) == 1: 864 json_name = list(json_value.keys())[0] 865 val = json_value[json_name] 866 return (val, *NtvUtil.from_obj_name(json_name), NtvConnector.is_json(val)) 867 return (json_value, None, None, None, NtvConnector.is_json(json_value)) 868 869 @staticmethod 870 def _create_ntvlist(str_typ, def_type, sep, ntv_value, typ_auto, no_typ, ntv_name, fast): 871 '''return a NtvList with parameters from Ntv.from_obj method''' 872 def_type = agreg_type(str_typ, def_type, False) 873 sep_val = ':' if sep and def_type else None 874 if isinstance(ntv_value, dict): 875 keys = list(ntv_value.keys()) 876 values = list(ntv_value.values()) 877 ntv_list = [Ntv.from_obj({key: val}, def_type, sep_val, fast=fast) 878 for key, val in zip(keys, values)] 879 else: 880 ntv_list = [Ntv.from_obj(val, def_type, sep_val, fast=fast) 881 for val in ntv_value] 882 if typ_auto and not def_type and ntv_list: 883 def_type = ntv_list[0].ntv_type 884 def_type = None if no_typ else def_type 885 return NtvList(ntv_list, ntv_name, def_type, typ_auto, fast=fast) 886 887 @staticmethod 888 def _listed(idx): 889 '''transform a tuple of tuple object in a list of list object''' 890 return [val if not isinstance(val, tuple) else Ntv._listed(val) for val in idx] 891 892 893class NtvSingle(Ntv): 894 ''' A NTV-single entity is a Ntv entity not composed with other entities. 895 896 *Attributes :* 897 - no additional attributes to those of parent class `Ntv` 898 899 *dynamic values (@property)* 900 - `json_array` 901 902 The additional methods defined in this class are : 903 904 *instance methods* 905 - `obj_value` 906 ''' 907 908 def __init__(self, value, ntv_name=None, ntv_type=None, fast=False): 909 '''NtvSingle constructor. 910 911 *Parameters* 912 913 - **ntv_name** : String (default None) - name of the NTV entity 914 - **ntv_type**: String (default None) - type of the entity 915 - **value**: value of the entity 916 - **fast**: boolean (default False) - Ntv is created with a list of json values 917 without control 918 ''' 919 if not fast: 920 value, ntv_name, ntv_type = NtvSingle._decode_s( 921 value, ntv_name, ntv_type) 922 if ntv_type and isinstance(ntv_type, str) and ntv_type[-1] == '.': 923 raise NtvError('the ntv_type is not valid') 924 super().__init__(value, ntv_name, ntv_type) 925 926 def __eq__(self, other): 927 ''' equal if name type and value are equal''' 928 return self.__class__.__name__ == other.__class__.__name__ and\ 929 self.ntv_name == other.ntv_name and self.ntv_type == other.ntv_type and\ 930 self.ntv_value == other.ntv_value 931 932 def __hash__(self): 933 '''return hash(name) + hash(type) + hash(value)''' 934 return hash(self.ntv_name) + hash(self.ntv_type) + \ 935 hash(json.dumps(self.ntv_value, cls=NtvJsonEncoder)) 936 937 def __copy__(self): 938 ''' Copy all the Ntv tree ''' 939 return self.__class__(copy.copy(self.ntv_value), self.ntv_name, 940 self.ntv_type, fast=True) 941 942 @property 943 def json_array(self): 944 ''' return the json_array dynamic attribute (always False)''' 945 return False 946 947 def obj_value(self, def_type=None, **kwargs): 948 '''return the ntv_value with different formats defined by kwargs''' 949 option = {'encoded': False, 'format': 'json', 950 'simpleval': False, 'fast': False} | kwargs 951 if option['fast'] or option['format'] in ('json', 'tuple'): 952 return self.ntv_value 953 if option['format'] == 'obj' and self.ntv_value == 'null': 954 return None 955 return NtvConnector.uncast(self, **option)[0] 956 957 def _obj_sep(self, json_name, json_type, def_type=None): # REQ5 958 ''' return separator to include in json_name''' 959 if json_type or not def_type and isinstance(self.ntv_value, (list, dict)): 960 return ':' 961 return '' 962 963 @staticmethod 964 def _decode_s(ntv_value, ntv_name, ntv_type): 965 '''return adjusted ntv_value, ntv_name, ntv_type''' 966 is_json = NtvConnector.is_json(ntv_value) 967 if is_json: 968 if isinstance(ntv_value, (list)): 969 ntv_value = [NtvSingle._decode_s(val, '', ntv_type)[ 970 0] for val in ntv_value] 971 elif isinstance(ntv_value, (dict)): 972 ntv_value = {key: NtvSingle._decode_s(val, '', ntv_type)[ 973 0] for key, val in ntv_value.items()} 974 elif isinstance(ntv_value, NtvSingle): 975 ntv_value = ntv_value.to_obj() 976 return (ntv_value, ntv_name, 'ntv') 977 else: 978 ntv_value, name, typ = NtvConnector.cast(ntv_value, ntv_name) 979 ntv_type = Datatype(typ) if typ else ntv_type 980 if not ntv_type: 981 if is_json: 982 ntv_type = 'json' 983 else: 984 ntv_type = typ 985 if not ntv_name: 986 ntv_name = name 987 elif not is_json and Datatype(ntv_type) != Datatype(typ): 988 raise NtvError('ntv_value is not compatible with ntv_type') 989 return (ntv_value, ntv_name, ntv_type) 990 991 992class NtvList(Ntv): 993 '''A NTV-list entity is a Ntv entity where: 994 995 - ntv_value is a list of NTV entities, 996 - ntv_type is a default type available for included NTV entities 997 998 *Attributes :* 999 - no additional attributes to those of parent class `Ntv` 1000 1001 *dynamic values (@property)* 1002 - `json_array` 1003 1004 The additional methods defined in this class are : 1005 1006 *instance methods* 1007 - `obj_value` 1008 ''' 1009 1010 def __init__(self, list_ntv, ntv_name=None, ntv_type=None, typ_auto=False, fast=False): 1011 '''NtvList constructor. 1012 1013 *Parameters* 1014 1015 - **ntv_name** : String (default None) - name of the NTV entity 1016 - **ntv_type**: String (default None) - default type or namespace of 1017 the included entities 1018 - **list_ntv**: list - list of Ntv objects or obj_value of Ntv objects 1019 - **fast**: boolean (default False) - if True, Ntv is created with a list 1020 of json values without control 1021 - **type_auto**: boolean (default False) - if True, default type for NtvList 1022 is the ntv_type of the first Ntv in the ntv_value''' 1023 if isinstance(list_ntv, NtvList): 1024 ntv_value = [copy.copy(ntv) for ntv in list_ntv.ntv_value] 1025 ntv_type = list_ntv.ntv_type 1026 ntv_name = list_ntv.ntv_name 1027 elif isinstance(list_ntv, list): 1028 ntv_value = [Ntv.from_obj(ntv, ntv_type, ':', fast=fast) 1029 for ntv in list_ntv] 1030 elif isinstance(list_ntv, dict): 1031 ntv_value = [Ntv.from_obj({key: val}, ntv_type, ':', fast=fast) 1032 for key, val in list_ntv.items()] 1033 else: 1034 raise NtvError('ntv_value is not a list') 1035 if typ_auto and not ntv_type and len(ntv_value) > 0 and ntv_value[0].ntv_type: 1036 ntv_type = ntv_value[0].ntv_type 1037 super().__init__(ntv_value, ntv_name, ntv_type) 1038 for ntv in self: 1039 ntv.parent = self 1040 1041 @property 1042 def json_array(self): 1043 ''' return the json_array dynamic attribute''' 1044 set_name = {ntv.ntv_name for ntv in self} 1045 return '' in set_name or len(set_name) != len(self) or len(set_name)==1 1046 1047 def __eq__(self, other): 1048 ''' equal if name and value are equal''' 1049 return self.__class__.__name__ == other.__class__.__name__ and\ 1050 self.ntv_name == other.ntv_name and self.ntv_value == other.ntv_value 1051 1052 def __hash__(self): 1053 '''return hash(name) + hash(value)''' 1054 return hash(self.ntv_name) + hash(tuple(self.ntv_value)) 1055 1056 def __copy__(self): 1057 ''' Copy all the data ''' 1058 cop = self.__class__(self) 1059 cop.parent = None 1060 return cop 1061 1062 def __setitem__(self, ind, value): 1063 ''' replace ntv_value item at the `ind` row with `value`''' 1064 if ind < 0 or ind >= len(self): 1065 raise NtvError("out of bounds") 1066 self.ntv_value[ind] = value 1067 if isinstance(value, (NtvSingle, NtvList)): 1068 value.parent = self 1069 1070 def __delitem__(self, ind): 1071 '''remove ntv_value item at the `ind` row''' 1072 if isinstance(ind, int): 1073 self.ntv_value.pop(ind) 1074 else: 1075 self.ntv_value.pop(self.ntv_value.index(self[ind])) 1076 1077 def append(self, ntv): 1078 ''' add ntv at the end of the list of Ntv entities included''' 1079 old_parent = ntv.parent 1080 if old_parent: 1081 del(old_parent[old_parent.ntv_value.index(ntv)]) 1082 self.ntv_value.append(ntv) 1083 ntv.parent = self 1084 1085 def insert(self, idx, ntv): 1086 ''' add ntv at the index idx of the list of Ntv entities included''' 1087 old_parent = ntv.parent 1088 if old_parent: 1089 del(old_parent[old_parent.ntv_value.index(ntv)]) 1090 self.ntv_value.insert(idx, ntv) 1091 ntv.parent = self 1092 1093 def _obj_sep(self, json_name, json_type, def_type=None): 1094 ''' return separator to include in json_name''' 1095 return '::' if (json_type and json_type[-1] != '.') or (json_type and json_name) else '' 1096 1097 def obj_value(self, def_type=None, **kwargs): 1098 '''return the ntv_value with different formats defined by kwargs 1099 ''' 1100 option = {'encoded': False, 'format': 'json', 'simpleval': False, 1101 'json_array': False, 'fast': False, 'maxi': -1} | kwargs 1102 opt2 = option | {'encoded': False} 1103 maxv = len(self.ntv_value) if option['maxi'] < 1 else option['maxi'] 1104 def_type = self.ntv_type.long_name if self.ntv_type else def_type 1105 values = [ntv.to_obj(def_type=def_type, **opt2) 1106 for ntv in self.ntv_value[:maxv]] 1107 if len(values) == 1 and isinstance(values[0], dict): 1108 return values[0] 1109 if self.json_array or option['simpleval'] or option['json_array']: 1110 return values 1111 return {list(val.items())[0][0]: list(val.items())[0][1] for val in values}
32class Ntv(ABC, NtvUtil): 33 ''' The Ntv class is an abstract class used by `NtvSingle`and `NtvList` classes. 34 35 *Attributes :* 36 - **ntv_name** : String - name of the NTV entity 37 - **ntv_type**: Datatype or Namespace - type of the entity 38 - **ntv_value**: value of the entity 39 40 *Internal attributes :* 41 - **parent**: parent NtvList entity 42 - **is_json**: True if ntv_value is a json_value 43 44 *dynamic values (@property)* 45 - `json_array` (abstract method) 46 - `type_str` 47 - `code_ntv` 48 - `max_len` 49 - `name` 50 - `tree` 51 - `val` 52 53 The methods defined in this class are : 54 55 *Ntv constructor (staticmethod)* 56 - `fast` 57 - `obj` 58 - `from_obj` 59 - `from_att` 60 61 *NTV conversion (instance methods)* 62 - `alike` 63 - `to_json_ntv` 64 - `to_obj_ntv` 65 66 *export - conversion (instance methods)* 67 - `expand` 68 - `to_fast` 69 - `to_name` 70 - `to_obj` 71 - `to_repr` 72 - `to_mermaid` 73 - `to_tuple` 74 - `to_ntvsingle` 75 - `to_ntvlist` 76 - `notype` 77 78 *tree methods (instance methods)* 79 - `childs` 80 - `pointer` 81 - `replace` 82 - `remove` 83 - `append` (NtvList only) 84 - `insert` (NtvList only) 85 86 *other instance methods* 87 - `from_value` 88 - `json_name` 89 - `set_name` 90 - `set_type` 91 - `set_value` 92 - `obj_value` (abstract method) 93 94 *utility methods* 95 - `decode_json` *(staticmethod)* 96 - `obj_ntv` *(staticmethod)* 97 ''' 98 99 def __init__(self, ntv_value, ntv_name, ntv_type): 100 '''Ntv constructor. 101 102 *Parameters* 103 104 - **ntv_value**: Json entity - value of the entity 105 - **ntv_name** : String (default None) - name of the NTV entity 106 - **ntv_type**: String or Datatype or Namespace (default None) - type of the entity 107 ''' 108 if ntv_type.__class__.__name__ in ['Datatype', 'Namespace']: 109 self.ntv_type = ntv_type 110 elif ntv_type and ntv_type[-1] != '.': 111 self.ntv_type = Datatype.add(ntv_type) 112 elif ntv_type and ntv_type[-1] == '.': 113 self.ntv_type = Namespace.add(ntv_type) 114 else: 115 self.ntv_type = None 116 if not isinstance(ntv_name, str): 117 ntv_name = '' 118 self.ntv_name = ntv_name 119 self.ntv_value = ntv_value 120 self.is_json = NtvConnector.is_json(ntv_value) 121 self.parent = None 122 123 @staticmethod 124 def fast(data, no_typ=False, typ_auto=False): 125 ''' return an Ntv entity from data without conversion. 126 127 *Parameters* : see `obj` method''' 128 return Ntv.obj(data, no_typ=no_typ, typ_auto=typ_auto, fast=True) 129 130 @staticmethod 131 def obj(data, no_typ=False, decode_str=False, typ_auto=False, fast=False): 132 ''' return an Ntv entity from data. 133 134 *Parameters* 135 136 - **Data** can be : 137 - a tuple with value, name, typ and cat (see `from_att` method) 138 - a value to decode (see `from_obj`method) 139 - **no_typ** : boolean (default False) - if True, NtvList is with None type 140 - **type_auto**: boolean (default False) - if True, default type for NtvList 141 is the ntv_type of the first Ntv in the ntv_value 142 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 143 - **decode_str**: boolean (default False) - if True, string are loaded in json data''' 144 #print('obj : ', Namespace.namespaces(), '\n') 145 146 if isinstance(data, tuple): 147 return Ntv.from_att(*data, decode_str=decode_str, fast=fast) 148 # if isinstance(data, str) and data.lstrip() and data.lstrip()[0] in '{[': 149 if isinstance(data, str): 150 try: 151 data = json.loads(data) 152 except json.JSONDecodeError: 153 pass 154 return Ntv.from_obj(data, no_typ=no_typ, decode_str=decode_str, 155 typ_auto=typ_auto, fast=fast) 156 157 @staticmethod 158 def from_att(value, name, typ, cat, decode_str=False, fast=False): 159 ''' return an Ntv entity. 160 161 *Parameters* 162 163 - **value**: Ntv entity or value to convert in an Ntv entity 164 - **name** : string - name of the Ntv entity 165 - **typ** : string or NtvType - type of the NTV entity 166 - **cat**: string - NTV category ('single', 'list') 167 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 168 - **decode_str**: boolean (default False) - if True, string are loaded as json data''' 169 170 value = Ntv._from_value(value, decode_str) 171 if value.__class__.__name__ in ['NtvSingle', 'NtvList']: 172 return value 173 if isinstance(value, list) and cat == 'list': 174 return NtvList(value, name, typ, fast=fast) 175 if cat == 'single': 176 return NtvSingle(value, name, typ, fast=fast) 177 return Ntv.from_obj(value, def_type=typ, fast=fast) 178 179 @staticmethod 180 def from_obj(value, def_type=None, def_sep=None, no_typ=False, decode_str=False, 181 typ_auto=False, fast=False): 182 ''' return an Ntv entity from an object value. 183 184 *Parameters* 185 186 - **value**: Ntv value to convert in an Ntv entity 187 - **no_typ** : boolean (default None) - if True, NtvList is with None type 188 - **def_type** : Datatype or Namespace (default None) - default type of the value 189 - **def_sep**: ':', '::' or None (default None) - default separator of the value 190 - **decode_str**: boolean (default False) - if True, string are loaded as json data 191 - **type_auto**: boolean (default False) - if True, default type for NtvList 192 is the ntv_type of the first Ntv in the ntv_value 193 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion''' 194 value = Ntv._from_value(value, decode_str) 195 if value.__class__.__name__ in ['NtvSingle', 'NtvList']: 196 return value 197 ntv_value, ntv_name, str_typ, sep, is_json = Ntv.decode_json(value) 198 sep = def_sep if not sep else sep 199 sep = None if str_typ and str_typ[-1] == '.' and sep == ':' else sep 200 if isinstance(ntv_value, (list, dict)) and sep in (None, '::'): 201 return Ntv._create_ntvlist(str_typ, def_type, sep, ntv_value, 202 typ_auto, no_typ, ntv_name, fast) 203 if sep == ':' or (sep is None and isinstance(ntv_value, dict)): 204 ntv_type = agreg_type(str_typ, def_type, False) 205 return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast) 206 if sep is None and not isinstance(ntv_value, dict): 207 #is_single_json = isinstance(value, (int, str, float, bool)) 208 is_single_json = isinstance(ntv_value, (int, str, float, bool)) 209 ntv_type = agreg_type(str_typ, def_type, is_single_json) 210 return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast) 211 raise NtvError('separator ":" is not compatible with value') 212 213 def __len__(self): 214 ''' len of ntv_value''' 215 if isinstance(self.ntv_value, list): 216 return len(self.ntv_value) 217 return 1 218 219 def __str__(self): 220 '''return string format''' 221 return self.to_obj(encoded=True) 222 223 def __repr__(self): 224 '''return classname and code''' 225 #return json.dumps(self.to_repr(False, False, False, 10), cls=NtvJsonEncoder) 226 return self.reduce(obj=False, level=3, maxi=6).to_obj(encoded=True) 227 228 def __contains__(self, item): 229 ''' item of Ntv entities''' 230 if isinstance(self.val, list): 231 return item in self.ntv_value 232 return item == self.ntv_value 233 234 def __iter__(self): 235 ''' iterator for Ntv entities''' 236 if isinstance(self, NtvSingle): 237 return iter([self.val]) 238 return iter(self.val) 239 240 def __getitem__(self, selec): 241 ''' return ntv_value item with selec: 242 - String beginning with "/" : json-pointer, 243 - string : name of the ntv, 244 - list : recursive selector 245 - tuple : list of name or index ''' 246 if selec is None or selec == [] or selec == () or selec == '': 247 return self 248 if isinstance(selec, (list, tuple)) and len(selec) == 1: 249 selec = selec[0] 250 if isinstance(selec, str) and len(selec) > 1 and selec[0] == '/': 251 selec = list(NtvPointer(selec)) 252 elif isinstance(selec, NtvPointer): 253 selec = list(selec) 254 if (selec == 0 or selec == self.ntv_name) and isinstance(self, NtvSingle): 255 return self.ntv_value 256 if isinstance(self, NtvSingle): 257 raise NtvError('item not present') 258 if isinstance(selec, tuple): 259 return [self[i] for i in selec] 260 if isinstance(selec, str) and isinstance(self, NtvList): 261 ind = [ntv.ntv_name for ntv in self.ntv_value].index(selec) 262 return self.ntv_value[ind] 263 if isinstance(selec, list) and isinstance(self, NtvList): 264 return self[selec[0]][selec[1:]] 265 return self.ntv_value[selec] 266 267 def __lt__(self, other): 268 ''' return a comparison between two ntv_value''' 269 # order: number > string > None 270 res = Ntv.lower(self, other) 271 if res is None: 272 res = None if len(self) == len(other) else len(self) < len(other) 273 res = self.to_obj(encoded=True) < other.to_obj(encoded=True) if res is None else res 274 return res 275 276 @staticmethod 277 def lower(val1, val2): 278 ''' compare two ntv_value and return True if val1 < val2, False if val1 > val2 and 279 None in the other cases''' 280 res = None 281 for v1, v2 in zip(Ntv.obj(val1).tree.leaf_nodes, Ntv.obj(val2).tree.leaf_nodes): 282 if v1.val is None: 283 res = True 284 elif isinstance(v1.val, (dict, list)): 285 res = Ntv.lower(v1.val, v2) 286 elif isinstance(v2.val, (dict, list)): 287 res = Ntv.lower(v1, v2.val) 288 elif isinstance(v1.val, Number): 289 if isinstance(v2.val, Number): 290 res = None if v1.val == v2.val else v1.val < v2.val 291 else: 292 res = False 293 elif isinstance(v1.val, str): 294 if isinstance(v2.val, Number): 295 res = True 296 elif isinstance(v2.val, str): 297 res = None if v1.val == v2.val else v1.val < v2.val 298 else: 299 res = False 300 if not res is None: 301 break 302 return res 303 304 def childs(self, obj=False, nam=False, typ=False): 305 ''' return a list of child Ntv entities or child data 306 307 *parameters* 308 309 - **obj**: boolean (default False) - return json-value 310 - **nam**: boolean (default False) - return name (with or without type) 311 - **typ**: boolean (default False) - return type (with or without name) 312 ''' 313 if isinstance(self, NtvSingle): 314 return [] 315 if not (obj or nam or typ): 316 return self.val 317 if obj: 318 return [ntv.to_obj() for ntv in self.val] 319 return [(ntv.name if nam else '') + (' - ' if nam and typ else '') + 320 (ntv.type_str if typ else '') for ntv in self.val] 321 322 def pointer(self, index=False, item_idx=None): 323 '''return a nested list of pointer from root 324 325 *Parameters* 326 327 - **index**: Boolean (default False) - use index instead of name 328 - **item_idx**: Integer (default None) - index value for the pointer 329 (useful with duplicate data)''' 330 if not self.parent: 331 return NtvPointer([]) 332 idx = item_idx if item_idx else self.parent.ntv_value.index(self) 333 num = index or (self.ntv_name == "" and self.parent.json_array) 334 pointer = self.parent.pointer(index) 335 pointer.append(idx if num else self.ntv_name) 336 return pointer 337 338 @property 339 def code_ntv(self): 340 '''return a string with the NTV code composed with 1 to 3 letters: 341 - 'l' (NtvList), 's' (NtvSingle / json_value) or 'o' (NtvSingle / obj_value) 342 - 'N' if ntv_name is present else none 343 - 'T' if ntv_type is present else none''' 344 dic = {'NtvList': 'l', 'NtvSingle': 's'} 345 code = dic[self.__class__.__name__] 346 if isinstance(self, NtvSingle) and not self.is_json: 347 code = 'o' 348 if self.ntv_name: 349 code += 'N' 350 if self.ntv_type and self.ntv_type.long_name != 'json': 351 code += 'T' 352 return code 353 354 @property 355 def max_len(self): 356 '''return the highest len of Ntv entity included''' 357 maxi = len(self) 358 if isinstance(self.ntv_value, (list, set)): 359 maxi = max(maxi, max(ntv.max_len for ntv in self.ntv_value)) 360 return maxi 361 362 @property 363 def name(self): 364 '''return the ntv_name of the entity''' 365 return self.ntv_name 366 367 @property 368 def type_str(self): 369 '''return a string with the value of the NtvType of the entity''' 370 if not self.ntv_type: 371 return '' 372 return self.ntv_type.long_name 373 374 @property 375 def val(self): 376 '''return the ntv_value of the entity''' 377 return self.ntv_value 378 379 def alike(self, ntv_value): 380 ''' return a Ntv entity with same name and type. 381 382 *Parameters* 383 384 - **ntv_value**: list of ntv values''' 385 return self.__class__(ntv_value, self.ntv_name, self.ntv_type) 386 387 def from_value(self): 388 '''return a Ntv entity from ntv_value''' 389 if isinstance(self.ntv_value, list): 390 return NtvList(self.ntv_value) 391 return Ntv.from_obj(self.ntv_value) 392 393 def json_name(self, def_type=None, string=False, explicit=False): 394 '''return the JSON name of the NTV entity (json-ntv format) 395 396 *Parameters* 397 398 - **def_typ** : Datatype or Namespace (default None) - type of the parent entity 399 - **string** : boolean (default False) - If True, return a string else a tuple 400 - **explicit** : boolean (default False) - If True, type is always included''' 401 if def_type is None: 402 def_type = '' 403 elif isinstance(def_type, (Datatype, Namespace)): 404 def_type = def_type.long_name 405 json_name = self.ntv_name if self.ntv_name else '' 406 json_type = relative_type( 407 def_type, self.type_str) if self.ntv_type else '' 408 implicit = isinstance(self, NtvSingle) and (json_type == 'json' 409 and (not def_type or def_type == 'json' or def_type[-1] == '.') 410 or not NtvConnector.is_json_class(self.val)) 411 if implicit and not explicit: 412 json_type = '' 413 json_sep = self._obj_sep(json_name, json_type, def_type) 414 if string: 415 return json_name + json_sep + json_type 416 return [json_name, json_sep, json_type] 417 418 def to_ntvsingle(self, name=None, typ=None, def_type=None, **kwargs): 419 '''convert NtvList entity to NtvSingle entity 420 421 *Parameters* 422 423 - **ntv_name** : String (default None) - name of the NTV entity 424 - **ntv_type**: String (default None) - type of the entity 425 - **value**: value of the entity 426 - **fast**: boolean (default False) - Ntv is created with a list of json values 427 without control 428 ''' 429 return NtvSingle(self.obj_value(def_type=def_type, **kwargs), 430 self.name if self.name else name, 431 self.type_str if self.type_str else typ) 432 433 def to_ntvlist(self, def_type=None, def_sep=None, no_typ=False, decode_str=False, 434 typ_auto=False, fast=False): 435 '''convert NtvSingle entity to NtvList entity 436 437 *Parameters* 438 439 - **value**: Ntv value to convert in an Ntv entity 440 - **no_typ** : boolean (default None) - if True, NtvList is with 'json' type 441 - **def_type** : Datatype or Namespace (default None) - default type of the value 442 - **def_sep**: ':', '::' or None (default None) - default separator of the value 443 - **decode_str**: boolean (default False) - if True, string are loaded as json data 444 - **type_auto**: boolean (default False) - if True, default type for NtvList 445 is the ntv_type of the first Ntv in the ntv_value 446 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 447 ''' 448 ntv = Ntv.from_obj(self.ntv_value, def_type, def_sep, no_typ, decode_str, 449 typ_auto, fast) 450 if ntv.__class__.__name__ == 'NtvSingle': 451 return NtvList([self]) 452 if self.ntv_name: 453 ntv.set_name(self.ntv_name) 454 return ntv 455 456 def notype(self): 457 '''convert NTV entity in a NV entity (with ntv_type is 'json' or None')''' 458 no_type = copy.copy(self) 459 for ntv in NtvTree(no_type).leaf_nodes: 460 ntv.set_type('json') 461 for ntv in NtvTree(no_type).inner_nodes: 462 ntv.set_type() 463 return no_type 464 465 def reduce(self, obj=True, maxi=6, level=3): 466 '''reduce the length and the level of the entity 467 468 *Parameters* 469 470 - **obj**: boolean (default True) - If True return jsonNTV else NTV entity 471 - **maxi**: integer (default 6) - Number of returned entities in an NtvList 472 - **level**: integer (default 6) - returned entities in an NtvList at this level is None 473 474 *return* 475 476 - **NTV entity** or **jsonNTV** 477 ''' 478 ntv = copy.copy(self) 479 cont = Ntv.obj('___') if self.json_array else Ntv.obj({'___':''}) 480 if isinstance(self, NtvSingle): 481 return ntv 482 if level == 0: 483 #ntv.ntv_value = [NtvSingle('___',ntv_type=ntv.type_str)] 484 ntv.ntv_value = [Ntv.obj('___',no_typ=True)] 485 #ntv.ntv_value = [Ntv.obj('___',typ_auto=True)] 486 if len(self) <= maxi: 487 ntv.ntv_value = [child.reduce(False, maxi, level-1) for child in ntv] 488 return ntv 489 mid = maxi // 2 490 cont.set_type(ntv.type_str) 491 start = [child.reduce(False, maxi, level-1) for child in ntv[:mid]] 492 #middle = [NtvSingle('...',ntv_type=ntv.type_str)] 493 middle = [cont] 494 end = [child.reduce(False, maxi, level-1) for child in ntv[-mid:]] 495 ntv.ntv_value = start + middle + end 496 if obj: 497 return ntv.to_obj() 498 return ntv 499 500 def set_name(self, name='', nodes='simple'): 501 '''set new names to the entity 502 503 *Parameters* 504 505 - **name**: list or string (default '') - New name values 506 - **nodes**: string (default 'simple') - nodes to be changed 507 'simple': current entity 508 'leaves': NtvSingle entities 509 'inner': NtvList entities 510 'all': all entities ''' 511 name = '' if name is None else name 512 match nodes: 513 case 'simple': 514 self.ntv_name = str(name) 515 case 'leaves': 516 if not isinstance(name, list): 517 name = [str(name)] * NtvTree(self).breadth 518 for nam, ntv in zip(name, NtvTree(self).leaf_nodes): 519 ntv.ntv_name = nam 520 case 'inner': 521 if not isinstance(name, list): 522 name = [str(name)] * len(NtvTree(self).inner_nodes) 523 for nam, ntv in zip(name, NtvTree(self).inner_nodes): 524 ntv.ntv_name = nam 525 case 'all': 526 if not isinstance(name, list): 527 name = [str(name)] * NtvTree(self).size 528 for nam, ntv in zip(name, NtvTree(self).nodes): 529 ntv.ntv_name = nam 530 case _: 531 raise NtvError('the nodes option is not valid') 532 533 def set_type(self, typ=None): 534 '''set a new type to the entity 535 536 *Parameters* 537 538 - **typ**: string, Datatype, Namespace (default None)''' 539 if typ and not isinstance(typ, (str, Datatype, Namespace)): 540 raise NtvError('the type is not a valid type') 541 self.ntv_type = str_type(typ, self.__class__.__name__ == 'NtvSingle') 542 543 def set_value(self, value=None, fast=False): 544 '''set new ntv_value of a single entity or of a list of entities included 545 546 *Parameters* 547 548 - **value**: list or single value 549 - **fast** : boolean (default False) - if True, value is not converted''' 550 if isinstance(self, NtvSingle): 551 self.ntv_value = NtvSingle(value, ntv_type=self.ntv_type, 552 fast=fast).val 553 return 554 if not isinstance(value, list): 555 value = [value] * NtvTree(self).breadth 556 ntv_val = NtvList(value, fast=fast) 557 for val, ntv in zip(ntv_val, NtvTree(self).leaf_nodes): 558 ntv.ntv_value = val.val 559 return 560 561 def to_mermaid(self, title='', disp=False, row=False, leaves=False): 562 '''return a mermaid flowchart. 563 564 *Parameters* 565 566 - **title**: String (default '') - title of the flowchart 567 - **disp**: Boolean (default False) - if true, return a display else return 568 a mermaid text diagram 569 - **row**: Boolean (default False) - if True, add the node row 570 - **leaves**: Boolean (default False) - if True, add the leaf row 571 ''' 572 option = {'title': title, 'disp': disp, 'row': row, 'leaves': leaves} 573 if disp: 574 Ntv.obj({':$mermaid': self.to_obj()}).to_obj( 575 format='obj', **option) 576 return None 577 return Ntv.obj({':$mermaid': self.to_obj()}).to_obj(format='obj', **option) 578 579 def expand(self, full=True, entity=True): 580 '''return a json representation of the triplet (name, type, value) 581 582 583 *Parameters* 584 585 - **full**: Boolean (default True) - If False only members with non empty values are present 586 - **entity**: Boolean (default True) - If True, member with entity name is added 587 ''' 588 exp = {ENTITY: self.__class__.__name__} if entity else {} 589 if isinstance(self, NtvList) and full: 590 return exp | {NAME: self.name, TYPE: self.type_str, 591 VALUE: [ntv.expand(full) for ntv in self.val]} 592 if isinstance(self, NtvSingle) and full: 593 return exp | {NAME: self.name, TYPE: self.type_str, VALUE: self.val} 594 exp |= {} if not self.name else {NAME: self.name} 595 if not self.type_str in ['json', ''] : 596 exp[TYPE] = self.type_str 597 if isinstance(self, NtvList): 598 exp[VALUE] = [ntv.expand(full) for ntv in self.val] 599 else: 600 exp[VALUE] = self.val 601 return exp 602 603 def to_repr(self, nam=True, typ=True, val=True, jsn=False, maxi=10): 604 '''return a simple json representation of the Ntv entity. 605 606 *Parameters* 607 608 - **nam**: Boolean(default True) - if true, the names are included 609 - **typ**: Boolean(default True) - if true, the types are included 610 - **val**: Boolean(default True) - if true, the values are included 611 - **jsn**: Boolean(default False) - if false, the 'json' type is not included 612 - **maxi**: Integer (default 10) - number of values to include for NtvList 613 entities. If maxi < 1 all the values are included. 614 ''' 615 ntv = self.code_ntv 616 if nam and typ: 617 ntv = ntv[0] 618 if self.ntv_name and nam: 619 ntv += '-' + self.ntv_name 620 if self.ntv_type and typ and (jsn or self.ntv_type.long_name != 'json'): 621 ntv += '-' + self.ntv_type.long_name 622 clas = self.__class__.__name__ 623 clas_val = self.ntv_value.__class__.__name__ 624 if clas == 'NtvSingle' and clas_val != 'NtvSingle': 625 if val: 626 if ntv: 627 ntv += '-' 628 ntv += json.dumps(self.ntv_value, cls=NtvJsonEncoder) 629 return ntv 630 if clas == 'NtvSingle' and clas_val == 'NtvSingle': 631 return {ntv: self.ntv_value.to_repr(nam, typ, val, jsn, maxi)} 632 if clas == 'NtvList': 633 maxv = len(self.ntv_value) if maxi < 1 else maxi 634 return {ntv: [ntvi.to_repr(nam, typ, val, jsn, maxi) 635 for ntvi in self.ntv_value[:maxv]]} 636 raise NtvError('the ntv entity is not consistent') 637 638 def to_name(self, default=''): 639 '''return the name of the NTV entity 640 641 *Parameters* 642 643 - **default**: string (default ''): returned value if name is not present ''' 644 if self.ntv_name == '': 645 return default 646 return self.ntv_name 647 648 def to_fast(self, def_type=None, **kwargs): 649 '''return the JSON representation of the NTV entity (json-ntv format) 650 without value conversion. 651 652 *Parameters* 653 654 - **def_type** : Datatype or Namespace (default None) - default type to apply 655 to the NTV entity 656 - **encoded** : boolean (default False) - choice for return format 657 (string/bytes if True, dict/list/tuple else) 658 - **format** : string (default 'json')- choice for return format 659 (json, cbor, obj) 660 - **simpleval** : boolean (default False) - if True, only value (without 661 name and type) is included 662 - **name** : boolean (default true) - if False, name is not included 663 - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList 664 - **maxi**: Integer (default -1) - number of values to include for NtvList 665 entities. If maxi < 1 all the values are included. 666 ''' 667 option = kwargs | {'fast': True} 668 return self.to_obj(def_type=def_type, **option) 669 670 def to_obj(self, def_type=None, **kwargs): 671 '''return the JSON representation of the NTV entity (json-ntv format). 672 673 *Parameters* 674 675 - **def_type** : Datatype or Namespace (default None) - default type to apply 676 to the NTV entity 677 - **encoded** : boolean (default False) - choice for return format 678 (string/bytes if True, dict/list/tuple else) 679 - **format** : string (default 'json')- choice for return format 680 (json, cbor, obj) 681 - **simpleval** : boolean (default False) - if True, only value (without 682 name and type) is included 683 - **name** : boolean (default true) - if False, name is not included 684 - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList 685 - **fast** : boolean (default False) - if True, json is created without conversion 686 - **maxi**: Integer (default -1) - number of values to include for NtvList 687 entities. If maxi < 1 all the values are included. 688 ''' 689 option = {'encoded': False, 'format': 'json', 'fast': False, 'maxi': -1, 690 'simpleval': False, 'name': True, 'json_array': False} | kwargs 691 value = self.obj_value(def_type=def_type, **option) 692 obj_name = self.json_name(def_type) 693 if not option['name']: 694 obj_name[0] = '' 695 if option['simpleval']: 696 name = '' 697 elif option['format'] in ('cbor', 'obj') and not NtvConnector.is_json_class(value): 698 name = obj_name[0] 699 else: 700 name = obj_name[0] + obj_name[1] + obj_name[2] 701 value = [value] if not name and isinstance(value, dict) and len(value) == 1 else value 702 json_obj = {name: value} if name else value 703 if option['encoded'] and option['format'] == 'json': 704 return json.dumps(json_obj, cls=NtvJsonEncoder) 705 if option['encoded'] and option['format'] == 'cbor': 706 return NtvConnector.connector()['CborConnec'].to_obj_ntv(json_obj) 707 return json_obj 708 709 @staticmethod 710 def obj_ntv(value, name='', typ='', single=False): 711 '''return a json-ntv representation without using Ntv structure. 712 713 *Parameters* 714 715 - **value** : ntv-value of the json-ntv 716 - **name** : string (default '') - ntv-name of the json-ntv 717 - **typ** : string (default '') - ntv_type of the json-ntv 718 - **single** : boolean (default False) - if True, value is a single object 719 else value is a set of objetcs. 720 ''' 721 value = {} if not value else value 722 name = '' if not name else name 723 typ = '' if not typ else typ 724 ntv_list = isinstance(value, (list, dict)) 725 if not single and not ntv_list: 726 raise NtvError('value is not compatible with not single NTV data') 727 sep = ':' if single else '::' 728 sep = '' if not typ and (not single or single and not ntv_list) else sep 729 name += sep + typ 730 value = [value] if not name and isinstance(value, dict) and len(value) == 1 else value 731 return {name: value} if name else value 732 733 def to_json_ntv(self): 734 ''' create a copy where ntv-value of the self-tree nodes is converted 735 in json-value''' 736 ntv = copy.copy(self) 737 for leaf in ntv.tree.leaf_nodes: 738 if isinstance(leaf.ntv_value, (NtvSingle, NtvList)): 739 leaf.ntv_value = leaf.ntv_value.to_obj() 740 leaf.ntv_type = Datatype('ntv') 741 elif not leaf.is_json: 742 leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.cast( 743 leaf.ntv_value, leaf.ntv_name, leaf.type_str) 744 leaf.ntv_type = Datatype.add(type_str) 745 leaf.is_json = True 746 return ntv 747 748 def to_obj_ntv(self, **kwargs): 749 ''' create a copy where ntv-value of the self-tree nodes is converted 750 in object-value 751 752 *Parameters* 753 754 - **kwargs** : parameters used in NtvConnector class (specific for each Connector)''' 755 ntv = copy.copy(self) 756 for leaf in ntv.tree.leaf_nodes: 757 if (leaf.is_json and leaf.type_str in set(NtvConnector.dic_type.values()) 758 or leaf.ntv_type is None): 759 leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.uncast( 760 leaf, **kwargs) 761 leaf.ntv_type = Datatype.add(type_str) if type_str else None 762 leaf.is_json = NtvConnector.is_json(leaf.ntv_value) 763 return ntv 764 765 def to_tuple(self, maxi=10): 766 '''return a nested tuple representation of the NTV entity 767 (NtvList/NtvSingle, ntv_name, ntv_type, ntv_value). 768 769 *Parameters* 770 771 - **maxi**: Integer (default 10) - number of values to include for NtvList 772 entities. If maxi < 1 all the values are included. 773 ''' 774 clas = self.__class__.__name__ 775 val = self.ntv_value 776 name = self.ntv_name 777 typ = None 778 if self.ntv_type: 779 typ = self.ntv_type.long_name 780 if isinstance(self, NtvSingle) and not isinstance(val, NtvSingle): 781 return (clas, name, typ, val) 782 if isinstance(self, NtvSingle) and isinstance(val, NtvSingle): 783 return (clas, name, typ, val.to_tuple(maxi=maxi)) 784 if isinstance(self, NtvList): 785 maxv = len(self.ntv_value) if maxi < 1 else maxi 786 return (clas, name, typ, [ntv.to_tuple(maxi=maxi) for ntv in val[:maxv]]) 787 raise NtvError('the ntv entity is not consistent') 788 789 def remove(self, first=True, index=None): 790 '''remove self from its parent entity. 791 792 *parameters* 793 794 - **first** : boolean (default True) - if True only the first instance 795 else all 796 - **index** : integer (default None) - index of self in its parent 797 ''' 798 parent = self.parent 799 if not parent: 800 return 801 idx = parent.ntv_value.index(self) if index is None else index 802 if not parent[idx] == self: 803 raise NtvError('the entity is not present at the index') 804 del parent.ntv_value[idx] 805 if not first and index is None: 806 while self in parent: 807 idx = parent.ntv_value.index(self) 808 del parent.ntv_value[idx] 809 if not self in parent: 810 self.parent = None 811 return 812 813 def replace(self, ntv): 814 '''replace self by ntv in the tree''' 815 parent = self.parent 816 if parent: 817 idx = parent.ntv_value.index(self) 818 parent.insert(idx, ntv) 819 del parent[idx+1] 820 if not self in parent: 821 self.parent=None 822 else: 823 self = ntv 824 825 @property 826 def tree(self): 827 '''return a tree with included entities (NtvTree object)''' 828 return NtvTree(self) 829 830 @abstractmethod 831 def obj_value(self): 832 '''return the ntv_value with different formats defined by kwargs (abstract method)''' 833 834 @property 835 @abstractmethod 836 def json_array(self): 837 ''' return the json_array dynamic attribute (abstract method)''' 838 839 @abstractmethod 840 def _obj_sep(self, json_type, def_type): 841 ''' return separator to include in json_name (abstract method)''' 842 843 @staticmethod 844 def _from_value(value, decode_str=False): 845 '''return a decoded value 846 847 *Parameters* 848 849 - **decode_str**: boolean (default False) - if True, string are loaded as json data 850 ''' 851 if isinstance(value, bytes): 852 value = Ntv.from_obj({'$cbor': value}).ntv_value 853 elif decode_str and isinstance(value, str) and value.lstrip() and\ 854 value.lstrip()[0] in '"-{[0123456789tfn': 855 try: 856 value = json.loads(value) 857 except json.JSONDecodeError: 858 pass 859 return value 860 861 @staticmethod 862 def decode_json(json_value): 863 '''return (value, name, type, separator, isjson) of a json object''' 864 if isinstance(json_value, dict) and len(json_value) == 1: 865 json_name = list(json_value.keys())[0] 866 val = json_value[json_name] 867 return (val, *NtvUtil.from_obj_name(json_name), NtvConnector.is_json(val)) 868 return (json_value, None, None, None, NtvConnector.is_json(json_value)) 869 870 @staticmethod 871 def _create_ntvlist(str_typ, def_type, sep, ntv_value, typ_auto, no_typ, ntv_name, fast): 872 '''return a NtvList with parameters from Ntv.from_obj method''' 873 def_type = agreg_type(str_typ, def_type, False) 874 sep_val = ':' if sep and def_type else None 875 if isinstance(ntv_value, dict): 876 keys = list(ntv_value.keys()) 877 values = list(ntv_value.values()) 878 ntv_list = [Ntv.from_obj({key: val}, def_type, sep_val, fast=fast) 879 for key, val in zip(keys, values)] 880 else: 881 ntv_list = [Ntv.from_obj(val, def_type, sep_val, fast=fast) 882 for val in ntv_value] 883 if typ_auto and not def_type and ntv_list: 884 def_type = ntv_list[0].ntv_type 885 def_type = None if no_typ else def_type 886 return NtvList(ntv_list, ntv_name, def_type, typ_auto, fast=fast) 887 888 @staticmethod 889 def _listed(idx): 890 '''transform a tuple of tuple object in a list of list object''' 891 return [val if not isinstance(val, tuple) else Ntv._listed(val) for val in idx]
The Ntv class is an abstract class used by NtvSingle
and NtvList
classes.
Attributes :
- ntv_name : String - name of the NTV entity
- ntv_type: Datatype or Namespace - type of the entity
- ntv_value: value of the entity
Internal attributes :
- parent: parent NtvList entity
- is_json: True if ntv_value is a json_value
dynamic values (@property)
The methods defined in this class are :
Ntv constructor (staticmethod)
NTV conversion (instance methods)
export - conversion (instance methods)
tree methods (instance methods)
other instance methods
utility methods
decode_json
(staticmethod)obj_ntv
(staticmethod)
99 def __init__(self, ntv_value, ntv_name, ntv_type): 100 '''Ntv constructor. 101 102 *Parameters* 103 104 - **ntv_value**: Json entity - value of the entity 105 - **ntv_name** : String (default None) - name of the NTV entity 106 - **ntv_type**: String or Datatype or Namespace (default None) - type of the entity 107 ''' 108 if ntv_type.__class__.__name__ in ['Datatype', 'Namespace']: 109 self.ntv_type = ntv_type 110 elif ntv_type and ntv_type[-1] != '.': 111 self.ntv_type = Datatype.add(ntv_type) 112 elif ntv_type and ntv_type[-1] == '.': 113 self.ntv_type = Namespace.add(ntv_type) 114 else: 115 self.ntv_type = None 116 if not isinstance(ntv_name, str): 117 ntv_name = '' 118 self.ntv_name = ntv_name 119 self.ntv_value = ntv_value 120 self.is_json = NtvConnector.is_json(ntv_value) 121 self.parent = None
Ntv constructor.
Parameters
- ntv_value: Json entity - value of the entity
- ntv_name : String (default None) - name of the NTV entity
- ntv_type: String or Datatype or Namespace (default None) - type of the entity
123 @staticmethod 124 def fast(data, no_typ=False, typ_auto=False): 125 ''' return an Ntv entity from data without conversion. 126 127 *Parameters* : see `obj` method''' 128 return Ntv.obj(data, no_typ=no_typ, typ_auto=typ_auto, fast=True)
return an Ntv entity from data without conversion.
Parameters : see obj
method
130 @staticmethod 131 def obj(data, no_typ=False, decode_str=False, typ_auto=False, fast=False): 132 ''' return an Ntv entity from data. 133 134 *Parameters* 135 136 - **Data** can be : 137 - a tuple with value, name, typ and cat (see `from_att` method) 138 - a value to decode (see `from_obj`method) 139 - **no_typ** : boolean (default False) - if True, NtvList is with None type 140 - **type_auto**: boolean (default False) - if True, default type for NtvList 141 is the ntv_type of the first Ntv in the ntv_value 142 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 143 - **decode_str**: boolean (default False) - if True, string are loaded in json data''' 144 #print('obj : ', Namespace.namespaces(), '\n') 145 146 if isinstance(data, tuple): 147 return Ntv.from_att(*data, decode_str=decode_str, fast=fast) 148 # if isinstance(data, str) and data.lstrip() and data.lstrip()[0] in '{[': 149 if isinstance(data, str): 150 try: 151 data = json.loads(data) 152 except json.JSONDecodeError: 153 pass 154 return Ntv.from_obj(data, no_typ=no_typ, decode_str=decode_str, 155 typ_auto=typ_auto, fast=fast)
return an Ntv entity from data.
Parameters
- Data can be :
- no_typ : boolean (default False) - if True, NtvList is with None type
- type_auto: boolean (default False) - if True, default type for NtvList is the ntv_type of the first Ntv in the ntv_value
- fast : boolean (default False) - if True, Ntv entity is created without conversion
- decode_str: boolean (default False) - if True, string are loaded in json data
157 @staticmethod 158 def from_att(value, name, typ, cat, decode_str=False, fast=False): 159 ''' return an Ntv entity. 160 161 *Parameters* 162 163 - **value**: Ntv entity or value to convert in an Ntv entity 164 - **name** : string - name of the Ntv entity 165 - **typ** : string or NtvType - type of the NTV entity 166 - **cat**: string - NTV category ('single', 'list') 167 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 168 - **decode_str**: boolean (default False) - if True, string are loaded as json data''' 169 170 value = Ntv._from_value(value, decode_str) 171 if value.__class__.__name__ in ['NtvSingle', 'NtvList']: 172 return value 173 if isinstance(value, list) and cat == 'list': 174 return NtvList(value, name, typ, fast=fast) 175 if cat == 'single': 176 return NtvSingle(value, name, typ, fast=fast) 177 return Ntv.from_obj(value, def_type=typ, fast=fast)
return an Ntv entity.
Parameters
- value: Ntv entity or value to convert in an Ntv entity
- name : string - name of the Ntv entity
- typ : string or NtvType - type of the NTV entity
- cat: string - NTV category ('single', 'list')
- fast : boolean (default False) - if True, Ntv entity is created without conversion
- decode_str: boolean (default False) - if True, string are loaded as json data
179 @staticmethod 180 def from_obj(value, def_type=None, def_sep=None, no_typ=False, decode_str=False, 181 typ_auto=False, fast=False): 182 ''' return an Ntv entity from an object value. 183 184 *Parameters* 185 186 - **value**: Ntv value to convert in an Ntv entity 187 - **no_typ** : boolean (default None) - if True, NtvList is with None type 188 - **def_type** : Datatype or Namespace (default None) - default type of the value 189 - **def_sep**: ':', '::' or None (default None) - default separator of the value 190 - **decode_str**: boolean (default False) - if True, string are loaded as json data 191 - **type_auto**: boolean (default False) - if True, default type for NtvList 192 is the ntv_type of the first Ntv in the ntv_value 193 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion''' 194 value = Ntv._from_value(value, decode_str) 195 if value.__class__.__name__ in ['NtvSingle', 'NtvList']: 196 return value 197 ntv_value, ntv_name, str_typ, sep, is_json = Ntv.decode_json(value) 198 sep = def_sep if not sep else sep 199 sep = None if str_typ and str_typ[-1] == '.' and sep == ':' else sep 200 if isinstance(ntv_value, (list, dict)) and sep in (None, '::'): 201 return Ntv._create_ntvlist(str_typ, def_type, sep, ntv_value, 202 typ_auto, no_typ, ntv_name, fast) 203 if sep == ':' or (sep is None and isinstance(ntv_value, dict)): 204 ntv_type = agreg_type(str_typ, def_type, False) 205 return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast) 206 if sep is None and not isinstance(ntv_value, dict): 207 #is_single_json = isinstance(value, (int, str, float, bool)) 208 is_single_json = isinstance(ntv_value, (int, str, float, bool)) 209 ntv_type = agreg_type(str_typ, def_type, is_single_json) 210 return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast) 211 raise NtvError('separator ":" is not compatible with value')
return an Ntv entity from an object value.
Parameters
- value: Ntv value to convert in an Ntv entity
- no_typ : boolean (default None) - if True, NtvList is with None type
- def_type : Datatype or Namespace (default None) - default type of the value
- def_sep: ':', '::' or None (default None) - default separator of the value
- decode_str: boolean (default False) - if True, string are loaded as json data
- type_auto: boolean (default False) - if True, default type for NtvList is the ntv_type of the first Ntv in the ntv_value
- fast : boolean (default False) - if True, Ntv entity is created without conversion
276 @staticmethod 277 def lower(val1, val2): 278 ''' compare two ntv_value and return True if val1 < val2, False if val1 > val2 and 279 None in the other cases''' 280 res = None 281 for v1, v2 in zip(Ntv.obj(val1).tree.leaf_nodes, Ntv.obj(val2).tree.leaf_nodes): 282 if v1.val is None: 283 res = True 284 elif isinstance(v1.val, (dict, list)): 285 res = Ntv.lower(v1.val, v2) 286 elif isinstance(v2.val, (dict, list)): 287 res = Ntv.lower(v1, v2.val) 288 elif isinstance(v1.val, Number): 289 if isinstance(v2.val, Number): 290 res = None if v1.val == v2.val else v1.val < v2.val 291 else: 292 res = False 293 elif isinstance(v1.val, str): 294 if isinstance(v2.val, Number): 295 res = True 296 elif isinstance(v2.val, str): 297 res = None if v1.val == v2.val else v1.val < v2.val 298 else: 299 res = False 300 if not res is None: 301 break 302 return res
compare two ntv_value and return True if val1 < val2, False if val1 > val2 and None in the other cases
304 def childs(self, obj=False, nam=False, typ=False): 305 ''' return a list of child Ntv entities or child data 306 307 *parameters* 308 309 - **obj**: boolean (default False) - return json-value 310 - **nam**: boolean (default False) - return name (with or without type) 311 - **typ**: boolean (default False) - return type (with or without name) 312 ''' 313 if isinstance(self, NtvSingle): 314 return [] 315 if not (obj or nam or typ): 316 return self.val 317 if obj: 318 return [ntv.to_obj() for ntv in self.val] 319 return [(ntv.name if nam else '') + (' - ' if nam and typ else '') + 320 (ntv.type_str if typ else '') for ntv in self.val]
return a list of child Ntv entities or child data
parameters
- obj: boolean (default False) - return json-value
- nam: boolean (default False) - return name (with or without type)
- typ: boolean (default False) - return type (with or without name)
322 def pointer(self, index=False, item_idx=None): 323 '''return a nested list of pointer from root 324 325 *Parameters* 326 327 - **index**: Boolean (default False) - use index instead of name 328 - **item_idx**: Integer (default None) - index value for the pointer 329 (useful with duplicate data)''' 330 if not self.parent: 331 return NtvPointer([]) 332 idx = item_idx if item_idx else self.parent.ntv_value.index(self) 333 num = index or (self.ntv_name == "" and self.parent.json_array) 334 pointer = self.parent.pointer(index) 335 pointer.append(idx if num else self.ntv_name) 336 return pointer
return a nested list of pointer from root
Parameters
- index: Boolean (default False) - use index instead of name
- item_idx: Integer (default None) - index value for the pointer (useful with duplicate data)
return a string with the NTV code composed with 1 to 3 letters:
- 'l' (NtvList), 's' (NtvSingle / json_value) or 'o' (NtvSingle / obj_value)
- 'N' if ntv_name is present else none
- 'T' if ntv_type is present else none
379 def alike(self, ntv_value): 380 ''' return a Ntv entity with same name and type. 381 382 *Parameters* 383 384 - **ntv_value**: list of ntv values''' 385 return self.__class__(ntv_value, self.ntv_name, self.ntv_type)
return a Ntv entity with same name and type.
Parameters
- ntv_value: list of ntv values
387 def from_value(self): 388 '''return a Ntv entity from ntv_value''' 389 if isinstance(self.ntv_value, list): 390 return NtvList(self.ntv_value) 391 return Ntv.from_obj(self.ntv_value)
return a Ntv entity from ntv_value
393 def json_name(self, def_type=None, string=False, explicit=False): 394 '''return the JSON name of the NTV entity (json-ntv format) 395 396 *Parameters* 397 398 - **def_typ** : Datatype or Namespace (default None) - type of the parent entity 399 - **string** : boolean (default False) - If True, return a string else a tuple 400 - **explicit** : boolean (default False) - If True, type is always included''' 401 if def_type is None: 402 def_type = '' 403 elif isinstance(def_type, (Datatype, Namespace)): 404 def_type = def_type.long_name 405 json_name = self.ntv_name if self.ntv_name else '' 406 json_type = relative_type( 407 def_type, self.type_str) if self.ntv_type else '' 408 implicit = isinstance(self, NtvSingle) and (json_type == 'json' 409 and (not def_type or def_type == 'json' or def_type[-1] == '.') 410 or not NtvConnector.is_json_class(self.val)) 411 if implicit and not explicit: 412 json_type = '' 413 json_sep = self._obj_sep(json_name, json_type, def_type) 414 if string: 415 return json_name + json_sep + json_type 416 return [json_name, json_sep, json_type]
return the JSON name of the NTV entity (json-ntv format)
Parameters
- def_typ : Datatype or Namespace (default None) - type of the parent entity
- string : boolean (default False) - If True, return a string else a tuple
- explicit : boolean (default False) - If True, type is always included
418 def to_ntvsingle(self, name=None, typ=None, def_type=None, **kwargs): 419 '''convert NtvList entity to NtvSingle entity 420 421 *Parameters* 422 423 - **ntv_name** : String (default None) - name of the NTV entity 424 - **ntv_type**: String (default None) - type of the entity 425 - **value**: value of the entity 426 - **fast**: boolean (default False) - Ntv is created with a list of json values 427 without control 428 ''' 429 return NtvSingle(self.obj_value(def_type=def_type, **kwargs), 430 self.name if self.name else name, 431 self.type_str if self.type_str else typ)
convert NtvList entity to NtvSingle entity
Parameters
- ntv_name : String (default None) - name of the NTV entity
- ntv_type: String (default None) - type of the entity
- value: value of the entity
- fast: boolean (default False) - Ntv is created with a list of json values without control
433 def to_ntvlist(self, def_type=None, def_sep=None, no_typ=False, decode_str=False, 434 typ_auto=False, fast=False): 435 '''convert NtvSingle entity to NtvList entity 436 437 *Parameters* 438 439 - **value**: Ntv value to convert in an Ntv entity 440 - **no_typ** : boolean (default None) - if True, NtvList is with 'json' type 441 - **def_type** : Datatype or Namespace (default None) - default type of the value 442 - **def_sep**: ':', '::' or None (default None) - default separator of the value 443 - **decode_str**: boolean (default False) - if True, string are loaded as json data 444 - **type_auto**: boolean (default False) - if True, default type for NtvList 445 is the ntv_type of the first Ntv in the ntv_value 446 - **fast** : boolean (default False) - if True, Ntv entity is created without conversion 447 ''' 448 ntv = Ntv.from_obj(self.ntv_value, def_type, def_sep, no_typ, decode_str, 449 typ_auto, fast) 450 if ntv.__class__.__name__ == 'NtvSingle': 451 return NtvList([self]) 452 if self.ntv_name: 453 ntv.set_name(self.ntv_name) 454 return ntv
convert NtvSingle entity to NtvList entity
Parameters
- value: Ntv value to convert in an Ntv entity
- no_typ : boolean (default None) - if True, NtvList is with 'json' type
- def_type : Datatype or Namespace (default None) - default type of the value
- def_sep: ':', '::' or None (default None) - default separator of the value
- decode_str: boolean (default False) - if True, string are loaded as json data
- type_auto: boolean (default False) - if True, default type for NtvList is the ntv_type of the first Ntv in the ntv_value
- fast : boolean (default False) - if True, Ntv entity is created without conversion
456 def notype(self): 457 '''convert NTV entity in a NV entity (with ntv_type is 'json' or None')''' 458 no_type = copy.copy(self) 459 for ntv in NtvTree(no_type).leaf_nodes: 460 ntv.set_type('json') 461 for ntv in NtvTree(no_type).inner_nodes: 462 ntv.set_type() 463 return no_type
convert NTV entity in a NV entity (with ntv_type is 'json' or None')
465 def reduce(self, obj=True, maxi=6, level=3): 466 '''reduce the length and the level of the entity 467 468 *Parameters* 469 470 - **obj**: boolean (default True) - If True return jsonNTV else NTV entity 471 - **maxi**: integer (default 6) - Number of returned entities in an NtvList 472 - **level**: integer (default 6) - returned entities in an NtvList at this level is None 473 474 *return* 475 476 - **NTV entity** or **jsonNTV** 477 ''' 478 ntv = copy.copy(self) 479 cont = Ntv.obj('___') if self.json_array else Ntv.obj({'___':''}) 480 if isinstance(self, NtvSingle): 481 return ntv 482 if level == 0: 483 #ntv.ntv_value = [NtvSingle('___',ntv_type=ntv.type_str)] 484 ntv.ntv_value = [Ntv.obj('___',no_typ=True)] 485 #ntv.ntv_value = [Ntv.obj('___',typ_auto=True)] 486 if len(self) <= maxi: 487 ntv.ntv_value = [child.reduce(False, maxi, level-1) for child in ntv] 488 return ntv 489 mid = maxi // 2 490 cont.set_type(ntv.type_str) 491 start = [child.reduce(False, maxi, level-1) for child in ntv[:mid]] 492 #middle = [NtvSingle('...',ntv_type=ntv.type_str)] 493 middle = [cont] 494 end = [child.reduce(False, maxi, level-1) for child in ntv[-mid:]] 495 ntv.ntv_value = start + middle + end 496 if obj: 497 return ntv.to_obj() 498 return ntv
reduce the length and the level of the entity
Parameters
- obj: boolean (default True) - If True return jsonNTV else NTV entity
- maxi: integer (default 6) - Number of returned entities in an NtvList
- level: integer (default 6) - returned entities in an NtvList at this level is None
return
- NTV entity or jsonNTV
500 def set_name(self, name='', nodes='simple'): 501 '''set new names to the entity 502 503 *Parameters* 504 505 - **name**: list or string (default '') - New name values 506 - **nodes**: string (default 'simple') - nodes to be changed 507 'simple': current entity 508 'leaves': NtvSingle entities 509 'inner': NtvList entities 510 'all': all entities ''' 511 name = '' if name is None else name 512 match nodes: 513 case 'simple': 514 self.ntv_name = str(name) 515 case 'leaves': 516 if not isinstance(name, list): 517 name = [str(name)] * NtvTree(self).breadth 518 for nam, ntv in zip(name, NtvTree(self).leaf_nodes): 519 ntv.ntv_name = nam 520 case 'inner': 521 if not isinstance(name, list): 522 name = [str(name)] * len(NtvTree(self).inner_nodes) 523 for nam, ntv in zip(name, NtvTree(self).inner_nodes): 524 ntv.ntv_name = nam 525 case 'all': 526 if not isinstance(name, list): 527 name = [str(name)] * NtvTree(self).size 528 for nam, ntv in zip(name, NtvTree(self).nodes): 529 ntv.ntv_name = nam 530 case _: 531 raise NtvError('the nodes option is not valid')
set new names to the entity
Parameters
- name: list or string (default '') - New name values
- nodes: string (default 'simple') - nodes to be changed 'simple': current entity 'leaves': NtvSingle entities 'inner': NtvList entities 'all': all entities
533 def set_type(self, typ=None): 534 '''set a new type to the entity 535 536 *Parameters* 537 538 - **typ**: string, Datatype, Namespace (default None)''' 539 if typ and not isinstance(typ, (str, Datatype, Namespace)): 540 raise NtvError('the type is not a valid type') 541 self.ntv_type = str_type(typ, self.__class__.__name__ == 'NtvSingle')
set a new type to the entity
Parameters
- typ: string, Datatype, Namespace (default None)
543 def set_value(self, value=None, fast=False): 544 '''set new ntv_value of a single entity or of a list of entities included 545 546 *Parameters* 547 548 - **value**: list or single value 549 - **fast** : boolean (default False) - if True, value is not converted''' 550 if isinstance(self, NtvSingle): 551 self.ntv_value = NtvSingle(value, ntv_type=self.ntv_type, 552 fast=fast).val 553 return 554 if not isinstance(value, list): 555 value = [value] * NtvTree(self).breadth 556 ntv_val = NtvList(value, fast=fast) 557 for val, ntv in zip(ntv_val, NtvTree(self).leaf_nodes): 558 ntv.ntv_value = val.val 559 return
set new ntv_value of a single entity or of a list of entities included
Parameters
- value: list or single value
- fast : boolean (default False) - if True, value is not converted
561 def to_mermaid(self, title='', disp=False, row=False, leaves=False): 562 '''return a mermaid flowchart. 563 564 *Parameters* 565 566 - **title**: String (default '') - title of the flowchart 567 - **disp**: Boolean (default False) - if true, return a display else return 568 a mermaid text diagram 569 - **row**: Boolean (default False) - if True, add the node row 570 - **leaves**: Boolean (default False) - if True, add the leaf row 571 ''' 572 option = {'title': title, 'disp': disp, 'row': row, 'leaves': leaves} 573 if disp: 574 Ntv.obj({':$mermaid': self.to_obj()}).to_obj( 575 format='obj', **option) 576 return None 577 return Ntv.obj({':$mermaid': self.to_obj()}).to_obj(format='obj', **option)
return a mermaid flowchart.
Parameters
- title: String (default '') - title of the flowchart
- disp: Boolean (default False) - if true, return a display else return a mermaid text diagram
- row: Boolean (default False) - if True, add the node row
- leaves: Boolean (default False) - if True, add the leaf row
579 def expand(self, full=True, entity=True): 580 '''return a json representation of the triplet (name, type, value) 581 582 583 *Parameters* 584 585 - **full**: Boolean (default True) - If False only members with non empty values are present 586 - **entity**: Boolean (default True) - If True, member with entity name is added 587 ''' 588 exp = {ENTITY: self.__class__.__name__} if entity else {} 589 if isinstance(self, NtvList) and full: 590 return exp | {NAME: self.name, TYPE: self.type_str, 591 VALUE: [ntv.expand(full) for ntv in self.val]} 592 if isinstance(self, NtvSingle) and full: 593 return exp | {NAME: self.name, TYPE: self.type_str, VALUE: self.val} 594 exp |= {} if not self.name else {NAME: self.name} 595 if not self.type_str in ['json', ''] : 596 exp[TYPE] = self.type_str 597 if isinstance(self, NtvList): 598 exp[VALUE] = [ntv.expand(full) for ntv in self.val] 599 else: 600 exp[VALUE] = self.val 601 return exp
return a json representation of the triplet (name, type, value)
Parameters
- full: Boolean (default True) - If False only members with non empty values are present
- entity: Boolean (default True) - If True, member with entity name is added
603 def to_repr(self, nam=True, typ=True, val=True, jsn=False, maxi=10): 604 '''return a simple json representation of the Ntv entity. 605 606 *Parameters* 607 608 - **nam**: Boolean(default True) - if true, the names are included 609 - **typ**: Boolean(default True) - if true, the types are included 610 - **val**: Boolean(default True) - if true, the values are included 611 - **jsn**: Boolean(default False) - if false, the 'json' type is not included 612 - **maxi**: Integer (default 10) - number of values to include for NtvList 613 entities. If maxi < 1 all the values are included. 614 ''' 615 ntv = self.code_ntv 616 if nam and typ: 617 ntv = ntv[0] 618 if self.ntv_name and nam: 619 ntv += '-' + self.ntv_name 620 if self.ntv_type and typ and (jsn or self.ntv_type.long_name != 'json'): 621 ntv += '-' + self.ntv_type.long_name 622 clas = self.__class__.__name__ 623 clas_val = self.ntv_value.__class__.__name__ 624 if clas == 'NtvSingle' and clas_val != 'NtvSingle': 625 if val: 626 if ntv: 627 ntv += '-' 628 ntv += json.dumps(self.ntv_value, cls=NtvJsonEncoder) 629 return ntv 630 if clas == 'NtvSingle' and clas_val == 'NtvSingle': 631 return {ntv: self.ntv_value.to_repr(nam, typ, val, jsn, maxi)} 632 if clas == 'NtvList': 633 maxv = len(self.ntv_value) if maxi < 1 else maxi 634 return {ntv: [ntvi.to_repr(nam, typ, val, jsn, maxi) 635 for ntvi in self.ntv_value[:maxv]]} 636 raise NtvError('the ntv entity is not consistent')
return a simple json representation of the Ntv entity.
Parameters
- nam: Boolean(default True) - if true, the names are included
- typ: Boolean(default True) - if true, the types are included
- val: Boolean(default True) - if true, the values are included
- jsn: Boolean(default False) - if false, the 'json' type is not included
- maxi: Integer (default 10) - number of values to include for NtvList entities. If maxi < 1 all the values are included.
638 def to_name(self, default=''): 639 '''return the name of the NTV entity 640 641 *Parameters* 642 643 - **default**: string (default ''): returned value if name is not present ''' 644 if self.ntv_name == '': 645 return default 646 return self.ntv_name
return the name of the NTV entity
Parameters
- default: string (default ''): returned value if name is not present
648 def to_fast(self, def_type=None, **kwargs): 649 '''return the JSON representation of the NTV entity (json-ntv format) 650 without value conversion. 651 652 *Parameters* 653 654 - **def_type** : Datatype or Namespace (default None) - default type to apply 655 to the NTV entity 656 - **encoded** : boolean (default False) - choice for return format 657 (string/bytes if True, dict/list/tuple else) 658 - **format** : string (default 'json')- choice for return format 659 (json, cbor, obj) 660 - **simpleval** : boolean (default False) - if True, only value (without 661 name and type) is included 662 - **name** : boolean (default true) - if False, name is not included 663 - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList 664 - **maxi**: Integer (default -1) - number of values to include for NtvList 665 entities. If maxi < 1 all the values are included. 666 ''' 667 option = kwargs | {'fast': True} 668 return self.to_obj(def_type=def_type, **option)
return the JSON representation of the NTV entity (json-ntv format) without value conversion.
Parameters
- def_type : Datatype or Namespace (default None) - default type to apply to the NTV entity
- encoded : boolean (default False) - choice for return format (string/bytes if True, dict/list/tuple else)
- format : string (default 'json')- choice for return format (json, cbor, obj)
- simpleval : boolean (default False) - if True, only value (without name and type) is included
- name : boolean (default true) - if False, name is not included
- json_array : boolean (default false) - if True, Json-object is not used for NtvList
- maxi: Integer (default -1) - number of values to include for NtvList entities. If maxi < 1 all the values are included.
670 def to_obj(self, def_type=None, **kwargs): 671 '''return the JSON representation of the NTV entity (json-ntv format). 672 673 *Parameters* 674 675 - **def_type** : Datatype or Namespace (default None) - default type to apply 676 to the NTV entity 677 - **encoded** : boolean (default False) - choice for return format 678 (string/bytes if True, dict/list/tuple else) 679 - **format** : string (default 'json')- choice for return format 680 (json, cbor, obj) 681 - **simpleval** : boolean (default False) - if True, only value (without 682 name and type) is included 683 - **name** : boolean (default true) - if False, name is not included 684 - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList 685 - **fast** : boolean (default False) - if True, json is created without conversion 686 - **maxi**: Integer (default -1) - number of values to include for NtvList 687 entities. If maxi < 1 all the values are included. 688 ''' 689 option = {'encoded': False, 'format': 'json', 'fast': False, 'maxi': -1, 690 'simpleval': False, 'name': True, 'json_array': False} | kwargs 691 value = self.obj_value(def_type=def_type, **option) 692 obj_name = self.json_name(def_type) 693 if not option['name']: 694 obj_name[0] = '' 695 if option['simpleval']: 696 name = '' 697 elif option['format'] in ('cbor', 'obj') and not NtvConnector.is_json_class(value): 698 name = obj_name[0] 699 else: 700 name = obj_name[0] + obj_name[1] + obj_name[2] 701 value = [value] if not name and isinstance(value, dict) and len(value) == 1 else value 702 json_obj = {name: value} if name else value 703 if option['encoded'] and option['format'] == 'json': 704 return json.dumps(json_obj, cls=NtvJsonEncoder) 705 if option['encoded'] and option['format'] == 'cbor': 706 return NtvConnector.connector()['CborConnec'].to_obj_ntv(json_obj) 707 return json_obj
return the JSON representation of the NTV entity (json-ntv format).
Parameters
- def_type : Datatype or Namespace (default None) - default type to apply to the NTV entity
- encoded : boolean (default False) - choice for return format (string/bytes if True, dict/list/tuple else)
- format : string (default 'json')- choice for return format (json, cbor, obj)
- simpleval : boolean (default False) - if True, only value (without name and type) is included
- name : boolean (default true) - if False, name is not included
- json_array : boolean (default false) - if True, Json-object is not used for NtvList
- fast : boolean (default False) - if True, json is created without conversion
- maxi: Integer (default -1) - number of values to include for NtvList entities. If maxi < 1 all the values are included.
709 @staticmethod 710 def obj_ntv(value, name='', typ='', single=False): 711 '''return a json-ntv representation without using Ntv structure. 712 713 *Parameters* 714 715 - **value** : ntv-value of the json-ntv 716 - **name** : string (default '') - ntv-name of the json-ntv 717 - **typ** : string (default '') - ntv_type of the json-ntv 718 - **single** : boolean (default False) - if True, value is a single object 719 else value is a set of objetcs. 720 ''' 721 value = {} if not value else value 722 name = '' if not name else name 723 typ = '' if not typ else typ 724 ntv_list = isinstance(value, (list, dict)) 725 if not single and not ntv_list: 726 raise NtvError('value is not compatible with not single NTV data') 727 sep = ':' if single else '::' 728 sep = '' if not typ and (not single or single and not ntv_list) else sep 729 name += sep + typ 730 value = [value] if not name and isinstance(value, dict) and len(value) == 1 else value 731 return {name: value} if name else value
return a json-ntv representation without using Ntv structure.
Parameters
- value : ntv-value of the json-ntv
- name : string (default '') - ntv-name of the json-ntv
- typ : string (default '') - ntv_type of the json-ntv
- single : boolean (default False) - if True, value is a single object else value is a set of objetcs.
733 def to_json_ntv(self): 734 ''' create a copy where ntv-value of the self-tree nodes is converted 735 in json-value''' 736 ntv = copy.copy(self) 737 for leaf in ntv.tree.leaf_nodes: 738 if isinstance(leaf.ntv_value, (NtvSingle, NtvList)): 739 leaf.ntv_value = leaf.ntv_value.to_obj() 740 leaf.ntv_type = Datatype('ntv') 741 elif not leaf.is_json: 742 leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.cast( 743 leaf.ntv_value, leaf.ntv_name, leaf.type_str) 744 leaf.ntv_type = Datatype.add(type_str) 745 leaf.is_json = True 746 return ntv
create a copy where ntv-value of the self-tree nodes is converted in json-value
748 def to_obj_ntv(self, **kwargs): 749 ''' create a copy where ntv-value of the self-tree nodes is converted 750 in object-value 751 752 *Parameters* 753 754 - **kwargs** : parameters used in NtvConnector class (specific for each Connector)''' 755 ntv = copy.copy(self) 756 for leaf in ntv.tree.leaf_nodes: 757 if (leaf.is_json and leaf.type_str in set(NtvConnector.dic_type.values()) 758 or leaf.ntv_type is None): 759 leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.uncast( 760 leaf, **kwargs) 761 leaf.ntv_type = Datatype.add(type_str) if type_str else None 762 leaf.is_json = NtvConnector.is_json(leaf.ntv_value) 763 return ntv
create a copy where ntv-value of the self-tree nodes is converted in object-value
Parameters
- kwargs : parameters used in NtvConnector class (specific for each Connector)
765 def to_tuple(self, maxi=10): 766 '''return a nested tuple representation of the NTV entity 767 (NtvList/NtvSingle, ntv_name, ntv_type, ntv_value). 768 769 *Parameters* 770 771 - **maxi**: Integer (default 10) - number of values to include for NtvList 772 entities. If maxi < 1 all the values are included. 773 ''' 774 clas = self.__class__.__name__ 775 val = self.ntv_value 776 name = self.ntv_name 777 typ = None 778 if self.ntv_type: 779 typ = self.ntv_type.long_name 780 if isinstance(self, NtvSingle) and not isinstance(val, NtvSingle): 781 return (clas, name, typ, val) 782 if isinstance(self, NtvSingle) and isinstance(val, NtvSingle): 783 return (clas, name, typ, val.to_tuple(maxi=maxi)) 784 if isinstance(self, NtvList): 785 maxv = len(self.ntv_value) if maxi < 1 else maxi 786 return (clas, name, typ, [ntv.to_tuple(maxi=maxi) for ntv in val[:maxv]]) 787 raise NtvError('the ntv entity is not consistent')
return a nested tuple representation of the NTV entity (NtvList/NtvSingle, ntv_name, ntv_type, ntv_value).
Parameters
- maxi: Integer (default 10) - number of values to include for NtvList entities. If maxi < 1 all the values are included.
789 def remove(self, first=True, index=None): 790 '''remove self from its parent entity. 791 792 *parameters* 793 794 - **first** : boolean (default True) - if True only the first instance 795 else all 796 - **index** : integer (default None) - index of self in its parent 797 ''' 798 parent = self.parent 799 if not parent: 800 return 801 idx = parent.ntv_value.index(self) if index is None else index 802 if not parent[idx] == self: 803 raise NtvError('the entity is not present at the index') 804 del parent.ntv_value[idx] 805 if not first and index is None: 806 while self in parent: 807 idx = parent.ntv_value.index(self) 808 del parent.ntv_value[idx] 809 if not self in parent: 810 self.parent = None 811 return
remove self from its parent entity.
parameters
- first : boolean (default True) - if True only the first instance else all
- index : integer (default None) - index of self in its parent
813 def replace(self, ntv): 814 '''replace self by ntv in the tree''' 815 parent = self.parent 816 if parent: 817 idx = parent.ntv_value.index(self) 818 parent.insert(idx, ntv) 819 del parent[idx+1] 820 if not self in parent: 821 self.parent=None 822 else: 823 self = ntv
replace self by ntv in the tree
830 @abstractmethod 831 def obj_value(self): 832 '''return the ntv_value with different formats defined by kwargs (abstract method)'''
return the ntv_value with different formats defined by kwargs (abstract method)
861 @staticmethod 862 def decode_json(json_value): 863 '''return (value, name, type, separator, isjson) of a json object''' 864 if isinstance(json_value, dict) and len(json_value) == 1: 865 json_name = list(json_value.keys())[0] 866 val = json_value[json_name] 867 return (val, *NtvUtil.from_obj_name(json_name), NtvConnector.is_json(val)) 868 return (json_value, None, None, None, NtvConnector.is_json(json_value))
return (value, name, type, separator, isjson) of a json object
Inherited Members
- json_ntv.ntv_util.NtvUtil
- from_obj_name
- decode_ntv_tab
894class NtvSingle(Ntv): 895 ''' A NTV-single entity is a Ntv entity not composed with other entities. 896 897 *Attributes :* 898 - no additional attributes to those of parent class `Ntv` 899 900 *dynamic values (@property)* 901 - `json_array` 902 903 The additional methods defined in this class are : 904 905 *instance methods* 906 - `obj_value` 907 ''' 908 909 def __init__(self, value, ntv_name=None, ntv_type=None, fast=False): 910 '''NtvSingle constructor. 911 912 *Parameters* 913 914 - **ntv_name** : String (default None) - name of the NTV entity 915 - **ntv_type**: String (default None) - type of the entity 916 - **value**: value of the entity 917 - **fast**: boolean (default False) - Ntv is created with a list of json values 918 without control 919 ''' 920 if not fast: 921 value, ntv_name, ntv_type = NtvSingle._decode_s( 922 value, ntv_name, ntv_type) 923 if ntv_type and isinstance(ntv_type, str) and ntv_type[-1] == '.': 924 raise NtvError('the ntv_type is not valid') 925 super().__init__(value, ntv_name, ntv_type) 926 927 def __eq__(self, other): 928 ''' equal if name type and value are equal''' 929 return self.__class__.__name__ == other.__class__.__name__ and\ 930 self.ntv_name == other.ntv_name and self.ntv_type == other.ntv_type and\ 931 self.ntv_value == other.ntv_value 932 933 def __hash__(self): 934 '''return hash(name) + hash(type) + hash(value)''' 935 return hash(self.ntv_name) + hash(self.ntv_type) + \ 936 hash(json.dumps(self.ntv_value, cls=NtvJsonEncoder)) 937 938 def __copy__(self): 939 ''' Copy all the Ntv tree ''' 940 return self.__class__(copy.copy(self.ntv_value), self.ntv_name, 941 self.ntv_type, fast=True) 942 943 @property 944 def json_array(self): 945 ''' return the json_array dynamic attribute (always False)''' 946 return False 947 948 def obj_value(self, def_type=None, **kwargs): 949 '''return the ntv_value with different formats defined by kwargs''' 950 option = {'encoded': False, 'format': 'json', 951 'simpleval': False, 'fast': False} | kwargs 952 if option['fast'] or option['format'] in ('json', 'tuple'): 953 return self.ntv_value 954 if option['format'] == 'obj' and self.ntv_value == 'null': 955 return None 956 return NtvConnector.uncast(self, **option)[0] 957 958 def _obj_sep(self, json_name, json_type, def_type=None): # REQ5 959 ''' return separator to include in json_name''' 960 if json_type or not def_type and isinstance(self.ntv_value, (list, dict)): 961 return ':' 962 return '' 963 964 @staticmethod 965 def _decode_s(ntv_value, ntv_name, ntv_type): 966 '''return adjusted ntv_value, ntv_name, ntv_type''' 967 is_json = NtvConnector.is_json(ntv_value) 968 if is_json: 969 if isinstance(ntv_value, (list)): 970 ntv_value = [NtvSingle._decode_s(val, '', ntv_type)[ 971 0] for val in ntv_value] 972 elif isinstance(ntv_value, (dict)): 973 ntv_value = {key: NtvSingle._decode_s(val, '', ntv_type)[ 974 0] for key, val in ntv_value.items()} 975 elif isinstance(ntv_value, NtvSingle): 976 ntv_value = ntv_value.to_obj() 977 return (ntv_value, ntv_name, 'ntv') 978 else: 979 ntv_value, name, typ = NtvConnector.cast(ntv_value, ntv_name) 980 ntv_type = Datatype(typ) if typ else ntv_type 981 if not ntv_type: 982 if is_json: 983 ntv_type = 'json' 984 else: 985 ntv_type = typ 986 if not ntv_name: 987 ntv_name = name 988 elif not is_json and Datatype(ntv_type) != Datatype(typ): 989 raise NtvError('ntv_value is not compatible with ntv_type') 990 return (ntv_value, ntv_name, ntv_type)
A NTV-single entity is a Ntv entity not composed with other entities.
Attributes :
- no additional attributes to those of parent class
Ntv
dynamic values (@property)
The additional methods defined in this class are :
instance methods
909 def __init__(self, value, ntv_name=None, ntv_type=None, fast=False): 910 '''NtvSingle constructor. 911 912 *Parameters* 913 914 - **ntv_name** : String (default None) - name of the NTV entity 915 - **ntv_type**: String (default None) - type of the entity 916 - **value**: value of the entity 917 - **fast**: boolean (default False) - Ntv is created with a list of json values 918 without control 919 ''' 920 if not fast: 921 value, ntv_name, ntv_type = NtvSingle._decode_s( 922 value, ntv_name, ntv_type) 923 if ntv_type and isinstance(ntv_type, str) and ntv_type[-1] == '.': 924 raise NtvError('the ntv_type is not valid') 925 super().__init__(value, ntv_name, ntv_type)
NtvSingle constructor.
Parameters
- ntv_name : String (default None) - name of the NTV entity
- ntv_type: String (default None) - type of the entity
- value: value of the entity
- fast: boolean (default False) - Ntv is created with a list of json values without control
948 def obj_value(self, def_type=None, **kwargs): 949 '''return the ntv_value with different formats defined by kwargs''' 950 option = {'encoded': False, 'format': 'json', 951 'simpleval': False, 'fast': False} | kwargs 952 if option['fast'] or option['format'] in ('json', 'tuple'): 953 return self.ntv_value 954 if option['format'] == 'obj' and self.ntv_value == 'null': 955 return None 956 return NtvConnector.uncast(self, **option)[0]
return the ntv_value with different formats defined by kwargs
Inherited Members
- Ntv
- fast
- obj
- from_att
- from_obj
- lower
- childs
- pointer
- code_ntv
- max_len
- name
- type_str
- val
- alike
- from_value
- json_name
- to_ntvsingle
- to_ntvlist
- notype
- reduce
- set_name
- set_type
- set_value
- to_mermaid
- expand
- to_repr
- to_name
- to_fast
- to_obj
- obj_ntv
- to_json_ntv
- to_obj_ntv
- to_tuple
- remove
- replace
- tree
- decode_json
- json_ntv.ntv_util.NtvUtil
- from_obj_name
- decode_ntv_tab
993class NtvList(Ntv): 994 '''A NTV-list entity is a Ntv entity where: 995 996 - ntv_value is a list of NTV entities, 997 - ntv_type is a default type available for included NTV entities 998 999 *Attributes :* 1000 - no additional attributes to those of parent class `Ntv` 1001 1002 *dynamic values (@property)* 1003 - `json_array` 1004 1005 The additional methods defined in this class are : 1006 1007 *instance methods* 1008 - `obj_value` 1009 ''' 1010 1011 def __init__(self, list_ntv, ntv_name=None, ntv_type=None, typ_auto=False, fast=False): 1012 '''NtvList constructor. 1013 1014 *Parameters* 1015 1016 - **ntv_name** : String (default None) - name of the NTV entity 1017 - **ntv_type**: String (default None) - default type or namespace of 1018 the included entities 1019 - **list_ntv**: list - list of Ntv objects or obj_value of Ntv objects 1020 - **fast**: boolean (default False) - if True, Ntv is created with a list 1021 of json values without control 1022 - **type_auto**: boolean (default False) - if True, default type for NtvList 1023 is the ntv_type of the first Ntv in the ntv_value''' 1024 if isinstance(list_ntv, NtvList): 1025 ntv_value = [copy.copy(ntv) for ntv in list_ntv.ntv_value] 1026 ntv_type = list_ntv.ntv_type 1027 ntv_name = list_ntv.ntv_name 1028 elif isinstance(list_ntv, list): 1029 ntv_value = [Ntv.from_obj(ntv, ntv_type, ':', fast=fast) 1030 for ntv in list_ntv] 1031 elif isinstance(list_ntv, dict): 1032 ntv_value = [Ntv.from_obj({key: val}, ntv_type, ':', fast=fast) 1033 for key, val in list_ntv.items()] 1034 else: 1035 raise NtvError('ntv_value is not a list') 1036 if typ_auto and not ntv_type and len(ntv_value) > 0 and ntv_value[0].ntv_type: 1037 ntv_type = ntv_value[0].ntv_type 1038 super().__init__(ntv_value, ntv_name, ntv_type) 1039 for ntv in self: 1040 ntv.parent = self 1041 1042 @property 1043 def json_array(self): 1044 ''' return the json_array dynamic attribute''' 1045 set_name = {ntv.ntv_name for ntv in self} 1046 return '' in set_name or len(set_name) != len(self) or len(set_name)==1 1047 1048 def __eq__(self, other): 1049 ''' equal if name and value are equal''' 1050 return self.__class__.__name__ == other.__class__.__name__ and\ 1051 self.ntv_name == other.ntv_name and self.ntv_value == other.ntv_value 1052 1053 def __hash__(self): 1054 '''return hash(name) + hash(value)''' 1055 return hash(self.ntv_name) + hash(tuple(self.ntv_value)) 1056 1057 def __copy__(self): 1058 ''' Copy all the data ''' 1059 cop = self.__class__(self) 1060 cop.parent = None 1061 return cop 1062 1063 def __setitem__(self, ind, value): 1064 ''' replace ntv_value item at the `ind` row with `value`''' 1065 if ind < 0 or ind >= len(self): 1066 raise NtvError("out of bounds") 1067 self.ntv_value[ind] = value 1068 if isinstance(value, (NtvSingle, NtvList)): 1069 value.parent = self 1070 1071 def __delitem__(self, ind): 1072 '''remove ntv_value item at the `ind` row''' 1073 if isinstance(ind, int): 1074 self.ntv_value.pop(ind) 1075 else: 1076 self.ntv_value.pop(self.ntv_value.index(self[ind])) 1077 1078 def append(self, ntv): 1079 ''' add ntv at the end of the list of Ntv entities included''' 1080 old_parent = ntv.parent 1081 if old_parent: 1082 del(old_parent[old_parent.ntv_value.index(ntv)]) 1083 self.ntv_value.append(ntv) 1084 ntv.parent = self 1085 1086 def insert(self, idx, ntv): 1087 ''' add ntv at the index idx of the list of Ntv entities included''' 1088 old_parent = ntv.parent 1089 if old_parent: 1090 del(old_parent[old_parent.ntv_value.index(ntv)]) 1091 self.ntv_value.insert(idx, ntv) 1092 ntv.parent = self 1093 1094 def _obj_sep(self, json_name, json_type, def_type=None): 1095 ''' return separator to include in json_name''' 1096 return '::' if (json_type and json_type[-1] != '.') or (json_type and json_name) else '' 1097 1098 def obj_value(self, def_type=None, **kwargs): 1099 '''return the ntv_value with different formats defined by kwargs 1100 ''' 1101 option = {'encoded': False, 'format': 'json', 'simpleval': False, 1102 'json_array': False, 'fast': False, 'maxi': -1} | kwargs 1103 opt2 = option | {'encoded': False} 1104 maxv = len(self.ntv_value) if option['maxi'] < 1 else option['maxi'] 1105 def_type = self.ntv_type.long_name if self.ntv_type else def_type 1106 values = [ntv.to_obj(def_type=def_type, **opt2) 1107 for ntv in self.ntv_value[:maxv]] 1108 if len(values) == 1 and isinstance(values[0], dict): 1109 return values[0] 1110 if self.json_array or option['simpleval'] or option['json_array']: 1111 return values 1112 return {list(val.items())[0][0]: list(val.items())[0][1] for val in values}
A NTV-list entity is a Ntv entity where:
- ntv_value is a list of NTV entities,
- ntv_type is a default type available for included NTV entities
Attributes :
- no additional attributes to those of parent class
Ntv
dynamic values (@property)
The additional methods defined in this class are :
instance methods
1011 def __init__(self, list_ntv, ntv_name=None, ntv_type=None, typ_auto=False, fast=False): 1012 '''NtvList constructor. 1013 1014 *Parameters* 1015 1016 - **ntv_name** : String (default None) - name of the NTV entity 1017 - **ntv_type**: String (default None) - default type or namespace of 1018 the included entities 1019 - **list_ntv**: list - list of Ntv objects or obj_value of Ntv objects 1020 - **fast**: boolean (default False) - if True, Ntv is created with a list 1021 of json values without control 1022 - **type_auto**: boolean (default False) - if True, default type for NtvList 1023 is the ntv_type of the first Ntv in the ntv_value''' 1024 if isinstance(list_ntv, NtvList): 1025 ntv_value = [copy.copy(ntv) for ntv in list_ntv.ntv_value] 1026 ntv_type = list_ntv.ntv_type 1027 ntv_name = list_ntv.ntv_name 1028 elif isinstance(list_ntv, list): 1029 ntv_value = [Ntv.from_obj(ntv, ntv_type, ':', fast=fast) 1030 for ntv in list_ntv] 1031 elif isinstance(list_ntv, dict): 1032 ntv_value = [Ntv.from_obj({key: val}, ntv_type, ':', fast=fast) 1033 for key, val in list_ntv.items()] 1034 else: 1035 raise NtvError('ntv_value is not a list') 1036 if typ_auto and not ntv_type and len(ntv_value) > 0 and ntv_value[0].ntv_type: 1037 ntv_type = ntv_value[0].ntv_type 1038 super().__init__(ntv_value, ntv_name, ntv_type) 1039 for ntv in self: 1040 ntv.parent = self
NtvList constructor.
Parameters
- ntv_name : String (default None) - name of the NTV entity
- ntv_type: String (default None) - default type or namespace of the included entities
- list_ntv: list - list of Ntv objects or obj_value of Ntv objects
- fast: boolean (default False) - if True, Ntv is created with a list of json values without control
- type_auto: boolean (default False) - if True, default type for NtvList is the ntv_type of the first Ntv in the ntv_value
1078 def append(self, ntv): 1079 ''' add ntv at the end of the list of Ntv entities included''' 1080 old_parent = ntv.parent 1081 if old_parent: 1082 del(old_parent[old_parent.ntv_value.index(ntv)]) 1083 self.ntv_value.append(ntv) 1084 ntv.parent = self
add ntv at the end of the list of Ntv entities included
1086 def insert(self, idx, ntv): 1087 ''' add ntv at the index idx of the list of Ntv entities included''' 1088 old_parent = ntv.parent 1089 if old_parent: 1090 del(old_parent[old_parent.ntv_value.index(ntv)]) 1091 self.ntv_value.insert(idx, ntv) 1092 ntv.parent = self
add ntv at the index idx of the list of Ntv entities included
1098 def obj_value(self, def_type=None, **kwargs): 1099 '''return the ntv_value with different formats defined by kwargs 1100 ''' 1101 option = {'encoded': False, 'format': 'json', 'simpleval': False, 1102 'json_array': False, 'fast': False, 'maxi': -1} | kwargs 1103 opt2 = option | {'encoded': False} 1104 maxv = len(self.ntv_value) if option['maxi'] < 1 else option['maxi'] 1105 def_type = self.ntv_type.long_name if self.ntv_type else def_type 1106 values = [ntv.to_obj(def_type=def_type, **opt2) 1107 for ntv in self.ntv_value[:maxv]] 1108 if len(values) == 1 and isinstance(values[0], dict): 1109 return values[0] 1110 if self.json_array or option['simpleval'] or option['json_array']: 1111 return values 1112 return {list(val.items())[0][0]: list(val.items())[0][1] for val in values}
return the ntv_value with different formats defined by kwargs
Inherited Members
- Ntv
- fast
- obj
- from_att
- from_obj
- lower
- childs
- pointer
- code_ntv
- max_len
- name
- type_str
- val
- alike
- from_value
- json_name
- to_ntvsingle
- to_ntvlist
- notype
- reduce
- set_name
- set_type
- set_value
- to_mermaid
- expand
- to_repr
- to_name
- to_fast
- to_obj
- obj_ntv
- to_json_ntv
- to_obj_ntv
- to_tuple
- remove
- replace
- tree
- decode_json
- json_ntv.ntv_util.NtvUtil
- from_obj_name
- decode_ntv_tab