json-duplicate-keys 2025.7.1__py3-none-any.whl → 2025.9.9__py3-none-any.whl

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,10 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
- json_duplicate_keys_VERSION = "2025.7.1"
3
-
4
2
  try:
5
- unicode # Python 2
3
+ unicode
6
4
  except NameError:
7
- unicode = str # Python 3
5
+ unicode = str
8
6
 
9
7
  from collections import OrderedDict
10
8
  import json, re, copy
@@ -24,7 +22,7 @@ def normalize_key(name, dupSign_start="{{{", dupSign_end="}}}", _isDebug_=False)
24
22
 
25
23
  if type(dupSign_end) not in [str, unicode]: dupSign_end = "}}}"
26
24
 
27
- return re.sub('{dupSign_start}_\\d+_{dupSign_end}$'.format(dupSign_start=re.escape(dupSign_start), dupSign_end=re.escape(dupSign_end)), "", name)
25
+ return re.sub(re.escape(dupSign_start)+'_\\d+_'+re.escape(dupSign_end)+'$', "", name)
28
26
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
29
27
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
30
28
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -118,13 +116,13 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skip
118
116
  Jstr = re.sub(r'"([^"]*)"[\s\t\r\n]*([,\]}])'.encode(), '\x04\x05\\1\x04\x05\\2'.encode(), Jstr)
119
117
 
120
118
 
121
- Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:'.encode(), r'"\1{dupSign_start}_dupSign_{dupSign_end}":'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape).encode(), Jstr)
119
+ Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:'.encode(), (r'"\1'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":').encode(), Jstr)
122
120
 
123
- Jstr = re.sub(r'""[\s\t\r\n]*:'.encode(), '"{dupSign_start}_dupSign_{dupSign_end}":'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape).encode(), Jstr)
121
+ Jstr = re.sub(r'""[\s\t\r\n]*:'.encode(), ('"'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":').encode(), Jstr)
124
122
 
125
123
  i = 0
126
- while re.search(r'{dupSign_start}_dupSign_{dupSign_end}"[\s\t\r\n]*:'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape).encode(), Jstr):
127
- Jstr = re.sub(r'{dupSign_start}_dupSign_{dupSign_end}"[\s\t\r\n]*:'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape).encode(), (dupSign_start_escape+"_"+str(i)+"_"+dupSign_end_escape+'":').encode(), Jstr, 1)
124
+ while re.search((dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:').encode(), Jstr):
125
+ Jstr = re.sub((dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:').encode(), (dupSign_start_escape+"_"+str(i)+"_"+dupSign_end_escape+'":').encode(), Jstr, 1)
128
126
  i += 1
129
127
 
130
128
  Jstr = re.sub('\x00\x01'.encode(), r'\\\\'.encode(), Jstr)
@@ -135,13 +133,13 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skip
135
133
  Jstr = re.sub(r'\\"', '\x02\x03', Jstr)
136
134
  Jstr = re.sub(r'"([^"]*)"[\s\t\r\n]*([,\]}])', '\x04\x05\\1\x04\x05\\2', Jstr)
137
135
 
138
- Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:', r'"\1{dupSign_start}_dupSign_{dupSign_end}":'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape), Jstr)
136
+ Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:', r'"\1'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":', Jstr)
139
137
 
140
- Jstr = re.sub(r'""[\s\t\r\n]*:', '"{dupSign_start}_dupSign_{dupSign_end}":'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape), Jstr)
138
+ Jstr = re.sub(r'""[\s\t\r\n]*:', '"'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":', Jstr)
141
139
 
142
140
  i = 0
143
- while re.search(r'{dupSign_start}_dupSign_{dupSign_end}"[\s\t\r\n]*:'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape), Jstr):
144
- Jstr = re.sub(r'{dupSign_start}_dupSign_{dupSign_end}"[\s\t\r\n]*:'.format(dupSign_start=dupSign_start_escape, dupSign_end=dupSign_end_escape), dupSign_start_escape+"_"+str(i)+"_"+dupSign_end_escape+'":', Jstr, 1)
141
+ while re.search(dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:', Jstr):
142
+ Jstr = re.sub(dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:', dupSign_start_escape+"_"+str(i)+"_"+dupSign_end_escape+'":', Jstr, 1)
145
143
  i += 1
146
144
 
147
145
  Jstr = re.sub('\x00\x01', r'\\\\', Jstr)
@@ -178,11 +176,15 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skip
178
176
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
179
177
  def load(Jfilepath, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skipDuplicated=False, _isDebug_=False):
180
178
  try:
181
- with open(Jfilepath) as Jfile: Jstr = Jfile.read()
182
- except Exception as e:
183
- with open(Jfilepath, "rb") as Jfile: Jstr = Jfile.read()
179
+ try:
180
+ with open(Jfilepath) as Jfile: Jstr = Jfile.read()
181
+ except Exception as e:
182
+ with open(Jfilepath, "rb") as Jfile: Jstr = Jfile.read()
184
183
 
185
- return loads(Jstr, dupSign_start=dupSign_start, dupSign_end=dupSign_end, ordered_dict=ordered_dict, skipDuplicated=skipDuplicated, _isDebug_=_isDebug_)
184
+ return loads(Jstr, dupSign_start=dupSign_start, dupSign_end=dupSign_end, ordered_dict=ordered_dict, skipDuplicated=skipDuplicated, _isDebug_=_isDebug_)
185
+ except Exception as e:
186
+ if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
187
+ return False
186
188
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
187
189
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
188
190
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -360,8 +362,8 @@ class JSON_DUPLICATE_KEYS:
360
362
  # User input data type validation
361
363
  if type(_isDebug_) != bool: _isDebug_ = False
362
364
 
363
- if type(name) not in [str, unicode]:
364
- if _isDebug_: print("\x1b[31m[-] DataTypeError: the KEY name must be str or unicode, not {}\x1b[0m".format(type(name)))
365
+ if type(name) not in [str, unicode, type(None)]:
366
+ if _isDebug_: print("\x1b[31m[-] DataTypeError: the KEY name must be str, unicode or None, not {}\x1b[0m".format(type(name)))
365
367
  return False
366
368
 
367
369
  if type(position) != int: position = None
@@ -379,6 +381,12 @@ class JSON_DUPLICATE_KEYS:
379
381
  if type(self.getObject()) not in [list, dict, OrderedDict]:
380
382
  if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
381
383
  return False
384
+
385
+ if (name is None or name == "") and type(self.getObject()) == list:
386
+ if position is None: position = len(self.getObject())
387
+
388
+ self.getObject().insert(position, value)
389
+ return True
382
390
 
383
391
  if re.search(re.escape(separator)+"$", name):
384
392
  if _isDebug_: print("\x1b[31m[-] KeyNameInvalidError: \x1b[0m"+name)
@@ -492,10 +500,10 @@ class JSON_DUPLICATE_KEYS:
492
500
  for k, v in JDKSObject.getObject().items():
493
501
  if type(k) == str and type(name) == str:
494
502
  if re.search(name, k):
495
- newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
503
+ newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
496
504
  else:
497
505
  if name == k:
498
- newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
506
+ newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
499
507
 
500
508
  return newJDKSObject
501
509
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -514,10 +522,10 @@ class JSON_DUPLICATE_KEYS:
514
522
  for k, v in JDKSObject.getObject().items():
515
523
  if type(v) == str and type(value) == str:
516
524
  if re.search(value, v):
517
- newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
525
+ newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
518
526
  else:
519
527
  if value == v:
520
- newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
528
+ newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
521
529
 
522
530
  return newJDKSObject
523
531
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -544,7 +552,7 @@ class JSON_DUPLICATE_KEYS:
544
552
 
545
553
  dupSign_end_escape_regex = re.escape(json.dumps({dupSign_end:""})[2:-6])
546
554
 
547
- return re.sub('{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))
555
+ return re.sub(dupSign_start_escape_regex+'_\\d+_'+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))
548
556
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
549
557
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
550
558
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -557,8 +565,8 @@ class JSON_DUPLICATE_KEYS:
557
565
  Jstr = self.dumps(dupSign_start=dupSign_start, dupSign_end=dupSign_end, _isDebug_=_isDebug_, 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)
558
566
 
559
567
  try:
560
- Jfile = open(Jfilepath, "w")
561
- Jfile.write(Jstr)
568
+ Jfile = open(Jfilepath, "wb")
569
+ Jfile.write(Jstr.encode("utf-8"))
562
570
  Jfile.close()
563
571
  except Exception as e:
564
572
  if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
@@ -600,7 +608,7 @@ class JSON_DUPLICATE_KEYS:
600
608
  else:
601
609
  for k,v in Jobj.items():
602
610
  _Jobj = v
603
- _key = "{key}{separator}{k}".format(key=key,separator=separator,k=k) if key != None else "{k}".format(k=k)
611
+ _key = key+separator+k if key != None else k
604
612
 
605
613
  __convert_Jobj_to_Jflat(_Jobj, _key)
606
614
  elif type(Jobj) == list:
@@ -609,7 +617,7 @@ class JSON_DUPLICATE_KEYS:
609
617
  else:
610
618
  for i,v in enumerate(Jobj):
611
619
  _Jobj = v
612
- _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)
620
+ _key = key+separator+parse_index+str(i)+parse_index if key != None else parse_index+str(i)+parse_index
613
621
 
614
622
  __convert_Jobj_to_Jflat(_Jobj, _key)
615
623
  else:
@@ -1,47 +1,48 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: json-duplicate-keys
3
- Version: 2025.7.1
3
+ Version: 2025.9.9
4
4
  Summary: Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys
5
- Home-page: https://github.com/truocphan/json-duplicate-keys
6
- Author: TP Cyber Security
7
- Author-email: tpcybersec2023@gmail.com
5
+ Author-email: TP Cyber Security <tpcybersec2023@gmail.com>
8
6
  License: MIT
7
+ Project-URL: Homepage, https://github.com/TPCyberSec/json-duplicate-keys
9
8
  Keywords: TPCyberSec,json,duplicate keys,json duplicate keys,flatten,unflatten
10
9
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 2
12
10
  Classifier: Programming Language :: Python :: Implementation :: Jython
13
11
  Description-Content-Type: text/markdown
14
12
  License-File: LICENSE
15
13
 
16
- # JSON Duplicate Keys - PyPI
17
- Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys
18
-
19
- <p align="center">
20
- <a href="https://github.com/truocphan/json-duplicate-keys/releases/"><img src="https://img.shields.io/github/release/truocphan/json-duplicate-keys" height=30></a>
21
- <a href="#"><img src="https://img.shields.io/github/downloads/truocphan/json-duplicate-keys/total" height=30></a>
22
- <a href="#"><img src="https://img.shields.io/github/stars/truocphan/json-duplicate-keys" height=30></a>
23
- <a href="#"><img src="https://img.shields.io/github/forks/truocphan/json-duplicate-keys" height=30></a>
24
- <a href="https://github.com/truocphan/json-duplicate-keys/issues?q=is%3Aopen+is%3Aissue"><img src="https://img.shields.io/github/issues/truocphan/json-duplicate-keys" height=30></a>
25
- <a href="https://github.com/truocphan/json-duplicate-keys/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed/truocphan/json-duplicate-keys" height=30></a>
14
+ <div align="center">
15
+ <h1>JSON Duplicate Keys - PyPI</h1>
16
+ <i>Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys</i>
17
+ <br><br>
18
+ <a href="https://github.com/TPCyberSec/json-duplicate-keys/releases/"><img src="https://img.shields.io/github/release/TPCyberSec/json-duplicate-keys" height=30></a>
19
+ <a href="#"><img src="https://img.shields.io/github/downloads/TPCyberSec/json-duplicate-keys/total" height=30></a>
20
+ <a href="#"><img src="https://img.shields.io/github/stars/TPCyberSec/json-duplicate-keys" height=30></a>
21
+ <a href="#"><img src="https://img.shields.io/github/forks/TPCyberSec/json-duplicate-keys" height=30></a>
22
+ <a href="https://github.com/TPCyberSec/json-duplicate-keys/issues?q=is%3Aopen+is%3Aissue"><img src="https://img.shields.io/github/issues/TPCyberSec/json-duplicate-keys" height=30></a>
23
+ <a href="https://github.com/TPCyberSec/json-duplicate-keys/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed/TPCyberSec/json-duplicate-keys" height=30></a>
26
24
  <br>
27
25
  <a href="#"><img src="https://img.shields.io/pypi/v/json-duplicate-keys" height=30></a>
26
+ <a href="#"><img src="https://img.shields.io/pypi/pyversions/json-duplicate-keys" height=30></a>
28
27
  <a href="#"><img src="https://img.shields.io/pypi/dm/json-duplicate-keys" height=30></a>
29
- </p>
28
+ </div>
30
29
 
31
- ## Installation
30
+ ---
31
+ # 🛠️ Installation
32
32
  #### From PyPI:
33
33
  ```console
34
34
  pip install json-duplicate-keys
35
35
  ```
36
36
  #### From Source:
37
37
  ```console
38
- git clone https://github.com/truocphan/json-duplicate-keys.git --branch <Branch/Tag>
38
+ git clone https://github.com/TPCyberSec/json-duplicate-keys.git --branch <Branch/Tag>
39
39
  cd json-duplicate-keys
40
- python setup.py build
41
- python setup.py install
40
+ python -m build
41
+ python -m pip install dist/json_duplicate_keys-<version>-py3-none-any.whl
42
42
  ```
43
43
 
44
- ## Basic Usage
44
+ ---
45
+ # 📘 Basic Usage
45
46
  ### normalize_key(`name`, `dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False)
46
47
  _Normalize Key name_
47
48
  - `name`: key name
@@ -54,8 +55,8 @@ import json_duplicate_keys as jdks
54
55
  print(jdks.normalize_key("version{{{_2_}}}"))
55
56
  # OUTPUT: version
56
57
  ```
57
- ---
58
58
 
59
+ ---
59
60
  ### loads(`Jstr`, `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `skipDuplicated`=False, `_isDebug_`=False)
60
61
  _Deserialize a JSON format string to a class `JSON_DUPLICATE_KEYS`_
61
62
  - `Jstr`: a JSON format string
@@ -74,8 +75,8 @@ JDKSObject = jdks.loads(Jstr)
74
75
  print(JDKSObject)
75
76
  # OUTPUT: <json_duplicate_keys.JSON_DUPLICATE_KEYS object at 0x00000270AE987940>
76
77
  ```
77
- ---
78
78
 
79
+ ---
79
80
  ### load(`Jfilepath`, `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `skipDuplicated`=False, `_isDebug_`=False)
80
81
  _Deserialize a JSON format string from a file to a class `JSON_DUPLICATE_KEYS`_
81
82
  - `Jfilepath`: The path to the file containing the JSON format string
@@ -96,8 +97,8 @@ JDKSObject = jdks.load(Jfilepath)
96
97
  print(JDKSObject)
97
98
  # OUTPUT: <json_duplicate_keys.JSON_DUPLICATE_KEYS object at 0x00000270AE986D40>
98
99
  ```
99
- ---
100
100
 
101
+ ---
101
102
  ### JSON_DUPLICATE_KEYS.getObject()
102
103
  _Get the JSON object_
103
104
  ```python
@@ -110,8 +111,8 @@ JDKSObject = jdks.loads(Jstr)
110
111
  print(JDKSObject.getObject())
111
112
  # OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan', 'version': '22.3.3', 'release': [{'version': 'latest'}]}}
112
113
  ```
113
- ---
114
114
 
115
+ ---
115
116
  ### JSON_DUPLICATE_KEYS.get(`name`, `case_insensitive`=False, `separator`="||", `parse_index`="$", `_isDebug_`=False)
116
117
  _Get value in the JSON object by `name`_
117
118
  - `name`: the key name of the JSON object. Supported flatten key name format
@@ -135,8 +136,8 @@ print(JDKSObject.get("release||$0$"))
135
136
  print(JDKSObject.get("snapshot||author"))
136
137
  # OUTPUT: {'name': 'snapshot||author', 'value': 'truocphan'}
137
138
  ```
138
- ---
139
139
 
140
+ ---
140
141
  ### JSON_DUPLICATE_KEYS.set(`name`, `value`, `case_insensitive`=False, `separator`="||", `parse_index`="$", `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `_isDebug_`=False)
141
142
  _Set a new `name` and `value` for the JSON object_
142
143
  - `name`: new key name for the JSON object. Supported flat key name format
@@ -181,8 +182,8 @@ JDKSObject.set("snapshot||author", "truocphan")
181
182
  print(JDKSObject.getObject())
182
183
  # OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan'}}
183
184
  ```
184
- ---
185
185
 
186
+ ---
186
187
  ### JSON_DUPLICATE_KEYS.insert(`name`, `value`, `position`=None, `case_insensitive`=False, `separator`="||", `parse_index`="$", `dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False)
187
188
  _Insert `value` at `position` in value list of `name`_
188
189
  - `name`: the key name of the JSON object. Supported flatten key name format
@@ -209,9 +210,19 @@ JDKSObject.insert("snapshot||release", {'version': '2025.1.1'}, 0)
209
210
 
210
211
  print(JDKSObject.getObject())
211
212
  # OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}, {'version': '2025.1.1'}], 'snapshot': {'author': 'truocphan', 'version': '22.3.3', 'release': [{'version': '2025.1.1'}, {'version': 'latest'}]}}
213
+
214
+
215
+ JDKSObject = jdks.loads("[]")
216
+
217
+ JDKSObject.insert(None, {"release": []})
218
+ JDKSObject.insert(None, {"author": "truocphan"}, 0)
219
+ JDKSObject.insert("$1$||release", {"version": "2025.9.9"})
220
+
221
+ print(JDKSObject.getObject())
222
+ # OUTPUT: [{'author': 'truocphan'}, {'release': [{'version': '2025.9.9'}]}]
212
223
  ```
213
- ---
214
224
 
225
+ ---
215
226
  ### JSON_DUPLICATE_KEYS.update(`name`, `value`, `case_insensitive`=False, `allow_new_key`=False, `separator`="||", `parse_index`="$", `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `_isDebug_`=False)
216
227
  _Update new `value` for existing `name` or Set a new `name` in the JSON object_
217
228
  - `name`: the key name of the JSON object. Supported flatten key name format
@@ -240,8 +251,8 @@ JDKSObject.update("snapshot||version", "latest")
240
251
  print(JDKSObject.getObject())
241
252
  # OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': ['22.3.3', 'latest'], 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan', 'version': 'latest', 'release': [{'version': 'latest'}]}}
242
253
  ```
243
- ---
244
254
 
255
+ ---
245
256
  ### JSON_DUPLICATE_KEYS.delete(`name`, `case_insensitive`=False, `separator`="||", `parse_index`="$", `_isDebug_`=False)
246
257
  _Delete a key-value pair in a JSON object by key `name`_
247
258
  - `name`: the key name of the JSON object. Supported flatten key name format
@@ -266,8 +277,8 @@ JDKSObject.delete("snapshot")
266
277
  print(JDKSObject.getObject())
267
278
  # OUTPUT: {'author': 'truocphan', 'version{{{_2_}}}': 'latest', 'release': []}
268
279
  ```
269
- ---
270
280
 
281
+ ---
271
282
  ### JSON_DUPLICATE_KEYS.filter_keys(`name`, `separator`="||", `parse_index`="$", `ordered_dict`=False)
