JsonhPy 2.4__tar.gz → 2.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JsonhPy
3
- Version: 2.4
3
+ Version: 2.6
4
4
  Summary: JSON for Humans in Python.
5
5
  Author-email: Joyless <joyless.mod@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "JsonhPy"
3
- version = "2.4"
3
+ version = "2.6"
4
4
  authors = [
5
5
  { name="Joyless", email="joyless.mod@gmail.com" },
6
6
  ]
@@ -1,6 +1,6 @@
1
1
  import math
2
2
  from enum import Enum
3
- from typing import Iterator, Iterable
3
+ from typing import Iterator, Iterable, cast
4
4
  import json
5
5
 
6
6
  class JsonhResult[T, E]:
@@ -8,28 +8,28 @@ class JsonhResult[T, E]:
8
8
  value_or_none: T | None
9
9
  error_or_none: E | None
10
10
 
11
- def __init__(self, is_error: bool, value_or_none: T | None = None, error_or_none: E | None = None):
11
+ def __init__(self, is_error: bool, value_or_none: T | None = None, error_or_none: E | None = None) -> None:
12
12
  self.is_error = is_error
13
13
  self.value_or_none = value_or_none
14
14
  self.error_or_none = error_or_none
15
15
 
16
16
  @staticmethod
17
- def from_value[T, E](value: T = None) -> "JsonhResult[T, E]":
18
- return JsonhResult(False, value, None)
17
+ def from_value[_T, _E](value: _T = None) -> "JsonhResult[_T, _E]": # type: ignore
18
+ return JsonhResult[_T, _E](False, value, None)
19
19
 
20
20
  @staticmethod
21
- def from_error[T, E](error: E = None) -> "JsonhResult[T, E]":
22
- return JsonhResult(True, None, error)
21
+ def from_error[_T, _E](error: _E = None) -> "JsonhResult[_T, _E]": # type: ignore
22
+ return JsonhResult[_T, _E](True, None, error)
23
23
 
24
24
  def value(self) -> T:
25
25
  if self.is_error:
26
26
  raise RuntimeError(f"Result was error: {self.error_or_none}")
27
- return self.value_or_none
27
+ return self.value_or_none # type: ignore
28
28
 
29
29
  def error(self) -> E:
30
30
  if not self.is_error:
31
31
  raise RuntimeError(f"Result was value: {self.value_or_none}")
32
- return self.error_or_none
32
+ return self.error_or_none # type: ignore
33
33
 
34
34
  def __repr__(self) -> str:
35
35
  if self.is_error:
@@ -39,7 +39,7 @@ class JsonhResult[T, E]:
39
39
  class JsonhRef[T]:
40
40
  ref: T
41
41
 
42
- def __init__(self, ref: T):
42
+ def __init__(self, ref: T) -> None:
43
43
  self.ref = ref
44
44
 
45
45
  class JsonhVersion(Enum):
@@ -135,10 +135,13 @@ class JsonTokenType(Enum):
135
135
  """
136
136
 
137
137
  class JsonhToken:
138
+ """
139
+ A single JSONH token.
140
+ """
138
141
  json_type: JsonTokenType
139
142
  value: str
140
143
 
141
- def __init__(self, json_type: JsonTokenType, value: str = ""):
144
+ def __init__(self, json_type: JsonTokenType, value: str = "") -> None:
142
145
  self.json_type = json_type
143
146
  self.value = value
144
147
 
@@ -185,7 +188,7 @@ class JsonhNumberParser:
185
188
 
186
189
  # Apply sign
187
190
  if sign != 1:
188
- number.value_or_none *= sign
191
+ number.value_or_none *= sign # type: ignore
189
192
  return number
190
193
 
191
194
  @staticmethod
@@ -306,7 +309,7 @@ class JsonhNumberParser:
306
309
  return JsonhResult.from_value(integer)
307
310
 
308
311
  @staticmethod
309
- def _index_of_any(input: str, chars: Iterable[str]) -> float:
312
+ def _index_of_any(input: str, chars: Iterable[str]) -> int:
310
313
  for i in range(0, len(input)):
311
314
  char: str = input[i]
312
315
  if char in chars:
@@ -317,7 +320,7 @@ class JsonhReaderOptions:
317
320
  """
