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 = list(self.path)[-1] 142 p_path = self.path[:-1].fragment 143 path = self.path.fragment 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[self.from_path.fragment]) 149 elif self.ope == 'move' and self.from_path: 150 ntv = ntv_res[self.from_path.fragment] 151 del ntv_res[self.from_path[:- 152 1].fragment][list(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 = list(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 (no specific attribute) 309 310 *dynamic values (@property)* 311 - `fragment` 312 313 *static method* 314 - `split` 315 - `pointer_json` 316 - `pointer_list` 317 318 *instance method* 319 - `append` 320 ''' 321 322 def __init__(self, pointer): 323 '''constructor 324 325 *Parameters* 326 327 - **pointer**: path from the root to the node 328 - list: list of int or str that identify a node 329 - NtvPointer: existing path to copy 330 - int: single level 331 - str: json_pointer 332 ''' 333 if isinstance(pointer, (list, NtvPointer)): 334 super().__init__(pointer) 335 elif isinstance(pointer, (int, str)): 336 super().__init__(NtvPointer.pointer_list(pointer)) 337 338 def __str__(self): 339 '''json-text representation of the NtvPointer''' 340 return NtvPointer.pointer_json(self) 341 342 def __getitem__(self, ind): 343 ''' return value record (value conversion)''' 344 return NtvPointer(super().__getitem__(ind)) 345 346 @property 347 def fragment(self): 348 '''convert a NtvPointer into a fragment URI''' 349 return NtvPointer.pointer_json(self, fragment=True) 350 351 def append(self, child): 352 '''append a child pointer into a pointer ''' 353 self += NtvPointer(child) 354 355 @staticmethod 356 def split(path): 357 '''return a tuple with the last pointer of the path 358 and the path without the last pointer''' 359 pointer = NtvPointer(path) 360 if not pointer: 361 return (None, None) 362 return (NtvPointer(pointer[-1]), NtvPointer(pointer[:-1])) 363 364 @staticmethod 365 def pointer_json(list_pointer, fragment=False): 366 '''convert a list of pointer into a json_pointer 367 368 *Parameters* 369 370 - **fragment**: Boolean (default False) - if True, insert '#' at the first place 371 ''' 372 json_p = '' if not fragment else '#' 373 for name in list_pointer: 374 json_p += str(name).replace('~', '~0').replace('/', '~1') + '/' 375 return json_p[:-1] 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 return [int(nam) if nam.isdigit() else nam.replace('~1', '/').replace('~0', '/') 385 for nam in split_pointer] 386 387 388class NtvOpError(Exception): 389 ''' NtvOp Exception''' 390 # 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 = list(self.path)[-1] 143 p_path = self.path[:-1].fragment 144 path = self.path.fragment 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[self.from_path.fragment]) 150 elif self.ope == 'move' and self.from_path: 151 ntv = ntv_res[self.from_path.fragment] 152 del ntv_res[self.from_path[:- 153 1].fragment][list(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 = list(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 = list(self.path)[-1] 143 p_path = self.path[:-1].fragment 144 path = self.path.fragment 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[self.from_path.fragment]) 150 elif self.ope == 'move' and self.from_path: 151 ntv = ntv_res[self.from_path.fragment] 152 del ntv_res[self.from_path[:- 153 1].fragment][list(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 = list(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 (no specific attribute) 310 311 *dynamic values (@property)* 312 - `fragment` 313 314 *static method* 315 - `split` 316 - `pointer_json` 317 - `pointer_list` 318 319 *instance method* 320 - `append` 321 ''' 322 323 def __init__(self, pointer): 324 '''constructor 325 326 *Parameters* 327 328 - **pointer**: path from the root to the node 329 - list: list of int or str that identify a node 330 - NtvPointer: existing path to copy 331 - int: single level 332 - str: json_pointer 333 ''' 334 if isinstance(pointer, (list, NtvPointer)): 335 super().__init__(pointer) 336 elif isinstance(pointer, (int, str)): 337 super().__init__(NtvPointer.pointer_list(pointer)) 338 339 def __str__(self): 340 '''json-text representation of the NtvPointer''' 341 return NtvPointer.pointer_json(self) 342 343 def __getitem__(self, ind): 344 ''' return value record (value conversion)''' 345 return NtvPointer(super().__getitem__(ind)) 346 347 @property 348 def fragment(self): 349 '''convert a NtvPointer into a fragment URI''' 350 return NtvPointer.pointer_json(self, fragment=True) 351 352 def append(self, child): 353 '''append a child pointer into a pointer ''' 354 self += NtvPointer(child) 355 356 @staticmethod 357 def split(path): 358 '''return a tuple with the last pointer of the path 359 and the path without the last pointer''' 360 pointer = NtvPointer(path) 361 if not pointer: 362 return (None, None) 363 return (NtvPointer(pointer[-1]), NtvPointer(pointer[:-1])) 364 365 @staticmethod 366 def pointer_json(list_pointer, fragment=False): 367 '''convert a list of pointer into a json_pointer 368 369 *Parameters* 370 371 - **fragment**: Boolean (default False) - if True, insert '#' at the first place 372 ''' 373 json_p = '' if not fragment else '#' 374 for name in list_pointer: 375 json_p += str(name).replace('~', '~0').replace('/', '~1') + '/' 376 return json_p[:-1] 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 return [int(nam) if nam.isdigit() else nam.replace('~1', '/').replace('~0', '/') 386 for nam in split_pointer]
The NtvPointer class defines methods to identify a node in a NTV entity
NtvPointer is child class of list
class (no specific attribute)
dynamic values (@property)
static method
instance method
323 def __init__(self, pointer): 324 '''constructor 325 326 *Parameters* 327 328 - **pointer**: path from the root to the node 329 - list: list of int or str that identify a node 330 - NtvPointer: existing path to copy 331 - int: single level 332 - str: json_pointer 333 ''' 334 if isinstance(pointer, (list, NtvPointer)): 335 super().__init__(pointer) 336 elif isinstance(pointer, (int, str)): 337 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
352 def append(self, child): 353 '''append a child pointer into a pointer ''' 354 self += NtvPointer(child)
append a child pointer into a pointer
356 @staticmethod 357 def split(path): 358 '''return a tuple with the last pointer of the path 359 and the path without the last pointer''' 360 pointer = NtvPointer(path) 361 if not pointer: 362 return (None, None) 363 return (NtvPointer(pointer[-1]), NtvPointer(pointer[:-1]))
return a tuple with the last pointer of the path and the path without the last pointer
365 @staticmethod 366 def pointer_json(list_pointer, fragment=False): 367 '''convert a list of pointer into a json_pointer 368 369 *Parameters* 370 371 - **fragment**: Boolean (default False) - if True, insert '#' at the first place 372 ''' 373 json_p = '' if not fragment else '#' 374 for name in list_pointer: 375 json_p += str(name).replace('~', '~0').replace('/', '~1') + '/' 376 return json_p[:-1]
convert a list of pointer into a json_pointer
Parameters
- fragment: Boolean (default False) - if True, insert '#' at the first place
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 return [int(nam) if nam.isdigit() else nam.replace('~1', '/').replace('~0', '/') 386 for nam in split_pointer]
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