272
283
  _Return a `JSON_DUPLICATE_KEYS` object with keys matching a pattern_
273
284
  - `name`:
@@ -287,8 +298,8 @@ print(JDKSObject.filter_keys("version").dumps())
287
298
  print(JDKSObject.dumps())
288
299
  # OUTPUT: {"author": "truocphan", "version": "22.3.3", "version": "latest", "release": [{"version": "latest"}], "snapshot": {"author": "truocphan", "version": "22.3.3", "release": [{"version": "latest"}]}}
289
300
  ```
290
- ---
291
301
 
302
+ ---
292
303
  ### JSON_DUPLICATE_KEYS.filter_values(`value`, `separator`="||", `parse_index`="$", `ordered_dict`=False)
293
304
  _Return a `JSON_DUPLICATE_KEYS` object with values matching a pattern_
294
305
  - `value`:
@@ -308,8 +319,8 @@ print(JDKSObject.filter_values("latest").dumps())
308
319
  print(JDKSObject.dumps())
309
320
  # OUTPUT: {"author": "truocphan", "version": "22.3.3", "version": "latest", "release": [{"version": "latest"}], "snapshot": {"author": "truocphan", "version": "22.3.3", "release": [{"version": "latest"}]}}
310
321
  ```
311
- ---
312
322
 
323
+ ---
313
324
  ### JSON_DUPLICATE_KEYS.dumps(`dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False, `skipkeys`=False, `ensure_ascii`=True, `check_circular`=True, `allow_nan`=True, `cls`=None, `indent`=None, `separators`=None, `default`=None, `sort_keys`=False)
314
325
  _Serialize a JSON object to a JSON format string_
315
326
  - `dupSign_start`: Start symbol for marking duplicates (default: `{{{`)
@@ -333,8 +344,8 @@ JDKSObject.delete("snapshot")
333
344
  print(JDKSObject.dumps())
334
345
  # OUTPUT: {"author": "truocphan", "version": "latest", "release": []}
335
346
  ```
336
- ---
337
347
 
348
+ ---
338
349
  ### JSON_DUPLICATE_KEYS.dump(`Jfilepath`, `dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False, `skipkeys`=False, `ensure_ascii`=True, `check_circular`=True, `allow_nan`=True, `cls`=None, `indent`=None, `separators`=None, `default`=None, `sort_keys`=False)
339
350
  _Serialize a JSON object to a JSON format string and write to a file_
340
351
  - `Jfilepath`: the path to the file to save the JSON format string
@@ -363,8 +374,8 @@ JDKSObject_load = jdks.load(Jfilepath)
363
374
  print(JDKSObject_load.getObject())
