NTV.json_ntv.ntv

Created on Feb 27 2023

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

The Ntv class is an abstract class used by NtvSingleand NtvList classes.

Attributes :

  • ntv_name : String - name of the NTV entity
  • ntv_type: NtvType - 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

Ntv(ntv_value, ntv_name, ntv_type)
 95    def __init__(self, ntv_value, ntv_name, ntv_type):
 96        '''Ntv constructor.
 97
 98        *Parameters*
 99
100        - **ntv_value**: Json entity - value of the entity
101        - **ntv_name** : String (default None) - name of the NTV entity
102        - **ntv_type**: String or NtvType or Namespace (default None) - type of the entity
103        '''
104        if isinstance(ntv_type, (NtvType, Namespace)):
105            self.ntv_type = ntv_type
106        elif ntv_type and ntv_type[-1] != '.':
107            self.ntv_type = NtvType.add(ntv_type)
108        elif ntv_type and ntv_type[-1] == '.':
109            self.ntv_type = Namespace.add(ntv_type)
110        else:
111            self.ntv_type = None
112        if not isinstance(ntv_name, str):
113            ntv_name = ''
114        self.ntv_name = ntv_name
115        self.ntv_value = ntv_value
116        self.is_json = NtvConnector.is_json(ntv_value)
117        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 NtvType or Namespace (default None) - type of the entity
@staticmethod
def fast(data, no_typ=False, typ_auto=False):
119    @staticmethod
120    def fast(data, no_typ=False, typ_auto=False):
121        ''' return an Ntv entity from data without conversion.
122
123        *Parameters* : see `obj` method'''
124        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

@staticmethod
def obj(data, no_typ=False, decode_str=False, typ_auto=False, fast=False):
126    @staticmethod
127    def obj(data, no_typ=False, decode_str=False, typ_auto=False, fast=False):
128        ''' return an Ntv entity from data.
129
130        *Parameters*
131
132        - **Data** can be :
133            - a tuple with value, name, typ and cat (see `from_att` method)
134            - a value to decode (see `from_obj`method)
135        - **no_typ** : boolean (default False) - if True, NtvList is with 'json' type
136        - **type_auto**: boolean (default False) - if True, default type for NtvList
137        is the ntv_type of the first Ntv in the ntv_value
138        - **fast** : boolean (default False) - if True, Ntv entity is created without conversion
139        - **decode_str**: boolean (default False) - if True, string are loaded in json data'''
140        if isinstance(data, tuple):
141            return Ntv.from_att(*data, decode_str=decode_str, fast=fast)
142        # if isinstance(data, str) and data.lstrip() and data.lstrip()[0] in '{[':
143        if isinstance(data, str):
144            try:
145                data = json.loads(data)
146            except json.JSONDecodeError:
147                pass
148        return Ntv.from_obj(data, no_typ=no_typ, decode_str=decode_str,
149                            typ_auto=typ_auto, fast=fast)

return an Ntv entity from data.

Parameters

  • Data can be :
    • a tuple with value, name, typ and cat (see from_att method)
    • a value to decode (see from_objmethod)
  • no_typ : boolean (default False) - if True, NtvList is with 'json' 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
@staticmethod
def from_att(value, name, typ, cat, decode_str=False, fast=False):
151    @staticmethod
152    def from_att(value, name, typ, cat, decode_str=False, fast=False):
153        ''' return an Ntv entity.
154
155        *Parameters*
156
157        - **value**: Ntv entity or value to convert in an Ntv entity
158        - **name** : string - name of the Ntv entity
159        - **typ** : string or NtvType - type of the NTV entity
160        - **cat**: string - NTV category ('single', 'list')
161        - **fast** : boolean (default False) - if True, Ntv entity is created without conversion
162        - **decode_str**: boolean (default False) - if True, string are loaded as json data'''
163
164        value = Ntv._from_value(value, decode_str)
165        if value.__class__.__name__ in ['NtvSingle', 'NtvList']:
166            return value
167        if isinstance(value, list) and cat == 'list':
168            return NtvList(value, name, typ, fast=fast)
169        if cat == 'single':
170            return NtvSingle(value, name, typ, fast=fast)
171        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
@staticmethod
def from_obj( value, def_type=None, def_sep=None, no_typ=False, decode_str=False, typ_auto=False, fast=False):
173    @staticmethod
174    def from_obj(value, def_type=None, def_sep=None, no_typ=False, decode_str=False,
175                 typ_auto=False, fast=False):
176        ''' return an Ntv entity from an object value.
177
178        *Parameters*
179
180        - **value**: Ntv value to convert in an Ntv entity
181        - **no_typ** : boolean (default None) - if True, NtvList is with 'json' type
182        - **def_type** : NtvType or Namespace (default None) - default type of the value
183        - **def_sep**: ':', '::' or None (default None) - default separator of the value
184        - **decode_str**: boolean (default False) - if True, string are loaded as json data
185        - **type_auto**: boolean (default False) - if True, default type for NtvList
186        is the ntv_type of the first Ntv in the ntv_value
187        - **fast** : boolean (default False) - if True, Ntv entity is created without conversion'''
188        value = Ntv._from_value(value, decode_str)
189        if value.__class__.__name__ in ['NtvSingle', 'NtvList']:
190            return value
191        ntv_value, ntv_name, str_typ, sep, is_json = Ntv.decode_json(value)
192        sep = def_sep if not sep else sep
193        if isinstance(ntv_value, list) and sep in (None, '::'):
194            return Ntv._create_ntvlist(str_typ, def_type, sep, ntv_value,
195                                       typ_auto, no_typ, ntv_name, fast)
196        if sep == ':' or (sep is None and isinstance(ntv_value, dict) and
197                          len(ntv_value) == 1):
198            ntv_type = agreg_type(str_typ, def_type, False)
199            return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast)
200        if sep is None and not isinstance(ntv_value, dict):
201            is_single_json = isinstance(value, (int, str, float, bool))
202            ntv_type = agreg_type(str_typ, def_type, is_single_json)
203            return NtvSingle(ntv_value, ntv_name, ntv_type, fast=fast)
204        if isinstance(ntv_value, dict) and (sep == '::' or len(ntv_value) != 1 and
205                                            sep is None):
206            return Ntv._create_ntvlist(str_typ, def_type, sep, ntv_value,
207                                       typ_auto, no_typ, ntv_name, fast)
208        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 'json' type
  • def_type : NtvType 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
