NTV.json_ntv.ntv_patch
Created on Sept 10 2023
@author: Philippe@loco-labs.io
The ntv_patch
module is part of the NTV.json_ntv
package (specification document).
It contains the classes NtvOp
, NtvPatch
, NtvPointer
1 - NtvPointer
NtvPointer defines a string syntax for identifying a specific node within a Ntv tree.
It is the transposition of JSON Pointer defined in RFC6901.
2 - NTV Patch and NtvOp
NTV Patch is a transposition of JSON Patch defined in RFC6902.
NTV Patch is a format for expressing a sequence of operations to be applied to a target NTV entity.
Each operation is defined by the NtvOp object
This format is also potentially useful in cases where it is necessary to make partial updates on an NTV entity.
The representation of an NtvPatch is a JSON-Array of NtvOp that can be added to an NTV entity (e.g. NtvComment - comments and change management).
The representation of an NtvOp is a JSON-Object
3 - Example
[
{'op': 'add', 'path': '/0/liste/0', 'entity': {'new value': 51}}
{'op': 'test', 'path': '/0/1/-', 'entity': {'new value': 51}}
{'op': 'remove', 'path': '/0/1/-'}
]
1# -*- coding: utf-8 -*- 2""" 3Created on Sept 10 2023 4 5@author: Philippe@loco-labs.io 6 7The `ntv_patch` 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 `NtvOp`, `NtvPatch`, `NtvPointer` 11 12# 1 - NtvPointer 13 14NtvPointer defines a string syntax for identifying a specific node within a 15Ntv tree. 16 17It is the transposition of JSON Pointer defined in RFC6901. 18 19# 2 - NTV Patch and NtvOp 20 21NTV Patch is a transposition of JSON Patch defined in RFC6902. 22 23NTV Patch is a format for expressing a sequence of operations to be applied to a 24target NTV entity. 25 26Each operation is defined by the NtvOp object 27 28This format is also potentially useful in cases where it is necessary to 29make partial updates on an NTV entity. 30 31The representation of an NtvPatch is a JSON-Array of NtvOp that can be added to an NTV 32entity (e.g. NtvComment - comments and change management). 33 34The representation of an NtvOp is a JSON-Object 35 36# 3 - Example 37 38``` 39 [ 40 {'op': 'add', 'path': '/0/liste/0', 'entity': {'new value': 51}} 41 {'op': 'test', 'path': '/0/1/-', 'entity': {'new value': 51}} 42 {'op': 'remove', 'path': '/0/1/-'} 43 ] 44``` 45 46""" 47import json 48from copy import copy 49 50OPERATIONS = ['add', 'test', 'move', 'remove', 'copy', 'replace'] 51 52 53class NtvOp: 54 ''' The NtvOp class defines operations to apply to an NTV entity 55 56 *Attributes :* 57 58 - **op** : string - type of operation to apply 59 - **entity**: Ntv - entity subject to the operation 60 - **comment**: string - description of the operation 61 - **path**: string - NtvPointer to the child entity concerned by the op 62 - **from_path**: string - NtvPointer to the origin path (copy and move) 63 64 *dynamic values (@property)* 65 - `json` 66 67 *instance method* 68 - `exe` 69 ''' 70 71 def __init__(self, ope, path=None, entity=None, comment=None, from_path=None): 72 '''constructor 73 74 *Parameters* 75 76 - **ope**: str or dict - operation (str) or set of attributes (dict) 77 - **path**: str (default None) - Json of NtvPointer to the child entity 78 concerned by the ope 79 - **entity**: Json-value (default None) - NTV entity 80 - **comment** str (default None) - comment about ope 81 - **from_path**: str (default None) - Json of NtvPointer to the origin 82 path (copy and move) 83 ''' 84 ope = ope.json if isinstance(ope, NtvOp) else ope 85 if isinstance(ope, str): 86 self.ope = None 87 self.entity = None 88 self.comment = ope 89 self.from_path = [] 90 self.path = [] 91 return 92 dic = isinstance(ope, dict) 93 self.ope = ope.get('op') if dic else ope 94 self.entity = ope.get('entity') if dic else entity 95 self.comment = ope.get('comment') if dic else comment 96 self.from_path = NtvPointer( 97 ope.get('from')) if dic else NtvPointer(from_path) 98 self.path = NtvPointer(ope.get('path')) if dic else NtvPointer(path) 99 if self.ope and (not self.path or not self.ope in OPERATIONS): 100 raise NtvOpError('path or op is not correct') 101 102 def __repr__(self): 103 '''return the op and the path''' 104 txt = '' 105 if self.ope: 106 txt += 'op : ' + (self.ope + ',').ljust(8, ' ') 107 if self.path: 108 txt += ' path : ' + str(self.path) 109 if self.comment: 110 txt += self.comment 111 return txt 112 # return 'op : ' + (self.ope + ',').ljust(8, ' ') + ' path : ' + str(self.path) 113 114 def __str__(self): 115 '''return json format''' 116 return json.dumps(self.json) 117 118 def __eq__(self, other): 119 ''' equal if all attributes are equal''' 120 return self.__class__.__name__ == other.__class__.__name__ and\ 121 self.ope == other.ope and self.path == other.path and\ 122 self.entity == other.entity and self.comment == other.comment and\ 123 self.from_path == other.from_path 124 125 def __copy__(self): 126 ''' Copy all the data ''' 127 cop = self.__class__(self) 128 return cop 129 130 @property 131 def json(self): 132 '''return the json-value representation (dict)''' 133 dic = {'op': self.ope, 'path': str(self.path), 'entity': self.entity, 134 'comment': self.comment, 'from': str(self.from_path)} 135 return {key: val for key, val in dic.items() if val and val != 'None'} 136 137 def exe(self, ntv): 138 '''applies the operation to the 'ntv' entity and return the resulting entity''' 139 from json_ntv.ntv import Ntv 140 ntv_res = copy(ntv) 141 idx = self.path[-1] 142 p_path = str(NtvPointer(self.path[:-1])) 143 path = str(self.path) 144 if self.ope in ['move', 'copy', 'add']: 145 if self.ope == 'add' and self.entity: 146 ntv = Ntv.obj(self.entity) 147 elif self.ope == 'copy' and self.from_path: 148 ntv = copy(ntv_res[str(self.from_path)]) 149 elif self.ope == 'move' and self.from_path: 150 ntv = ntv_res[str(self.from_path)] 151 del ntv_res[str(NtvPointer(self.from_path[:-1])) 152 ][self.from_path[-1]] 153 ntv.parent = None 154 else: 155 raise NtvOpError('op is not correct') 156 if idx == '-': 157 ntv_res[p_path].append(ntv) 158 else: 159 ntv_res[p_path].insert(idx, ntv) 160 elif self.ope == 'test' and self.entity: 161 ntv = Ntv.obj(self.entity) 162 if not (idx == '-' and ntv in ntv_res[p_path]) and not ( 163 isinstance(idx, int) and ntv == ntv_res[path]): 164 raise NtvOpError('test is not correct') 165 elif self.ope == 'remove': 166 idx = self.path[-1] 167 idx = len(ntv[p_path]) - 1 if idx == '-' else idx 168 ntv_res[p_path+'/'+str(idx)].remove(index=idx) 169 elif self.ope == 'replace' and self.entity: 170 ntv_res[path].replace(Ntv.obj(self.entity)) 171 else: 172 raise NtvOpError('op add no result') 173 return ntv_res 174 175 176class NtvPatch: 177 ''' The NtvPatch class defines a sequence of operations to apply to an 178 NTV entity 179 180 181 *Attributes :* 182 183 - **list_op** : list - list of NtvOp to apply 184 - **comment**: string - description of the patch 185 186 *dynamic values (@property)* 187 - `json` 188 189 *instance method* 190 - `append` 191 - `exe` 192 ''' 193 194 def __init__(self, list_op, comment=None): 195 '''constructor 196 197 *Parameters* 198 199 - **list_op**: list, dict, str, NtvOp, NtvPatch - list of operations 200 - list - list of op 201 - dict - json representation of a NtvPatch 202 - str - comment without op 203 - NtvOp - if only one op 204 - NtvPatch - copy of an existing NtvPatch 205 - **comment**: str (default None) - comment if not included in the list_op 206 ''' 207 if isinstance(list_op, NtvPatch): 208 self.list_op = list_op.list_op 209 self.comment = list_op.comment 210 return 211 if isinstance(list_op, NtvOp): 212 self.comment = list_op.comment 213 self.list_op = [copy(list_op)] 214 self.list_op[0].comment = None 215 return 216 if isinstance(list_op, str): 217 self.comment = list_op 218 self.list_op = [] 219 return 220 if isinstance(list_op, dict): 221 self.comment = list_op.get('comment', None) 222 lis = list_op.get('list-op', []) 223 self.list_op = [NtvOp(ope) for ope in lis] 224 return 225 list_op = [] if not list_op else list_op 226 self.list_op = [NtvOp(ope) for ope in list_op] 227 self.comment = comment 228 return 229 230 def __eq__(self, other): 231 ''' equal if list_op are equal''' 232 return self.__class__.__name__ == other.__class__.__name__ and\ 233 self.list_op == other.list_op and self.comment == other.comment 234 235 def __copy__(self): 236 ''' Copy all the data ''' 237 cop = self.__class__(self) 238 return cop 239 240 def __setitem__(self, ind, ope): 241 ''' replace op item in list_op at the `ind` row with `ope`''' 242 if ind < 0 or ind >= len(self): 243 raise NtvOpError("out of bounds") 244 self.list_op[ind] = ope 245 246 def __delitem__(self, ind): 247 '''remove op item at the `ind` row''' 248 if isinstance(ind, int): 249 self.list_op.pop(ind) 250 else: 251 self.list_op.pop(self.list_op.index(self[ind])) 252 253 def __len__(self): 254 ''' len of list_op''' 255 return len(self.list_op) 256 257 def __str__(self): 258 '''return comment and list of op in json-text format''' 259 return json.dumps(self.json) 260 261 def __repr__(self): 262 '''return classname, comment and list of op''' 263 rep = 'NtvPatch :' + (self.comment if self.comment else '') 264 for ind, ope in enumerate(self): 265 rep += '\n op' + str(ind).ljust(3, ' ') + ' : ' + repr(ope)[5:] 266 return rep 267 268 def __contains__(self, item): 269 ''' return item is in the list of op''' 270 return item in self.list_op 271 272 def __iter__(self): 273 ''' iterator for list of op''' 274 return iter(self.list_op) 275 276 def __getitem__(self, selec): 277 ''' return op item in list of op''' 278 if selec is None or selec == [] or selec == () or selec == '': 279 return self 280 if isinstance(selec, (list, tuple)) and len(selec) == 1: 281 selec = selec[0] 282 if isinstance(selec, (list, tuple)): 283 return [self[i] for i in selec] 284 return self.list_op[selec] 285 286 def append(self, ope): 287 '''append 'ope' in the list of op''' 288 self.list_op.append(ope) 289 290 @property 291 def json(self): 292 '''return list of op in json-value format''' 293 return {'comment': self.comment, 294 'list-op': [ope.json for ope in self.list_op]} 295 296 def exe(self, ntv): 297 '''apply the included operations to NTV entity (ntv) and return 298 the resulting NTV entity''' 299 ntv_res = ntv 300 for ope in self: 301 ntv_res = ope.exe(ntv_res) 302 return ntv_res 303 304 305class NtvPointer(list): 306 ''' The NtvPointer class defines methods to identify a node in a NTV entity 307 308 NtvPointer is child class of `list` class 309 310 *dynamic values (@property)* 311 - `split` 312 - `pointer_json` 313 - `pointer_list` 314 315 *instance method* 316 - `json` 317 - `append` 318 ''' 319 320 def __init__(self, pointer): 321 '''constructor 322 323 *Parameters* 324 325 - **pointer**: path from the root to the node 326 - list: list of int or str that identify a node 327 - NtvPointer: existing path to copy 328 - int: single level 329 - str: json_pointer 330 ''' 331 if isinstance(pointer, (list, NtvPointer)): 332 super().__init__(pointer) 333 elif isinstance(pointer, (int, str)): 334 super().__init__(NtvPointer.pointer_list(pointer)) 335 336 def __str__(self): 337 '''json-text representation of the NtvPointer''' 338 return self.json() 339 340 def json(self, default=''): 341 '''convert a NtvPointer into a json_pointer 342 343 *Parameters* 344 345 - **default**: Str (default '') - default value if pointer is empty 346 ''' 347 return NtvPointer.pointer_json(self, default=default) 348 349 def append(self, child): 350 '''append a child pointer into a pointer ''' 351 self += NtvPointer(child) 352 353 @staticmethod 354 def split(path): 355 '''return a tuple with the last pointer of the path 356 and the path without the last pointer''' 357 pointer = NtvPointer(path) 358 if not pointer: 359 return (None, None) 360 return (NtvPointer(pointer[-1]), NtvPointer(pointer[:-1])) 361 362 @staticmethod 363 def pointer_json(list_pointer, default=''): 364 '''convert a list of pointer into a json_pointer 365 366 *Parameters* 367 368 - **default**: Str (default '') - default value if pointer is empty 369 ''' 370 json_p = '' 371 if list_pointer == []: 372 return default 373 for name in list_pointer: 374 json_p += '/' + str(name).replace('~', '~0').replace('/', '~1') 375 return json_p 376 377 @staticmethod 378 def pointer_list(json_pointer): 379 '''convert a json_pointer string into a pointer list''' 380 json_pointer = str(json_pointer) 381 split_pointer = json_pointer.split('/') 382 if len(split_pointer) == 0: 383 return [] 384 if split_pointer[0] != '' and len(split_pointer) > 1: 385 raise NtvOpError("json_pointer is not correct") 386 if split_pointer[0] != '': 387 split_pointer.insert(0, '') 388 return [int(nam) if nam.isdigit() else nam.replace('~1', '/').replace('~0', '/') 389 for nam in split_pointer[1:]] 390 391 392class NtvOpError(Exception): 393 ''' NtvOp Exception''' 394 # pass
54class NtvOp: 55 ''' The NtvOp class defines operations to apply to an NTV entity 56 57 *Attributes :* 58 59 - **op** : string - type of operation to apply 60 - **entity**: Ntv - entity subject to the operation 61 - **comment**: string - description of the operation 62 - **path**: string - NtvPointer to the child entity concerned by the op 63 - **from_path**: string - NtvPointer to the origin path (copy and move) 64 65 *dynamic values (@property)* 66 - `json` 67 68 *instance method* 69 - `exe` 70 ''' 71 72 def __init__(self, ope, path=None, entity=None, comment=None, from_path=None): 73 '''constructor 74 75 *Parameters* 76 77 - **ope**: str or dict - operation (str) or set of attributes (dict) 78 - **path**: str (default None) - Json of NtvPointer to the child entity 79 concerned by the ope 80 - **entity**: Json-value (default None) - NTV entity 81 - **comment** str (default None) - comment about ope 82 - **from_path**: str (default None) - Json of NtvPointer to the origin 83 path (copy and move) 84 ''' 85 ope = ope.json if isinstance(ope, NtvOp) else ope 86 if isinstance(ope, str): 87 self.ope = None 88 self.entity = None 89 self.comment = ope 90 self.from_path = [] 91 self.path = [] 92 return 93 dic = isinstance(ope, dict) 94 self.ope = ope.get('op') if dic else ope 95 self.entity = ope.get('entity') if dic else entity 96 self.comment = ope.get('comment') if dic else comment 97 self.from_path = NtvPointer( 98 ope.get('from')) if dic else NtvPointer(from_path) 99 self.path = NtvPointer(ope.get('path')) if dic else NtvPointer(path) 100 if self.ope and (not self.path or not self.ope in OPERATIONS): 101 raise NtvOpError('path or op is not correct') 102 103 def __repr__(self): 104 '''return the op and the path''' 105 txt = '' 106 if self.ope: 107 txt += 'op : ' + (self.ope + ',').ljust(8, ' ') 108 if self.path: 109 txt += ' path : ' + str(self.path) 110 if self.comment: 111 txt += self.comment 112 return txt 113 # return 'op : ' + (self.ope + ',').ljust(8, ' ') + ' path : ' + str(self.path) 114 115 def __str__(self): 116 '''return json format''' 117 return json.dumps(self.json) 118 119 def __eq__(self, other): 120 ''' equal if all attributes are equal''' 121 return self.__class__.__name__ == other.__class__.__name__ and\ 122 self.ope == other.ope and self.path == other.path and\ 123 self.entity == other.entity and self.comment == other.comment and\ 124 self.from_path == other.from_path 125 126 def __copy__(self): 127 ''' Copy all the data ''' 128 cop = self.__class__(self) 129 return cop 130 131 @property 132 def json(self): 133 '''return the json-value representation (dict)''' 134 dic = {'op': self.ope, 'path': str(self.path), 'entity': self.entity, 135 'comment': self.comment, 'from': str(self.from_path)} 136 return {key: val for key, val in dic.items() if val and val != 'None'} 137 138 def exe(self, ntv): 139 '''applies the operation to the 'ntv' entity and return the resulting entity''' 140 from json_ntv.ntv import Ntv 141 ntv_res = copy(ntv) 142 idx = self.path[-1] 143 p_path = str(NtvPointer(self.path[:-1])) 144 path = str(self.path) 145 if self.ope in ['move', 'copy', 'add']: 146 if self.ope == 'add' and self.entity: 147 ntv = Ntv.obj(self.entity) 148 elif self.ope == 'copy' and self.from_path: 149 ntv = copy(ntv_res[str(self.from_path)]) 150 elif self.ope == 'move' and self.from_path: 151 ntv = ntv_res[str(self.from_path)] 152 del ntv_res[str(NtvPointer(self.from_path[:-1])) 153 ][self.from_path[-1]] 154 ntv.parent = None 155 else: 156 raise NtvOpError('op is not correct') 157 if idx == '-': 158 ntv_res[p_path].append(ntv) 159 else: 160 ntv_res[p_path].insert(idx, ntv) 161 elif self.ope == 'test' and self.entity: 162 ntv = Ntv.obj(self.entity) 163 if not (idx == '-' and ntv in ntv_res[p_path]) and not ( 164 isinstance(idx, int) and ntv == ntv_res[path]): 165 raise NtvOpError('test is not correct') 166 elif self.ope == 'remove': 167 idx = self.path[-1] 168 idx = len(ntv[p_path]) - 1 if idx == '-' else idx 169 ntv_res[p_path+'/'+str(idx)].remove(index=idx) 170 elif self.ope == 'replace' and self.entity: 171 ntv_res[path].replace(Ntv.obj(self.entity)) 172 else: 173 raise NtvOpError('op add no result') 174 return ntv_res
The NtvOp class defines operations to apply to an NTV entity
Attributes :
- op : string - type of operation to apply
- entity: Ntv - entity subject to the operation
- comment: string - description of the operation
- path: string - NtvPointer to the child entity concerned by the op
- from_path: string - NtvPointer to the origin path (copy and move)
dynamic values (@property)
instance method
72 def __init__(self, ope, path=None, entity=None, comment=None, from_path=None): 73 '''constructor 74 75 *Parameters* 76 77 - **ope**: str or dict - operation (str) or set of attributes (dict) 78 - **path**: str (default None) - Json of NtvPointer to the child entity 79 concerned by the ope 80 - **entity**: Json-value (default None) - NTV entity 81 - **comment** str (default None) - comment about ope 82 - **from_path**: str (default None) - Json of NtvPointer to the origin 83 path (copy and move) 84 ''' 85 ope = ope.json if isinstance(ope, NtvOp) else ope 86 if isinstance(ope, str): 87 self.ope = None 88 self.entity = None 89 self.comment = ope 90 self.from_path = [] 91 self.path = [] 92 return 93 dic = isinstance(ope, dict) 94 self.ope = ope.get('op') if dic else ope 95 self.entity = ope.get('entity') if dic else entity 96 self.comment = ope.get('comment') if dic else comment 97 self.from_path = NtvPointer( 98 ope.get('from')) if dic else NtvPointer(from_path) 99 self.path = NtvPointer(ope.get('path')) if dic else NtvPointer(path) 100 if self.ope and (not self.path or not self.ope in OPERATIONS): 101 raise NtvOpError('path or op is not correct')
constructor
Parameters
- ope: str or dict - operation (str) or set of attributes (dict)
- path: str (default None) - Json of NtvPointer to the child entity concerned by the ope
- entity: Json-value (default None) - NTV entity
- comment str (default None) - comment about ope
- from_path: str (default None) - Json of NtvPointer to the origin path (copy and move)
138 def exe(self, ntv): 139 '''applies the operation to the 'ntv' entity and return the resulting entity''' 140 from json_ntv.ntv import Ntv 141 ntv_res = copy(ntv) 142 idx = self.path[-1] 143 p_path = str(NtvPointer(self.path[:-1])) 144 path = str(self.path) 145 if self.ope in ['move', 'copy', 'add']: 146 if self.ope == 'add' and self.entity: 147 ntv = Ntv.obj(self.entity) 148 elif self.ope == 'copy' and self.from_path: 149 ntv = copy(ntv_res[str(self.from_path)]) 150 elif self.ope == 'move' and self.from_path: 151 ntv = ntv_res[str(self.from_path)] 152 del ntv_res[str(NtvPointer(self.from_path[:-1])) 153 ][self.from_path[-1]] 154 ntv.parent = None 155 else: 156 raise NtvOpError('op is not correct') 157 if idx == '-': 158 ntv_res[p_path].append(ntv) 159 else: 160 ntv_res[p_path].insert(idx, ntv) 161 elif self.ope == 'test' and self.entity: 162 ntv = Ntv.obj(self.entity) 163 if not (idx == '-' and ntv in ntv_res[p_path]) and not ( 164 isinstance(idx, int) and ntv == ntv_res[path]): 165 raise NtvOpError('test is not correct') 166 elif self.ope == 'remove': 167 idx = self.path[-1] 168 idx = len(ntv[p_path]) - 1 if idx == '-' else idx 169 ntv_res[p_path+'/'+str(idx)].remove(index=idx) 170 elif self.ope == 'replace' and self.entity: 171 ntv_res[path].replace(Ntv.obj(self.entity)) 172 else: 173 raise NtvOpError('op add no result') 174 return ntv_res
applies the operation to the 'ntv' entity and return the resulting entity
177class NtvPatch: 178 ''' The NtvPatch class defines a sequence of operations to apply to an 179 NTV entity 180 181 182 *Attributes :* 183 184 - **list_op** : list - list of NtvOp to apply 185 - **comment**: string - description of the patch 186 187 *dynamic values (@property)* 188 - `json` 189 190 *instance method* 191 - `append` 192 - `exe` 193 ''' 194 195 def __init__(self, list_op, comment=None): 196 '''constructor 197 198 *Parameters* 199 200 - **list_op**: list, dict, str, NtvOp, NtvPatch - list of operations 201 - list - list of op 202 - dict - json representation of a NtvPatch 203 - str - comment without op 204 - NtvOp - if only one op 205 - NtvPatch - copy of an existing NtvPatch 206 - **comment**: str (default None) - comment if not included in the list_op 207 ''' 208 if isinstance(list_op, NtvPatch): 209 self.list_op = list_op.list_op 210 self.comment = list_op.comment 211 return 212 if isinstance(list_op, NtvOp): 213 self.comment = list_op.comment 214 self.list_op = [copy(list_op)] 215 self.list_op[0].comment = None 216 return 217 if isinstance(list_op, str): 218 self.comment = list_op 219 self.list_op = [] 220 return 221 if isinstance(list_op, dict): 222 self.comment = list_op.get('comment', None) 223 lis = list_op.get('list-op', []) 224 self.list_op = [NtvOp(ope) for ope in lis] 225 return 226 list_op = [] if not list_op else list_op 227 self.list_op = [NtvOp(ope) for ope in list_op] 228 self.comment = comment 229 return 230 231 def __eq__(self, other): 232 ''' equal if list_op are equal''' 233 return self.__class__.__name__ == other.__class__.__name__ and\ 234 self.list_op == other.list_op and self.comment == other.comment 235 236 def __copy__(self): 237 ''' Copy all the data ''' 238 cop = self.__class__(self) 239 return cop 240 241 def __setitem__(self, ind, ope): 242 ''' replace op item in list_op at the `ind` row with `ope`''' 243 if ind < 0 or ind >= len(self): 244 raise NtvOpError("out of bounds") 245 self.list_op[ind] = ope 246 247 def __delitem__(self, ind): 248 '''remove op item at the `ind` row''' 249 if isinstance(ind, int): 250 self.list_op.pop(ind) 251 else: 252 self.list_op.pop(self.list_op.index(self[ind])) 253 254 def __len__(self): 255 ''' len of list_op''' 256 return len(self.list_op) 257 258 def __str__(self): 259 '''return comment and list of op in json-text format''' 260 return json.dumps(self.json) 261 262 def __repr__(self): 263 '''return classname, comment and list of op''' 264 rep = 'NtvPatch :' + (self.comment if self.comment else '') 265 for ind, ope in enumerate(self): 266 rep += '\n op' + str(ind).ljust(3, ' ') + ' : ' + repr(ope)[5:] 267 return rep 268 269 def __contains__(self, item): 270 ''' return item is in the list of op''' 271 return item in self.list_op 272 273 def __iter__(self): 274 ''' iterator for list of op''' 275 return iter(self.list_op) 276 277 def __getitem__(self, selec): 278 ''' return op item in list of op''' 279 if selec is None or selec == [] or selec == () or selec == '': 280 return self 281 if isinstance(selec, (list, tuple)) and len(selec) == 1: 282 selec = selec[0] 283 if isinstance(selec, (list, tuple)): 284 return [self[i] for i in selec] 285 return self.list_op[selec] 286 287 def append(self, ope): 288 '''append 'ope' in the list of op''' 289 self.list_op.append(ope) 290 291 @property 292 def json(self): 293 '''return list of op in json-value format''' 294 return {'comment': self.comment, 295 'list-op': [ope.json for ope in self.list_op]} 296 297 def exe(self, ntv): 298 '''apply the included operations to NTV entity (ntv) and return 299 the resulting NTV entity''' 300 ntv_res = ntv 301 for ope in self: 302 ntv_res = ope.exe(ntv_res) 303 return ntv_res
The NtvPatch class defines a sequence of operations to apply to an NTV entity
Attributes :
- list_op : list - list of NtvOp to apply
- comment: string - description of the patch
dynamic values (@property)
instance method
195 def __init__(self, list_op, comment=None): 196 '''constructor 197 198 *Parameters* 199 200 - **list_op**: list, dict, str, NtvOp, NtvPatch - list of operations 201 - list - list of op 202 - dict - json representation of a NtvPatch 203 - str - comment without op 204 - NtvOp - if only one op 205 - NtvPatch - copy of an existing NtvPatch 206 - **comment**: str (default None) - comment if not included in the list_op 207 ''' 208 if isinstance(list_op, NtvPatch): 209 self.list_op = list_op.list_op 210 self.comment = list_op.comment 211 return 212 if isinstance(list_op, NtvOp): 213 self.comment = list_op.comment 214 self.list_op = [copy(list_op)] 215 self.list_op[0].comment = None 216 return 217 if isinstance(list_op, str): 218 self.comment = list_op 219 self.list_op = [] 220 return 221 if isinstance(list_op, dict): 222 self.comment = list_op.get('comment', None) 223 lis = list_op.get('list-op', []) 224 self.list_op = [NtvOp(ope) for ope in lis] 225 return 226 list_op = [] if not list_op else list_op 227 self.list_op = [NtvOp(ope) for ope in list_op] 228 self.comment = comment 229 return
constructor
Parameters
- list_op: list, dict, str, NtvOp, NtvPatch - list of operations
- list - list of op
- dict - json representation of a NtvPatch
- str - comment without op
- NtvOp - if only one op
- NtvPatch - copy of an existing NtvPatch
- comment: str (default None) - comment if not included in the list_op
297 def exe(self, ntv): 298 '''apply the included operations to NTV entity (ntv) and return 299 the resulting NTV entity''' 300 ntv_res = ntv 301 for ope in self: 302 ntv_res = ope.exe(ntv_res) 303 return ntv_res
apply the included operations to NTV entity (ntv) and return the resulting NTV entity
306class NtvPointer(list): 307 ''' The NtvPointer class defines methods to identify a node in a NTV entity 308 309 NtvPointer is child class of `list` class 310 311 *dynamic values (@property)* 312 - `split` 313 - `pointer_json` 314 - `pointer_list` 315 316 *instance method* 317 - `json` 318 - `append` 319 ''' 320 321 def __init__(self, pointer): 322 '''constructor 323 324 *Parameters* 325 326 - **pointer**: path from the root to the node 327 - list: list of int or str that identify a node 328 - NtvPointer: existing path to copy 329 - int: single level 330 - str: json_pointer 331 ''' 332 if isinstance(pointer, (list, NtvPointer)): 333 super().__init__(pointer) 334 elif isinstance(pointer, (int, str)): 335 super().__init__(NtvPointer.pointer_list(pointer)) 336 337 def __str__(self): 338 '''json-text representation of the NtvPointer''' 339 return self.json() 340 341 def json(self, default=''): 342 '''convert a NtvPointer into a json_pointer 343 344 *Parameters* 345 346 - **default**: Str (default '') - default value if pointer is empty 347 ''' 348 return NtvPointer.pointer_json(self, default=default) 349 350 def append(self, child): 351 '''append a child pointer into a pointer ''' 352 self += NtvPointer(child) 353 354 @staticmethod 355 def split(path): 356 '''return a tuple with the last pointer of the path 357 and the path without the last pointer''' 358 pointer = NtvPointer(path) 359 if not pointer: 360 return (None, None) 361 return (NtvPointer(pointer[-1]), NtvPointer(pointer[:-1])) 362 363 @staticmethod 364 def pointer_json(list_pointer, default=''): 365 '''convert a list of pointer into a json_pointer 366 367 *Parameters* 368 369 - **default**: Str (default '') - default value if pointer is empty 370 ''' 371 json_p = '' 372 if list_pointer == []: 373 return default 374 for name in list_pointer: 375 json_p += '/' + str(name).replace('~', '~0').replace('/', '~1') 376 return json_p 377 378 @staticmethod 379 def pointer_list(json_pointer): 380 '''convert a json_pointer string into a pointer list''' 381 json_pointer = str(json_pointer) 382 split_pointer = json_pointer.split('/') 383 if len(split_pointer) == 0: 384 return [] 385 if split_pointer[0] != '' and len(split_pointer) > 1: 386 raise NtvOpError("json_pointer is not correct") 387 if split_pointer[0] != '': 388 split_pointer.insert(0, '') 389 return [int(nam) if nam.isdigit() else nam.replace('~1', '/').replace('~0', '/') 390 for nam in split_pointer[1:]]
The NtvPointer class defines methods to identify a node in a NTV entity
NtvPointer is child class of list
class
dynamic values (@property)
instance method
321 def __init__(self, pointer): 322 '''constructor 323 324 *Parameters* 325 326 - **pointer**: path from the root to the node 327 - list: list of int or str that identify a node 328 - NtvPointer: existing path to copy 329 - int: single level 330 - str: json_pointer 331 ''' 332 if isinstance(pointer, (list, NtvPointer)): 333 super().__init__(pointer) 334 elif isinstance(pointer, (int, str)): 335 super().__init__(NtvPointer.pointer_list(pointer))
constructor
Parameters
- pointer: path from the root to the node
- list: list of int or str that identify a node
- NtvPointer: existing path to copy
- int: single level
- str: json_pointer
341 def json(self, default=''): 342 '''convert a NtvPointer into a json_pointer 343 344 *Parameters* 345 346 - **default**: Str (default '') - default value if pointer is empty 347 ''' 348 return NtvPointer.pointer_json(self, default=default)
convert a NtvPointer into a json_pointer
Parameters
- default: Str (default '') - default value if pointer is empty
350 def append(self, child): 351 '''append a child pointer into a pointer ''' 352 self += NtvPointer(child)
append a child pointer into a pointer
354 @staticmethod 355 def split(path): 356 '''return a tuple with the last pointer of the path 357 and the path without the last pointer''' 358 pointer = NtvPointer(path) 359 if not pointer: 360 return (None, None) 361 return (NtvPointer(pointer[-1]), NtvPointer(pointer[:-1]))
return a tuple with the last pointer of the path and the path without the last pointer
363 @staticmethod 364 def pointer_json(list_pointer, default=''): 365 '''convert a list of pointer into a json_pointer 366 367 *Parameters* 368 369 - **default**: Str (default '') - default value if pointer is empty 370 ''' 371 json_p = '' 372 if list_pointer == []: 373 return default 374 for name in list_pointer: 375 json_p += '/' + str(name).replace('~', '~0').replace('/', '~1') 376 return json_p
convert a list of pointer into a json_pointer
Parameters
- default: Str (default '') - default value if pointer is empty
378 @staticmethod 379 def pointer_list(json_pointer): 380 '''convert a json_pointer string into a pointer list''' 381 json_pointer = str(json_pointer) 382 split_pointer = json_pointer.split('/') 383 if len(split_pointer) == 0: 384 return [] 385 if split_pointer[0] != '' and len(split_pointer) > 1: 386 raise NtvOpError("json_pointer is not correct") 387 if split_pointer[0] != '': 388 split_pointer.insert(0, '') 389 return [int(nam) if nam.isdigit() else nam.replace('~1', '/').replace('~0', '/') 390 for nam in split_pointer[1:]]
convert a json_pointer string into a pointer list
Inherited Members
- builtins.list
- clear
- copy
- insert
- extend
- pop
- remove
- index
- count
- reverse
- sort
NtvOp Exception
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback