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 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)