@staticmethod
def lower(val1, val2):
273    @staticmethod
274    def lower(val1, val2):
275        ''' compare two ntv_value and return True if val1 < val2, False if val1 > val2 and 
276        None in the other cases'''
277        res = None
278        for v1, v2 in zip(Ntv.obj(val1).tree.leaf_nodes, Ntv.obj(val2).tree.leaf_nodes):
279            if v1.val is None:
280                res = True
281            elif isinstance(v1.val, (dict, list)):
282                res = Ntv.lower(v1.val, v2)
283            elif isinstance(v2.val, (dict, list)):
284                res = Ntv.lower(v1, v2.val)
285            elif isinstance(v1.val, Number):
286                if isinstance(v2.val, Number):
287                    res = None if v1.val == v2.val else v1.val < v2.val
288                else:
289                    res = False
290            elif isinstance(v1.val, str):
291                if isinstance(v2.val, Number):
292                    res = True
293                elif isinstance(v2.val, str):
294                    res = None if v1.val == v2.val else v1.val < v2.val
295                else:
296                    res = False
297            if not res is None:
298                break
299        return res 

compare two ntv_value and return True if val1 < val2, False if val1 > val2 and None in the other cases

def childs(self, obj=False, nam=False, typ=False):
301    def childs(self, obj=False, nam=False, typ=False):
302        ''' return a list of child Ntv entities or child data
303        
304        *parameters*
305        
306        - **obj**: boolean (default False) - return json-value
307        - **nam**: boolean (default False) - return name (with or without type) 
308        - **typ**: boolean (default False) - return type (with or without name) 
309        '''
310        if isinstance(self, NtvSingle):
311            return []
312        if not (obj or nam or typ):
313            return self.val
314        if obj:
315            return [ntv.to_obj() for ntv in self.val]
316        return [(ntv.name if nam else '') + (' - ' if nam and typ else '') + 
317                (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)
def pointer(self, index=False, item_idx=None):
319    def pointer(self, index=False, item_idx=None):
320        '''return a nested list of pointer from root
321        
322        *Parameters*
323
324        - **index**: Boolean (default False) - use index instead of name
325        - **item_idx**: Integer (default None) - index value for the pointer 
326        (useful with duplicate data)'''
327        if not self.parent:
328            return NtvPointer([])        
329        idx = item_idx if item_idx else self.parent.ntv_value.index(self)
330        num = index or (self.ntv_name == "" and self.parent.json_array)
331        pointer = self.parent.pointer(index)
332        pointer.append(idx if num else self.ntv_name)
333        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)
code_ntv

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
max_len

return the highest len of Ntv entity included

name

return the ntv_name of the entity

type_str

return a string with the value of the NtvType of the entity

val

return the ntv_value of the entity

def alike(self, ntv_value):
376    def alike(self, ntv_value):
377        ''' return a Ntv entity with same name and type.
378
379        *Parameters*
380
381        - **ntv_value**: list of ntv values'''
382        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
def from_value(self):
384    def from_value(self):
385        '''return a Ntv entity from ntv_value'''
386        if isinstance(self.ntv_value, list):
387            return NtvList(self.ntv_value)
388        return Ntv.from_obj(self.ntv_value)

return a Ntv entity from ntv_value

def json_name(self, def_type=None, string=False, explicit=False):
390    def json_name(self, def_type=None, string=False, explicit=False):
391        '''return the JSON name of the NTV entity (json-ntv format)
392
393        *Parameters*
394
395        - **def_typ** : NtvType or Namespace (default None) - type of the parent entity
396        - **string** : boolean (default False) - If True, return a string else a tuple
397        - **explicit** : boolean (default False) - If True, type is always included'''
398        if def_type is None:
399            def_type = ''
400        elif isinstance(def_type, (NtvType, Namespace)):
401            def_type = def_type.long_name
402        json_name = self.ntv_name if self.ntv_name else ''
403        json_type = relative_type(
404            def_type, self.type_str) if self.ntv_type else ''
405        implicit = (json_type == 'json' and (not def_type or def_type == 'json') or
406                    not NtvConnector.is_json_class(self.val))
407        if implicit and not explicit:
408            json_type = ''
409        json_sep = self._obj_sep(json_type, def_type)
410        if string:
411            return json_name + json_sep + json_type
412        return [json_name, json_sep, json_type]

return the JSON name of the NTV entity (json-ntv format)

Parameters

  • def_typ : NtvType 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
