json-repair 0.29.3__py3-none-any.whl → 0.29.4__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,,