318
321
  Options for a JsonhReader.
319
322
  """
320
- version: JsonhVersion.LATEST
323
+ version: JsonhVersion = JsonhVersion.LATEST
321
324
  """
322
325
  Specifies the major version of the JSONH specification to use.
323
326
  """
@@ -363,7 +366,7 @@ class JsonhReaderOptions:
363
366
  Only some tokens can be incomplete in this mode, so it should not be relied upon.
364
367
  """
365
368
 
366
- def __init__(self, version: JsonhVersion = JsonhVersion.LATEST, parse_single_element: bool = False, max_depth: int = 64, incomplete_inputs: bool = False):
369
+ def __init__(self, version: JsonhVersion = JsonhVersion.LATEST, parse_single_element: bool = False, max_depth: int = 64, incomplete_inputs: bool = False) -> None:
367
370
  """
368
371
  Constructs options for a JsonhReader.
369
372
  """
@@ -385,11 +388,14 @@ class JsonhReaderOptions:
385
388
  return options_version.value >= given_version.value
386
389
 
387
390
  class JsonhReader:
391
+ """
392
+ A reader that reads JSONH tokens from a `str`.
393
+ """
388
394
  string: str
389
395
  """
390
396
  The string to read characters from.
391
397
  """
392
- index: int
398
+ string_index: int
393
399
  """
394
400
  The index in the string.
395
401
  """
@@ -438,7 +444,7 @@ class JsonhReader:
438
444
  Constructs a reader that reads JSONH from a string.
439
445
  """
440
446
  self.string = string
441
- self.index = 0
447
+ self.string_index = 0
442
448
  self.options = options
443
449
  self.char_counter = 0
444
450
  self.depth = 0
@@ -466,12 +472,12 @@ class JsonhReader:
466
472
  return True
467
473
  # Array item
468
474
  if current_property_name == None:
469
- current_array: list[object] = current_elements[-1]
475
+ current_array: list[object] = cast(list[object], current_elements[-1])
470
476
  current_array.append(element)
471
477
  return False
472
478
  # Object property
473
479
  else:
474
- current_object: dict[str, object] = current_elements[-1]
480
+ current_object: dict[str, object] = cast(dict[str, object], current_elements[-1])
475
481
  current_object[current_property_name] = element
476
482
  current_property_name = None
477
483
  return False
@@ -495,40 +501,40 @@ class JsonhReader:
495
501
  match token_result.value().json_type:
496
502
  # Null
497
503
  case JsonTokenType.NULL:
498
- element: None = None
499
- if submit_element(element):
500
- return JsonhResult.from_value(element)
504
+ element_null: None = None
505
+ if submit_element(element_null):
506
+ return JsonhResult.from_value(element_null)
501
507
  # True
502
508
  case JsonTokenType.TRUE:
503
- element: bool = True
504
- if submit_element(element):
505
- return JsonhResult.from_value(element)
509
+ element_true: bool = True
510
+ if submit_element(element_true):
511
+ return JsonhResult.from_value(element_true)
506
512
  # False
507
513
  case JsonTokenType.FALSE:
508
- element: bool = False
509
- if submit_element(element):
510
- return JsonhResult.from_value(element)
514
+ element_false: bool = False
515
+ if submit_element(element_false):
516
+ return JsonhResult.from_value(element_false)
511
517
  # String
512
518
  case JsonTokenType.STRING:
513
- element: bool = token_result.value().value
514
- if submit_element(element):
515
- return JsonhResult.from_value(element)
519
+ element_string: str = token_result.value().value
520
+ if submit_element(element_string):
521
+ return JsonhResult.from_value(element_string)
516
522
  # Number
517
523
  case JsonTokenType.NUMBER:
518
- result: JsonhResult[float] = JsonhNumberParser.parse(token_result.value().value)
524
+ result: JsonhResult[float, str] = JsonhNumberParser.parse(token_result.value().value)
519
525
  if result.is_error:
520
526
  return JsonhResult.from_error(result.error())
521
- element: float = result.value()
522
- if submit_element(element):
523
- return JsonhResult.from_value(element)
527
+ element_number: float = result.value()
528
+ if submit_element(element_number):
529
+ return JsonhResult.from_value(element_number)
524
530
  # Start Object
525
531
  case JsonTokenType.START_OBJECT:
526
- element: dict[str, object] = {}
527
- start_element(element)
532
+ element_object: dict[str, object] = {}
533
+ start_element(element_object)
528
534
  # Start Array
529
535
  case JsonTokenType.START_ARRAY:
530
- element: list[object] = []
531
- start_element(element)
536
+ element_array: list[object] = []
537
+ start_element(element_array)
532
538
  # End Object/Array
533
539
  case JsonTokenType.END_OBJECT | JsonTokenType.END_ARRAY:
534
540
  # Nested element
@@ -547,7 +553,10 @@ class JsonhReader:
547
553
  case _:
548
554
  return JsonhResult.from_error("Token type not implemented")
549
555
 
550
- next_element = parse_next_element()
556
+ # End of input
557
+ return JsonhResult.from_error("Expected token, got end of input")
558
+
559
+ next_element: JsonhResult[object, str] = parse_next_element()
551
560
 
552
561
  # Ensure exactly one element
553
562
  if not next_element.is_error:
@@ -566,123 +575,136 @@ class JsonhReader:
566
575
 
567
576
  If `indent` is not null, the output is pretty-printed with the given indentation.
568
577
 
569
- The result is not safe to embed in HTML.
578
+ Note: The result is **NOT** safe to embed in HTML. To safely embed in HTML, you need to escape characters like `<`, `>` and `&`.
570
579
  """
