json-repair 0.28.0__py3-none-any.whl → 0.28.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|