json-repair 0.28.0__py3-none-any.whl → 0.28.2__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.
- json_repair/json_repair.py +23 -20
- {json_repair-0.28.0.dist-info → json_repair-0.28.2.dist-info}/METADATA +1 -1
- json_repair-0.28.2.dist-info/RECORD +8 -0
- json_repair-0.28.0.dist-info/RECORD +0 -8
- {json_repair-0.28.0.dist-info → json_repair-0.28.2.dist-info}/LICENSE +0 -0
- {json_repair-0.28.0.dist-info → json_repair-0.28.2.dist-info}/WHEEL +0 -0
- {json_repair-0.28.0.dist-info → json_repair-0.28.2.dist-info}/top_level.txt +0 -0
json_repair/json_repair.py
CHANGED
@@ -24,7 +24,7 @@ All supported use cases are in the unit tests
|
|
24
24
|
|
25
25
|
import os
|
26
26
|
import json
|
27
|
-
from typing import Any, Dict, List, Optional, Union, TextIO, Tuple
|
27
|
+
from typing import Any, Dict, List, Optional, Union, TextIO, Tuple, Literal
|
28
28
|
|
29
29
|
|
30
30
|
class StringFileWrapper:
|
@@ -33,7 +33,7 @@ class StringFileWrapper:
|
|
33
33
|
self.fd = fd
|
34
34
|
self.length: int = 0
|
35
35
|
|
36
|
-
def __getitem__(self, index: int) -> str:
|
36
|
+
def __getitem__(self, index: int | slice) -> str:
|
37
37
|
if isinstance(index, slice):
|
38
38
|
self.fd.seek(index.start)
|
39
39
|
value = self.fd.read(index.stop - index.start)
|
@@ -177,7 +177,7 @@ class JSONParser:
|
|
177
177
|
# <member> starts with a <string>
|
178
178
|
key = ""
|
179
179
|
while self.get_char_at():
|
180
|
-
key = self.parse_string()
|
180
|
+
key = str(self.parse_string())
|
181
181
|
|
182
182
|
if key != "" or (key == "" and self.get_char_at() == ":"):
|
183
183
|
# If the string is empty but there is a object divider, we are done here
|
@@ -255,7 +255,7 @@ class JSONParser:
|
|
255
255
|
self.reset_context()
|
256
256
|
return arr
|
257
257
|
|
258
|
-
def parse_string(self) -> Union[str,
|
258
|
+
def parse_string(self) -> Union[str, bool, None]:
|
259
259
|
# <string> is a string of valid characters enclosed in quotes
|
260
260
|
# i.e. { name: "John" }
|
261
261
|
# Somehow all weird cases in an invalid JSON happen to be resolved in this function, so be careful here
|
@@ -382,7 +382,7 @@ class JSONParser:
|
|
382
382
|
string_acc += char
|
383
383
|
self.index += 1
|
384
384
|
char = self.get_char_at()
|
385
|
-
if len(string_acc) > 0 and string_acc[-1] == "\\":
|
385
|
+
if char and len(string_acc) > 0 and string_acc[-1] == "\\":
|
386
386
|
# This is a special case, if people use real strings this might happen
|
387
387
|
self.log("Found a stray escape sequence, normalizing it", "info")
|
388
388
|
string_acc = string_acc[:-1]
|
@@ -473,7 +473,7 @@ class JSONParser:
|
|
473
473
|
"While parsing a string, we a misplaced quote that would have closed the string but has a different meaning here since this is the last element of the object, ignoring it",
|
474
474
|
"info",
|
475
475
|
)
|
476
|
-
string_acc += char
|
476
|
+
string_acc += str(char)
|
477
477
|
self.index += 1
|
478
478
|
char = self.get_char_at()
|
479
479
|
elif next_c == rstring_delimiter:
|
@@ -503,7 +503,7 @@ class JSONParser:
|
|
503
503
|
"While parsing a string, we a misplaced quote that would have closed the string but has a different meaning here, ignoring it",
|
504
504
|
"info",
|
505
505
|
)
|
506
|
-
string_acc += char
|
506
|
+
string_acc += str(char)
|
507
507
|
self.index += 1
|
508
508
|
char = self.get_char_at()
|
509
509
|
|
@@ -521,7 +521,8 @@ class JSONParser:
|
|
521
521
|
if self.get_char_at() not in [":", ","]:
|
522
522
|
return ""
|
523
523
|
|
524
|
-
# A fallout of the previous special case in the while loop,
|
524
|
+
# A fallout of the previous special case in the while loop,
|
525
|
+
# we need to update the index only if we had a closing quote
|
525
526
|
if char != rstring_delimiter:
|
526
527
|
self.log(
|
527
528
|
"While parsing a string, we missed the closing quote, ignoring",
|
@@ -563,6 +564,7 @@ class JSONParser:
|
|
563
564
|
# <boolean> is one of the literal strings 'true', 'false', or 'null' (unquoted)
|
564
565
|
starting_index = self.index
|
565
566
|
char = (self.get_char_at() or "").lower()
|
567
|
+
value: Optional[Tuple[str, Optional[bool]]]
|
566
568
|
if char == "t":
|
567
569
|
value = ("true", True)
|
568
570
|
elif char == "f":
|
@@ -583,7 +585,7 @@ class JSONParser:
|
|
583
585
|
self.index = starting_index
|
584
586
|
return ""
|
585
587
|
|
586
|
-
def get_char_at(self, count: int = 0) -> Union[str,
|
588
|
+
def get_char_at(self, count: int = 0) -> Union[str, Literal[False]]:
|
587
589
|
# Why not use something simpler? Because try/except in python is a faster alternative to an "if" statement that is often True
|
588
590
|
try:
|
589
591
|
return self.json_str[self.index + count]
|
@@ -632,18 +634,18 @@ class JSONParser:
|
|
632
634
|
|
633
635
|
def repair_json(
|
634
636
|
json_str: str = "",
|
635
|
-
return_objects:
|
636
|
-
skip_json_loads:
|
637
|
-
logging:
|
637
|
+
return_objects: bool = False,
|
638
|
+
skip_json_loads: bool = False,
|
639
|
+
logging: bool = False,
|
638
640
|
json_fd: Optional[TextIO] = None,
|
639
|
-
ensure_ascii:
|
641
|
+
ensure_ascii: bool = True,
|
640
642
|
) -> Union[JSONReturnType, Tuple[JSONReturnType, List[Dict[str, str]]]]:
|
641
643
|
"""
|
642
644
|
Given a json formatted string, it will try to decode it and, if it fails, it will try to fix it.
|
643
645
|
It will return the fixed string by default.
|
644
646
|
When `return_objects=True` is passed, it will return the decoded data structure instead.
|
645
647
|
When `skip_json_loads=True` is passed, it will not call the built-in json.loads() function
|
646
|
-
When `logging=True` is passed, it will return
|
648
|
+
When `logging=True` is passed, it will return a tuple with the repaired json and a log of all repair actions
|
647
649
|
"""
|
648
650
|
parser = JSONParser(json_str, json_fd, logging)
|
649
651
|
if skip_json_loads:
|
@@ -656,7 +658,8 @@ def repair_json(
|
|
656
658
|
parsed_json = json.loads(json_str)
|
657
659
|
except json.JSONDecodeError:
|
658
660
|
parsed_json = parser.parse()
|
659
|
-
# It's useful to return the actual object instead of the json string,
|
661
|
+
# It's useful to return the actual object instead of the json string,
|
662
|
+
# it allows this lib to be a replacement of the json library
|
660
663
|
if return_objects or logging:
|
661
664
|
return parsed_json
|
662
665
|
return json.dumps(parsed_json, ensure_ascii=ensure_ascii)
|
@@ -664,8 +667,8 @@ def repair_json(
|
|
664
667
|
|
665
668
|
def loads(
|
666
669
|
json_str: str,
|
667
|
-
skip_json_loads:
|
668
|
-
logging:
|
670
|
+
skip_json_loads: bool = False,
|
671
|
+
logging: bool = False,
|
669
672
|
) -> Union[JSONReturnType, Tuple[JSONReturnType, List[Dict[str, str]]]]:
|
670
673
|
"""
|
671
674
|
This function works like `json.loads()` except that it will fix your JSON in the process.
|
@@ -680,7 +683,7 @@ def loads(
|
|
680
683
|
|
681
684
|
|
682
685
|
def load(
|
683
|
-
fd: TextIO, skip_json_loads:
|
686
|
+
fd: TextIO, skip_json_loads: bool = False, logging: bool = False
|
684
687
|
) -> Union[JSONReturnType, Tuple[JSONReturnType, List[Dict[str, str]]]]:
|
685
688
|
"""
|
686
689
|
This function works like `json.load()` except that it will fix your JSON in the process.
|
@@ -696,8 +699,8 @@ def load(
|
|
696
699
|
|
697
700
|
def from_file(
|
698
701
|
filename: str,
|
699
|
-
skip_json_loads:
|
700
|
-
logging:
|
702
|
+
skip_json_loads: bool = False,
|
703
|
+
logging: bool = False,
|
701
704
|
) -> Union[JSONReturnType, Tuple[JSONReturnType, List[Dict[str, str]]]]:
|
702
705
|
"""
|
703
706
|
This function is a wrapper around `load()` so you can pass the filename as string
|
@@ -0,0 +1,8 @@
|
|
1
|
+
json_repair/__init__.py,sha256=IIzSm1DsCRrr8seF3UeMZXwxcq-tE3j-8d1WBxvEJvE,178
|
2
|
+
json_repair/json_repair.py,sha256=v43na-l2g34pwTZH5FDljI_r5ArIaZfCeHW_LbB8puw,30123
|
3
|
+
json_repair/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
json_repair-0.28.2.dist-info/LICENSE,sha256=wrjQo8MhNrNCicXtMe3MHmS-fx8AmQk1ue8AQwiiFV8,1076
|
5
|
+
json_repair-0.28.2.dist-info/METADATA,sha256=llPJ1A8UePeGKbPSkC6-b2kE2somdgSMiq-wuPANGZ8,8043
|
6
|
+
json_repair-0.28.2.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
7
|
+
json_repair-0.28.2.dist-info/top_level.txt,sha256=7-VZwZN2CgB_n0NlSLk-rEUFh8ug21lESbsblOYuZqw,12
|
8
|
+
json_repair-0.28.2.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
json_repair/__init__.py,sha256=IIzSm1DsCRrr8seF3UeMZXwxcq-tE3j-8d1WBxvEJvE,178
|
2
|
-
json_repair/json_repair.py,sha256=5WjVoNO7Grdq9wfnbSjggiVlDv2XVcvWbCIQVmREP38,30109
|
3
|
-
json_repair/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
json_repair-0.28.0.dist-info/LICENSE,sha256=wrjQo8MhNrNCicXtMe3MHmS-fx8AmQk1ue8AQwiiFV8,1076
|
5
|
-
json_repair-0.28.0.dist-info/METADATA,sha256=rPrWno-My7ZQt7EJIR0BodmpLQ84fr0vjJwBM4XYmYU,8043
|
6
|
-
json_repair-0.28.0.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
7
|
-
json_repair-0.28.0.dist-info/top_level.txt,sha256=7-VZwZN2CgB_n0NlSLk-rEUFh8ug21lESbsblOYuZqw,12
|
8
|
-
json_repair-0.28.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|