571
580
 
572
- current_depth: int = 0
573
- isStartOfStructure: bool = True
574
- is_property_value: bool = False
581
+ def parse_next_element_as_json() -> JsonhResult[str, str]:
582
+ current_depth: int = 0
583
+ is_start_of_structure: bool = True
584
+ is_property_value: bool = False
575
585
 
576
- resultBuilder: str = ""
586
+ result_builder: str = ""
577
587
 
578
- for token_result in self.read_element():
579
- # Check error
580
- if (token_result.is_error):
581
- return JsonhResult.from_error(token_result.error())
582
- token: JsonhToken = token_result.value()
583
-
584
- # Add comments and indents
585
- if not is_property_value:
586
- # Add comma before property/item
587
- if (token.json_type not in [JsonTokenType.NONE, JsonTokenType.COMMENT]) and (current_depth > 0) and (not isStartOfStructure):
588
- # Don't add trailing comma
589
- if token.json_type not in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY]:
590
- resultBuilder += ','
591
-
592
- # Apply indentation
593
- if indent != None:
594
- # Don't indent inside empty structures
595
- if not (token.json_type in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY] and isStartOfStructure):
596
- # Don't indent comment if not included
597
- if (not (token.json_type == JsonTokenType.COMMENT and (not include_comments))):
598
- # Don't indent root elements
599
- if current_depth > 0:
600
- # Add newline before element
601
- resultBuilder += '\n'
602
-
603
- # Get current indent count
604
- indent_count: int = current_depth
605
- if token.json_type in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY]:
606
- indent_count -= 1
607
-
608
- # Add indent
609
- for _ in range(0, indent_count):
610
- resultBuilder += indent
611
- # Track start of structure to avoid adding leading comma
612
- if token.json_type not in [JsonTokenType.NONE, JsonTokenType.COMMENT]:
613
- isStartOfStructure = False
614
- if token.json_type in [JsonTokenType.START_OBJECT, JsonTokenType.START_ARRAY]:
615
- isStartOfStructure = True
616
-
617
- match token.json_type:
618
- # Null
619
- case JsonTokenType.NONE:
620
- resultBuilder += "null"
621
- if current_depth == 0:
622
- return JsonhResult.from_value(resultBuilder)
623
- # True
624
- case JsonTokenType.TRUE:
625
- resultBuilder += "true"
626
- if current_depth == 0:
627
- return JsonhResult.from_value(resultBuilder)
628
- # False
629
- case JsonTokenType.FALSE:
630
- resultBuilder += "false"
631
- if current_depth == 0:
632
- return JsonhResult.from_value(resultBuilder)
633
- # String
634
- case JsonTokenType.STRING:
635
- resultBuilder += json.dumps(token.value, ensure_ascii=False)
636
- if current_depth == 0:
637
- return JsonhResult.from_value(resultBuilder)
638
- # Number
639
- case JsonTokenType.NUMBER:
640
- result: JsonhResult[float] = JsonhNumberParser.parse(token_result.value().value)
641
- if (result.is_error):
642
- return JsonhResult.from_error(result.error())
643
- resultBuilder += str(result.value())
644
- if current_depth == 0:
645
- return JsonhResult.from_value(resultBuilder)
646
- # Start Object
647
- case JsonTokenType.START_OBJECT:
648
- resultBuilder += '{'
649
- current_depth += 1
650
- # Start Array
651
- case JsonTokenType.START_ARRAY:
652
- resultBuilder += '['
653
- current_depth += 1
654
- # End Object
655
- case JsonTokenType.END_OBJECT:
656
- resultBuilder += '}'
657
- current_depth -= 1
658
- if current_depth == 0:
659
- return JsonhResult.from_value(resultBuilder)
660
- # End Array
661
- case JsonTokenType.END_ARRAY:
662
- resultBuilder += ']'
663
- current_depth -= 1
664
- if current_depth == 0:
665
- return JsonhResult.from_value(resultBuilder)
666
- # Property Name
667
- case JsonTokenType.PROPERTY_NAME:
668
- resultBuilder += json.dumps(token.value, ensure_ascii=False)
669
- resultBuilder += ':'
588
+ for token_result in self.read_element():
589
+ # Check error
590
+ if token_result.is_error:
591
+ return JsonhResult.from_error(token_result.error())
592
+ token: JsonhToken = token_result.value()
593
+
594
+ # Add comments and indents
595
+ if not is_property_value:
596
+ # Add comma before property/item
597
+ if (token.json_type not in [JsonTokenType.NONE, JsonTokenType.COMMENT]) and (current_depth > 0) and (not is_start_of_structure):
598
+ # Don't add trailing comma
599
+ if token.json_type not in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY]:
600
+ result_builder += ','
601
+
602
+ # Apply indentation
670
603
  if indent != None:
671
- resultBuilder += ' '
672
- # Comment
673
- case JsonTokenType.COMMENT:
674
- if (include_comments):
675
- resultBuilder += "/*"
676
- resultBuilder += token.value.replace("/*", "/ *").replace("*/", "* /")
677
- resultBuilder += "*/"
678
- # Not implemented
679
- case _:
680
- return JsonhResult.from_error("Token type not implemented")
681
-
682
- is_property_value = token.json_type == JsonTokenType.PROPERTY_NAME
683
-
684
- # End of input
685
- return JsonhResult.from_error("Expected token, got end of input")
604
+ # Don't indent inside empty structures
605
+ if not (token.json_type in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY] and is_start_of_structure):
606
+ # Don't indent comment if not included
607
+ if not (token.json_type == JsonTokenType.COMMENT and (not include_comments)):
608
+ # Don't indent root elements
609
+ if current_depth > 0:
610
+ # Add newline before element
611
+ result_builder += '\n'
612
+
613
+ # Get current indent count
614
+ indent_count: int = current_depth
615
+ if token.json_type in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY]:
616
+ indent_count -= 1
617
+
618
+ # Add indent
619
+ for _ in range(0, indent_count):
620
+ result_builder += indent
621
+ # Track start of structure to avoid adding leading comma
622
+ if token.json_type not in [JsonTokenType.NONE, JsonTokenType.COMMENT]:
623
+ is_start_of_structure = False
624
+ if token.json_type in [JsonTokenType.START_OBJECT, JsonTokenType.START_ARRAY]:
625
+ is_start_of_structure = True
626
+
627
+ match token.json_type:
628
+ # Null
629
+ case JsonTokenType.NONE:
630
+ result_builder += "null"
631
+ if current_depth == 0:
632
+ return JsonhResult.from_value(result_builder)
633
+ # True
634
+ case JsonTokenType.TRUE:
635
+ result_builder += "true"
636
+ if current_depth == 0:
637
+ return JsonhResult.from_value(result_builder)
638
+ # False
639
+ case JsonTokenType.FALSE:
640
+ result_builder += "false"
641
+ if current_depth == 0:
642
+ return JsonhResult.from_value(result_builder)
643
+ # String
644
+ case JsonTokenType.STRING:
645
+ result_builder += json.dumps(token.value, ensure_ascii=False)
646
+ if current_depth == 0:
647
+ return JsonhResult.from_value(result_builder)
648
+ # Number
649
+ case JsonTokenType.NUMBER:
650
+ result: JsonhResult[float, str] = JsonhNumberParser.parse(token_result.value().value)
651
+ if result.is_error:
652
+ return JsonhResult.from_error(result.error())
653
+ result_builder += str(result.value()).removesuffix(".0")
654
+ if current_depth == 0:
655
+ return JsonhResult.from_value(result_builder)
656
+ # Start Object
657
+ case JsonTokenType.START_OBJECT:
658
+ result_builder += '{'
659
+ current_depth += 1
660
+ # Start Array
661
+ case JsonTokenType.START_ARRAY:
662
+ result_builder += '['
663
+ current_depth += 1
664
+ # End Object
665
+ case JsonTokenType.END_OBJECT:
666
+ result_builder += '}'
667
+ current_depth -= 1
668
+ if current_depth == 0:
669
+ return JsonhResult.from_value(result_builder)
670
+ # End Array
671
+ case JsonTokenType.END_ARRAY:
672
+ result_builder += ']'
673
+ current_depth -= 1
674
+ if current_depth == 0:
675
+ return JsonhResult.from_value(result_builder)
676
+ # Property Name
677
+ case JsonTokenType.PROPERTY_NAME:
678
+ result_builder += json.dumps(token.value, ensure_ascii=False)
679
+ result_builder += ':'
680
+ if indent != None:
681
+ result_builder += ' '
682
+ # Comment
683
+ case JsonTokenType.COMMENT:
684
+ if include_comments:
685
+ result_builder += "/*"
686
+ result_builder += token.value.replace("/*", "/ *").replace("*/", "* /")
687
+ result_builder += "*/"
688
+ # Not implemented
689
+ case _:
690
+ return JsonhResult.from_error("Token type not implemented")
691
+
692
+ if token.json_type != JsonTokenType.COMMENT:
693
+ is_property_value = token.json_type == JsonTokenType.PROPERTY_NAME
694
+
695
+ # End of input
696
+ return JsonhResult.from_error("Expected token, got end of input")
697
+
698
+ next_element_as_json: JsonhResult[str, str] = parse_next_element_as_json()
699
+
700
+ # Ensure exactly one element
701
+ if not next_element_as_json.is_error:
702
+ if self.options.parse_single_element:
703
+ for token in self.read_end_of_elements():
704
+ if token.is_error:
705
+ return JsonhResult.from_error(token.error())
706
+
707
+ return next_element_as_json
686
708
 
