Package jsondata :: Module JSONTree
[hide private]
[frames] | no frames]

Source Code for Module jsondata.JSONTree

  1  # -*- coding:utf-8   -*- 
  2  """The JSONTree module provides features for in-memory JSON structures. 
  3   
  4  The provided features comprise: 
  5   
  6  * The construction and printout of tree formatted  
  7    structures for screen analysis. 
  8  * Comparison of JSON strings as tree structures. 
  9   
 10   
 11  """ 
 12  __author__ = 'Arno-Can Uestuensoez' 
 13  __maintainer__ = 'Arno-Can Uestuensoez' 
 14  __license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints" 
 15  __copyright__ = "Copyright (C) 2015-2016 Arno-Can Uestuensoez @Ingenieurbuero Arno-Can Uestuensoez" 
 16  __version__ = '0.2.14' 
 17  __uuid__='63b597d6-4ada-4880-9f99-f5e0961351fb' 
 18   
 19  import sys 
 20   
 21  version = '{0}.{1}'.format(*sys.version_info[:2]) 
 22  if not version in ('2.6','2.7',): # pragma: no cover 
 23      raise Exception("Requires Python-2.6.* or higher") 
 24  # if version < '2.7': # pragma: no cover 
 25  #     raise Exception("Requires Python-2.7.* or higher") 
 26   
 27  #import re 
 28  #import json, jsonschema 
 29   
 30  if sys.modules.get('json'): 
 31      import json as myjson 
 32  elif sys.modules.get('ujson'): 
 33      import ujson as myjson 
 34  else: 
 35      import json as myjson 
 36   
 37  # default 
 38  _appname = "jsonpatch" 
 39  """Sets display for inetractive JSON/JSONschema design.""" 
 40   
 41  _interactive = False 
 42  """Activates interactive mode.""" 
 43   
 44  DIFF_FIRST = 0 
 45  """break display of diff after first""" 
 46   
 47  DIFF_ALL = 1 
 48  """list all diffs""" 
 49   
 50  CHARS_RAW = 0 
 51  """display character set as raw""" 
 52   
 53  CHARS_STR = 1 
 54  """display character set as str""" 
 55   
 56  CHARS_UTF = 2 
 57  """display character set as utf""" 
 58   
 59  LINE_CUT = 0 
 60  """force line fit""" 
 61   
 62  LINE_WRAP = 1 
 63  """wrap line in order to fit to length""" 
 64   
 65   
