json-repair 0.47.8__tar.gz → 0.49.0__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.
Files changed (35) hide show
  1. {json_repair-0.47.8/src/json_repair.egg-info → json_repair-0.49.0}/PKG-INFO +2 -1
  2. {json_repair-0.47.8 → json_repair-0.49.0}/README.md +1 -0
  3. {json_repair-0.47.8 → json_repair-0.49.0}/pyproject.toml +1 -1
  4. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/json_parser.py +3 -0
  5. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/json_repair.py +7 -3
  6. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/parse_string.py +8 -4
  7. {json_repair-0.47.8 → json_repair-0.49.0/src/json_repair.egg-info}/PKG-INFO +2 -1
  8. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_json_repair.py +19 -0
  9. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_parse_string.py +2 -0
  10. {json_repair-0.47.8 → json_repair-0.49.0}/LICENSE +0 -0
  11. {json_repair-0.47.8 → json_repair-0.49.0}/setup.cfg +0 -0
  12. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/__init__.py +0 -0
  13. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/__main__.py +0 -0
  14. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/constants.py +0 -0
  15. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/json_context.py +0 -0
  16. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/object_comparer.py +0 -0
  17. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/parse_array.py +0 -0
  18. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/parse_boolean_or_null.py +0 -0
  19. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/parse_comment.py +0 -0
  20. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/parse_number.py +0 -0
  21. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/parse_object.py +0 -0
  22. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/py.typed +0 -0
  23. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair/string_file_wrapper.py +0 -0
  24. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair.egg-info/SOURCES.txt +0 -0
  25. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair.egg-info/dependency_links.txt +0 -0
  26. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair.egg-info/entry_points.txt +0 -0
  27. {json_repair-0.47.8 → json_repair-0.49.0}/src/json_repair.egg-info/top_level.txt +0 -0
  28. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_parse_array.py +0 -0
  29. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_parse_boolean_or_null.py +0 -0
  30. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_parse_comment.py +0 -0
  31. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_parse_number.py +0 -0
  32. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_parse_object.py +0 -0
  33. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_performance.py +0 -0
  34. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_repair_json_cli.py +0 -0
  35. {json_repair-0.47.8 → json_repair-0.49.0}/tests/test_repair_json_from_file.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: json_repair
3
- Version: 0.47.8
3
+ Version: 0.49.0
4
4
  Summary: A package to repair broken json strings
5
5
  Author-email: Stefano Baccianella <4247706+mangiucugna@users.noreply.github.com>
6
6
  License: MIT License
