json-repair 0.29.3__py3-none-any.whl → 0.29.4__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,5 +1,5 @@
1
1
  from enum import Enum, auto
2
- from typing import List
2
+ from typing import List, Optional
3
3
 
4
4
 
5
5
  class ContextValues(Enum):
@@ -11,6 +11,8 @@ class ContextValues(Enum):
11
11
  class JsonContext:
12
12
  def __init__(self) -> None:
13
13
  self.context: List[ContextValues] = []
14
+ self.current: Optional[ContextValues] = None
15
+ self.empty: bool = True
14
16
 
15
17
  def set(self, value: ContextValues) -> None:
16
18
  """
@@ -25,6 +27,8 @@ class JsonContext:
25
27
  # If a value is provided update the context variable and save in stack
26
28
  if value:
27
29
  self.context.append(value)
30
+ self.current = value
31
+ self.empty = False
28
32
 
29
33
  def reset(self) -> None:
30
34
  """
@@ -33,37 +37,9 @@ class JsonContext:
33
37
  Returns:
34
38
  None
35
39
  """
36
- self.context.pop()
37
-
38
- def is_current(self, context: ContextValues) -> bool:
39
- """
40
- Check if the given context is the current (most recent) context.
41
-
42
- Args:
43
- context (ContextValues): The context value to check.
44
-
45
- Returns:
46
- bool: True if the given context is the same as the most recent context in the stack, False otherwise.
47
- """
48
- return self.context[-1] == context
49
-
50
- def is_any(self, context: ContextValues) -> bool:
51
- """
52
- Check if the given context exists anywhere in the context stack.
53
-
54
- Args:
55
- context (ContextValues): The context value to check.
56
-
57
- Returns:
58
- bool: True if the given context exists in the stack, False otherwise.
59
- """
60
- return context in self.context
61
-
62
- def is_empty(self) -> bool:
63
- """
64
- Check if the context stack is empty.
65
-
66
- Returns:
67
- bool: True if the context stack is empty, False otherwise.
68
- """
69
- return len(self.context) == 0
40
+ try:
41
+ self.context.pop()
42
+ self.current = self.context[-1]
43
+ except IndexError:
44
+ self.current = None
45
+ self.empty = True
@@ -34,7 +34,8 @@ class JSONParser:
34
34
  self.logger: List[Dict[str, str]] = []
35
35
  self.log = self._log
36
36
  else:
37
- self.log = self.noop
37
+ # No-op
38
+ self.log = lambda *args, **kwargs: None
38
39
 
39
40
  def parse(
40
41
  self,
@@ -88,12 +89,10 @@ class JSONParser:
88
89
  )
89
90
  return ""
90
91
  # <string> starts with a quote
91
- elif not self.context.is_empty() and (
92
- char in ['"', "'", "“"] or char.isalpha()
93
- ):
92
+ elif not self.context.empty and (char in ['"', "'", "“"] or char.isalpha()):
94
93
  return self.parse_string()
95
94
  # <number> starts with [0-9] or minus
96
- elif not self.context.is_empty() and (
95
+ elif not self.context.empty and (
97
96
  char.isdigit() or char == "-" or char == "."
98
97
  ):
99
98
  return self.parse_number()
@@ -234,8 +233,9 @@ class JSONParser:
234
233
  elif char.isalnum():
235
234
  # This could be a <boolean> and not a string. Because (T)rue or (F)alse or (N)ull are valid
236
235
  # But remember, object keys are only of type string
237
- if char.lower() in ["t", "f", "n"] and not self.context.is_current(
238
- ContextValues.OBJECT_KEY
236
+ if (
237
+ char.lower() in ["t", "f", "n"]
238
+ and self.context.current != ContextValues.OBJECT_KEY
239
239
  ):
240
240
  value = self.parse_boolean_or_null()
241
241
  if value != "":
@@ -255,15 +255,13 @@ class JSONParser:
255
255
  if self.get_char_at() == lstring_delimiter:
256
256
  # If it's an empty key, this was easy
257
257
  if (
258
- self.context.is_current(ContextValues.OBJECT_KEY)
258
+ self.context.current == ContextValues.OBJECT_KEY
259
259
  and self.get_char_at(1) == ":"
260
260
  ):
261
261
  self.index += 1
262
262
  return ""
263
263
  # Find the next delimiter
264
- i = self.skip_to_character(
265
- character=rstring_delimiter, idx=1, move_main_index=False
266
- )
264
+ i = self.skip_to_character(character=rstring_delimiter, idx=1)
267
265
  next_c = self.get_char_at(i)
268
266
  # Now check that the next character is also a delimiter to ensure that we have "".....""
269
267
  # In that case we ignore this rstring delimiter
@@ -296,22 +294,20 @@ class JSONParser:
296
294
  while char and char != rstring_delimiter:
297
295
  if (
298
296
  missing_quotes
299
- and self.context.is_current(ContextValues.OBJECT_KEY)
297
+ and self.context.current == ContextValues.OBJECT_KEY
300
298
  and (char == ":" or char.isspace())
301
299
  ):
302
300
  self.log(
303
301
  "While parsing a string missing the left delimiter in object key context, we found a :, stopping here",
304
302
  )
305
303
  break
306
- if self.context.is_current(ContextValues.OBJECT_VALUE) and char in [
304
+ if self.context.current == ContextValues.OBJECT_VALUE and char in [
307
305
  ",",
308
306
  "}",
309
307
  ]:
310
308
  rstring_delimiter_missing = True
311
309
  # check if this is a case in which the closing comma is NOT missing instead
312
- i = self.skip_to_character(
313
- character=rstring_delimiter, idx=1, move_main_index=False
314
- )
310
+ i = self.skip_to_character(character=rstring_delimiter, idx=1)
315
311
  next_c = self.get_char_at(i)
316
312
  if next_c:
317
313
  i += 1
@@ -345,8 +341,9 @@ class JSONParser:
345
341
  "While parsing a string, we found a doubled quote, ignoring it"
346
342
  )
347
343
  self.index += 1
348
- elif missing_quotes and self.context.is_current(
349
- ContextValues.OBJECT_VALUE
344
+ elif (
345
+ missing_quotes
346
+ and self.context.current == ContextValues.OBJECT_VALUE
350
347
  ):
351
348
  # In case of missing starting quote I need to check if the delimeter is the end or the beginning of a key
352
349
  i = 1
@@ -387,20 +384,20 @@ class JSONParser:
387
384
  # If we are in an object context, let's check for the right delimiters
388
385
  if (
389
386
  (
390
- self.context.is_any(ContextValues.OBJECT_KEY)
387
+ ContextValues.OBJECT_KEY in self.context.context
391
388
  and next_c in [":", "}"]
392
389
  )
393
390
  or (
394
- self.context.is_any(ContextValues.OBJECT_VALUE)
391
+ ContextValues.OBJECT_VALUE in self.context.context
395
392
  and next_c == "}"
396
393
  )
397
394
  or (
398
- self.context.is_any(ContextValues.ARRAY)
395
+ ContextValues.ARRAY in self.context.context
399
396
  and next_c in ["]", ","]
400
397
  )
401
398
  or (
402
399
  check_comma_in_object_value
403
- and self.context.is_current(ContextValues.OBJECT_VALUE)
400
+ and self.context.current == ContextValues.OBJECT_VALUE
404
401
  and next_c == ","
405
402
  )
406
403
  ):
@@ -408,13 +405,12 @@ class JSONParser:
408
405
  i += 1
409
406
  next_c = self.get_char_at(i)
410
407
  # If we stopped for a comma in object_value context, let's check if find a "} at the end of the string
411
- if next_c == "," and self.context.is_current(
412
- ContextValues.OBJECT_VALUE
408
+ if (
409
+ next_c == ","
410
+ and self.context.current == ContextValues.OBJECT_VALUE
413
411
  ):
414
412
  i += 1
415
- i = self.skip_to_character(
416
- character=rstring_delimiter, idx=i, move_main_index=False
417
- )
413
+ i = self.skip_to_character(character=rstring_delimiter, idx=i)
418
414
  next_c = self.get_char_at(i)
419
415
  # Ok now I found a delimiter, let's skip whitespaces and see if next we find a }
420
416
  i += 1
@@ -429,15 +425,13 @@ class JSONParser:
429
425
  self.index += 1
430
426
  char = self.get_char_at()
431
427
  elif next_c == rstring_delimiter:
432
- if self.context.is_current(ContextValues.OBJECT_VALUE):
428
+ if self.context.current == ContextValues.OBJECT_VALUE:
433
429
  # But this might not be it! This could be just a missing comma
434
430
  # We found a delimiter and we need to check if this is a key
435
431
  # so find a rstring_delimiter and a colon after
436
432
  i += 1
437
433
  i = self.skip_to_character(
438
- character=rstring_delimiter,
439
- idx=i,
440
- move_main_index=False,
434
+ character=rstring_delimiter, idx=i
441
435
  )
442
436
  i += 1
443
437
  next_c = self.get_char_at(i)
@@ -462,7 +456,7 @@ class JSONParser:
462
456
  if (
463
457
  char
464
458
  and missing_quotes
465
- and self.context.is_current(ContextValues.OBJECT_KEY)
459
+ and self.context.current == ContextValues.OBJECT_KEY
466
460
  and char.isspace()
467
461
  ):
468
462
  self.log(
@@ -488,7 +482,7 @@ class JSONParser:
488
482
  number_str = ""
489
483
  number_chars = set("0123456789-.eE/,")
490
484
  char = self.get_char_at()
491
- is_array = self.context.is_current(ContextValues.ARRAY)
485
+ is_array = self.context.current == ContextValues.ARRAY
492
486
  while char and char in number_chars and (char != "," or not is_array):
493
487
  number_str += char
494
488
  self.index += 1
@@ -561,9 +555,7 @@ class JSONParser:
561
555
  return idx
562
556
  return idx
563
557
 
564
- def skip_to_character(
565
- self, character: str, idx: int = 0, move_main_index=True
566
- ) -> int:
558
+ def skip_to_character(self, character: str, idx: int = 0) -> int:
567
559
  """
