Pyjoyment 0.1.0__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.
- Pyjo/App/ASGI.py +735 -0
- Pyjo/App/CGI.py +773 -0
- Pyjo/App/FastCGI.py +631 -0
- Pyjo/App/Lambda.py +987 -0
- Pyjo/App/WSGI.py +427 -0
- Pyjo/App/__init__.py +409 -0
- Pyjo/Asset/File.py +377 -0
- Pyjo/Asset/Memory.py +235 -0
- Pyjo/Asset/__init__.py +200 -0
- Pyjo/Base.py +215 -0
- Pyjo/Cache.py +119 -0
- Pyjo/Collection.py +570 -0
- Pyjo/Content/MultiPart.py +325 -0
- Pyjo/Content/Single.py +193 -0
- Pyjo/Content/__init__.py +806 -0
- Pyjo/Cookie/Request.py +90 -0
- Pyjo/Cookie/Response.py +294 -0
- Pyjo/Cookie/__init__.py +143 -0
- Pyjo/DOM/CSS.py +1019 -0
- Pyjo/DOM/HTML.py +550 -0
- Pyjo/DOM/__init__.py +1329 -0
- Pyjo/Date.py +294 -0
- Pyjo/EventEmitter.py +522 -0
- Pyjo/Exception.py +494 -0
- Pyjo/File.py +959 -0
- Pyjo/GetOpt.py +605 -0
- Pyjo/Headers.py +760 -0
- Pyjo/HelloWorld.py +77 -0
- Pyjo/Home.py +109 -0
- Pyjo/IOLoop/ChildProcess.py +591 -0
- Pyjo/IOLoop/Client.py +736 -0
- Pyjo/IOLoop/Datagram.py +982 -0
- Pyjo/IOLoop/Messages.py +664 -0
- Pyjo/IOLoop/Server.py +458 -0
- Pyjo/IOLoop/Stdio.py +446 -0
- Pyjo/IOLoop/Stream.py +644 -0
- Pyjo/IOLoop/Subprocess.py +419 -0
- Pyjo/IOLoop/TLS.py +360 -0
- Pyjo/IOLoop/__init__.py +1036 -0
- Pyjo/IOLoop/certs/README.md +41 -0
- Pyjo/IOLoop/certs/ca.crt +20 -0
- Pyjo/IOLoop/certs/server.crt +21 -0
- Pyjo/IOLoop/certs/server.key +28 -0
- Pyjo/JSON/Pointer.py +135 -0
- Pyjo/JSON/RPC.py +772 -0
- Pyjo/JSON/Schema.py +2506 -0
- Pyjo/JSON/__init__.py +573 -0
- Pyjo/Loader.py +342 -0
- Pyjo/Log.py +723 -0
- Pyjo/Message/Request.py +725 -0
- Pyjo/Message/Response.py +476 -0
- Pyjo/Message/__init__.py +830 -0
- Pyjo/Parameters.py +472 -0
- Pyjo/Path.py +419 -0
- Pyjo/Promise.py +894 -0
- Pyjo/Prove.py +1305 -0
- Pyjo/Reactor/Asyncio.py +854 -0
- Pyjo/Reactor/Poll.py +439 -0
- Pyjo/Reactor/__init__.py +525 -0
- Pyjo/SSE.py +119 -0
- Pyjo/Server/ASGI.py +486 -0
- Pyjo/Server/CGI.py +259 -0
- Pyjo/Server/Daemon.py +1007 -0
- Pyjo/Server/FastCGI.py +517 -0
- Pyjo/Server/Hot/__init__.py +687 -0
- Pyjo/Server/Hot/__main__.py +5 -0
- Pyjo/Server/Lambda.py +641 -0
- Pyjo/Server/Prefork.py +917 -0
- Pyjo/Server/Prethread.py +394 -0
- Pyjo/Server/Reload/Backend/Poll.py +114 -0
- Pyjo/Server/Reload/Backend/__init__.py +126 -0
- Pyjo/Server/Reload/__init__.py +482 -0
- Pyjo/Server/Reload/__main__.py +5 -0
- Pyjo/Server/Stdio.py +228 -0
- Pyjo/Server/WSGI.py +349 -0
- Pyjo/Server/__init__.py +396 -0
- Pyjo/String/Bytes.py +532 -0
- Pyjo/String/HTML.py +210 -0
- Pyjo/String/Mixin.py +333 -0
- Pyjo/String/Template.py +470 -0
- Pyjo/String/Unicode.py +553 -0
- Pyjo/String/__init__.py +0 -0
- Pyjo/TOML.py +232 -0
- Pyjo/Template.py +1290 -0
- Pyjo/Test/Pyjo.py +1454 -0
- Pyjo/Test/__init__.py +1233 -0
- Pyjo/Test/pytest_plugin.py +305 -0
- Pyjo/Transaction/HTTP.py +374 -0
- Pyjo/Transaction/WebSocket.py +709 -0
- Pyjo/Transaction/__init__.py +429 -0
- Pyjo/URL/Template.py +459 -0
- Pyjo/URL/__init__.py +651 -0
- Pyjo/Upload.py +139 -0
- Pyjo/UserAgent/CookieJar.py +391 -0
- Pyjo/UserAgent/Proxy.py +138 -0
- Pyjo/UserAgent/Server.py +239 -0
- Pyjo/UserAgent/Transactor.py +766 -0
- Pyjo/UserAgent/__init__.py +1243 -0
- Pyjo/Util.py +3567 -0
- Pyjo/WebSocket.py +332 -0
- Pyjo/YAML.py +1167 -0
- Pyjo/__init__.py +441 -0
- Pyjo/__main__.py +35 -0
- Pyjo/py.typed +0 -0
- Pyjoyment/Command/Author/__init__.py +20 -0
- Pyjoyment/Command/Author/generate/__init__.py +106 -0
- Pyjoyment/Command/Author/generate/app.py +299 -0
- Pyjoyment/Command/Author/generate/dockerfile.py +281 -0
- Pyjoyment/Command/Author/generate/kubernetes.py +514 -0
- Pyjoyment/Command/Author/generate/lambda_zip.py +372 -0
- Pyjoyment/Command/Author/generate/lite_app.py +113 -0
- Pyjoyment/Command/Author/generate/plugin.py +267 -0
- Pyjoyment/Command/Author/generate/pyproject.py +123 -0
- Pyjoyment/Command/Author/inflate.py +101 -0
- Pyjoyment/Command/__init__.py +332 -0
- Pyjoyment/Command/asgi.py +92 -0
- Pyjoyment/Command/cgi.py +90 -0
- Pyjoyment/Command/daemon.py +160 -0
- Pyjoyment/Command/eval.py +128 -0
- Pyjoyment/Command/fastcgi.py +99 -0
- Pyjoyment/Command/get.py +305 -0
- Pyjoyment/Command/lambda.py +117 -0
- Pyjoyment/Command/prefork.py +181 -0
- Pyjoyment/Command/prethread.py +126 -0
- Pyjoyment/Command/routes.py +133 -0
- Pyjoyment/Command/stdio.py +92 -0
- Pyjoyment/Command/version.py +141 -0
- Pyjoyment/Command/wsgi.py +93 -0
- Pyjoyment/Commands.py +546 -0
- Pyjoyment/Controller.py +1307 -0
- Pyjoyment/HelloWorld.py +56 -0
- Pyjoyment/Lite.py +494 -0
- Pyjoyment/Plugin/AllowedHosts.py +205 -0
- Pyjoyment/Plugin/Config.py +248 -0
- Pyjoyment/Plugin/DefaultHelpers.py +1202 -0
- Pyjoyment/Plugin/EPLRenderer.py +134 -0
- Pyjoyment/Plugin/EPRenderer.py +212 -0
- Pyjoyment/Plugin/HeaderCondition.py +98 -0
- Pyjoyment/Plugin/Health.py +325 -0
- Pyjoyment/Plugin/JSONConfig.py +172 -0
- Pyjoyment/Plugin/Mount.py +223 -0
- Pyjoyment/Plugin/PyRenderer.py +209 -0
- Pyjoyment/Plugin/TOMLConfig.py +141 -0
- Pyjoyment/Plugin/TagHelpers.py +959 -0
- Pyjoyment/Plugin/YAMLConfig.py +178 -0
- Pyjoyment/Plugin/__init__.py +80 -0
- Pyjoyment/Plugins.py +215 -0
- Pyjoyment/Renderer.py +673 -0
- Pyjoyment/Routes/Match.py +251 -0
- Pyjoyment/Routes/Pattern.py +443 -0
- Pyjoyment/Routes/Route.py +827 -0
- Pyjoyment/Routes/__init__.py +419 -0
- Pyjoyment/Sessions.py +255 -0
- Pyjoyment/Static.py +421 -0
- Pyjoyment/Types.py +238 -0
- Pyjoyment/Validator/Validation.py +395 -0
- Pyjoyment/Validator/__init__.py +304 -0
- Pyjoyment/__init__.py +1083 -0
- Pyjoyment/__main__.py +5 -0
- Pyjoyment/py.typed +0 -0
- Pyjoyment/resources/public/favicon.ico +0 -0
- Pyjoyment/resources/public/favicon.svg +345 -0
- Pyjoyment/resources/public/pyjo/bootstrap/LICENSE +21 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.bundle.min.js.map +1 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.css +6 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.js +7 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.min.css.map +1 -0
- Pyjoyment/resources/public/pyjo/failunicat.png +0 -0
- Pyjoyment/resources/public/pyjo/failunicat.svg +50 -0
- Pyjoyment/resources/public/pyjo/highlight.js/LICENSE +29 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight-mojo-dark.css +56 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight.min.js +1262 -0
- Pyjoyment/resources/public/pyjo/highlight.js/pyjoyment.min.js +1 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo.png +0 -0
- Pyjoyment/resources/public/pyjo/logo.svg +346 -0
- Pyjoyment/resources/public/pyjo/notfound.png +0 -0
- Pyjoyment/resources/public/pyjo/notfound.svg +3 -0
- Pyjoyment/resources/public/pyjo/nounicat.png +0 -0
- Pyjoyment/resources/public/pyjo/nounicat.svg +5 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.svg +4 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.svg +4 -0
- Pyjoyment/resources/public/pyjo/pyjo.css +204 -0
- Pyjoyment/resources/templates/pyjo/debug.html.ep +346 -0
- Pyjoyment/resources/templates/pyjo/exception.html.ep +32 -0
- Pyjoyment/resources/templates/pyjo/not_found.html.ep +45 -0
- pyjoyment-0.1.0.dist-info/METADATA +376 -0
- pyjoyment-0.1.0.dist-info/RECORD +200 -0
- pyjoyment-0.1.0.dist-info/WHEEL +4 -0
- pyjoyment-0.1.0.dist-info/entry_points.txt +8 -0
- pyjoyment-0.1.0.dist-info/licenses/LICENSE +201 -0
Pyjo/TOML.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjo.TOML - TOML loader and dumper
|
|
3
|
+
==================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
from Pyjo.TOML import dump, load
|
|
7
|
+
|
|
8
|
+
config = load('name = "Pyjoyment"\\n\\n[server]\\nworkers = 4\\n')
|
|
9
|
+
|
|
10
|
+
string = dump({'name': 'Pyjoyment', 'server': {'workers': 4}})
|
|
11
|
+
|
|
12
|
+
:mod:`Pyjo.TOML` loads `TOML 1.0 <https://toml.io>`_ with :mod:`tomllib`
|
|
13
|
+
of the standard library, which has no writer of TOML, and dumps it, the
|
|
14
|
+
format of :mod:`Pyjoyment.Plugin.TOMLConfig` and of the stash value ``toml``
|
|
15
|
+
of the renderer of :mod:`Pyjoyment`.
|
|
16
|
+
|
|
17
|
+
:func:`dump` writes a :class:`dict` as a table, whose keys come first, and
|
|
18
|
+
then its tables, ``[server]``, a :class:`dict` of a :class:`dict`, and its
|
|
19
|
+
arrays of tables, ``[[products]]``, a :class:`list` of :class:`dict`, whose
|
|
20
|
+
tables follow each of them. A table with keys only in its tables has no line
|
|
21
|
+
of its own, as ``[a.b]`` defines ``a``. Other lists and tuples are arrays,
|
|
22
|
+
whose dicts are inline tables, ``[{ name = "x" }, 2]``. A string is a basic
|
|
23
|
+
string, with the escapes of TOML, and a string of several lines is a
|
|
24
|
+
multi-line basic string, ``\"\"\"...\"\"\"``. :class:`datetime.datetime`,
|
|
25
|
+
:class:`datetime.date` and :class:`datetime.time` are the date-times, the
|
|
26
|
+
dates and the times of TOML, an aware one with its offset. A key is bare
|
|
27
|
+
where TOML allows it, and quoted otherwise. ::
|
|
28
|
+
|
|
29
|
+
# 'name = "app"\\n\\n[server]\\nworkers = 4\\n'
|
|
30
|
+
dump({'name': 'app', 'server': {'workers': 4}})
|
|
31
|
+
|
|
32
|
+
TOML has no null and no bytes, so ``None`` and :class:`bytes` raise an error,
|
|
33
|
+
as do a key that is not a string, a value at the top that is not a table, and
|
|
34
|
+
a collection inside itself. Another object is what :mod:`Pyjo.JSON` encodes,
|
|
35
|
+
the value of its method ``__json__`` or its string.
|
|
36
|
+
|
|
37
|
+
See also
|
|
38
|
+
--------
|
|
39
|
+
|
|
40
|
+
:mod:`Pyjoyment.Plugin.TOMLConfig`, :mod:`Pyjo.YAML`, https://mojolicious.org.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
import Pyjo.Exception
|
|
44
|
+
|
|
45
|
+
from Pyjo.YAML import _data as _yaml_data # pyright: ignore[reportPrivateUsage]
|
|
46
|
+
|
|
47
|
+
import datetime
|
|
48
|
+
import math
|
|
49
|
+
import re
|
|
50
|
+
import tomllib
|
|
51
|
+
|
|
52
|
+
from typing import Any, cast
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# A key that does not need its quotes
|
|
56
|
+
_RE_BARE = re.compile(r'[A-Za-z0-9_-]+')
|
|
57
|
+
|
|
58
|
+
# The characters that a basic string escapes, and the ones that a multi-line basic string escapes, without the line
|
|
59
|
+
# break and the tab
|
|
60
|
+
_RE_ESCAPE = re.compile(r'["\\\x00-\x1f\x7f\ud800-\udfff]')
|
|
61
|
+
_RE_ESCAPE_MULTILINE = re.compile(r'["\\\x00-\x08\x0b-\x1f\x7f\ud800-\udfff]')
|
|
62
|
+
|
|
63
|
+
_ESCAPED = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r'}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def dump(value: Any, *, sort_keys: bool = False) -> str:
|
|
67
|
+
"""::
|
|
68
|
+
|
|
69
|
+
string = dump(value)
|
|
70
|
+
string = dump(value, sort_keys=True)
|
|
71
|
+
|
|
72
|
+
Dump a table to a TOML string, with the keys of a table in the order of the
|
|
73
|
+
:class:`dict`, or sorted with ``sort_keys``. ::
|
|
74
|
+
|
|
75
|
+
# 'name = "Pyjoyment"\\n'
|
|
76
|
+
dump({'name': 'Pyjoyment'})
|
|
77
|
+
"""
|
|
78
|
+
table = _data(value)
|
|
79
|
+
if not isinstance(table, dict):
|
|
80
|
+
raise _error(f'needs a table at the top, not a {type(table).__name__}')
|
|
81
|
+
lines: list[str] = []
|
|
82
|
+
_Dumper(lines, sort_keys).table(cast(dict[Any, Any], table), [], None)
|
|
83
|
+
return ''.join(f'{line}\n' for line in lines)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def load(string: str) -> dict[str, Any]:
|
|
87
|
+
"""::
|
|
88
|
+
|
|
89
|
+
value = load(string)
|
|
90
|
+
|
|
91
|
+
Load a TOML string with :func:`tomllib.loads`, whose error is a
|
|
92
|
+
:mod:`Pyjo.Exception`. ::
|
|
93
|
+
|
|
94
|
+
# {'name': 'Pyjoyment'}
|
|
95
|
+
load('name = "Pyjoyment"')
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
return tomllib.loads(string)
|
|
99
|
+
except tomllib.TOMLDecodeError as e:
|
|
100
|
+
raise _error(f'failed to parse: {e}') from None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# An object as Pyjo.YAML has it, and a time, which TOML has a type of
|
|
104
|
+
def _data(value: Any) -> Any:
|
|
105
|
+
return value if isinstance(value, datetime.time) else _yaml_data(value)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _error(message: str) -> Pyjo.Exception.object:
|
|
109
|
+
return Pyjo.Exception.new(f'TOML {message}')
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class _Dumper:
|
|
113
|
+
def __init__(self, lines: list[str], sort_keys: bool = False) -> None:
|
|
114
|
+
self.lines = lines
|
|
115
|
+
self.sort_keys = sort_keys
|
|
116
|
+
self.parents: set[int] = set()
|
|
117
|
+
|
|
118
|
+
def enter(self, value: Any) -> None:
|
|
119
|
+
if id(value) in self.parents:
|
|
120
|
+
raise _error('found a collection inside itself')
|
|
121
|
+
self.parents.add(id(value))
|
|
122
|
+
|
|
123
|
+
def header(self, header: str) -> None:
|
|
124
|
+
if self.lines:
|
|
125
|
+
self.lines.append('')
|
|
126
|
+
self.lines.append(header)
|
|
127
|
+
|
|
128
|
+
def inline(self, value: Any) -> str:
|
|
129
|
+
# A value on the line of its key or in an array
|
|
130
|
+
value = _data(value)
|
|
131
|
+
if isinstance(value, dict):
|
|
132
|
+
mapping = cast(dict[Any, Any], value)
|
|
133
|
+
self.enter(mapping)
|
|
134
|
+
pairs = [f'{_key(key)} = {self.inline(item)}' for key, item in self.items(mapping)]
|
|
135
|
+
self.parents.remove(id(mapping))
|
|
136
|
+
return f'{{ {", ".join(pairs)} }}' if pairs else '{}'
|
|
137
|
+
if isinstance(value, (list, tuple)):
|
|
138
|
+
sequence = cast(list[Any] | tuple[Any, ...], value)
|
|
139
|
+
self.enter(sequence)
|
|
140
|
+
items = [self.inline(item) for item in sequence]
|
|
141
|
+
self.parents.remove(id(sequence))
|
|
142
|
+
return f'[{", ".join(items)}]'
|
|
143
|
+
return _scalar(value)
|
|
144
|
+
|
|
145
|
+
def table(self, table: dict[Any, Any], path: list[str], header: str | None) -> None:
|
|
146
|
+
self.enter(table)
|
|
147
|
+
keys: list[tuple[str, Any]] = []
|
|
148
|
+
tables: list[tuple[str, dict[Any, Any]]] = []
|
|
149
|
+
arrays: list[tuple[str, list[dict[Any, Any]]]] = []
|
|
150
|
+
for key, value in self.items(table):
|
|
151
|
+
name = _key(key)
|
|
152
|
+
value = _data(value)
|
|
153
|
+
if isinstance(value, dict):
|
|
154
|
+
tables.append((name, cast(dict[Any, Any], value)))
|
|
155
|
+
elif _is_array_of_tables(value):
|
|
156
|
+
arrays.append((name, [_data(item) for item in cast(list[Any] | tuple[Any, ...], value)]))
|
|
157
|
+
else:
|
|
158
|
+
keys.append((name, value))
|
|
159
|
+
|
|
160
|
+
# The line of the table, which a table with keys only in its tables does without
|
|
161
|
+
if header is not None and (header.startswith('[[') or keys or not tables and not arrays):
|
|
162
|
+
self.header(header)
|
|
163
|
+
for name, value in keys:
|
|
164
|
+
self.lines.append(f'{name} = {self.multiline(value)}')
|
|
165
|
+
for name, value in tables:
|
|
166
|
+
self.table(value, [*path, name], f'[{".".join([*path, name])}]')
|
|
167
|
+
for name, items in arrays:
|
|
168
|
+
for item in items:
|
|
169
|
+
self.table(item, [*path, name], f'[[{".".join([*path, name])}]]')
|
|
170
|
+
self.parents.remove(id(table))
|
|
171
|
+
|
|
172
|
+
def items(self, mapping: dict[Any, Any]) -> list[tuple[Any, Any]]:
|
|
173
|
+
# The keys and the values of a table, in its order or sorted
|
|
174
|
+
items = list(mapping.items())
|
|
175
|
+
if self.sort_keys:
|
|
176
|
+
items.sort(key=lambda item: str(item[0]))
|
|
177
|
+
return items
|
|
178
|
+
|
|
179
|
+
def multiline(self, value: Any) -> str:
|
|
180
|
+
# A string of several lines in a multi-line basic string, whose line break after the quotes is not its own
|
|
181
|
+
if isinstance(value, str) and '\n' in value:
|
|
182
|
+
string = str.__str__(value)
|
|
183
|
+
return '"""\n' + _RE_ESCAPE_MULTILINE.sub(_escape, string) + '"""'
|
|
184
|
+
return self.inline(value)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _escape(m: re.Match[str]) -> str:
|
|
188
|
+
if (escaped := _ESCAPED.get(c := m[0])) is not None:
|
|
189
|
+
return escaped
|
|
190
|
+
if 0xD800 <= ord(c) <= 0xDFFF:
|
|
191
|
+
raise _error(f'does not support the surrogate \\u{ord(c):04x}')
|
|
192
|
+
return f'\\u{ord(c):04X}'
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# A list of tables, which is an array of tables, where an empty list is an array
|
|
196
|
+
def _is_array_of_tables(value: Any) -> bool:
|
|
197
|
+
if not value or not isinstance(value, (list, tuple)):
|
|
198
|
+
return False
|
|
199
|
+
return all(isinstance(_data(item), dict) for item in cast(list[Any] | tuple[Any, ...], value))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _key(key: Any) -> str:
|
|
203
|
+
if not isinstance(key, str):
|
|
204
|
+
raise _error(f"does not support a key of the type '{type(key).__name__}'")
|
|
205
|
+
string = str.__str__(key)
|
|
206
|
+
return string if _RE_BARE.fullmatch(string) else _string(string)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _scalar(value: Any) -> str:
|
|
210
|
+
if isinstance(value, str):
|
|
211
|
+
return _string(str.__str__(value))
|
|
212
|
+
if isinstance(value, bool):
|
|
213
|
+
return 'true' if value else 'false'
|
|
214
|
+
if isinstance(value, int):
|
|
215
|
+
return int.__repr__(value)
|
|
216
|
+
if isinstance(value, float):
|
|
217
|
+
if math.isnan(value):
|
|
218
|
+
return 'nan'
|
|
219
|
+
if math.isinf(value):
|
|
220
|
+
return 'inf' if value > 0 else '-inf'
|
|
221
|
+
return float.__repr__(value)
|
|
222
|
+
if isinstance(value, (datetime.datetime, datetime.date)):
|
|
223
|
+
return value.isoformat()
|
|
224
|
+
if isinstance(value, datetime.time):
|
|
225
|
+
if value.tzinfo is not None:
|
|
226
|
+
raise _error('does not support a time with an offset')
|
|
227
|
+
return value.isoformat()
|
|
228
|
+
raise _error(f"does not support a value of the type '{type(value).__name__}'")
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _string(string: str) -> str:
|
|
232
|
+
return '"' + _RE_ESCAPE.sub(_escape, string) + '"'
|