364
375
  # OUTPUT: {'author': 'truocphan', 'version': 'latest', 'release': []}
365
376
  ```
366
- ---
367
377
 
378
+ ---
368
379
  ### JSON_DUPLICATE_KEYS.flatten(`separator`="||", `parse_index`="$", `ordered_dict`=False, `_isDebug_`=False)
369
380
  _Flatten a JSON object to a single key-value pairs_
370
381
  - `separator`: Separator for flatten keys (default: `||`)
@@ -386,8 +397,8 @@ JDKSObject.flatten()
386
397
  print(JDKSObject.getObject())
387
398
  # OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release||$0$||version': 'latest', 'snapshot||author': 'truocphan', 'snapshot||version': '22.3.3', 'snapshot||release||$0$||version': 'latest'}
388
399
  ```
389
- ---
390
400
 
401
+ ---
391
402
  ### JSON_DUPLICATE_KEYS.unflatten(`separator`="||", `parse_index`="$", `ordered_dict`=False, `_isDebug_`=False)
392
403
  _Unflatten a flattened JSON object back to a JSON object_
393
404
  - `separator`: Separator for flatten keys (default: `||`)
@@ -409,33 +420,41 @@ JDKSObject.unflatten()
409
420
  print(JDKSObject.getObject())
410
421
  # OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan', 'version': '22.3.3', 'release': [{'version': 'latest'}]}}
