json-duplicate-keys 2024.4.20__tar.gz → 2024.7.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: json-duplicate-keys
3
- Version: 2024.4.20
3
+ Version: 2024.7.17
4
4
  Summary: Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys
5
5
  Home-page: https://github.com/truocphan/json-duplicate-keys
6
6
  Author: TP Cyber Security
@@ -388,6 +388,9 @@ Description: # JSON Duplicate Keys - PyPI
388
388
  ---
389
389
 
390
390
  ## CHANGELOG
391
+ #### [json-duplicate-keys v2024.7.17](https://github.com/truocphan/json-duplicate-keys/tree/2024.7.17)
392
+ - **Fixed**: issue [#3](https://github.com/truocphan/json-duplicate-keys/issues/3) break the set function when the key's value is empty. Thanks [ptth222](https://github.com/ptth222) for reporting this issue.
393
+
391
394
  #### [json-duplicate-keys v2024.4.20](https://github.com/truocphan/json-duplicate-keys/tree/2024.4.20)
392
395
  - **New**: _filter_values_
393
396
  - **Updated**: _filter_keys_
@@ -380,6 +380,9 @@ print(JDKSObject.getObject())
380
380
  ---
381
381
 
382
382
  ## CHANGELOG
383
+ #### [json-duplicate-keys v2024.7.17](https://github.com/truocphan/json-duplicate-keys/tree/2024.7.17)
384
+ - **Fixed**: issue [#3](https://github.com/truocphan/json-duplicate-keys/issues/3) break the set function when the key's value is empty. Thanks [ptth222](https://github.com/ptth222) for reporting this issue.
385
+
383
386
  #### [json-duplicate-keys v2024.4.20](https://github.com/truocphan/json-duplicate-keys/tree/2024.4.20)
384
387
  - **New**: _filter_values_
385
388
  - **Updated**: _filter_keys_
@@ -6,18 +6,21 @@ def normalize_key(name, dupSign_start="{{{", dupSign_end="}}}", _isDebug_=False)
6
6
 
7
7
  # User input data type validation
8
8
  if type(_isDebug_) != bool: _isDebug_ = False
9
+
9
10
  try:
10
- if type(name) not in [str, unicode]:
11
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
11
+ if type(name) not in [str, unicode]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
12
+
12
13
  if type(dupSign_start) not in [str, unicode]: dupSign_start = "{{{"
14
+
13
15
  if type(dupSign_end) not in [str, unicode]: dupSign_end = "}}}"
14
16
  except Exception as e:
15
- if type(name) not in [str]:
16
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
17
+ if type(name) not in [str]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
18
+
17
19
  if type(dupSign_start) not in [str]: dupSign_start = "{{{"
20
+
18
21
  if type(dupSign_end) not in [str]: dupSign_end = "}}}"
19
22
 
20
- return re.sub('{dupSign_start}_\d+_{dupSign_end}$'.format(dupSign_start=re.escape(dupSign_start), dupSign_end=re.escape(dupSign_end)), "", name)
23
+ return re.sub('{dupSign_start}_\\d+_{dupSign_end}$'.format(dupSign_start=re.escape(dupSign_start), dupSign_end=re.escape(dupSign_end)), "", name)
21
24
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
22
25
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
23
26
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -32,22 +35,26 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, _isD
32
35
 
33
36
  # User input data type validation
34
37
  if type(_isDebug_) != bool: _isDebug_ = False
38
+
35
39
  if type(ordered_dict) != bool: ordered_dict = False
40
+
36
41
  try:
37
- if type(Jstr) not in [str, unicode]:
38
- exit("\x1b[31m[-] DataTypeError: the JSON object must be str or unicode, not {}\x1b[0m".format(type(Jstr)))
42
+ if type(Jstr) not in [str, unicode]: exit("\x1b[31m[-] DataTypeError: the JSON object must be str or unicode, not {}\x1b[0m".format(type(Jstr)))
43
+
39
44
  if type(dupSign_start) not in [str, unicode]: dupSign_start = "{{{"
45
+
40
46
  if type(dupSign_end) not in [str, unicode]: dupSign_end = "}}}"
41
47
  except Exception as e:
42
- if type(Jstr) not in [str]:
43
- exit("\x1b[31m[-] DataTypeError: the JSON object must be str or unicode, not {}\x1b[0m".format(type(Jstr)))
48
+ if type(Jstr) not in [str]: exit("\x1b[31m[-] DataTypeError: the JSON object must be str or unicode, not {}\x1b[0m".format(type(Jstr)))
49
+
44
50
  if type(dupSign_start) not in [str]: dupSign_start = "{{{"
51
+
45
52
  if type(dupSign_end) not in [str]: dupSign_end = "}}}"
46
53
 
47
54
  def __convert_Jloads_to_Jobj(Jloads, Jobj):
48
55
  if type(Jloads) in [dict, OrderedDict]:
49
56
  for k in Jloads.keys():
50
- _key = re.split(dupSign_start_escape_regex+"_\d+_"+dupSign_end_escape_regex+"$", k)[0]
57
+ _key = re.split(dupSign_start_escape_regex+"_\\d+_"+dupSign_end_escape_regex+"$", k)[0]
51
58
 
52
59
  if _key not in Jobj.keys():
53
60
  if type(Jloads[k]) not in [list, dict, OrderedDict]:
@@ -62,7 +69,7 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, _isD
62
69
 
63
70
  __convert_Jloads_to_Jobj(Jloads[k], Jobj[_key])
64
71
  else:
65
- countObj = len([i for i in Jobj.keys() if _key==re.split(dupSign_start_escape_regex+"_\d+_"+dupSign_end_escape_regex+"$", i)[0]])
72
+ countObj = len([i for i in Jobj.keys() if _key==re.split(dupSign_start_escape_regex+"_\\d+_"+dupSign_end_escape_regex+"$", i)[0]])
66
73
  if type(Jloads[k]) not in [list, dict, OrderedDict]:
67
74
  Jobj[_key+dupSign_start+"_"+str(countObj+1)+"_"+dupSign_end] = Jloads[k]
68
75
  else:
@@ -90,8 +97,7 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, _isD
90
97
 
91
98
  try:
92
99
  Jloads = json.loads(Jstr)
93
- if ordered_dict:
94
- Jloads = json.loads(Jstr, object_pairs_hook=OrderedDict)
100
+ if ordered_dict: Jloads = json.loads(Jstr, object_pairs_hook=OrderedDict)
95
101
 
96
102
  if type(Jloads) in [list, dict, OrderedDict]:
97
103
  dupSign_start_escape = "".join(["\\\\u"+hex(ord(c))[2:].zfill(4) for c in dupSign_start])
@@ -189,40 +195,43 @@ class JSON_DUPLICATE_KEYS:
189
195
 
190
196
  # User input data type validation
191
197
  if type(_isDebug_) != bool: _isDebug_ = False
198
+
192
199
  try:
193
- if type(name) not in [str, unicode]:
194
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
200
+ if type(name) not in [str, unicode]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
201
+
195
202
  if type(separator) not in [str, unicode]: separator = "||"
203
+
196
204
  if type(parse_index) not in [str, unicode]: parse_index = "$"
197
205
  except Exception as e:
198
- if type(name) not in [str]:
199
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
206
+ if type(name) not in [str]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
207
+
200
208
  if type(separator) not in [str]: separator = "||"
209
+
201
210
  if type(parse_index) not in [str]: parse_index = "$"
202
211
 
203
- if type(self.getObject()) in [list, dict, OrderedDict]:
204
- try:
205
- Jobj = self.__Jobj
206
- Jval = "JSON_DUPLICATE_KEYS_ERROR"
207
- name_split = name.split(separator)
208
-
209
- for i in range(len(name_split)):
210
- if type(Jobj) in [dict, OrderedDict] and name_split[i] in Jobj.keys():
211
- Jval = Jobj[name_split[i]]
212
- Jobj = Jobj[name_split[i]]
213
- elif type(Jobj) in [list] and re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", name_split[i]):
214
- Jval = Jobj[int(name_split[i].split(parse_index)[1])]
215
- Jobj = Jobj[int(name_split[i].split(parse_index)[1])]
216
- else:
217
- if _isDebug_: print("\x1b[31m[-] KeyNotFoundError: \x1b[0m"+separator.join(name_split[:i+1]))
218
- return "JSON_DUPLICATE_KEYS_ERROR"
219
- return Jval
220
- except Exception as e:
221
- if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
222
- return "JSON_DUPLICATE_KEYS_ERROR"
223
- else:
212
+ if type(self.getObject()) not in [list, dict, OrderedDict]:
224
213
  if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
225
214
  return "JSON_DUPLICATE_KEYS_ERROR"
215
+
216
+ try:
217
+ Jobj = self.__Jobj
218
+ Jval = "JSON_DUPLICATE_KEYS_ERROR"
219
+ name_split = name.split(separator)
220
+
221
+ for i in range(len(name_split)):
222
+ if type(Jobj) in [dict, OrderedDict] and name_split[i] in Jobj.keys():
223
+ Jval = Jobj[name_split[i]]
224
+ Jobj = Jobj[name_split[i]]
225
+ elif type(Jobj) in [list] and re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", name_split[i]):
226
+ Jval = Jobj[int(name_split[i].split(parse_index)[1])]
227
+ Jobj = Jobj[int(name_split[i].split(parse_index)[1])]
228
+ else:
229
+ if _isDebug_: print("\x1b[31m[-] KeyNotFoundError: \x1b[0m"+separator.join(name_split[:i+1]))
230
+ return "JSON_DUPLICATE_KEYS_ERROR"
231
+ return Jval
232
+ except Exception as e:
233
+ if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
234
+ return "JSON_DUPLICATE_KEYS_ERROR"
226
235
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
227
236
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
228
237
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -237,125 +246,145 @@ class JSON_DUPLICATE_KEYS:
237
246
 
238
247
  # User input data type validation
239
248
  if type(_isDebug_) != bool: _isDebug_ = False
249
+
240
250
  if type(ordered_dict) != bool: ordered_dict = False
251
+
241
252
  try:
242
- if type(name) not in [str, unicode]:
243
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
253
+ if type(name) not in [str, unicode]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
254
+
244
255
  if type(separator) not in [str, unicode]: separator = "||"
256
+
245
257
  if type(parse_index) not in [str, unicode]: parse_index = "$"
258
+
246
259
  if type(dupSign_start) not in [str, unicode]: dupSign_start = "{{{"
260
+
247
261
  if type(dupSign_end) not in [str, unicode]: dupSign_end = "}}}"
248
262
  except Exception as e:
249
- if type(name) not in [str]:
250
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
263
+ if type(name) not in [str]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
264
+
251
265
  if type(separator) not in [str]: separator = "||"
266
+
252
267
  if type(parse_index) not in [str]: parse_index = "$"
268
+
253
269
  if type(dupSign_start) not in [str]: dupSign_start = "{{{"
254
- if type(dupSign_end) not in [str]: dupSign_end = "}}}"
255
270
 
256
- if type(self.getObject()) in [list, dict, OrderedDict]:
257
- try:
258
- name_split = name.split(separator)
259
- name_split_first = name_split[:-1]
260
- name_split_lastKey = name_split[-1]
261
-
262
- if not re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", name_split_lastKey):
263
- """
264
- name = name_split_first||name_split_lastKey
265
-
266
- if "name" exist in "self.getObject()"
267
- => Add duplicate key
268
- else if "name_split_first" exist in "self.getObject()"
269
- if typeof "name_split_first" is list
270
- if length of "name_split_lastKey" is 0
271
- => Add new key (append "value" to "name_split_first")
272
- else
273
- => Add new key (append dict "name_split_lastKey"/"value" to "name_split_first")
274
- else if typeof "name_split_first" is dict
275
- => Add new key ( name_split_first[name_split_lastKey] = value )
276
- else if length of "name_split_first" is 0 => Add new key
277
- if typeof self.getObject() is list
278
- if length of "name_split_lastKey" is 0
279
- => Add new key (append "value" to self.__Jobj)
280
- else
281
- => Add new key (append dict "name_split_lastKey"/"value" to self.__Jobj)
282
- else if typeof self.getObject() is dict
283
- => Add new key ( self.__Jobj[name_split_lastKey] = value )
284
- """
285
- # Add duplicate key
286
- if self.get(separator.join(name_split), separator=separator, parse_index=parse_index) != "JSON_DUPLICATE_KEYS_ERROR":
287
- index = 2
288
- while True:
289
- if self.get(separator.join(name_split)+dupSign_start+"_"+str(index)+"_"+dupSign_end, separator=separator, parse_index=parse_index) == "JSON_DUPLICATE_KEYS_ERROR":
290
- break
291
- index += 1
271
+ if type(dupSign_end) not in [str]: dupSign_end = "}}}"
292
272
 
293
- exec_expression = "self.getObject()"
273
+ if type(self.getObject()) not in [list, dict, OrderedDict]:
274
+ if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
275
+ return False
294
276
 
295
- name_split[-1] = name_split[-1]+dupSign_start+"_"+str(index)+"_"+dupSign_end
296
- for k in name_split:
297
- if re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", k):
298
- exec_expression += "["+k.split(parse_index)[1]+"]"
299
- else:
300
- exec_expression += "["+repr(k)+"]"
277
+ try:
278
+ name_split = name.split(separator)
279
+ name_split_first = name_split[:-1]
280
+ name_split_lastKey = name_split[-1]
281
+
282
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", name_split_lastKey):
283
+ if _isDebug_: print("\x1b[31m[-] KeyNameInvalidError: The key name does not end with the list index\x1b[0m")
284
+ return False
285
+
286
+ """
287
+ name = name_split_first||name_split_lastKey
288
+
289
+ if "name" exist in "self.getObject()"
290
+ => Add duplicate key
291
+ else if "name_split_first" exist in "self.getObject()"
292
+ if typeof "name_split_first" is list
293
+ if length of "name_split_lastKey" is 0
294
+ => Add new key (append "value" to "name_split_first")
295
+ else
296
+ => Add new key (append dict "name_split_lastKey"/"value" to "name_split_first")
297
+ else if typeof "name_split_first" is dict
298
+ => Add new key ( name_split_first[name_split_lastKey] = value )
299
+ else if length of "name_split_first" is 0 => Add new key
300
+ if typeof self.getObject() is list
301
+ if length of "name_split_lastKey" is 0
302
+ => Add new key (append "value" to self.__Jobj)
303
+ else
304
+ => Add new key (append dict "name_split_lastKey"/"value" to self.__Jobj)
305
+ else if typeof self.getObject() is dict
306
+ => Add new key ( self.__Jobj[name_split_lastKey] = value )
307
+ """
308
+ # Add duplicate key
309
+ if self.get(separator.join(name_split), separator=separator, parse_index=parse_index) != "JSON_DUPLICATE_KEYS_ERROR":
310
+ index = 2
311
+ while True:
312
+ if self.get(separator.join(name_split)+dupSign_start+"_"+str(index)+"_"+dupSign_end, separator=separator, parse_index=parse_index) == "JSON_DUPLICATE_KEYS_ERROR":
313
+ break
314
+ index += 1
301
315
 
302
- exec(exec_expression+"="+repr(value))
303
- return True
304
- # Add new key
305
- elif self.get(separator.join(name_split_first), separator=separator, parse_index=parse_index) != "JSON_DUPLICATE_KEYS_ERROR":
306
- if type(self.get(separator.join(name_split_first), separator=separator, parse_index=parse_index)) == list:
307
- if name_split_lastKey == "":
308
- exec_expression = "self.getObject()"
309
-
310
- for k in name_split_first:
311
- if re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", k):
312
- exec_expression += "["+k.split(parse_index)[1]+"]"
313
- else:
314
- exec_expression += "["+repr(k)+"]"
315
-
316
- exec(exec_expression+".append("+repr(value)+")")
317
- else:
318
- exec_expression = "self.getObject()"
316
+ exec_expression = "self.getObject()"
319
317
 
320
- for k in name_split_first:
321
- if re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", k):
322
- exec_expression += "["+k.split(parse_index)[1]+"]"
323
- else:
324
- exec_expression += "["+repr(k)+"]"
318
+ name_split[-1] = name_split[-1]+dupSign_start+"_"+str(index)+"_"+dupSign_end
319
+ for k in name_split:
320
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", k):
321
+ exec_expression += "["+k.split(parse_index)[1]+"]"
322
+ else:
323
+ exec_expression += "["+repr(k)+"]"
325
324
 
326
- exec(exec_expression+".append({"+repr(name_split_lastKey)+":"+repr(value)+"})")
327
- return True
328
- elif type(self.get(separator.join(name_split_first), separator=separator, parse_index=parse_index)) == dict:
325
+ exec(exec_expression+"="+repr(value))
326
+ return True
327
+ # Add new key
328
+ elif self.get(separator.join(name_split_first), separator=separator, parse_index=parse_index) != "JSON_DUPLICATE_KEYS_ERROR":
329
+ if len(name_split_first) > 0:
330
+ if type(self.get(separator.join(name_split_first), separator=separator, parse_index=parse_index)) == list:
331
+ if name_split_lastKey == "":
329
332
  exec_expression = "self.getObject()"
330
333
 
331
334
  for k in name_split_first:
332
- if re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", k):
335
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", k):
333
336
  exec_expression += "["+k.split(parse_index)[1]+"]"
334
337
  else:
335
338
  exec_expression += "["+repr(k)+"]"
336
339
 
337
- exec(exec_expression+"["+repr(name_split_lastKey)+"]="+repr(value))
338
- return True
340
+ exec(exec_expression+".append("+repr(value)+")")
339
341
  else:
340
- if _isDebug_: print("\x1b[31m[-] KeyNameNotExistError: {}\x1b[0m".format(separator.join(name_split_first)))
341
- # Add new key
342
- elif len(name_split_first) == 0:
343
- if type(self.getObject()) == list:
344
- if name_split_lastKey == "":
345
- self.__Jobj.append(value)
342
+ exec_expression = "self.getObject()"
343
+
344
+ for k in name_split_first:
345
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", k):
346
+ exec_expression += "["+k.split(parse_index)[1]+"]"
347
+ else:
348
+ exec_expression += "["+repr(k)+"]"
349
+
350
+ exec(exec_expression+".append({"+repr(name_split_lastKey)+":"+repr(value)+"})")
351
+ return True
352
+ elif type(self.get(separator.join(name_split_first), separator=separator, parse_index=parse_index)) == dict:
353
+ exec_expression = "self.getObject()"
354
+
355
+ for k in name_split_first:
356
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", k):
357
+ exec_expression += "["+k.split(parse_index)[1]+"]"
346
358
  else:
347
- self.__Jobj.append({name_split_lastKey: value})
348
- else:
349
- self.__Jobj[name_split_lastKey] = value
359
+ exec_expression += "["+repr(k)+"]"
360
+
361
+ exec(exec_expression+"["+repr(name_split_lastKey)+"]="+repr(value))
350
362
  return True
351
363
  else:
352
- if _isDebug_: print("\x1b[31m[-] KeyNameInvalidError: {}\x1b[0m".format(separator.join(name_split_first)))
364
+ if _isDebug_: print("\x1b[31m[-] KeyNameNotExistError: {}\x1b[0m".format(separator.join(name_split_first)))
353
365
  else:
354
- if _isDebug_: print("\x1b[31m[-] KeyNameInvalidError: The key name does not end with the list index\x1b[0m")
355
- except Exception as e:
356
- if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
357
- else:
358
- if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
366
+ if type(self.getObject()) == list:
367
+ if name_split_lastKey == "":
368
+ self.__Jobj.append(value)
369
+ else:
370
+ self.__Jobj.append({name_split_lastKey: value})
371
+ else:
372
+ self.__Jobj[name_split_lastKey] = value
373
+ return True
374
+ # Add new key
375
+ elif len(name_split_first) == 0:
376
+ if type(self.getObject()) == list:
377
+ if name_split_lastKey == "":
378
+ self.__Jobj.append(value)
379
+ else:
380
+ self.__Jobj.append({name_split_lastKey: value})
381
+ else:
382
+ self.__Jobj[name_split_lastKey] = value
383
+ return True
384
+ else:
385
+ if _isDebug_: print("\x1b[31m[-] KeyNameInvalidError: {}\x1b[0m".format(separator.join(name_split_first)))
386
+ except Exception as e:
387
+ if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
359
388
 
360
389
  return False
361
390
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -371,15 +400,18 @@ class JSON_DUPLICATE_KEYS:
371
400
 
372
401
  # User input data type validation
373
402
  if type(_isDebug_) != bool: _isDebug_ = False
403
+
374
404
  try:
375
- if type(name) not in [str, unicode]:
376
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
405
+ if type(name) not in [str, unicode]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
406
+
377
407
  if type(separator) not in [str, unicode]: separator = "||"
408
+
378
409
  if type(parse_index) not in [str, unicode]: parse_index = "$"
379
410
  except Exception as e:
380
- if type(name) not in [str]:
381
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
411
+ if type(name) not in [str]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
412
+
382
413
  if type(separator) not in [str]: separator = "||"
414
+
383
415
  if type(parse_index) not in [str]: parse_index = "$"
384
416
 
385
417
  if self.get(name, separator=separator, parse_index=parse_index, _isDebug_=_isDebug_) != "JSON_DUPLICATE_KEYS_ERROR":
@@ -387,7 +419,7 @@ class JSON_DUPLICATE_KEYS:
387
419
  exec_expression = "self.getObject()"
388
420
 
389
421
  for k in name.split(separator):
390
- if re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", k):
422
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", k):
391
423
  exec_expression += "["+k.split(parse_index)[1]+"]"
392
424
  else:
393
425
  exec_expression += "["+repr(k)+"]"
@@ -413,14 +445,16 @@ class JSON_DUPLICATE_KEYS:
413
445
  if type(_isDebug_) != bool: _isDebug_ = False
414
446
 
415
447
  try:
416
- if type(name) not in [str, unicode]:
417
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
448
+ if type(name) not in [str, unicode]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
449
+
418
450
  if type(separator) not in [str, unicode]: separator = "||"
451
+
419
452
  if type(parse_index) not in [str, unicode]: parse_index = "$"
420
453
  except Exception as e:
421
- if type(name) not in [str]:
422
- exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
454
+ if type(name) not in [str]: exit("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
455
+
423
456
  if type(separator) not in [str]: separator = "||"
457
+
424
458
  if type(parse_index) not in [str]: parse_index = "$"
425
459
 
426
460
  if self.get(name, separator=separator, parse_index=parse_index, _isDebug_=_isDebug_) != "JSON_DUPLICATE_KEYS_ERROR":
@@ -428,7 +462,7 @@ class JSON_DUPLICATE_KEYS:
428
462
  exec_expression = "del self.getObject()"
429
463
 
430
464
  for k in name.split(separator):
431
- if re.search("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$", k):
465
+ if re.search("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$", k):
432
466
  exec_expression += "["+k.split(parse_index)[1]+"]"
433
467
  else:
434
468
  exec_expression += "["+repr(k)+"]"
@@ -501,22 +535,25 @@ class JSON_DUPLICATE_KEYS:
501
535
 
502
536
  # User input data type validation
503
537
  if type(_isDebug_) != bool: _isDebug_ = False
538
+
504
539
  try:
505
540
  if type(dupSign_start) not in [str, unicode]: dupSign_start = "{{{"
541
+
506
542
  if type(dupSign_end) not in [str, unicode]: dupSign_end = "}}}"
507
543
  except Exception as e:
508
544
  if type(dupSign_start) not in [str]: dupSign_start = "{{{"
509
- if type(dupSign_end) not in [str]: dupSign_end = "}}}"
510
-
511
- if type(self.getObject()) in [list, dict, OrderedDict]:
512
- dupSign_start_escape_regex = re.escape(json.dumps({dupSign_start:""})[2:-6])
513
545
 
514
- dupSign_end_escape_regex = re.escape(json.dumps({dupSign_end:""})[2:-6])
546
+ if type(dupSign_end) not in [str]: dupSign_end = "}}}"
515
547
 
516
- return re.sub(r'{dupSign_start}_\d+_{dupSign_end}":'.format(dupSign_start=dupSign_start_escape_regex, dupSign_end=dupSign_end_escape_regex), '":', json.dumps(self.getObject(), skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, allow_nan=allow_nan, cls=cls, indent=indent, separators=separators, default=default, sort_keys=sort_keys))
517
- else:
548
+ if type(self.getObject()) not in [list, dict, OrderedDict]:
518
549
  if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
519
550
  return "JSON_DUPLICATE_KEYS_ERROR"
551
+
552
+ dupSign_start_escape_regex = re.escape(json.dumps({dupSign_start:""})[2:-6])
553
+
554
+ dupSign_end_escape_regex = re.escape(json.dumps({dupSign_end:""})[2:-6])
555
+
556
+ return re.sub(r'{dupSign_start}_\\d+_{dupSign_end}":'.format(dupSign_start=dupSign_start_escape_regex, dupSign_end=dupSign_end_escape_regex), '":', json.dumps(self.getObject(), skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, allow_nan=allow_nan, cls=cls, indent=indent, separators=separators, default=default, sort_keys=sort_keys))
520
557
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
521
558
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
522
559
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -547,52 +584,57 @@ class JSON_DUPLICATE_KEYS:
547
584
 
548
585
  # User input data type validation
549
586
  if type(_isDebug_) != bool: _isDebug_ = False
587
+
550
588
  if type(ordered_dict) != bool: ordered_dict = False
589
+
551
590
  try:
552
591
  if type(separator) not in [str, unicode]: separator = "||"
592
+
553
593
  if type(parse_index) not in [str, unicode]: parse_index = "$"
554
594
  except Exception as e:
555
595
  if type(separator) not in [str]: separator = "||"
596
+
556
597
  if type(parse_index) not in [str]: parse_index = "$"
557
598
 
558
- if type(self.getObject()) in [list, dict, OrderedDict]:
559
- if len(self.getObject()) > 0:
560
- try:
561
- Jflat = dict()
562
- if ordered_dict:
563
- Jflat = OrderedDict()
564
-
565
- def __convert_Jobj_to_Jflat(Jobj, key=None):
566
- if type(Jobj) in [dict, OrderedDict]:
567
- if len(Jobj) == 0:
568
- Jflat[key] = dict()
569
- if ordered_dict:
570
- Jflat[key] = OrderedDict()
571
- else:
572
- for k,v in Jobj.items():
573
- _Jobj = v
574
- _key = "{key}{separator}{k}".format(key=key,separator=separator,k=k) if key != None else "{k}".format(k=k)
575
-
576
- __convert_Jobj_to_Jflat(_Jobj, _key)
577
- elif type(Jobj) == list:
578
- if len(Jobj) == 0:
579
- Jflat[key] = list()
580
- else:
581
- for i,v in enumerate(Jobj):
582
- _Jobj = v
583
- _key = "{key}{separator}{parse_index}{i}{parse_index}".format(key=key, separator=separator, parse_index=parse_index, i=i) if key != None else "{parse_index}{i}{parse_index}".format(parse_index=parse_index, i=i)
599
+ if type(self.getObject()) not in [list, dict, OrderedDict]:
600
+ if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
601
+ exit()
584
602
 
585
- __convert_Jobj_to_Jflat(_Jobj, _key)
603
+ if len(self.getObject()) > 0:
604
+ try:
605
+ Jflat = dict()
606
+ if ordered_dict:
607
+ Jflat = OrderedDict()
608
+
609
+ def __convert_Jobj_to_Jflat(Jobj, key=None):
610
+ if type(Jobj) in [dict, OrderedDict]:
611
+ if len(Jobj) == 0:
612
+ Jflat[key] = dict()
613
+ if ordered_dict:
614
+ Jflat[key] = OrderedDict()
586
615
  else:
587
- Jflat[key] = Jobj
616
+ for k,v in Jobj.items():
617
+ _Jobj = v
618
+ _key = "{key}{separator}{k}".format(key=key,separator=separator,k=k) if key != None else "{k}".format(k=k)
619
+
620
+ __convert_Jobj_to_Jflat(_Jobj, _key)
621
+ elif type(Jobj) == list:
622
+ if len(Jobj) == 0:
623
+ Jflat[key] = list()
624
+ else:
625
+ for i,v in enumerate(Jobj):
626
+ _Jobj = v
627
+ _key = "{key}{separator}{parse_index}{i}{parse_index}".format(key=key, separator=separator, parse_index=parse_index, i=i) if key != None else "{parse_index}{i}{parse_index}".format(parse_index=parse_index, i=i)
588
628
 
589
- __convert_Jobj_to_Jflat(self.getObject())
629
+ __convert_Jobj_to_Jflat(_Jobj, _key)
630
+ else:
631
+ Jflat[key] = Jobj
590
632
 
591
- self.__Jobj = Jflat
592
- except Exception as e:
593
- if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
594
- else:
595
- if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
633
+ __convert_Jobj_to_Jflat(self.getObject())
634
+
635
+ self.__Jobj = Jflat
636
+ except Exception as e:
637
+ if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
596
638
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
597
639
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
598
640
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -607,42 +649,47 @@ class JSON_DUPLICATE_KEYS:
607
649
 
608
650
  # User input data type validation
609
651
  if type(_isDebug_) != bool: _isDebug_ = False
652
+
610
653
  if type(ordered_dict) != bool: ordered_dict = False
654
+
611
655
  try:
612
656
  if type(separator) not in [str, unicode]: separator = "||"
657
+
613
658
  if type(parse_index) not in [str, unicode]: parse_index = "$"
614
659
  except Exception as e:
615
660
  if type(separator) not in [str]: separator = "||"
661
+
616
662
  if type(parse_index) not in [str]: parse_index = "$"
617
663
 
618
- if type(self.getObject()) in [dict, OrderedDict]:
619
- if len(self.getObject()) > 0:
620
- try:
621
- Jobj = list() if len([k for k in self.__Jobj.keys() if re.compile("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$").match(str(k).split(separator)[0])]) == len(self.__Jobj.keys()) else OrderedDict() if ordered_dict else dict()
664
+ if type(self.getObject()) not in [dict, OrderedDict]:
665
+ if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
666
+ exit()
622
667
 
623
- for k, v in self.__Jobj.items():
624
- Jtmp = Jobj
625
- Jkeys = k.split(separator)
668
+ if len(self.getObject()) > 0:
669
+ try:
670
+ Jobj = list() if len([k for k in self.__Jobj.keys() if re.compile("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$").match(str(k).split(separator)[0])]) == len(self.__Jobj.keys()) else OrderedDict() if ordered_dict else dict()
626
671
 
627
- for count, (Jkey, next_Jkeys) in enumerate(zip(Jkeys, Jkeys[1:] + [v]), 1):
628
- v = next_Jkeys if count == len(Jkeys) else list() if re.compile("^"+re.escape(parse_index)+"\d+"+re.escape(parse_index)+"$").match(next_Jkeys) else OrderedDict() if ordered_dict else dict()
672
+ for k, v in self.__Jobj.items():
673
+ Jtmp = Jobj
674
+ Jkeys = k.split(separator)
629
675
 
630
- if type(Jtmp) == list:
631
- Jkey = int(re.compile(re.escape(parse_index)+"(\d+)"+re.escape(parse_index)).match(Jkey).group(1))
676
+ for count, (Jkey, next_Jkeys) in enumerate(zip(Jkeys, Jkeys[1:] + [v]), 1):
677
+ v = next_Jkeys if count == len(Jkeys) else list() if re.compile("^"+re.escape(parse_index)+"\\d+"+re.escape(parse_index)+"$").match(next_Jkeys) else OrderedDict() if ordered_dict else dict()
632
678
 
633
- while Jkey >= len(Jtmp):
634
- Jtmp.append(v)
679
+ if type(Jtmp) == list:
680
+ Jkey = int(re.compile(re.escape(parse_index)+"(\\d+)"+re.escape(parse_index)).match(Jkey).group(1))
635
681
 
636
- elif Jkey not in Jtmp:
637
- Jtmp[Jkey] = v
682
+ while Jkey >= len(Jtmp):
683
+ Jtmp.append(v)
638
684
 
639
- Jtmp = Jtmp[Jkey]
685
+ elif Jkey not in Jtmp:
686
+ Jtmp[Jkey] = v
640
687
 
641
- self.__Jobj = Jobj
642
- except Exception as e:
643
- if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
644
- else:
645
- if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
688
+ Jtmp = Jtmp[Jkey]
689
+
690
+ self.__Jobj = Jobj
691
+ except Exception as e:
692
+ if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
646
693
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
647
694
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
648
695
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: json-duplicate-keys
3
- Version: 2024.4.20
3
+ Version: 2024.7.17
4
4
  Summary: Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys
5
5
  Home-page: https://github.com/truocphan/json-duplicate-keys
6
6
  Author: TP Cyber Security
@@ -388,6 +388,9 @@ Description: # JSON Duplicate Keys - PyPI
388
388
  ---
389
389
 
390
390
  ## CHANGELOG
391
+ #### [json-duplicate-keys v2024.7.17](https://github.com/truocphan/json-duplicate-keys/tree/2024.7.17)
392
+ - **Fixed**: issue [#3](https://github.com/truocphan/json-duplicate-keys/issues/3) break the set function when the key's value is empty. Thanks [ptth222](https://github.com/ptth222) for reporting this issue.
393
+
391
394
  #### [json-duplicate-keys v2024.4.20](https://github.com/truocphan/json-duplicate-keys/tree/2024.4.20)
392
395
  - **New**: _filter_values_
393
396
  - **Updated**: _filter_keys_
@@ -2,7 +2,7 @@ import setuptools
2
2
 
3
3
  setuptools.setup(
4
4
  name="json-duplicate-keys",
5
- version="2024.4.20",
5
+ version="2024.7.17",
6
6
  author="TP Cyber Security",
7
7
  license="MIT",
8
8
  author_email="tpcybersec2023@gmail.com",