def to_ntvsingle(self, name=None, typ=None, def_type=None, **kwargs):
414    def to_ntvsingle(self, name=None, typ=None, def_type=None, **kwargs):
415        '''convert NtvList entity to NtvSingle entity
416
417        *Parameters*
418
419        - **ntv_name** : String (default None) - name of the NTV entity
420        - **ntv_type**: String (default None) - type of the entity
421        - **value**: value of the entity
422        - **fast**: boolean (default False) - Ntv is created with a list of json values
423        without control
424        '''
425        return NtvSingle(self.obj_value(def_type=def_type, **kwargs),
426                         self.name if self.name else name,
427                         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
def to_ntvlist( self, def_type=None, def_sep=None, no_typ=False, decode_str=False, typ_auto=False, fast=False):
429    def to_ntvlist(self, def_type=None, def_sep=None, no_typ=False, decode_str=False,
430                 typ_auto=False, fast=False):
431        '''convert NtvSingle entity to NtvList entity
432
433        *Parameters*
434
435        - **value**: Ntv value to convert in an Ntv entity
436        - **no_typ** : boolean (default None) - if True, NtvList is with 'json' type
437        - **def_type** : NtvType or Namespace (default None) - default type of the value
438        - **def_sep**: ':', '::' or None (default None) - default separator of the value
439        - **decode_str**: boolean (default False) - if True, string are loaded as json data
440        - **type_auto**: boolean (default False) - if True, default type for NtvList
441        is the ntv_type of the first Ntv in the ntv_value
442        - **fast** : boolean (default False) - if True, Ntv entity is created without conversion
443        '''
444        ntv = Ntv.from_obj(self.ntv_value, def_type, def_sep, no_typ, decode_str,
445                     typ_auto, fast)
446        if ntv.__class__.__name__ == 'NtvSingle':
447            return NtvList([self])
448        if self.ntv_name:
449            ntv.set_name(self.ntv_name)
450        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 : NtvType 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
def notype(self):
452    def notype(self):
453        '''convert NTV entity in a NV entity (with ntv_type is 'json' or None')'''
454        no_type = copy.copy(self)
455        for ntv in NtvTree(no_type).leaf_nodes:
456            ntv.set_type('json')           
457        for ntv in NtvTree(no_type).inner_nodes:
458            ntv.set_type()
459        return no_type

convert NTV entity in a NV entity (with ntv_type is 'json' or None')

def reduce(self, obj=True, maxi=6, level=3):
461    def reduce(self, obj=True, maxi=6, level=3):
462        '''reduce the length and the level of the entity
463        
464        *Parameters*
465
466        - **obj**: boolean (default True) - If True return jsonNTV else NTV entity
467        - **maxi**: integer (default 6) - Number of returned entities in an NtvList
468        - **level**: integer (default 6) - returned entities in an NtvList at this level is None
469        
470        *return*
471        
472        - **NTV entity** or **jsonNTV**
473        '''
474        ntv = copy.copy(self)
475        cont = Ntv.obj('...') if self.json_array else Ntv.obj({'...':''})            
476        if isinstance(self, NtvSingle):
477            return ntv
478        if level == 0:
479            ntv.ntv_value = [NtvSingle('...',ntv_type=ntv.type_str)]
480        if len(self) <= maxi:
481            ntv.ntv_value = [child.reduce(False, maxi, level-1) for child in ntv]
482            return ntv
483        mid = maxi // 2
484        cont.set_type(ntv.type_str)
485        start = [child.reduce(False, maxi, level-1) for child in ntv[:mid]]
486        #middle = [NtvSingle('...',ntv_type=ntv.type_str)]
487        middle = [cont]
488        end = [child.reduce(False, maxi, level-1) for child in ntv[-mid:]]
489        ntv.ntv_value = start + middle + end
490        if obj:
491            return ntv.to_obj()
492        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
def set_name(self, name='', nodes='simple'):
494    def set_name(self, name='', nodes='simple'):
495        '''set new names to the entity
496
497        *Parameters*
498
499        - **name**: list or string (default '') - New name values
500        - **nodes**: string (default 'simple') - nodes to be changed
501            'simple': current entity
502            'leaves': NtvSingle entities
503            'inner': NtvList entities
504            'all': all entities  '''
505        match nodes:
506            case 'simple':
507                self.ntv_name = str(name)
508            case 'leaves':
509                if not isinstance(name, list):
510                    name = [str(name)] * NtvTree(self).breadth
511                for nam, ntv in zip(name, NtvTree(self).leaf_nodes):
512                    ntv.ntv_name = nam
513            case 'inner':
514                if not isinstance(name, list):
515                    name = [str(name)] * len(NtvTree(self).inner_nodes)
516                for nam, ntv in zip(name, NtvTree(self).inner_nodes):
517                    ntv.ntv_name = nam
518            case 'all':
519                if not isinstance(name, list):
520                    name = [str(name)] * NtvTree(self).size
521                for nam, ntv in zip(name, NtvTree(self).nodes):
522                    ntv.ntv_name = nam
523            case _:
524                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
def set_type(self, typ=None):
526    def set_type(self, typ=None):
527        '''set a new type to the entity
528
529        *Parameters*
530
531        - **typ**: string, NtvType, Namespace (default None)'''
532        if typ and not isinstance(typ, (str, NtvType, Namespace)):
533            raise NtvError('the type is not a valid type')
534        self.ntv_type = str_type(typ, self.__class__.__name__ == 'NtvSingle')

set a new type to the entity

Parameters

  • typ: string, NtvType, Namespace (default None)
def set_value(self, value=None, fast=False):
536    def set_value(self, value=None, fast=False):
537        '''set new ntv_value of a single entity or of a list of entities included
538
539        *Parameters*
540
541        - **value**: list or single value
542        - **fast** : boolean (default False) - if True, value is not converted'''
543        if isinstance(self, NtvSingle):
544            self.ntv_value = NtvSingle(value, ntv_type=self.ntv_type, 
545                                       fast=fast).val
546            return
547        if not isinstance(value, list):
548            value = [value] * NtvTree(self).breadth
549        ntv_val = NtvList(value, fast=fast)
550        for val, ntv in zip(ntv_val, NtvTree(self).leaf_nodes):
551            ntv.ntv_value = val.val
552        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
def to_mermaid(self, title='', disp=False, row=False, leaves=False):
554    def to_mermaid(self, title='', disp=False, row=False, leaves=False):
555        '''return a mermaid flowchart.
556
557        *Parameters*
558
559        - **title**: String (default '') - title of the flowchart
560        - **disp**: Boolean (default False) - if true, return a display else return
561        a mermaid text diagram
562        - **row**: Boolean (default False) - if True, add the node row
563        - **leaves**: Boolean (default False) - if True, add the leaf row
564        '''
565        option = {'title': title, 'disp': disp, 'row': row, 'leaves': leaves}
566        if disp:
567            Ntv.obj({':$mermaid': self.to_obj()}).to_obj(
568                format='obj', **option)
569            return None
570        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
def expand(self, full=True):
572    def expand(self, full=True):
573        '''return a json representation of the triplet (name, type, value)'''
574        if isinstance(self, NtvList) and full:
575            return {'name': self.name, 'type': self.type_str, 
576                    'value': [ntv.expand(full) for ntv in self.val]}
577        if isinstance(self, NtvSingle) and full:
578            return {'name': self.name, 'type': self.type_str, 'value': self.val}
579        exp = {} if not self.name else {'name': self.name}
580        if not self.type_str in ['json', ''] :
581            exp['type'] = self.type_str
582        if isinstance(self, NtvList):
583            exp['value'] = [ntv.expand(full) for ntv in self.val]
584        else:
585            exp['value'] = self.val
586        return exp

return a json representation of the triplet (name, type, value)

def to_repr(self, nam=True, typ=True, val=True, jsn=False, maxi=10):
588    def to_repr(self, nam=True, typ=True, val=True, jsn=False, maxi=10):
589        '''return a simple json representation of the Ntv entity.
590
591        *Parameters*
592
593        - **nam**: Boolean(default True) - if true, the names are included
594        - **typ**: Boolean(default True) - if true, the types are included
595        - **val**: Boolean(default True) - if true, the values are included
596        - **jsn**: Boolean(default False) - if false, the 'json' type is not included
597        - **maxi**: Integer (default 10) - number of values to include for NtvList
598        entities. If maxi < 1 all the values are included.
599        '''
600        ntv = self.code_ntv
601        if nam and typ:
602            ntv = ntv[0]
603        if self.ntv_name and nam:
604            ntv += '-' + self.ntv_name
605        if self.ntv_type and typ and (jsn or self.ntv_type.long_name != 'json'):
606            ntv += '-' + self.ntv_type.long_name
607        clas = self.__class__.__name__
608        clas_val = self.ntv_value.__class__.__name__
609        if clas == 'NtvSingle' and clas_val != 'NtvSingle':
610            if val:
611                if ntv:
612                    ntv += '-'
613                ntv += json.dumps(self.ntv_value, cls=NtvJsonEncoder)
614            return ntv
615        if clas == 'NtvSingle' and clas_val == 'NtvSingle':
616            return {ntv:  self.ntv_value.to_repr(nam, typ, val, jsn, maxi)}
617        if clas == 'NtvList':
618            maxv = len(self.ntv_value) if maxi < 1 else maxi
619            return {ntv:  [ntvi.to_repr(nam, typ, val, jsn, maxi) 
620                           for ntvi in self.ntv_value[:maxv]]}
621        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.
def to_name(self, default=''):
623    def to_name(self, default=''):
624        '''return the name of the NTV entity
625
626        *Parameters*
627
628        - **default**: string (default ''): returned value if name is not present '''
629        if self.ntv_name == '':
630            return default
631        return self.ntv_name

return the name of the NTV entity

Parameters

  • default: string (default ''): returned value if name is not present
def to_fast(self, def_type=None, **kwargs):
633    def to_fast(self, def_type=None, **kwargs):
634        '''return the JSON representation of the NTV entity (json-ntv format)
635        without value conversion.
636
637        *Parameters*
638
639        - **def_type** : NtvType or Namespace (default None) - default type to apply
640        to the NTV entity
641        - **encoded** : boolean (default False) - choice for return format
642        (string/bytes if True, dict/list/tuple else)
643        - **format**  : string (default 'json')- choice for return format
644        (json, cbor, obj)
645        - **simpleval** : boolean (default False) - if True, only value (without
646        name and type) is included
647        - **name** : boolean (default true) - if False, name is not included
648        - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList
649        - **maxi**: Integer (default -1) - number of values to include for NtvList
650        entities. If maxi < 1 all the values are included.
651        '''
652        option = kwargs | {'fast': True}
653        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 : NtvType 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.
def to_obj(self, def_type=None, **kwargs):
655    def to_obj(self, def_type=None, **kwargs):
656        '''return the JSON representation of the NTV entity (json-ntv format).
657
658        *Parameters*
659
660        - **def_type** : NtvType or Namespace (default None) - default type to apply
661        to the NTV entity
662        - **encoded** : boolean (default False) - choice for return format
663        (string/bytes if True, dict/list/tuple else)
664        - **format**  : string (default 'json')- choice for return format
665        (json, cbor, obj)
666        - **simpleval** : boolean (default False) - if True, only value (without
667        name and type) is included
668        - **name** : boolean (default true) - if False, name is not included
669        - **json_array** : boolean (default false) - if True, Json-object is not used for NtvList
670        - **fast** : boolean (default False) - if True, json is created without conversion
671        - **maxi**: Integer (default -1) - number of values to include for NtvList
672        entities. If maxi < 1 all the values are included.
673        '''
674        option = {'encoded': False, 'format': 'json', 'fast': False, 'maxi': -1,
675                  'simpleval': False, 'name': True, 'json_array': False} | kwargs
676        value = self.obj_value(def_type=def_type, **option)
677        obj_name = self.json_name(def_type)
678        if not option['name']:
679            obj_name[0] = ''
680        if option['simpleval']:
681            name = ''
682        elif option['format'] in ('cbor', 'obj') and not NtvConnector.is_json_class(value):
683            name = obj_name[0]
684        else:
685            name = obj_name[0] + obj_name[1] + obj_name[2]
686        json_obj = {name: value} if name else value
687        if option['encoded'] and option['format'] == 'json':
688            return json.dumps(json_obj, cls=NtvJsonEncoder)
689        if option['encoded'] and option['format'] == 'cbor':
690            return NtvConnector.connector()['CborConnec'].to_obj_ntv(json_obj)
691        return json_obj

return the JSON representation of the NTV entity (json-ntv format).

Parameters

  • def_type : NtvType 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.
@staticmethod
def obj_ntv(value, name='', typ='', single=False):
693    @staticmethod
694    def obj_ntv(value, name='', typ='', single=False):
695        '''return a json-ntv representation without using Ntv structure.
696
697        *Parameters*
698
699        - **value** : ntv-value of the json-ntv
700        - **name** : string (default '') - ntv-name of the json-ntv
701        - **typ** : string (default '') - ntv_type of the json-ntv
702        - **single** : boolean (default False) - if True, value is a single object
703        else value is a set of objetcs.
704        '''
705        value = {} if not value else value
706        name = '' if not name else name
707        typ = '' if not typ else typ
708        ntv_list = len(value) != 1 if isinstance(
709            value, dict) else isinstance(value, list)
710        if not single and not ntv_list:
711            raise NtvError('value is not compatible with not single NTV data')
712        sep = ':' if single else '::'
713        sep = '' if not typ and (not single or single and not ntv_list) else sep
714        name += sep + typ
715        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.
def to_json_ntv(self):
717    def to_json_ntv(self):
718        ''' create a copy where ntv-value of the self-tree nodes is converted 
719        in json-value'''
720        ntv = copy.copy(self)
721        for leaf in ntv.tree.leaf_nodes:
722            if isinstance(leaf.ntv_value, (NtvSingle, NtvList)):
723                leaf.ntv_value = leaf.ntv_value.to_obj()
724                leaf.ntv_type = NtvType('ntv')
725            elif not leaf.is_json:
726                leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.cast(
727                    leaf.ntv_value, leaf.ntv_name, leaf.type_str)
728                leaf.ntv_type = NtvType.add(type_str)
729                leaf.is_json = True
730        return ntv

create a copy where ntv-value of the self-tree nodes is converted in json-value

def to_obj_ntv(self, **kwargs):
732    def to_obj_ntv(self, **kwargs):
733        ''' create a copy where ntv-value of the self-tree nodes is converted 
734        in object-value
735
736        *Parameters*
737
738        - **kwargs** : parameters used in NtvConnector class (specific for each Connector)'''
739        ntv = copy.copy(self)
740        for leaf in ntv.tree.leaf_nodes:
741            if (leaf.is_json and leaf.type_str in set(NtvConnector.dic_type.values())
742                    or leaf.ntv_type is None):
743                leaf.ntv_value, leaf.ntv_name, type_str = NtvConnector.uncast(
744                    leaf, **kwargs)
745                leaf.ntv_type = NtvType.add(type_str) if type_str else None
746                leaf.is_json = NtvConnector.is_json(leaf.ntv_value)
747        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)
def to_tuple(self, maxi=10):
749    def to_tuple(self, maxi=10):
750        '''return a nested tuple representation of the NTV entity
751        (NtvList/NtvSingle, ntv_name, ntv_type, ntv_value).
752
753        *Parameters*
754
755        - **maxi**: Integer (default 10) - number of values to include for NtvList
756        entities. If maxi < 1 all the values are included.
757        '''
758        clas = self.__class__.__name__
759        val = self.ntv_value
760        name = self.ntv_name
761        typ = None
762        if self.ntv_type:
763            typ = self.ntv_type.long_name
764        if isinstance(self, NtvSingle) and not isinstance(val, NtvSingle):
765            return (clas, name, typ, val)
766        if isinstance(self, NtvSingle) and isinstance(val, NtvSingle):
767            return (clas, name, typ, val.to_tuple(maxi=maxi))
768        if isinstance(self, NtvList):
769            maxv = len(self.ntv_value) if maxi < 1 else maxi
770            return (clas, name, typ, [ntv.to_tuple(maxi=maxi) for ntv in val[:maxv]])
771        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.
def remove(self, first=True, index=None):
773    def remove(self, first=True, index=None):
774        '''remove self from its parent entity.
775        
776        *parameters*
777        
778        - **first** : boolean (default True) - if True only the first instance
779        else all
780        - **index** : integer (default None) - index of self in its parent
781        '''
782        parent = self.parent
783        if not parent:
784            return
785        idx = parent.ntv_value.index(self) if index is None else index
786        if not parent[idx] == self:
787            raise NtvError('the entity is not present at the index')
788        del parent.ntv_value[idx]
789        if not first and index is None:
790            while self in parent:
791                idx = parent.ntv_value.index(self)
792                del parent.ntv_value[idx]                
793        if not self in parent:
794            self.parent = None
795        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
def replace(self, ntv):
797    def replace(self, ntv):
798        '''replace self by ntv in the tree'''
799        parent = self.parent
800        if parent:
801            idx = parent.ntv_value.index(self)
802            parent.insert(idx, ntv)
803            del parent[idx+1]
804            if not self in parent:
805                self.parent=None
806        else:
807            self = ntv

replace self by ntv in the tree

tree

return a tree with included entities (NtvTree object)

@abstractmethod
def obj_value(self):
814    @abstractmethod
815    def obj_value(self):
816        '''return the ntv_value with different formats defined by kwargs (abstract method)'''

return the ntv_value with different formats defined by kwargs (abstract method)

json_array

return the json_array dynamic attribute (abstract method)

@staticmethod
def decode_json(json_value):
845    @staticmethod
846    def decode_json(json_value):
847        '''return (value, name, type, separator, isjson) of a json object'''
848        if isinstance(json_value, dict) and len(json_value) == 1:
849            json_name = list(json_value.keys())[0]
850            val = json_value[json_name]
851            return (val, *NtvUtil.from_obj_name(json_name), NtvConnector.is_json(val))
852        return (json_value, None, None, None, NtvConnector.is_json(json_value))

return (value, name, type, separator, isjson) of a json object

class NtvSingle(Ntv):
878class NtvSingle(Ntv):
879    ''' A NTV-single entity is a Ntv entity not composed with other entities.
880
881    *Attributes :*
882    - no additional attributes to those of parent class `Ntv`
883
884    *dynamic values (@property)*
885    - `json_array`
886
887    The additional methods defined in this class are :
888
889    *instance methods*
890    - `obj_value`
891    '''
892
893    def __init__(self, value, ntv_name=None, ntv_type=None, fast=False):
894        '''NtvSingle constructor.
895
896        *Parameters*
897
898        - **ntv_name** : String (default None) - name of the NTV entity
899        - **ntv_type**: String (default None) - type of the entity
900        - **value**: value of the entity
901        - **fast**: boolean (default False) - Ntv is created with a list of json values
902        without control
903        '''
904        if not fast:
905            value, ntv_name, ntv_type = NtvSingle._decode_s(
906                value, ntv_name, ntv_type)
907            if ntv_type and isinstance(ntv_type, str) and ntv_type[-1] == '.':
908                raise NtvError('the ntv_type is not valid')
909        super().__init__(value, ntv_name, ntv_type)
910
911    def __eq__(self, other):
912        ''' equal if name type and value are equal'''
913        return self.__class__.__name__ == other.__class__.__name__ and\
914            self.ntv_name == other.ntv_name and self.ntv_type == other.ntv_type and\
915            self.ntv_value == other.ntv_value
916
917    def __hash__(self):
918        '''return hash(name) + hash(type) + hash(value)'''
919        return hash(self.ntv_name) + hash(self.ntv_type) + \
920            hash(json.dumps(self.ntv_value, cls=NtvJsonEncoder))
921
922    def __copy__(self):
923        ''' Copy all the Ntv tree '''
924        return self.__class__(copy.copy(self.ntv_value), self.ntv_name,
925                              self.ntv_type, fast=True)
926
927    @property
928    def json_array(self):
929        ''' return the json_array dynamic attribute (always False)'''
930        return False
931
932    def obj_value(self, def_type=None, **kwargs):
933        '''return the ntv_value with different formats defined by kwargs'''
934        option = {'encoded': False, 'format': 'json',
935                  'simpleval': False, 'fast': False} | kwargs
936        if option['fast'] or option['format'] in ('json', 'tuple'):
937            return self.ntv_value
938        if option['format'] == 'obj' and self.ntv_value == 'null':
939            return None
940        return NtvConnector.uncast(self, **option)[0]
941
942    def _obj_sep(self, json_type, def_type=None):
943        ''' return separator to include in json_name'''
944        if json_type or not def_type and \
945            (isinstance(self.ntv_value, list) or
946             isinstance(self.ntv_value, dict) and len(self.ntv_value) != 1):
947            return ':'
948        return ''
949
950    @staticmethod
951    def _decode_s(ntv_value, ntv_name, ntv_type):
952        '''return adjusted ntv_value, ntv_name, ntv_type'''
953        is_json = NtvConnector.is_json(ntv_value)
954        if is_json:
955            if isinstance(ntv_value, (list)):
956                ntv_value = [NtvSingle._decode_s(val, '', ntv_type)[
957                    0] for val in ntv_value]
958            elif isinstance(ntv_value, (dict)):
959                ntv_value = {key: NtvSingle._decode_s(val, '', ntv_type)[
960                    0] for key, val in ntv_value.items()}
961        elif isinstance(ntv_value, NtvSingle):
962            ntv_value = ntv_value.to_obj()
963            return (ntv_value, ntv_name, 'ntv')
964        else:
965            ntv_value, name, typ = NtvConnector.cast(ntv_value, ntv_name)  
966            ntv_type = NtvType(typ) if typ else ntv_type
967        if not ntv_type:
968            if is_json:
969                ntv_type = 'json'
970            else:
971                ntv_type = typ
972                if not ntv_name:
973                    ntv_name = name
974        elif not is_json and NtvType(ntv_type) != NtvType(typ):
975            raise NtvError('ntv_value is not compatible with ntv_type')
976        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

NtvSingle(value, ntv_name=None, ntv_type=None, fast=False)
893    def __init__(self, value, ntv_name=None, ntv_type=None, fast=False):
894        '''NtvSingle constructor.
895
896        *Parameters*
897
898        - **ntv_name** : String (default None) - name of the NTV entity
899        - **ntv_type**: String (default None) - type of the entity
900        - **value**: value of the entity
901        - **fast**: boolean (default False) - Ntv is created with a list of json values
902        without control
903        '''
904        if not fast:
905            value, ntv_name, ntv_type = NtvSingle._decode_s(
906                value, ntv_name, ntv_type)
907            if ntv_type and isinstance(ntv_type, str) and ntv_type[-1] == '.':
908                raise NtvError('the ntv_type is not valid')
909        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
json_array

return the json_array dynamic attribute (always False)

def obj_value(self, def_type=None, **kwargs):
932    def obj_value(self, def_type=None, **kwargs):
933        '''return the ntv_value with different formats defined by kwargs'''
934        option = {'encoded': False, 'format': 'json',
935                  'simpleval': False, 'fast': False} | kwargs
936        if option['fast'] or option['format'] in ('json', 'tuple'):
937            return self.ntv_value
938        if option['format'] == 'obj' and self.ntv_value == 'null':
939            return None
940        return NtvConnector.uncast(self, **option)[0]

return the ntv_value with different formats defined by kwargs

class NtvList(Ntv):
 979class NtvList(Ntv):
 980    '''A NTV-list entity is a Ntv entity where:
 981
 982    - ntv_value is a list of NTV entities,
 983    - ntv_type is a default type available for included NTV entities
 984
 985    *Attributes :*
 986    - no additional attributes to those of parent class `Ntv`
 987
 988    *dynamic values (@property)*
 989    - `json_array`
 990
 991    The additional methods defined in this class are :
 992
 993    *instance methods*
 994    - `obj_value`
 995    '''
 996
 997    def __init__(self, list_ntv, ntv_name=None, ntv_type=None, typ_auto=False, fast=False):
 998        '''NtvList constructor.
 999
1000        *Parameters*
1001
1002        - **ntv_name** : String (default None) - name of the NTV entity
1003        - **ntv_type**: String (default None) - default type or namespace of
1004        the included entities
1005        - **list_ntv**: list - list of Ntv objects or obj_value of Ntv objects
1006        - **fast**: boolean (default False) - if True, Ntv is created with a list
1007        of json values without control
1008        - **type_auto**: boolean (default False) - if True, default type for NtvList
1009        is the ntv_type of the first Ntv in the ntv_value'''
1010        if isinstance(list_ntv, NtvList):
1011            ntv_value = [copy.copy(ntv) for ntv in list_ntv.ntv_value]
1012            ntv_type = list_ntv.ntv_type
1013            ntv_name = list_ntv.ntv_name
1014        elif isinstance(list_ntv, list):
1015            ntv_value = [Ntv.from_obj(ntv, ntv_type, ':', fast=fast)
1016                         for ntv in list_ntv]
1017        elif isinstance(list_ntv, dict):
1018            ntv_value = [Ntv.from_obj({key: val}, ntv_type, ':', fast=fast)
1019                         for key, val in list_ntv.items()]
1020        else:
1021            raise NtvError('ntv_value is not a list')
1022        if typ_auto and not ntv_type and len(ntv_value) > 0 and ntv_value[0].ntv_type:
1023            ntv_type = ntv_value[0].ntv_type
1024        super().__init__(ntv_value, ntv_name, ntv_type)
1025        for ntv in self:
1026            ntv.parent = self
1027
1028    @property
1029    def json_array(self):
1030        ''' return the json_array dynamic attribute'''
1031        set_name = {ntv.ntv_name for ntv in self}
1032        return '' in set_name or len(set_name) != len(self) or len(set_name)==1
1033
1034    def __eq__(self, other):
1035        ''' equal if name and value are equal'''
1036        return self.__class__.__name__ == other.__class__.__name__ and\
1037            self.ntv_name == other.ntv_name and self.ntv_value == other.ntv_value
1038
1039    def __hash__(self):
1040        '''return hash(name) + hash(value)'''
1041        return hash(self.ntv_name) + hash(tuple(self.ntv_value))
1042
1043    def __copy__(self):
1044        ''' Copy all the data '''
1045        cop = self.__class__(self)
1046        cop.parent = None
1047        return cop
1048
1049    def __setitem__(self, ind, value):
1050        ''' replace ntv_value item at the `ind` row with `value`'''
1051        if ind < 0 or ind >= len(self):
1052            raise NtvError("out of bounds")
1053        self.ntv_value[ind] = value
1054        if isinstance(value, (NtvSingle, NtvList)):
1055            value.parent = self
1056
1057    def __delitem__(self, ind):
1058        '''remove ntv_value item at the `ind` row'''
1059        if isinstance(ind, int):
1060            self.ntv_value.pop(ind)
1061        else:            
1062            self.ntv_value.pop(self.ntv_value.index(self[ind]))
1063
1064    def append(self, ntv):
1065        ''' add ntv at the end of the list of Ntv entities included'''
1066        old_parent = ntv.parent
1067        if old_parent:
1068            del(old_parent[old_parent.ntv_value.index(ntv)])
1069        self.ntv_value.append(ntv)
1070        ntv.parent = self
1071
1072    def insert(self, idx, ntv):
1073        ''' add ntv at the index idx of the list of Ntv entities included'''
1074        old_parent = ntv.parent
1075        if old_parent:
1076            del(old_parent[old_parent.ntv_value.index(ntv)])
1077        self.ntv_value.insert(idx, ntv)
1078        ntv.parent = self      
1079        
1080    def _obj_sep(self, json_type, def_type=None):
1081        ''' return separator to include in json_name'''
1082        if json_type or (len(self.ntv_value) == 1 and not self.json_array):
1083            return '::'
1084        return ''
1085
1086    def obj_value(self, def_type=None, **kwargs):
1087        '''return the ntv_value with different formats defined by kwargs
1088        '''
1089        option = {'encoded': False, 'format': 'json', 'simpleval': False,
1090                  'json_array': False, 'fast': False, 'maxi': -1} | kwargs
1091        opt2 = option | {'encoded': False}
1092        maxv = len(self.ntv_value) if option['maxi'] < 1 else option['maxi']
1093        def_type = self.ntv_type.long_name if self.ntv_type else def_type
1094        if self.json_array or option['simpleval'] or option['json_array']:
1095            return [ntv.to_obj(def_type=def_type, **opt2) for ntv in self.ntv_value[:maxv]]
1096        values = [ntv.to_obj(def_type=def_type, **opt2)
1097                  for ntv in self.ntv_value[:maxv]]
1098        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

NtvList(list_ntv, ntv_name=None, ntv_type=None, typ_auto=False, fast=False)
 997    def __init__(self, list_ntv, ntv_name=None, ntv_type=None, typ_auto=False, fast=False):
 998        '''NtvList constructor.
 999
1000        *Parameters*
1001
1002        - **ntv_name** : String (default None) - name of the NTV entity
1003        - **ntv_type**: String (default None) - default type or namespace of
1004        the included entities
1005        - **list_ntv**: list - list of Ntv objects or obj_value of Ntv objects
1006        - **fast**: boolean (default False) - if True, Ntv is created with a list
1007        of json values without control
1008        - **type_auto**: boolean (default False) - if True, default type for NtvList
1009        is the ntv_type of the first Ntv in the ntv_value'''
1010        if isinstance(list_ntv, NtvList):
1011            ntv_value = [copy.copy(ntv) for ntv in list_ntv.ntv_value]
1012            ntv_type = list_ntv.ntv_type
1013            ntv_name = list_ntv.ntv_name
1014        elif isinstance(list_ntv, list):
1015            ntv_value = [Ntv.from_obj(ntv, ntv_type, ':', fast=fast)
1016                         for ntv in list_ntv]
1017        elif isinstance(list_ntv, dict):
1018            ntv_value = [Ntv.from_obj({key: val}, ntv_type, ':', fast=fast)
1019                         for key, val in list_ntv.items()]
1020        else:
1021            raise NtvError('ntv_value is not a list')
1022        if typ_auto and not ntv_type and len(ntv_value) > 0 and ntv_value[0].ntv_type:
1023            ntv_type = ntv_value[0].ntv_type
1024        super().__init__(ntv_value, ntv_name, ntv_type)
1025        for ntv in self:
1026            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
json_array

return the json_array dynamic attribute

def append(self, ntv):
1064    def append(self, ntv):
1065        ''' add ntv at the end of the list of Ntv entities included'''
1066        old_parent = ntv.parent
1067        if old_parent:
1068            del(old_parent[old_parent.ntv_value.index(ntv)])
1069        self.ntv_value.append(ntv)
1070        ntv.parent = self

add ntv at the end of the list of Ntv entities included

def insert(self, idx, ntv):
1072    def insert(self, idx, ntv):
1073        ''' add ntv at the index idx of the list of Ntv entities included'''
1074        old_parent = ntv.parent
1075        if old_parent:
1076            del(old_parent[old_parent.ntv_value.index(ntv)])
1077        self.ntv_value.insert(idx, ntv)
1078        ntv.parent = self      

add ntv at the index idx of the list of Ntv entities included

def obj_value(self, def_type=None, **kwargs):
1086    def obj_value(self, def_type=None, **kwargs):
1087        '''return the ntv_value with different formats defined by kwargs
1088        '''
1089        option = {'encoded': False, 'format': 'json', 'simpleval': False,
1090                  'json_array': False, 'fast': False, 'maxi': -1} | kwargs
1091        opt2 = option | {'encoded': False}
1092        maxv = len(self.ntv_value) if option['maxi'] < 1 else option['maxi']
1093        def_type = self.ntv_type.long_name if self.ntv_type else def_type
1094        if self.json_array or option['simpleval'] or option['json_array']:
1095            return [ntv.to_obj(def_type=def_type, **opt2) for ntv in self.ntv_value[:maxv]]
1096        values = [ntv.to_obj(def_type=def_type, **opt2)
1097                  for ntv in self.ntv_value[:maxv]]
1098        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