411
422
  ```
423
+
412
424
  ---
425
+ # 📝 CHANGELOG
426
+ ### [json-duplicate-keys v2025.9.9](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.9.9)
427
+ - **Fixed**: Inserting a value with an `empty` or `null` name
413
428
 
414
- ## CHANGELOG
415
- #### [json-duplicate-keys v2025.7.1](https://github.com/truocphan/json-duplicate-keys/tree/2025.7.1)
416
- - [**Updated**] Fixed some issues when loading JSON strings with `skipDuplicated` option
417
- - [**Updated**] Allow loading of JSON data in byte string format
418
- - [**Updated**] Issue with getting and setting an empty list
429
+ ### [json-duplicate-keys v2025.8.19](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.8.19)
430
+ - **Updated**: Add an exception when loading a non-existent file
431
+ - **Updated**: Dump Unicode characters to a file
419
432
 
420
- #### [json-duplicate-keys v2025.6.6](https://github.com/truocphan/json-duplicate-keys/tree/2025.6.6)
421
- - [**Updated**] Added `skipDuplicated` parameter to `load` and `loads` functions to improve performance when parsing large JSON strings by skipping duplicate keys.
433
+ ### [json-duplicate-keys v2025.7.1](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.7.1)
434
+ - **Updated**: Fixed some issues when loading JSON strings with `skipDuplicated` option
435
+ - **Updated**: Allow loading of JSON data in byte string format
436
+ - **Updated**: Issue with getting and setting an empty list
422
437
 
423
- #### [json-duplicate-keys v2024.12.12](https://github.com/truocphan/json-duplicate-keys/tree/2024.12.12)
438
+ ### [json-duplicate-keys v2025.6.6](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.6.6)
439
+ - **Updated** Added `skipDuplicated` parameter to `load` and `loads` functions to improve performance when parsing large JSON strings by skipping duplicate keys.
440
+
441
+ ### [json-duplicate-keys v2024.12.12](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.12.12)
424
442
  - **New**: _insert_ function
425
443
 
426
- #### [json-duplicate-keys v2024.11.28](https://github.com/truocphan/json-duplicate-keys/tree/2024.11.28)
444
+ ### [json-duplicate-keys v2024.11.28](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.11.28)
427
445
  - **Fixed**: Add subkey name to empty dict of existing key name
428
446
 
429
- #### [json-duplicate-keys v2024.11.19](https://github.com/truocphan/json-duplicate-keys/tree/2024.11.19)
447
+ ### [json-duplicate-keys v2024.11.19](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.11.19)
430
448
  - **Updated**: Allows getting (`JSON_DUPLICATE_KEYS.get`), setting (`JSON_DUPLICATE_KEYS.set`), updating (`JSON_DUPLICATE_KEYS.update`), deleting (`JSON_DUPLICATE_KEYS.delete`) JSON_DUPLICATE_KEYS objects with case-insensitive key names
431
449
 
432
- #### [json-duplicate-keys v2024.7.17](https://github.com/truocphan/json-duplicate-keys/tree/2024.7.17)
433
- - **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.
450
+ ### [json-duplicate-keys v2024.7.17](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.7.17)
451
+ - **Fixed**: issue #3 break the set function when the key's value is empty. Thanks [ptth222](https://github.com/ptth222) for reporting this issue.
434
452
 
435
- #### [json-duplicate-keys v2024.4.20](https://github.com/truocphan/json-duplicate-keys/tree/2024.4.20)
453
+ ### [json-duplicate-keys v2024.4.20](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.4.20)
436
454
  - **New**: _filter_values_
437
455
  - **Updated**: _filter_keys_
438
456
 
439
- #### [json-duplicate-keys v2024.3.24](https://github.com/truocphan/json-duplicate-keys/tree/2024.3.24)
457
+ ### [json-duplicate-keys v2024.3.24](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.3.24)
440
458
  - **Updated**: _normalize_key_, _loads_, _get_, _set_, _update_, _delete_
459
+
441
460
  ---
@@ -0,0 +1,6 @@
1
+ json_duplicate_keys/__init__.py,sha256=Ns_b4ZkssTizVwPQmpStuspo_FRLhJOWy_raNJ7I63I,30311
2
+ json_duplicate_keys-2025.9.9.dist-info/LICENSE,sha256=_hudSGMciUc27wGR8EMKfeb3atJRlf6rbhJtLnel-nc,1093
3
+ json_duplicate_keys-2025.9.9.dist-info/METADATA,sha256=SXON-ghmCMYFVuxKsEFIbF4tjfsyJZKdZDp8CY5Yx5E,23508
4
+ json_duplicate_keys-2025.9.9.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
5
+ json_duplicate_keys-2025.9.9.dist-info/top_level.txt,sha256=vdsGrPLVS_l-BFL1i4hCJBY5_-gq4Cwp-11yegA750Y,20
6
+ json_duplicate_keys-2025.9.9.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- json_duplicate_keys/__init__.py,sha256=ClhnGD0jyYwBRsOs9zHevi6WWGtnMEOjczwkUC0BMv8,30753
2
- json_duplicate_keys-2025.7.1.dist-info/LICENSE,sha256=_hudSGMciUc27wGR8EMKfeb3atJRlf6rbhJtLnel-nc,1093
3
- json_duplicate_keys-2025.7.1.dist-info/METADATA,sha256=wvDz2_ia5VuzhLvNiVZnrI7YJEVfjGVwy07RGb2-dQk,22717
4
- json_duplicate_keys-2025.7.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
5
- json_duplicate_keys-2025.7.1.dist-info/top_level.txt,sha256=vdsGrPLVS_l-BFL1i4hCJBY5_-gq4Cwp-11yegA750Y,20
6
- json_duplicate_keys-2025.7.1.dist-info/RECORD,,