66 -class JSONTreeException(Exception):
67 """Error in JSONTree.""" 68 pass
69 70
71 -class JSONTree(object):
72
73 - def __init__(self,**kargs):
74 """Create an object for the tree representation. 75 76 Args: 77 **kargs: Parameter specific for the operation, 78 79 scope: 80 81 * all: Display all diffs. 82 * first: Display first diff only. 83 84 default:=first 85 86 charset: 87 88 * raw: Use 'raw'. 89 * str: Use 'str'. 90 * utf: Use 'utf'. 91 92 default:=raw 93 94 debug: 95 96 Add developer information. 97 98 linefit: 99 100 * cut: Cut lines to length. 101 * wrap: Split lines to length. 102 103 default:=wrap 104 105 indent=#numchars: 106 107 Number of characters for indentation. 108 109 linewidth=#numchars: 110 111 Length of lines. 112 113 verbose: 114 115 Add progress and status dialogue output. 116 117 Returns: 118 When successful returns 'True', else raises an exception. 119 120 Raises: 121 passed through exceptions: 122 123 """ 124 self.verbose = False 125 self.debug = False 126 self.difflist = [] 127 128 self.scope = DIFF_ALL 129 self.linefit = LINE_WRAP 130 self.linewidth = 60 131 self.charset = CHARS_RAW 132 self.indent = 4 133 134 for k,v in kargs.items(): 135 if k in ("scope"): 136 if v in ('all', DIFF_ALL): 137 self.scope = DIFF_ALL 138 elif v in ('first', DIFF_FIRST): 139 self.scope = DIFF_FIRST 140 else: 141 self.scope = DIFF_FIRST 142 143 elif k in ("charset"): 144 if v in ('raw', CHARS_RAW): 145 self.charset = CHARS_RAW 146 elif v in ('str', CHARS_STR): 147 self.charset = CHARS_STR 148 elif v in ('utf', CHARS_UTF): 149 self.charset = CHARS_UTF 150 else: 151 self.charset = CHARS_RAW 152 153 elif k in ("linefit"): 154 if v in ('cut', LINE_CUT): 155 self.linefit = LINE_CUT 156 elif v in ('wrap', LINE_WRAP): 157 self.linefit = LINE_WRAP 158 else: 159 self.linefit = LINE_WRAP 160 161 elif k in ("indent"): 162 if type(v) is int: 163 self.indent = v 164 165 elif k in ("linewidth"): 166 if type(v) is int: 167 self.linewidth = v 168 169 elif k in ("verbose"): 170 self.verbose = True 171 172 elif k in ("debug"): 173 self.debug = True
174
175 - def printDiff(self):
176 """Prints out the resulting list of differences. 177 178 Args: 179 ffs. 180 181 Returns: 182 When successful returns tree represantation. 183 184 Raises: 185 passed through exceptions: 186 187 """ 188 ret="" 189 _i=" "*self.indent 190 w = self.linewidth 191 192 for d in self.difflist: 193 if w and self.linefit == LINE_CUT: 194 ret += "path="+str(d['p']) +"\n" 195 line = _i+"n0"+str(d['p'])+" = "+str(d['n0']) 196 ret += line[:w]+"\n" 197 line = _i+"n1"+str(d['p'])+" = "+str(d['n1']) 198 ret += line[:w]+"\n" 199 elif w and self.linefit == LINE_WRAP: 200 ret += "path="+str(d['p']) +"\n" 201 line = _i+"n0"+str(d['p'])+" = "+str(d['n0']) 202 while line: 203 ret += line[:w]+"\n" 204 line = line[w:] 205 if line: 206 ret += _i*2 207 line = _i+"n1"+str(d['p'])+" = "+str(d['n1']) 208 while line: 209 ret += line[:w]+"\n" 210 line = line[w:] 211 if line: 212 ret += _i*2 213 else: 214 ret += "path="+str(d['p']) +"\n" 215 ret += " n0"+str(d['p'])+" = "+str(d['n0'])+"\n" 216 ret += " n1"+str(d['p'])+" = "+str(d['n1'])+"\n" 217 218 return ret
219
220 - def fetchDiff(self,n0, n1, p=[], dl=0):
221 """Recursive tree compare for Python trees as used for the package 'json'. 222 223 Finds diff in native Python trees assembled by the standard package 'json' 224 and compatible, e.g. 'ujson'. 225 226 227 * leveltop 228 * levelbottom 229 * delta (for containers) 230 * scope(all, first) 231 * linewidth 232 * displaycharset (str,utf) 233 * pathonly 234 235 Args: 236 237 n0: 238 239 JSON string of type 'str', or 'unicode' 240 241 n1: 242 243 JSON string of type 'str', or 'unicode' 244 245 p=[]: 246 247 248 Result entries for each difference: 249 :: 250 251 {'n0':n0,'n1':n1,'dl':dl,'p':p[:]} 252 253 #. first JSON data 254 #. second JSON data 255 #. diff count increment value 256 #. current diff including path 257 258 List of differences as of: 259 260 #. non equal types are different: type(n0) != type(n1) 261 #. equal types, both list: type(n0) is list 262 263 #. length is different: len(n0.keys()) != len(n1.keys()) 264 #. at leats one item is different: n1.get(ni) and v != n1[ni] 265 266 #. equal types, both dict: type(n0) is dict and type(n1) is dict 267 268 #. length is different: len(n0.keys()) != len(n1.keys()) 269 #. at leats one item is different: n1.get(ni) and v != n1[ni] 270 271 default:=0 272 273 Returns: 274 When no diffs returns True, else False or raises an exception. 275 The resulting differences are contained in the provided 276 list parameter 'p'. When not provided the resulting list 277 is suppressed. 278 279 Raises: 280 passed through exceptions: 281 282 """ 283 ret = True 284 285 self.leveltop = -1 286 self.levelbottom = -1 287 self.delta = False 288 self.pathonly = False 289 290 291 # assure JSON strings 292 if type(n0) is str: 293 n0 = unicode(n0) 294 if type(n1) is str: 295 n1 = unicode(n1) 296 297 dl +=1 298 299 if type(n0) != type(n1): # non equal types are different 300 if self.verbose: 301 print 'type:'+str(type(n0))+' != '+str(type(n1)) 302 self.difflist.append({'n0':n0,'n1':n1,'dl':dl,'p':p[:]}) 303 ret &= False 304 305 elif type(n0) is list: # equal types, both list 306 if len(n0) != len(n1): 307 if self.verbose: 308 print 'len:'+str(len(n0))+' != '+str(len(n1)) 309 self.difflist.append({'n0':n0,'n1':n1,'dl':dl,'p':p[:]}) 310 ret &= False 311 else: 312 for ni in range(0,len(n0)): 313 if not p: 314 pni=[ni] 315 else: 316 pni=p[:] 317 pni.append(ni) 318 ret &= self.fetchDiff(n0[ni],n1[ni],pni,dl) 319 320 if self.scope == DIFF_FIRST: 321 if not ret: 322 break 323 324 elif type(n0) is dict: 325 326 if len(n0.keys()) != len(n1.keys()): 327 if self.verbose: 328 print 'len:'+str(len(n0.keys()))+' != '+str(len(n1.keys())) 329 self.difflist.append({'n0':n0,'n1':n1,'dl':dl,'p':p[:]}) 330 ret &= False 331 332 else: 333 for ni,v in n0.items(): 334 if not p: 335 pni=[ni] 336 else: 337 pni=p[:] 338 pni.append(ni) 339 if n1.get(ni) and v != n1[ni]: 340 if self.verbose: 341 print 'item('+str(ni)+'):'+str(v)+' != '+str(n1[ni]) 342 if type(v) in (list,dict): 343 ret &= self.fetchDiff(v,n1[ni],pni,dl) 344 else: 345 self.difflist.append({'ni':ni, 'n0':n0[ni],'n1':n1[ni],'dl':dl,'p':p[:]}) 346 ret &= False 347 348 if self.scope == DIFF_FIRST: 349 if not ret: 350 break 351 352 elif type(v) in (list,dict): 353 ret &= self.fetchDiff(v,n1[ni],pni,dl) 354 355 else: # invalid types may have been eliminated already 356 if n0 != n1: 357 self.difflist.append({'n0':n0,'n1':n1,'dl':dl,'p':p[:]}) 358 ret &= False 359 360 return ret
361