jsonyx 0.0.1__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.
- jsonyx/__init__.py +132 -0
- jsonyx/_accelerator.c +1922 -0
- jsonyx/_accelerator.py +11 -0
- jsonyx/_accelerator.pyi +22 -0
- jsonyx/decoder.py +307 -0
- jsonyx/encoder.py +42 -0
- jsonyx/py.typed +1 -0
- jsonyx/scanner.py +164 -0
- jsonyx/tool.py +91 -0
- jsonyx-0.0.1.dist-info/METADATA +15 -0
- jsonyx-0.0.1.dist-info/RECORD +13 -0
- jsonyx-0.0.1.dist-info/WHEEL +4 -0
- jsonyx-0.0.1.dist-info/licenses/LICENSE +674 -0
jsonyx/__init__.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Copyright (C) 2024 Nice Zombies
|
|
2
|
+
"""JSONYX module."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__: list[str] = ["dump", "dumps", "load", "loads"]
|
|
6
|
+
|
|
7
|
+
from codecs import (
|
|
8
|
+
BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE,
|
|
9
|
+
)
|
|
10
|
+
from os.path import realpath
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from typing_extensions import Any, Literal
|
|
14
|
+
|
|
15
|
+
from jsonyx.decoder import JSONDecoder
|
|
16
|
+
from jsonyx.encoder import JSONEncoder
|
|
17
|
+
from jsonyx.scanner import JSONSyntaxError
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Callable, Container
|
|
21
|
+
|
|
22
|
+
from _typeshed import SupportsRead, SupportsWrite
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# pylint: disable-next=R0913
|
|
26
|
+
def dump( # noqa: PLR0913
|
|
27
|
+
obj: Any,
|
|
28
|
+
fp: SupportsWrite[str],
|
|
29
|
+
*,
|
|
30
|
+
allow: Container[Literal["nan"] | str] = (),
|
|
31
|
+
ensure_ascii: bool = False,
|
|
32
|
+
indent: int | str | None = None,
|
|
33
|
+
item_separator: str = ", ",
|
|
34
|
+
key_separator: str = ": ",
|
|
35
|
+
sort_keys: bool = False,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Serialize object to a JSON formatted file."""
|
|
38
|
+
for chunk in JSONEncoder(
|
|
39
|
+
allow=allow,
|
|
40
|
+
ensure_ascii=ensure_ascii,
|
|
41
|
+
indent=indent,
|
|
42
|
+
item_separator=item_separator,
|
|
43
|
+
key_separator=key_separator,
|
|
44
|
+
sort_keys=sort_keys,
|
|
45
|
+
).iterencode(obj):
|
|
46
|
+
fp.write(chunk)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# pylint: disable-next=R0913
|
|
50
|
+
def dumps( # noqa: PLR0913
|
|
51
|
+
obj: Any,
|
|
52
|
+
*,
|
|
53
|
+
allow: Container[Literal["nan"] | str] = (),
|
|
54
|
+
ensure_ascii: bool = False,
|
|
55
|
+
indent: int | str | None = None,
|
|
56
|
+
item_separator: str = ", ",
|
|
57
|
+
key_separator: str = ": ",
|
|
58
|
+
sort_keys: bool = False,
|
|
59
|
+
) -> str:
|
|
60
|
+
"""Serialize object to a JSON formatted string."""
|
|
61
|
+
return JSONEncoder(
|
|
62
|
+
allow=allow,
|
|
63
|
+
ensure_ascii=ensure_ascii,
|
|
64
|
+
indent=indent,
|
|
65
|
+
item_separator=item_separator,
|
|
66
|
+
key_separator=key_separator,
|
|
67
|
+
sort_keys=sort_keys,
|
|
68
|
+
).encode(obj)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _decode_bytes(b: bytearray | bytes) -> str:
|
|
72
|
+
encoding: str = "utf-8"
|
|
73
|
+
startswith: Callable[[bytes | tuple[bytes, ...]], bool] = b.startswith
|
|
74
|
+
if startswith((BOM_UTF32_BE, BOM_UTF32_LE)):
|
|
75
|
+
encoding = "utf-32"
|
|
76
|
+
elif startswith((BOM_UTF16_BE, BOM_UTF16_LE)):
|
|
77
|
+
encoding = "utf-16"
|
|
78
|
+
elif startswith(BOM_UTF8):
|
|
79
|
+
encoding = "utf-8-sig"
|
|
80
|
+
elif len(b) >= 4:
|
|
81
|
+
if not b[0]:
|
|
82
|
+
# 00 00 -- -- - utf-32-be
|
|
83
|
+
# 00 XX -- -- - utf-16-be
|
|
84
|
+
encoding = "utf-16-be" if b[1] else "utf-32-be"
|
|
85
|
+
elif not b[1]:
|
|
86
|
+
# XX 00 00 00 - utf-32-le
|
|
87
|
+
# XX 00 00 XX - utf-16-le
|
|
88
|
+
# XX 00 XX -- - utf-16-le
|
|
89
|
+
encoding = "utf-16-le" if b[2] or b[3] else "utf-32-le"
|
|
90
|
+
elif len(b) == 2:
|
|
91
|
+
if not b[0]:
|
|
92
|
+
# 00 XX - utf-16-be
|
|
93
|
+
encoding = "utf-16-be"
|
|
94
|
+
elif not b[1]:
|
|
95
|
+
# XX 00 - utf-16-le
|
|
96
|
+
encoding = "utf-16-le"
|
|
97
|
+
|
|
98
|
+
return b.decode(encoding, "surrogatepass")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def load(
|
|
102
|
+
fp: SupportsRead[bytearray | bytes | str],
|
|
103
|
+
*,
|
|
104
|
+
allow: Container[
|
|
105
|
+
Literal["comments", "duplicate_keys", "nan", "trailing_comma"] | str
|
|
106
|
+
] = (),
|
|
107
|
+
) -> Any:
|
|
108
|
+
"""Deserialize a JSON file to a Python object."""
|
|
109
|
+
return loads(
|
|
110
|
+
fp.read(), allow=allow, filename=getattr(fp, "name", "<string>"),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def loads(
|
|
115
|
+
s: bytearray | bytes | str,
|
|
116
|
+
*,
|
|
117
|
+
allow: Container[
|
|
118
|
+
Literal["comments", "duplicate_keys", "nan", "trailing_comma"] | str
|
|
119
|
+
] = (),
|
|
120
|
+
filename: str = "<string>",
|
|
121
|
+
) -> Any:
|
|
122
|
+
"""Deserialize a JSON document to a Python object."""
|
|
123
|
+
if not filename.startswith("<") and not filename.endswith(">"):
|
|
124
|
+
filename = realpath(filename)
|
|
125
|
+
|
|
126
|
+
if not isinstance(s, str):
|
|
127
|
+
s = _decode_bytes(s)
|
|
128
|
+
elif s.startswith("\ufeff"):
|
|
129
|
+
msg: str = "Unexpected UTF-8 BOM"
|
|
130
|
+
raise JSONSyntaxError(msg, filename, s, 0)
|
|
131
|
+
|
|
132
|
+
return JSONDecoder(allow=allow).decode(s, filename=filename)
|