Coverage for gws-app/gws/lib/jsonx/__init__.py: 82%
38 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""JSON utilities.
3Thin wrappers around the standard ``json`` module that read and write JSON strings and
4files. Objects that are not JSON serializable are converted to their attribute dicts
5(``vars``) or to strings, so that ``gws.Data`` objects can be serialized directly.
6All errors are raised as ``Error``.
8Example::
10 s = gws.lib.jsonx.to_pretty_string({'a': 1, 'b': [1, 2]})
11 d = gws.lib.jsonx.from_string(s)
12 gws.lib.jsonx.to_path('/tmp/data.json', d)
13"""
15import json
17import gws
20class Error(gws.Error):
21 """JSON error."""
23 pass
26def from_path(path: str):
27 """Read a JSON file.
29 Args:
30 path: Path to a UTF-8 encoded JSON file.
32 Returns:
33 The decoded object.
35 Raises:
36 ``Error``: If the file cannot be read or is not valid JSON.
37 """
39 try:
40 with open(path, 'rb') as fp:
41 s = fp.read()
42 return json.loads(s.decode('utf8'))
43 except Exception as exc:
44 raise Error() from exc
47def from_string(s: str):
48 """Decode a JSON string.
50 Args:
51 s: JSON string.
53 Returns:
54 The decoded object, or an empty dict if the string is empty or blank.
56 Raises:
57 ``Error``: If the string is not valid JSON.
58 """
60 if not s.strip():
61 return {}
62 try:
63 return json.loads(s)
64 except Exception as exc:
65 raise Error() from exc
68def to_path(path: str, x, pretty: bool = False, ensure_ascii: bool = True, default=None):
69 """Write an object to a JSON file, UTF-8 encoded.
71 Args:
72 path: File path.
73 x: Object to write.
74 pretty: If ``True``, sort the keys and indent the output.
75 ensure_ascii: If ``True``, escape non-ASCII characters.
76 default: Function that returns a serializable version of an object that is not serializable otherwise.
77 By default, objects are converted to their ``vars``, or to strings if they have none.
79 Raises:
80 ``Error``: If the object cannot be encoded or the file cannot be written.
81 """
83 s = to_string(x, pretty=pretty, ensure_ascii=ensure_ascii, default=default)
84 try:
85 gws.u.write_file_b(path, s.encode('utf8'))
86 except Exception as exc:
87 raise Error() from exc
90def to_string(x, pretty: bool = False, ensure_ascii: bool = True, default=None) -> str:
91 """Encode an object as a JSON string.
93 Args:
94 x: Object to encode.
95 pretty: If ``True``, sort the keys and indent the output.
96 ensure_ascii: If ``True``, escape non-ASCII characters.
97 default: Function that returns a serializable version of an object that is not serializable otherwise.
98 By default, objects are converted to their ``vars``, or to strings if they have none.
100 Returns:
101 The JSON string.
103 Raises:
104 ``Error``: If the object cannot be encoded.
105 """
107 try:
108 if pretty:
109 return json.dumps(
110 x,
111 check_circular=False,
112 default=default or _json_default,
113 ensure_ascii=ensure_ascii,
114 indent=4,
115 sort_keys=True,
116 )
117 return json.dumps(
118 x,
119 check_circular=False,
120 default=default or _json_default,
121 ensure_ascii=ensure_ascii,
122 )
123 except Exception as exc:
124 raise Error() from exc
127def to_pretty_string(x, ensure_ascii: bool = True, default=None) -> str:
128 """Encode an object as a JSON string with sorted keys and indentation.
130 Args:
131 x: Object to encode.
132 ensure_ascii: If ``True``, escape non-ASCII characters.
133 default: Function that returns a serializable version of an object that is not serializable otherwise.
134 By default, objects are converted to their ``vars``, or to strings if they have none.
136 Returns:
137 The JSON string.
139 Raises:
140 ``Error``: If the object cannot be encoded.
141 """
143 return to_string(x, pretty=True, ensure_ascii=ensure_ascii, default=default)
146def _json_default(x):
147 """Convert an object to its attribute dict, or to a string if it has none."""
148 try:
149 return vars(x)
150 except TypeError:
151 return str(x)