@@ -40,6 +40,7 @@ Dynamic: license-file
40
40
  [![PyPI](https://img.shields.io/pypi/v/json-repair)](https://pypi.org/project/json-repair/)
41
41
  ![Python version](https://img.shields.io/badge/python-3.10+-important)
42
42
  [![PyPI downloads](https://img.shields.io/pypi/dm/json-repair)](https://pypi.org/project/json-repair/)
43
+ [![PyPI Downloads](https://static.pepy.tech/badge/json-repair)](https://pepy.tech/projects/json-repair)
43
44
  [![Github Sponsors](https://img.shields.io/github/sponsors/mangiucugna)](https://github.com/sponsors/mangiucugna)
44
45
  [![GitHub Repo stars](https://img.shields.io/github/stars/mangiucugna/json_repair?style=flat)](https://github.com/mangiucugna/json_repair/stargazers)
45
46
 
@@ -1,6 +1,7 @@
1
1
  [![PyPI](https://img.shields.io/pypi/v/json-repair)](https://pypi.org/project/json-repair/)
2
2
  ![Python version](https://img.shields.io/badge/python-3.10+-important)
3
3
  [![PyPI downloads](https://img.shields.io/pypi/dm/json-repair)](https://pypi.org/project/json-repair/)
4
+ [![PyPI Downloads](https://static.pepy.tech/badge/json-repair)](https://pepy.tech/projects/json-repair)
4
5
  [![Github Sponsors](https://img.shields.io/github/sponsors/mangiucugna)](https://github.com/sponsors/mangiucugna)
5
6
  [![GitHub Repo stars](https://img.shields.io/github/stars/mangiucugna/json_repair?style=flat)](https://github.com/mangiucugna/json_repair/stargazers)
6
7
 
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.0"]
3
3
  build-backend = "setuptools.build_meta"
4
4
  [project]
5
5
  name = "json_repair"
6
- version = "0.47.8"
6
+ version = "0.49.0"
7
7
  license = {file = "LICENSE"}
8
8
  authors = [
9
9
  { name="Stefano Baccianella", email="4247706+mangiucugna@users.noreply.github.com" },
@@ -169,6 +169,9 @@ class JSONParser:
169
169
  char = self.json_str[self.index + idx]
170
170
  except IndexError:
171
171
  return idx
172
+ if self.json_str[self.index + idx - 1] == "\\":
173
+ # Ah shoot this was actually escaped, continue
174
+ return self.skip_to_character(character, idx + 1)
172
175
  return idx
173
176
 
174
177
  def _log(self, text: str) -> None:
@@ -66,7 +66,7 @@ def repair_json(
66
66
  chunk_length: int = 0,
67
67
  stream_stable: bool = False,
68
68
  **json_dumps_args,
69
- ) -> JSONReturnType | tuple[JSONReturnType, list[dict[str, str]]]:
69
+ ) -> JSONReturnType | tuple[JSONReturnType, list[dict[str, str]]] | tuple[JSONReturnType, list]:
70
70
  """
71
71
  Given a json formatted string, it will try to decode it and, if it fails, it will try to fix it.
72
72
 
@@ -74,13 +74,13 @@ def repair_json(
74
74
  json_str (str, optional): The JSON string to repair. Defaults to an empty string.
75
75
  return_objects (bool, optional): If True, return the decoded data structure. Defaults to False.
76
76
  skip_json_loads (bool, optional): If True, skip calling the built-in json.loads() function to verify that the json is valid before attempting to repair. Defaults to False.
77
- logging (bool, optional): If True, return a tuple with the repaired json and a log of all repair actions. Defaults to False.
77
+ logging (bool, optional): If True, return a tuple with the repaired json and a log of all repair actions. Defaults to False. When no repairs were required, the repair log will be an empty list.
78
78
  json_fd (Optional[TextIO], optional): File descriptor for JSON input. Do not use! Use `from_file` or `load` instead. Defaults to None.
79
79
  ensure_ascii (bool, optional): Set to False to avoid converting non-latin characters to ascii (for example when using chinese characters). Defaults to True. Ignored if `skip_json_loads` is True.
80
80
  chunk_length (int, optional): Size in bytes of the file chunks to read at once. Ignored if `json_fd` is None. Do not use! Use `from_file` or `load` instead. Defaults to 1MB.
81
81
  stream_stable (bool, optional): When the json to be repaired is the accumulation of streaming json at a certain moment.If this parameter to True will keep the repair results stable.
82
82
  Returns:
83
- Union[JSONReturnType, Tuple[JSONReturnType, List[Dict[str, str]]]]: The repaired JSON or a tuple with the repaired JSON and repair log.
83
+ Union[JSONReturnType, Tuple[JSONReturnType, List[Dict[str, str]]]]: The repaired JSON or a tuple with the repaired JSON and repair log when logging is True.
84
84
  """
85
85
  parser = JSONParser(json_str, json_fd, logging, chunk_length, stream_stable)
86
86
  if skip_json_loads:
@@ -93,6 +93,10 @@ def repair_json(
93
93
  # It's useful to return the actual object instead of the json string,
94
94
  # it allows this lib to be a replacement of the json library
95
95
  if return_objects or logging:
96
+ # If logging is True, the user should expect a tuple.
97
+ # If json.load(s) worked, the repair log list is empty
98
+ if logging and not isinstance(parsed_json, tuple):
99
+ return parsed_json, []
96
100
  return parsed_json
97
101
  # Avoid returning only a pair of quotes if it's an empty string
98
102
  elif parsed_json == "":
@@ -213,8 +213,7 @@ def parse_string(self: "JSONParser") -> str | bool | None:
213
213
  while char and string_acc[-1] == "\\" and char in [rstring_delimiter, "\\"]:
214
214
  # this is a bit of a special case, if I don't do this it will close the loop or create a train of \\
215
215
  # I don't love it though
216
- string_acc = string_acc[:-1]
217
- string_acc += char
216
+ string_acc = string_acc[:-1] + char
218
217
  self.index += 1
219
218
  char = self.get_char_at()
220
219
  continue
@@ -224,11 +223,16 @@ def parse_string(self: "JSONParser") -> str | bool | None:
224
223
  next_chars = self.json_str[self.index + 1 : self.index + 1 + num_chars]
225
224
  if len(next_chars) == num_chars and all(c in "0123456789abcdefABCDEF" for c in next_chars):
226
225
  self.log("Found a unicode escape sequence, normalizing it")
227
- string_acc = string_acc[:-1]
228
- string_acc += chr(int(next_chars, 16))
226
+ string_acc = string_acc[:-1] + chr(int(next_chars, 16))
229
227
  self.index += 1 + num_chars
230
228
  char = self.get_char_at()
231
229
  continue
230
+ elif char in STRING_DELIMITERS and char != rstring_delimiter:
231
+ self.log("Found a delimiter that was escaped but shouldn't be escaped, removing the escape")
232
+ string_acc = string_acc[:-1] + char
233
+ self.index += 1
234
+ char = self.get_char_at()
235
+ continue
232
236
  # If we are in object key context and we find a colon, it could be a missing right quote
233
237
  if char == ":" and not missing_quotes and self.context.current == ContextValues.OBJECT_KEY:
234
238
  # Ok now we need to check if this is followed by a value like "..."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: json_repair
3
- Version: 0.47.8
3
+ Version: 0.49.0
4
4
  Summary: A package to repair broken json strings
5
5
  Author-email: Stefano Baccianella <4247706+mangiucugna@users.noreply.github.com>
6
6
  License: MIT License
@@ -40,6 +40,7 @@ Dynamic: license-file
40
40
  [![PyPI](https://img.shields.io/pypi/v/json-repair)](https://pypi.org/project/json-repair/)
41
41
  ![Python version](https://img.shields.io/badge/python-3.10+-important)
42
42
  [![PyPI downloads](https://img.shields.io/pypi/dm/json-repair)](https://pypi.org/project/json-repair/)
43
+ [![PyPI Downloads](https://static.pepy.tech/badge/json-repair)](https://pepy.tech/projects/json-repair)
43
44
  [![Github Sponsors](https://img.shields.io/github/sponsors/mangiucugna)](https://github.com/sponsors/mangiucugna)
44
45
  [![GitHub Repo stars](https://img.shields.io/github/stars/mangiucugna/json_repair?style=flat)](https://github.com/mangiucugna/json_repair/stargazers)
45
46
 
@@ -158,3 +158,22 @@ def test_stream_stable():
158
158
  assert repair_json('{"key": "val\\n', stream_stable=True) == '{"key": "val\\n"}'
159
159
  assert repair_json('{"key": "val\\n123,`key2:value2', stream_stable=True) == '{"key": "val\\n123,`key2:value2"}'
160
160
  assert repair_json('{"key": "val\\n123,`key2:value2`"}', stream_stable=True) == '{"key": "val\\n123,`key2:value2`"}'
161
+
162
+
163
+ def test_logging():
164
+ assert repair_json("{}", logging=True) == ({}, [])
165
+ assert repair_json('{"key": "value}', logging=True) == (
166
+ {"key": "value"},
167
+ [
168
+ {
169
+ "context": 'y": "value}',
170
+ "text": "While parsing a string missing the left delimiter in object value "
171
+ "context, we found a , or } and we couldn't determine that a right "
172
+ "delimiter was present. Stopping here",
173
+ },
174
+ {
175
+ "context": 'y": "value}',
176
+ "text": "While parsing a string, we missed the closing quote, ignoring",
177
+ },
178
+ ],
179
+ )
@@ -72,6 +72,8 @@ def test_escaping():
72
72
  assert repair_json('{"key\t_": "value"}') == '{"key\\t_": "value"}'
73
73
  assert repair_json("{\"key\": '\u0076\u0061\u006c\u0075\u0065'}") == '{"key": "value"}'
74
74
  assert repair_json('{"key": "\\u0076\\u0061\\u006C\\u0075\\u0065"}', skip_json_loads=True) == '{"key": "value"}'
75
+ assert repair_json("""{"key": "valu\\'e"}""") == """{"key": "valu'e"}"""
76
+ assert repair_json('{\'key\': "{\\"key\\": 1, \\"key2\\": 1}"}') == '{"key": "{\\"key\\": 1, \\"key2\\": 1}"}'
75
77
 
76
78
 
77
79
  def test_markdown():
File without changes
File without changes