568
560
  This function quickly iterates to find a character, syntactic sugar to make the code more concise
569
561
  """
@@ -572,10 +564,7 @@ class JSONParser:
572
564
  except IndexError:
573
565
  return idx
574
566
  while char != character:
575
- if move_main_index: # pragma: no cover
576
- self.index += 1
577
- else:
578
- idx += 1
567
+ idx += 1
579
568
  try:
580
569
  char = self.json_str[self.index + idx]
581
570
  except IndexError:
@@ -593,6 +582,3 @@ class JSONParser:
593
582
  "context": context,
594
583
  }
595
584
  )
596
-
597
- def noop(*args: Any, **kwargs: Any) -> None:
598
- pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: json_repair
3
- Version: 0.29.3
3
+ Version: 0.29.4
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
@@ -0,0 +1,13 @@
1
+ json_repair/__init__.py,sha256=IIzSm1DsCRrr8seF3UeMZXwxcq-tE3j-8d1WBxvEJvE,178
2
+ json_repair/__main__.py,sha256=EsJb-y89uZEvGQQg1GdIDWzfDwfOMvVekKEtdguQXCM,67
3
+ json_repair/json_context.py,sha256=DdJu3DJR-ANvr8KrWfJqdtOE3uI6_B0VQidKvE3PjJA,1080
4
+ json_repair/json_parser.py,sha256=BUPyAsb7wzkjNrBmsZgxgoOM9JhksCN-8cHcbJQpcPU,25525
5
+ json_repair/json_repair.py,sha256=GTg3OAXRbAJAHWs8oiQDqUHh4h6qKDVvWPXcrqafzLY,6100
6
+ json_repair/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ json_repair/string_file_wrapper.py,sha256=EHLhNBWoyUitzT08thytYJiNZh_klEFwfT8zutPSdb4,3905
8
+ json_repair-0.29.4.dist-info/LICENSE,sha256=wrjQo8MhNrNCicXtMe3MHmS-fx8AmQk1ue8AQwiiFV8,1076
9
+ json_repair-0.29.4.dist-info/METADATA,sha256=dBmPfg4wBTxOFXklH4V38aiO4pUks5FS7HcvQlZ4NIg,10686
10
+ json_repair-0.29.4.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
11
+ json_repair-0.29.4.dist-info/entry_points.txt,sha256=SNfge3zPSP-ASqriYU9r3NAPaXdseYr7ciPMKdV2uSw,57
12
+ json_repair-0.29.4.dist-info/top_level.txt,sha256=7-VZwZN2CgB_n0NlSLk-rEUFh8ug21lESbsblOYuZqw,12
13
+ json_repair-0.29.4.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- json_repair/__init__.py,sha256=IIzSm1DsCRrr8seF3UeMZXwxcq-tE3j-8d1WBxvEJvE,178
2
- json_repair/__main__.py,sha256=EsJb-y89uZEvGQQg1GdIDWzfDwfOMvVekKEtdguQXCM,67
3
- json_repair/json_context.py,sha256=MOzT0z4Pc03SWhggwwEpDNXyeHm04kLfvDBOBd3xkVU,1782
4
- json_repair/json_parser.py,sha256=Gimn0LFUTpdGCFo9rOGjH3W39PEj00_Lrj4mPOSnBFU,25949
5
- json_repair/json_repair.py,sha256=GTg3OAXRbAJAHWs8oiQDqUHh4h6qKDVvWPXcrqafzLY,6100
6
- json_repair/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- json_repair/string_file_wrapper.py,sha256=EHLhNBWoyUitzT08thytYJiNZh_klEFwfT8zutPSdb4,3905
8
- json_repair-0.29.3.dist-info/LICENSE,sha256=wrjQo8MhNrNCicXtMe3MHmS-fx8AmQk1ue8AQwiiFV8,1076
9
- json_repair-0.29.3.dist-info/METADATA,sha256=tQ_crOtYbu3fseCXoc-VDIHIJq0HtGRA9SvmCIldvUE,10686
10
- json_repair-0.29.3.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
11
- json_repair-0.29.3.dist-info/entry_points.txt,sha256=SNfge3zPSP-ASqriYU9r3NAPaXdseYr7ciPMKdV2uSw,57
12
- json_repair-0.29.3.dist-info/top_level.txt,sha256=7-VZwZN2CgB_n0NlSLk-rEUFh8ug21lESbsblOYuZqw,12
13
- json_repair-0.29.3.dist-info/RECORD,,