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.

1 - JSON-NTV structure

The NTV triplet (name, type, value) is represented using a JSON-NTV format inspired by the JSON-ND project :

  • value (if name and type are not documented)
  • { "name" : value } (if name is documented but not type)
  • { ":type" : value } for primitive entities and { "::type" : value } for structured entities (if type is documented but not name)
  • { "name:type" : value } for primitive entities and { "name::type" : value } for structured entities (if type and name are documented).

For an NTV-single, the value is the JSON-value of the entity. For an NTV-list, value is a JSON-array (JSON-object) where JSON-elements (JSON-members) are the JSON-NTV formats of included NTV entities.

This JSON-NTV format allows full compatibility with existing JSON structures:

  • a JSON-number, JSON-string or JSON-boolean is the representation of an NTV-single entity,
  • a JSON-object with a single member is the representation of an NTV-single entity
  • a JSON-array or JSON-object is the representation of an NTV-list entity

2 - Examples of JSON-NTV representations

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

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

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

replace self by ntv in the tree

tree

return a tree with included entities (NtvTree object)

@abstractmethod
def obj_value(self):
809    @abstractmethod
810    def obj_value(self):
811        '''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):
840    @staticmethod
841    def decode_json(json_value):
842        '''return (value, name, type, separator, isjson) of a json object'''
843        if isinstance(json_value, dict) and len(json_value) == 1:
844            json_name = list(json_value.keys())[0]
845            val = json_value[json_name]
846            return (val, *NtvUtil.from_obj_name(json_name), NtvConnector.is_json(val))
847        return (json_value, None, None, None, NtvConnector.is_json(json_value))

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

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

return the ntv_value with different formats defined by kwargs

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

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

def insert(self, idx, ntv):
1068    def insert(self, idx, ntv):
1069        ''' add ntv at the index idx of the list of Ntv entities included'''
1070        old_parent = ntv.parent
1071        if old_parent:
1072            del(old_parent[old_parent.ntv_value.index(ntv)])
1073        self.ntv_value.insert(idx, ntv)
1074        ntv.parent = self      

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

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