Package jsondata ::
Module JSONTree
|
|
1
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',):
23 raise Exception("Requires Python-2.6.* or higher")
24
25
26
27
28
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
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
67 """Error in JSONTree."""
68 pass
69
70
72
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
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
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
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):
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:
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:
356 if n0 != n1:
357 self.difflist.append({'n0':n0,'n1':n1,'dl':dl,'p':p[:]})
358 ret &= False
359
360 return ret
361