687
709
  def find_property_value(self, property_name: str) -> bool:
688
710
  """
@@ -732,7 +754,7 @@ class JsonhReader:
732
754
  # Peek char
733
755
  return self._peek() != None
734
756
 
735
- def read_end_of_elements(self) -> Iterator[JsonhResult]:
757
+ def read_end_of_elements(self) -> Iterator[JsonhResult[JsonhToken, str]]:
736
758
  """
737
759
  Reads comments and whitespace and errors if the reader contains another element.
738
760
  """
@@ -827,6 +849,7 @@ class JsonhReader:
827
849
  return
828
850
  # Missing closing brace
829
851
  yield JsonhResult.from_error("Expected `}` to end object, got end of input")
852
+ return
830
853
 
831
854
  # Closing brace
832
855
  if next == '}':
@@ -951,14 +974,12 @@ class JsonhReader:
951
974
  # Optional comma
952
975
  self._read_one(',')
953
976
 
954
- def _read_property_name(self, string: str | None = None) -> Iterator[JsonhResult[JsonhToken, str]]:
977
+ def _read_property_name(self) -> Iterator[JsonhResult[JsonhToken, str]]:
955
978
  # String
956
- if string == None:
957
- string_token: JsonhResult[JsonhToken, str] = self._read_string()
958
- if string_token.is_error:
959
- yield string_token
960
- return
961
- string = string_token.value().value
979
+ string_token: JsonhResult[JsonhToken, str] = self._read_string()
980
+ if string_token.is_error:
981
+ yield string_token
982
+ return
962
983
 
963
984
  # Comments & whitespace
964
985
  for token in self._read_comments_and_whitespace():
@@ -973,7 +994,7 @@ class JsonhReader:
973
994
  return
974
995
 
975
996
  # End of property name
976
- yield JsonhResult.from_value(JsonhToken(JsonTokenType.PROPERTY_NAME, string))
997
+ yield JsonhResult.from_value(JsonhToken(JsonTokenType.PROPERTY_NAME, string_token.value().value))
977
998
 
978
999
  def _read_array(self) -> Iterator[JsonhResult[JsonhToken, str]]:
979
1000
  # Opening bracket
@@ -1058,7 +1079,7 @@ class JsonhReader:
1058
1079
  return self._read_quoteless_string("", is_verbatim)
1059
1080
 
1060
1081
  # Count multiple quotes
1061
- start_quote_counter = 1
1082
+ start_quote_counter: int = 1
1062
1083
  while self._read_one(start_quote):
1063
1084
  start_quote_counter += 1
1064
1085
 
@@ -1073,24 +1094,24 @@ class JsonhReader:
1073
1094
  string_builder: str = ""
1074
1095
 
1075
1096
  while True:
1076
- next: str | None = self._read()
1077
- if next == None:
1097
+ next2: str | None = self._read()
1098
+ if next2 == None:
1078
1099
  return JsonhResult.from_error("Expected end of string, got end of input")
1079
1100
 
1080
1101
  # Partial end quote was actually part of string
1081
- if next != start_quote:
1102
+ if next2 != start_quote:
1082
1103
  string_builder += start_quote * end_quote_counter
1083
1104
  end_quote_counter = 0
1084
1105
 
1085
1106
  # End quote
1086
- if next == start_quote:
1107
+ if next2 == start_quote:
1087
1108
  end_quote_counter += 1
1088
1109
  if end_quote_counter == start_quote_counter:
1089
1110
  break
1090
1111
  # Escape sequence
1091
- elif next == '\\':
1112
+ elif next2 == '\\':
1092
1113
  if is_verbatim:
1093
- string_builder += next
1114
+ string_builder += next2
1094
1115
  else:
1095
1116
  escape_sequence_result: JsonhResult[str, str] = self._read_escape_sequence()
1096
1117
  if escape_sequence_result.is_error:
@@ -1098,7 +1119,7 @@ class JsonhReader:
1098
1119
  string_builder += escape_sequence_result.value()
1099
1120
  # Literal character
1100
1121
  else:
1101
- string_builder += next
1122
+ string_builder += next2
1102
1123
 
1103
1124
  # Condition: skip remaining steps unless started with multiple quotes
1104
1125
  if start_quote_counter > 1:
@@ -1107,19 +1128,19 @@ class JsonhReader:
1107
1128
  leading_whitespace_newline_counter: int = 0
1108
1129
  index: int = 0
1109
1130
  while index < len(string_builder):
1110
- next: str = string_builder[index]
1131
+ next3: str = string_builder[index]
1111
1132
 
1112
1133
  # Newline
1113
- if next in self._NEWLINE_CHARS:
1134
+ if next3 in self._NEWLINE_CHARS:
1114
1135
  # Join CR LF
1115
- if next == '\r' and index + 1 < len(string_builder) and string_builder[index + 1] == '\n':
1136
+ if next3 == '\r' and index + 1 < len(string_builder) and string_builder[index + 1] == '\n':
1116
1137
  index += 1
1117
1138
 
1118
1139
  has_leading_whitespace_newline = True
1119
1140
  leading_whitespace_newline_counter = index + 1
1120
1141
  break
1121
1142
  # Non-whitespace
1122
- elif next not in self._WHITESPACE_CHARS:
1143
+ elif next3 not in self._WHITESPACE_CHARS:
1123
1144
  break
1124
1145
 
1125
1146
  index += 1
@@ -1132,19 +1153,19 @@ class JsonhReader:
1132
1153
  trailing_whitespace_counter: int = 0
1133
1154
  index: int = 0
1134
1155
  while index < len(string_builder):
1135
- next: str = string_builder[index]
1156
+ next4: str = string_builder[index]
1136
1157
 
1137
1158
  # Newline
1138
- if next in self._NEWLINE_CHARS:
1159
+ if next4 in self._NEWLINE_CHARS:
1139
1160
  has_trailing_newline_whitespace = True
1140
1161
  last_newline_index = index
1141
1162
  trailing_whitespace_counter = 0
1142
1163
 
1143
1164
  # Join CR LF
1144
- if next == '\r' and index + 1 < len(string_builder) and string_builder[index + 1] == '\n':
1165
+ if next4 == '\r' and index + 1 < len(string_builder) and string_builder[index + 1] == '\n':
1145
1166
  index += 1
1146
1167
  # Whitespace
1147
- elif next in self._WHITESPACE_CHARS:
1168
+ elif next4 in self._WHITESPACE_CHARS:
1148
1169
  trailing_whitespace_counter += 1
1149
1170
  # Non-whitespace
1150
1171
  else:
@@ -1168,14 +1189,14 @@ class JsonhReader:
1168
1189
  line_leading_whitespace_counter: int = 0
1169
1190
  index: int = 0
1170
1191
  while index < len(string_builder):
1171
- next: str = string_builder[index]
1192
+ next5: str = string_builder[index]
1172
1193
 
1173
1194
  # Newline
1174
- if next in self._NEWLINE_CHARS:
1195
+ if next5 in self._NEWLINE_CHARS:
1175
1196
  is_line_leading_whitespace = True
1176
1197
  line_leading_whitespace_counter = 0
1177
1198
  # Whitespace
1178
- elif next in self._WHITESPACE_CHARS:
1199
+ elif next5 in self._WHITESPACE_CHARS:
1179
1200
  if is_line_leading_whitespace:
1180
1201
  # Increment line-leading whitespace
1181
1202
  line_leading_whitespace_counter += 1
@@ -1219,7 +1240,7 @@ class JsonhReader:
1219
1240
  if is_verbatim:
1220
1241
  string_builder += next
1221
1242
  else:
1222
- escape_sequence_result: JsonhResult[str] = self._read_escape_sequence()
1243
+ escape_sequence_result: JsonhResult[str, str] = self._read_escape_sequence()
1223
1244
  if escape_sequence_result.is_error:
1224
1245
  return JsonhResult.from_error(escape_sequence_result.error())
1225
1246
  string_builder += escape_sequence_result.value()
@@ -1325,9 +1346,9 @@ class JsonhReader:
1325
1346
  has_leading_zero = False
1326
1347
 
1327
1348
  # Read main number
1328
- main_result: JsonhResult[None, None] = self._read_number_no_exponent(number_builder, base_digits, has_base_specifier, has_leading_zero)
1349
+ main_result: JsonhResult[None, str] = self._read_number_no_exponent(number_builder, base_digits, has_base_specifier, has_leading_zero)
1329
1350
  if main_result.is_error:
1330
- number: JsonhResult[None, str] = JsonhResult.from_error(main_result.error())
1351
+ number: JsonhResult[JsonhToken, str] = JsonhResult.from_error(main_result.error())
1331
1352
  partial_chars_read: str = number_builder.ref
1332
1353
  return number, partial_chars_read
1333
1354
 
@@ -1340,16 +1361,16 @@ class JsonhReader:
1340
1361
 
1341
1362
  # Missing digit between base specifier and exponent (e.g. `0xe+`)
1342
1363
  if has_base_specifier and len(number_builder.ref) == 4:
1343
- number: JsonhResult[None, str] = JsonhResult.from_error("Missing digit between base specifier and exponent")
1364
+ number2: JsonhResult[JsonhToken, str] = JsonhResult.from_error("Missing digit between base specifier and exponent")
1344
1365
  partial_chars_read: str = number_builder.ref
1345
- return number, partial_chars_read
1366
+ return number2, partial_chars_read
1346
1367
 
1347
1368
  # Read exponent number
1348
- exponent_result: JsonhResult[None, None] = self._read_number_no_exponent(number_builder, base_digits)
1369
+ exponent_result: JsonhResult[None, str] = self._read_number_no_exponent(number_builder, base_digits)
1349
1370
  if exponent_result.is_error:
1350
- number: JsonhResult[None, str] = JsonhResult.from_error(exponent_result.error())
1371
+ number3: JsonhResult[JsonhToken, str] = JsonhResult.from_error(exponent_result.error())
1351
1372
  partial_chars_read: str = number_builder.ref
1352
- return number, partial_chars_read
1373
+ return number3, partial_chars_read
1353
1374
  # Exponent
1354
1375
  else:
1355
1376
  exponent_char: str | None = self._read_any('e', 'E')
@@ -1362,20 +1383,20 @@ class JsonhReader:
1362
1383
  number_builder.ref += exponent_sign
1363
1384
 
1364
1385
  # Read exponent number
1365
- exponent_result: JsonhResult[None, None] = self._read_number_no_exponent(number_builder, base_digits)
1366
- if exponent_result.is_error:
1367
- number: JsonhResult[None, str] = JsonhResult.from_error(exponent_result.error())
1386
+ exponent_result2: JsonhResult[None, str] = self._read_number_no_exponent(number_builder, base_digits)
1387
+ if exponent_result2.is_error:
1388
+ number4: JsonhResult[JsonhToken, str] = JsonhResult.from_error(exponent_result2.error())
1368
1389
  partial_chars_read: str = number_builder.ref
1369
- return number, partial_chars_read
1390
+ return number4, partial_chars_read
1370
1391
 
1371
1392
  # End of number
1372
- number: JsonhResult[JsonhToken, str] = JsonhResult.from_value(JsonhToken(JsonTokenType.NUMBER, number_builder.ref))
1393
+ number5: JsonhResult[JsonhToken, str] = JsonhResult.from_value(JsonhToken(JsonTokenType.NUMBER, number_builder.ref))
1373
1394
  partial_chars_read: str = ""
1374
- return number, partial_chars_read
1395
+ return number5, partial_chars_read
1375
1396
 
1376
- def _read_number_no_exponent(self, number_builder: JsonhRef[str], base_digits: str, has_base_specifier: bool = False, has_leading_zero: bool = False) -> JsonhResult[None, None]:
1397
+ def _read_number_no_exponent(self, number_builder: JsonhRef[str], base_digits: str, has_base_specifier: bool = False, has_leading_zero: bool = False) -> JsonhResult[None, str]:
1377
1398
  # Leading underscore
1378
- if (not has_base_specifier) and not (has_leading_zero) and self._peek() == '_':
1399
+ if (not has_base_specifier) and (not has_leading_zero) and self._peek() == '_':
1379
1400
  return JsonhResult.from_error("Leading `_` in number")
1380
1401
 
1381
1402
  is_fraction: bool = False
@@ -1694,16 +1715,16 @@ class JsonhReader:
1694
1715
  return code_point >= 0xDC00 and code_point <= 0xDFFF
1695
1716
 
1696
1717
  def _peek(self) -> str | None:
1697
- if self.index >= len(self.string):
1718
+ if self.string_index >= len(self.string):
1698
1719
  return None
1699
- next: str = self.string[self.index]
1720
+ next: str = self.string[self.string_index]
1700
1721
  return next
1701
1722
 
1702
1723
  def _read(self) -> str | None:
1703
- if self.index >= len(self.string):
1724
+ if self.string_index >= len(self.string):
1704
1725
  return None
1705
- next: str = self.string[self.index]
1706
- self.index += 1
1726
+ next: str = self.string[self.string_index]
1727
+ self.string_index += 1
1707
1728
  self.char_counter += 1
1708
1729
  return next
1709
1730
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JsonhPy
3
- Version: 2.4
3
+ Version: 2.6
4
4
  Summary: JSON for Humans in Python.
5
5
  Author-email: Joyless <joyless.mod@gmail.com>
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes
File without changes