JsonhPy 2.3__tar.gz → 2.5__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.
- {jsonhpy-2.3 → jsonhpy-2.5}/PKG-INFO +1 -1
- {jsonhpy-2.3 → jsonhpy-2.5}/pyproject.toml +1 -1
- {jsonhpy-2.3 → jsonhpy-2.5}/src/JsonhPy/JsonhPy.py +141 -1
- {jsonhpy-2.3 → jsonhpy-2.5}/src/JsonhPy.egg-info/PKG-INFO +1 -1
- {jsonhpy-2.3 → jsonhpy-2.5}/LICENSE.md +0 -0
- {jsonhpy-2.3 → jsonhpy-2.5}/README.md +0 -0
- {jsonhpy-2.3 → jsonhpy-2.5}/setup.cfg +0 -0
- {jsonhpy-2.3 → jsonhpy-2.5}/src/JsonhPy/__init__.py +0 -0
- {jsonhpy-2.3 → jsonhpy-2.5}/src/JsonhPy.egg-info/SOURCES.txt +0 -0
- {jsonhpy-2.3 → jsonhpy-2.5}/src/JsonhPy.egg-info/dependency_links.txt +0 -0
- {jsonhpy-2.3 → jsonhpy-2.5}/src/JsonhPy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import math
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from typing import Iterator, Iterable
|
|
4
|
+
import json
|
|
4
5
|
|
|
5
6
|
class JsonhResult[T, E]:
|
|
6
7
|
is_error: bool
|
|
@@ -546,7 +547,7 @@ class JsonhReader:
|
|
|
546
547
|
case _:
|
|
547
548
|
return JsonhResult.from_error("Token type not implemented")
|
|
548
549
|
|
|
549
|
-
next_element = parse_next_element()
|
|
550
|
+
next_element: JsonhResult[object, str] = parse_next_element()
|
|
550
551
|
|
|
551
552
|
# Ensure exactly one element
|
|
552
553
|
if not next_element.is_error:
|
|
@@ -557,6 +558,145 @@ class JsonhReader:
|
|
|
557
558
|
|
|
558
559
|
return next_element
|
|
559
560
|
|
|
561
|
+
def parse_json(self, include_comments: bool = False, indent: str | None = None) -> JsonhResult[str, str]:
|
|
562
|
+
"""
|
|
563
|
+
Parses a single element as JSON from the reader.
|
|
564
|
+
|
|
565
|
+
If `include_comments` is true, comments are included (`/*` and `*/` are escaped as `/ *` and `* /`).
|
|
566
|
+
|
|
567
|
+
If `indent` is not null, the output is pretty-printed with the given indentation.
|
|
568
|
+
|
|
569
|
+
Note: The result is **NOT** safe to embed in HTML. To safely embed in HTML, you need to escape characters like `<`, `>` and `&`.
|
|
570
|
+
"""
|
|
571
|
+
|
|
572
|
+
def parse_next_element_as_json() -> JsonhResult[str, str]:
|
|
573
|
+
current_depth: int = 0
|
|
574
|
+
isStartOfStructure: bool = True
|
|
575
|
+
is_property_value: bool = False
|
|
576
|
+
|
|
577
|
+
result_builder: str = ""
|
|
578
|
+
|
|
579
|
+
for token_result in self.read_element():
|
|
580
|
+
# Check error
|
|
581
|
+
if (token_result.is_error):
|
|
582
|
+
return JsonhResult.from_error(token_result.error())
|
|
583
|
+
token: JsonhToken = token_result.value()
|
|
584
|
+
|
|
585
|
+
# Add comments and indents
|
|
586
|
+
if not is_property_value:
|
|
587
|
+
# Add comma before property/item
|
|
588
|
+
if (token.json_type not in [JsonTokenType.NONE, JsonTokenType.COMMENT]) and (current_depth > 0) and (not isStartOfStructure):
|
|
589
|
+
# Don't add trailing comma
|
|
590
|
+
if token.json_type not in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY]:
|
|
591
|
+
result_builder += ','
|
|
592
|
+
|
|
593
|
+
# Apply indentation
|
|
594
|
+
if indent != None:
|
|
595
|
+
# Don't indent inside empty structures
|
|
596
|
+
if not (token.json_type in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY] and isStartOfStructure):
|
|
597
|
+
# Don't indent comment if not included
|
|
598
|
+
if (not (token.json_type == JsonTokenType.COMMENT and (not include_comments))):
|
|
599
|
+
# Don't indent root elements
|
|
600
|
+
if current_depth > 0:
|
|
601
|
+
# Add newline before element
|
|
602
|
+
result_builder += '\n'
|
|
603
|
+
|
|
604
|
+
# Get current indent count
|
|
605
|
+
indent_count: int = current_depth
|
|
606
|
+
if token.json_type in [JsonTokenType.END_OBJECT, JsonTokenType.END_ARRAY]:
|
|
607
|
+
indent_count -= 1
|
|
608
|
+
|
|
609
|
+
# Add indent
|
|
610
|
+
for _ in range(0, indent_count):
|
|
611
|
+
result_builder += indent
|
|
612
|
+
# Track start of structure to avoid adding leading comma
|
|
613
|
+
if token.json_type not in [JsonTokenType.NONE, JsonTokenType.COMMENT]:
|
|
614
|
+
isStartOfStructure = False
|
|
615
|
+
if token.json_type in [JsonTokenType.START_OBJECT, JsonTokenType.START_ARRAY]:
|
|
616
|
+
isStartOfStructure = True
|
|
617
|
+
|
|
618
|
+
match token.json_type:
|
|
619
|
+
# Null
|
|
620
|
+
case JsonTokenType.NONE:
|
|
621
|
+
result_builder += "null"
|
|
622
|
+
if current_depth == 0:
|
|
623
|
+
return JsonhResult.from_value(result_builder)
|
|
624
|
+
# True
|
|
625
|
+
case JsonTokenType.TRUE:
|
|
626
|
+
result_builder += "true"
|
|
627
|
+
if current_depth == 0:
|
|
628
|
+
return JsonhResult.from_value(result_builder)
|
|
629
|
+
# False
|
|
630
|
+
case JsonTokenType.FALSE:
|
|
631
|
+
result_builder += "false"
|
|
632
|
+
if current_depth == 0:
|
|
633
|
+
return JsonhResult.from_value(result_builder)
|
|
634
|
+
# String
|
|
635
|
+
case JsonTokenType.STRING:
|
|
636
|
+
result_builder += json.dumps(token.value, ensure_ascii=False)
|
|
637
|
+
if current_depth == 0:
|
|
638
|
+
return JsonhResult.from_value(result_builder)
|
|
639
|
+
# Number
|
|
640
|
+
case JsonTokenType.NUMBER:
|
|
641
|
+
result: JsonhResult[float] = JsonhNumberParser.parse(token_result.value().value)
|
|
642
|
+
if (result.is_error):
|
|
643
|
+
return JsonhResult.from_error(result.error())
|
|
644
|
+
result_builder += str(result.value()).removesuffix(".0")
|
|
645
|
+
if current_depth == 0:
|
|
646
|
+
return JsonhResult.from_value(result_builder)
|
|
647
|
+
# Start Object
|
|
648
|
+
case JsonTokenType.START_OBJECT:
|
|
649
|
+
result_builder += '{'
|
|
650
|
+
current_depth += 1
|
|
651
|
+
# Start Array
|
|
652
|
+
case JsonTokenType.START_ARRAY:
|
|
653
|
+
result_builder += '['
|
|
654
|
+
current_depth += 1
|
|
655
|
+
# End Object
|
|
656
|
+
case JsonTokenType.END_OBJECT:
|
|
657
|
+
result_builder += '}'
|
|
658
|
+
current_depth -= 1
|
|
659
|
+
if current_depth == 0:
|
|
660
|
+
return JsonhResult.from_value(result_builder)
|
|
661
|
+
# End Array
|
|
662
|
+
case JsonTokenType.END_ARRAY:
|
|
663
|
+
result_builder += ']'
|
|
664
|
+
current_depth -= 1
|
|
665
|
+
if current_depth == 0:
|
|
666
|
+
return JsonhResult.from_value(result_builder)
|
|
667
|
+
# Property Name
|
|
668
|
+
case JsonTokenType.PROPERTY_NAME:
|
|
669
|
+
result_builder += json.dumps(token.value, ensure_ascii=False)
|
|
670
|
+
result_builder += ':'
|
|
671
|
+
if indent != None:
|
|
672
|
+
result_builder += ' '
|
|
673
|
+
# Comment
|
|
674
|
+
case JsonTokenType.COMMENT:
|
|
675
|
+
if (include_comments):
|
|
676
|
+
result_builder += "/*"
|
|
677
|
+
result_builder += token.value.replace("/*", "/ *").replace("*/", "* /")
|
|
678
|
+
result_builder += "*/"
|
|
679
|
+
# Not implemented
|
|
680
|
+
case _:
|
|
681
|
+
return JsonhResult.from_error("Token type not implemented")
|
|
682
|
+
|
|
683
|
+
if token.json_type != JsonTokenType.COMMENT:
|
|
684
|
+
is_property_value = token.json_type == JsonTokenType.PROPERTY_NAME
|
|
685
|
+
|
|
686
|
+
# End of input
|
|
687
|
+
return JsonhResult.from_error("Expected token, got end of input")
|
|
688
|
+
|
|
689
|
+
next_element_as_json: JsonhResult[str, str] = parse_next_element_as_json()
|
|
690
|
+
|
|
691
|
+
# Ensure exactly one element
|
|
692
|
+
if not next_element_as_json.is_error:
|
|
693
|
+
if self.options.parse_single_element:
|
|
694
|
+
for token in self.read_end_of_elements():
|
|
695
|
+
if token.is_error:
|
|
696
|
+
return JsonhResult.from_error(token.error())
|
|
697
|
+
|
|
698
|
+
return next_element_as_json
|
|
699
|
+
|
|
560
700
|
def find_property_value(self, property_name: str) -> bool:
|
|
561
701
|
"""
|
|
562
702
|
Tries to find the given property name in the reader.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|