omlish 0.0.0.dev305__py3-none-any.whl → 0.0.0.dev306__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.
- omlish/.manifests.json +14 -0
- omlish/__about__.py +3 -3
- omlish/formats/edn/LICENSE +16 -0
- omlish/formats/edn/__init__.py +15 -0
- omlish/formats/edn/codec.py +26 -0
- omlish/formats/edn/parsing.py +359 -0
- omlish/formats/edn/values.py +162 -0
- {omlish-0.0.0.dev305.dist-info → omlish-0.0.0.dev306.dist-info}/METADATA +3 -3
- {omlish-0.0.0.dev305.dist-info → omlish-0.0.0.dev306.dist-info}/RECORD +13 -8
- {omlish-0.0.0.dev305.dist-info → omlish-0.0.0.dev306.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev305.dist-info → omlish-0.0.0.dev306.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev305.dist-info → omlish-0.0.0.dev306.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev305.dist-info → omlish-0.0.0.dev306.dist-info}/top_level.txt +0 -0
omlish/.manifests.json
CHANGED
@@ -51,6 +51,20 @@
|
|
51
51
|
}
|
52
52
|
}
|
53
53
|
},
|
54
|
+
{
|
55
|
+
"module": ".formats.edn.codec",
|
56
|
+
"attr": "_EDN_LAZY_CODEC",
|
57
|
+
"file": "omlish/formats/edn/codec.py",
|
58
|
+
"line": 25,
|
59
|
+
"value": {
|
60
|
+
"$.codecs.base.LazyLoadedCodec": {
|
61
|
+
"mod_name": "omlish.formats.edn.codec",
|
62
|
+
"attr_name": "EDN_CODEC",
|
63
|
+
"name": "edn",
|
64
|
+
"aliases": null
|
65
|
+
}
|
66
|
+
}
|
67
|
+
},
|
54
68
|
{
|
55
69
|
"module": ".formats.ini.codec",
|
56
70
|
"attr": "_INI_LAZY_CODEC",
|
omlish/__about__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
__version__ = '0.0.0.
|
2
|
-
__revision__ = '
|
1
|
+
__version__ = '0.0.0.dev306'
|
2
|
+
__revision__ = 'dda70244f84192bfce2428b682f9a5e2349fb05a'
|
3
3
|
|
4
4
|
|
5
5
|
#
|
@@ -101,7 +101,7 @@ class Project(ProjectBase):
|
|
101
101
|
|
102
102
|
'apsw ~= 3.49',
|
103
103
|
|
104
|
-
'sqlean.py ~= 3.
|
104
|
+
'sqlean.py ~= 3.49',
|
105
105
|
|
106
106
|
'duckdb ~= 1.2',
|
107
107
|
],
|
@@ -0,0 +1,16 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Jorin Vogel
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
6
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
7
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
11
|
+
Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
14
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
15
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ..codecs import make_object_lazy_loaded_codec
|
4
|
+
from ..codecs import make_str_object_codec
|
5
|
+
from .parsing import parse
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
|
10
|
+
|
11
|
+
def dumps(obj: ta.Any) -> str:
|
12
|
+
# return json.dumps(obj)
|
13
|
+
raise NotImplementedError
|
14
|
+
|
15
|
+
|
16
|
+
def loads(s: str) -> ta.Any:
|
17
|
+
return parse(s)
|
18
|
+
|
19
|
+
|
20
|
+
##
|
21
|
+
|
22
|
+
|
23
|
+
EDN_CODEC = make_str_object_codec('edn', dumps, loads)
|
24
|
+
|
25
|
+
# @omlish-manifest
|
26
|
+
_EDN_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'EDN_CODEC', EDN_CODEC)
|
@@ -0,0 +1,359 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- reader meta - ^:foo
|
4
|
+
"""
|
5
|
+
# https://github.com/jorinvo/edn-data/blob/1e5824f63803eb58f35e98839352000053d47115/test/parse.test.ts
|
6
|
+
import datetime
|
7
|
+
import enum
|
8
|
+
import re
|
9
|
+
import typing as ta
|
10
|
+
|
11
|
+
from ... import check
|
12
|
+
from .values import Char
|
13
|
+
from .values import Keyword
|
14
|
+
from .values import List
|
15
|
+
from .values import Map
|
16
|
+
from .values import Set
|
17
|
+
from .values import Symbol
|
18
|
+
from .values import TaggedVal
|
19
|
+
from .values import Vector
|
20
|
+
|
21
|
+
|
22
|
+
##
|
23
|
+
|
24
|
+
|
25
|
+
class ListParser:
|
26
|
+
DEFAULT_TAG_HANDLERS: ta.ClassVar[ta.Mapping[str, ta.Callable[..., ta.Any]]] = {
|
27
|
+
'inst': lambda val: datetime.datetime.fromisoformat(val) if isinstance(val, str) else None,
|
28
|
+
}
|
29
|
+
|
30
|
+
def __init__(
|
31
|
+
self,
|
32
|
+
*,
|
33
|
+
keyword_maker: ta.Callable[..., ta.Any] = Keyword,
|
34
|
+
char_maker: ta.Callable[..., ta.Any] = Char,
|
35
|
+
symbol_maker: ta.Callable[..., ta.Any] = Symbol,
|
36
|
+
|
37
|
+
list_maker: ta.Callable[..., ta.Any] = List.new,
|
38
|
+
vector_maker: ta.Callable[..., ta.Any] = Vector.new,
|
39
|
+
set_maker: ta.Callable[..., ta.Any] = Set.new,
|
40
|
+
map_maker: ta.Callable[..., ta.Any] = Map.new,
|
41
|
+
|
42
|
+
tag_handlers: ta.Mapping[str, ta.Callable[..., ta.Any]] | None = None,
|
43
|
+
) -> None:
|
44
|
+
super().__init__()
|
45
|
+
|
46
|
+
self._keyword_maker = keyword_maker
|
47
|
+
self._char_maker = char_maker
|
48
|
+
self._symbol_maker = symbol_maker
|
49
|
+
|
50
|
+
self._list_maker = list_maker
|
51
|
+
self._vector_maker = vector_maker
|
52
|
+
self._set_maker = set_maker
|
53
|
+
self._map_maker = map_maker
|
54
|
+
|
55
|
+
self._tag_handlers = {
|
56
|
+
**self.DEFAULT_TAG_HANDLERS,
|
57
|
+
**(tag_handlers or {}),
|
58
|
+
}
|
59
|
+
|
60
|
+
self._stack: list[tuple[ListParser._ParseMode | ListParser._StackItem, ta.Any]] = []
|
61
|
+
self._mode: ListParser._ParseMode = ListParser._ParseMode.IDLE
|
62
|
+
self._state = ''
|
63
|
+
self._result: ta.Any = self._UNDEFINED
|
64
|
+
|
65
|
+
#
|
66
|
+
|
67
|
+
class _UNDEFINED: # noqa
|
68
|
+
def __new__(cls, *args, **kwargs): # noqa
|
69
|
+
raise TypeError
|
70
|
+
|
71
|
+
class _ParseMode(enum.Enum):
|
72
|
+
IDLE = 0
|
73
|
+
STRING = 1
|
74
|
+
ESCAPE = 2
|
75
|
+
COMMENT = 3
|
76
|
+
|
77
|
+
class _StackItem(enum.Enum):
|
78
|
+
VECTOR = 0
|
79
|
+
LIST = 1
|
80
|
+
MAP = 2
|
81
|
+
SET = 3
|
82
|
+
TAG = 4
|
83
|
+
|
84
|
+
#
|
85
|
+
|
86
|
+
def _update_stack(self) -> None:
|
87
|
+
if not self._stack or self._result is self._UNDEFINED:
|
88
|
+
return
|
89
|
+
|
90
|
+
stack_item, prev_state = self._stack[-1]
|
91
|
+
|
92
|
+
if stack_item == ListParser._StackItem.VECTOR:
|
93
|
+
prev_state.append(self._result)
|
94
|
+
|
95
|
+
elif stack_item == ListParser._StackItem.LIST:
|
96
|
+
prev_state.append(self._result)
|
97
|
+
|
98
|
+
elif stack_item == ListParser._StackItem.SET:
|
99
|
+
prev_state.append(self._result)
|
100
|
+
|
101
|
+
elif stack_item == ListParser._StackItem.MAP:
|
102
|
+
if len(prev_state[1]) > 0:
|
103
|
+
prev_state[0].append([prev_state[1].pop(), self._result])
|
104
|
+
else:
|
105
|
+
prev_state[1].append(self._result)
|
106
|
+
|
107
|
+
elif stack_item == ListParser._StackItem.TAG:
|
108
|
+
self._stack.pop()
|
109
|
+
|
110
|
+
if prev_state == '_':
|
111
|
+
self._result = self._UNDEFINED
|
112
|
+
|
113
|
+
else:
|
114
|
+
tag_handler = self._tag_handlers.get(prev_state)
|
115
|
+
if tag_handler:
|
116
|
+
self._result = tag_handler(self._result)
|
117
|
+
else:
|
118
|
+
self._result = TaggedVal(prev_state, self._result)
|
119
|
+
|
120
|
+
self._update_stack()
|
121
|
+
return
|
122
|
+
|
123
|
+
# TODO: else error
|
124
|
+
# Reset result after updating stack
|
125
|
+
self._result = self._UNDEFINED
|
126
|
+
|
127
|
+
#
|
128
|
+
|
129
|
+
_INT_PAT = re.compile(r'^[-+]?(0|[1-9][0-9]*)$')
|
130
|
+
_BIGINT_PAT = re.compile(r'^[-+]?(0|[1-9][0-9]*)N$')
|
131
|
+
_FLOAT_PAT = re.compile(r'^[-+]?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?M?$')
|
132
|
+
|
133
|
+
def _match(self) -> None:
|
134
|
+
if self._state == 'nil':
|
135
|
+
self._result = None
|
136
|
+
|
137
|
+
elif self._state == 'true':
|
138
|
+
self._result = True
|
139
|
+
|
140
|
+
elif self._state == 'false':
|
141
|
+
self._result = False
|
142
|
+
|
143
|
+
elif self._state.startswith(':'):
|
144
|
+
# Keyword
|
145
|
+
self._result = self._keyword_maker(self._state[1:])
|
146
|
+
|
147
|
+
elif self._state.startswith('#'):
|
148
|
+
# Tag
|
149
|
+
self._stack.append((ListParser._StackItem.TAG, self._state[1:]))
|
150
|
+
self._result = self._UNDEFINED
|
151
|
+
|
152
|
+
elif self._INT_PAT.match(self._state):
|
153
|
+
# Int
|
154
|
+
self._result = int(self._state)
|
155
|
+
|
156
|
+
elif self._FLOAT_PAT.match(self._state):
|
157
|
+
# Float
|
158
|
+
self._result = float(self._state)
|
159
|
+
|
160
|
+
elif self._BIGINT_PAT.match(self._state):
|
161
|
+
# BigInt
|
162
|
+
self._result = int(self._state[:-1]) # In Python we don't need special handling for bigint
|
163
|
+
|
164
|
+
elif self._state.startswith('\\'):
|
165
|
+
# Char
|
166
|
+
check.state(len(self._state) > 1)
|
167
|
+
if self._state == '\\space':
|
168
|
+
c = ' '
|
169
|
+
elif self._state == '\\newline':
|
170
|
+
c = '\n'
|
171
|
+
elif self._state == '\\return':
|
172
|
+
c = '\r'
|
173
|
+
elif self._state == '\\tab':
|
174
|
+
c = '\t'
|
175
|
+
elif self._state == '\\\\':
|
176
|
+
c = '\\'
|
177
|
+
elif self._state.startswith('\\u'):
|
178
|
+
check.state(len(self._state) == 6)
|
179
|
+
c = chr(int(self._state[2:], 16))
|
180
|
+
else:
|
181
|
+
check.state(len(self._state) == 2)
|
182
|
+
c = self._state[1:]
|
183
|
+
|
184
|
+
self._result = self._char_maker(c)
|
185
|
+
|
186
|
+
elif self._state:
|
187
|
+
# Symbol
|
188
|
+
self._result = self._symbol_maker(self._state)
|
189
|
+
|
190
|
+
self._state = ''
|
191
|
+
|
192
|
+
#
|
193
|
+
|
194
|
+
_SPACE_CHARS: ta.ClassVar[ta.AbstractSet[str]] = frozenset([',', ' ', '\t', '\n', '\r'])
|
195
|
+
|
196
|
+
_STRING_ESCAPE_MAP: ta.ClassVar[ta.Mapping[str, str]] = {
|
197
|
+
't': '\t',
|
198
|
+
'r': '\r',
|
199
|
+
'n': '\n',
|
200
|
+
'\\': '\\',
|
201
|
+
'"': '"',
|
202
|
+
}
|
203
|
+
|
204
|
+
def parse(self, src: str) -> list[ta.Any]:
|
205
|
+
values = []
|
206
|
+
|
207
|
+
i = -1
|
208
|
+
for i in range(len(src)):
|
209
|
+
if not self._stack and self._result is not self._UNDEFINED:
|
210
|
+
values.append(self._result)
|
211
|
+
self._result = self._UNDEFINED
|
212
|
+
|
213
|
+
char = src[i]
|
214
|
+
|
215
|
+
if self._mode == ListParser._ParseMode.IDLE:
|
216
|
+
if char == '"':
|
217
|
+
self._match()
|
218
|
+
self._update_stack()
|
219
|
+
self._mode = ListParser._ParseMode.STRING
|
220
|
+
self._state = ''
|
221
|
+
continue
|
222
|
+
|
223
|
+
if char == ';':
|
224
|
+
self._mode = ListParser._ParseMode.COMMENT
|
225
|
+
continue
|
226
|
+
|
227
|
+
if char in self._SPACE_CHARS:
|
228
|
+
self._match()
|
229
|
+
self._update_stack()
|
230
|
+
continue
|
231
|
+
|
232
|
+
if char == '}':
|
233
|
+
self._match()
|
234
|
+
self._update_stack()
|
235
|
+
|
236
|
+
if self._stack:
|
237
|
+
stack_item, prev_state = self._stack.pop()
|
238
|
+
|
239
|
+
if stack_item == ListParser._StackItem.MAP:
|
240
|
+
check.empty(prev_state[1])
|
241
|
+
self._result = self._map_maker(prev_state[0])
|
242
|
+
|
243
|
+
else: # Set
|
244
|
+
# FIXME:
|
245
|
+
# check.state(stack_item == ListParser._StackItem.SET)
|
246
|
+
self._result = self._set_maker(prev_state)
|
247
|
+
|
248
|
+
self._update_stack()
|
249
|
+
continue
|
250
|
+
|
251
|
+
if char == ']':
|
252
|
+
self._match()
|
253
|
+
self._update_stack()
|
254
|
+
stack_item, prev_state = self._stack.pop()
|
255
|
+
self._result = self._vector_maker(tuple(prev_state))
|
256
|
+
self._update_stack()
|
257
|
+
continue
|
258
|
+
|
259
|
+
if char == ')':
|
260
|
+
self._match()
|
261
|
+
self._update_stack()
|
262
|
+
stack_item, prev_state = self._stack.pop()
|
263
|
+
self._result = self._list_maker(prev_state)
|
264
|
+
self._update_stack()
|
265
|
+
continue
|
266
|
+
|
267
|
+
if char == '[':
|
268
|
+
self._match()
|
269
|
+
self._update_stack()
|
270
|
+
self._stack.append((ListParser._StackItem.VECTOR, []))
|
271
|
+
continue
|
272
|
+
|
273
|
+
if char == '(':
|
274
|
+
self._match()
|
275
|
+
self._update_stack()
|
276
|
+
self._stack.append((ListParser._StackItem.LIST, []))
|
277
|
+
continue
|
278
|
+
|
279
|
+
state_plus_char = self._state + char
|
280
|
+
if state_plus_char == '#_':
|
281
|
+
self._stack.append((ListParser._StackItem.TAG, char))
|
282
|
+
self._result = self._UNDEFINED
|
283
|
+
self._state = ''
|
284
|
+
continue
|
285
|
+
|
286
|
+
if state_plus_char.endswith('#{'):
|
287
|
+
self._state = self._state[:-1] # Remove the '#'
|
288
|
+
self._match()
|
289
|
+
self._update_stack()
|
290
|
+
self._stack.append((ListParser._StackItem.SET, []))
|
291
|
+
self._state = ''
|
292
|
+
continue
|
293
|
+
|
294
|
+
if char == '{':
|
295
|
+
self._match()
|
296
|
+
self._update_stack()
|
297
|
+
self._stack.append((ListParser._StackItem.MAP, [[], []]))
|
298
|
+
self._state = ''
|
299
|
+
continue
|
300
|
+
|
301
|
+
self._state += char
|
302
|
+
continue
|
303
|
+
|
304
|
+
elif self._mode == ListParser._ParseMode.STRING: # noqa
|
305
|
+
if char == '\\':
|
306
|
+
self._stack.append((self._mode, self._state))
|
307
|
+
self._mode = ListParser._ParseMode.ESCAPE
|
308
|
+
self._state = ''
|
309
|
+
continue
|
310
|
+
|
311
|
+
if char == '"':
|
312
|
+
self._mode = ListParser._ParseMode.IDLE
|
313
|
+
self._result = self._state
|
314
|
+
self._update_stack()
|
315
|
+
self._state = ''
|
316
|
+
continue
|
317
|
+
|
318
|
+
self._state += char
|
319
|
+
|
320
|
+
elif self._mode == ListParser._ParseMode.ESCAPE:
|
321
|
+
# TODO what should happen when escaping other char
|
322
|
+
escaped_char = self._STRING_ESCAPE_MAP.get(char, char)
|
323
|
+
stack_item, prev_state = self._stack.pop()
|
324
|
+
self._mode = check.isinstance(stack_item, ListParser._ParseMode)
|
325
|
+
self._state = prev_state + escaped_char
|
326
|
+
|
327
|
+
elif self._mode == ListParser._ParseMode.COMMENT:
|
328
|
+
if char == '\n':
|
329
|
+
self._mode = ListParser._ParseMode.IDLE
|
330
|
+
|
331
|
+
else:
|
332
|
+
raise RuntimeError(self._mode)
|
333
|
+
|
334
|
+
if i >= 0:
|
335
|
+
self._match()
|
336
|
+
self._update_stack()
|
337
|
+
|
338
|
+
check.state(not self._stack)
|
339
|
+
|
340
|
+
if self._result is not self._UNDEFINED:
|
341
|
+
values.append(self._result)
|
342
|
+
return values
|
343
|
+
|
344
|
+
|
345
|
+
#
|
346
|
+
|
347
|
+
|
348
|
+
def parse_list(src: str, **kwargs: ta.Any) -> list[ta.Any]:
|
349
|
+
"""Parse an edn string and return the corresponding Python object."""
|
350
|
+
|
351
|
+
parser = ListParser(**kwargs)
|
352
|
+
return parser.parse(src)
|
353
|
+
|
354
|
+
|
355
|
+
def parse(src: str, **kwargs: ta.Any) -> ta.Any | None:
|
356
|
+
values = parse_list(src, **kwargs)
|
357
|
+
if not values:
|
358
|
+
return None
|
359
|
+
return check.single(values)
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from ... import check
|
5
|
+
from ... import lang
|
6
|
+
from ...lite.dataclasses import dataclass_cache_hash
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
|
11
|
+
|
12
|
+
_DEBUG = __debug__
|
13
|
+
# _DEBUG = True
|
14
|
+
|
15
|
+
|
16
|
+
@dc.dataclass(frozen=True)
|
17
|
+
class Value(lang.Abstract, lang.Sealed):
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
#
|
22
|
+
|
23
|
+
|
24
|
+
@dc.dataclass(frozen=True)
|
25
|
+
class Scalar(Value, lang.Abstract):
|
26
|
+
pass
|
27
|
+
|
28
|
+
|
29
|
+
@dataclass_cache_hash()
|
30
|
+
@dc.dataclass(frozen=True)
|
31
|
+
class Keyword(Scalar, lang.Final):
|
32
|
+
s: str
|
33
|
+
|
34
|
+
def __repr__(self) -> str:
|
35
|
+
return f'{self.__class__.__name__}({self.s!r})'
|
36
|
+
|
37
|
+
if _DEBUG:
|
38
|
+
def __post_init__(self) -> None:
|
39
|
+
check.isinstance(self.s, str)
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass_cache_hash()
|
43
|
+
@dc.dataclass(frozen=True)
|
44
|
+
class Char(Scalar, lang.Final):
|
45
|
+
c: str
|
46
|
+
|
47
|
+
def __repr__(self) -> str:
|
48
|
+
return f'{self.__class__.__name__}({self.c!r})'
|
49
|
+
|
50
|
+
if _DEBUG:
|
51
|
+
def __post_init__(self) -> None:
|
52
|
+
check.isinstance(self.c, str)
|
53
|
+
check.equal(len(self.c), 1)
|
54
|
+
|
55
|
+
|
56
|
+
@dataclass_cache_hash()
|
57
|
+
@dc.dataclass(frozen=True)
|
58
|
+
class Symbol(Scalar, lang.Final):
|
59
|
+
n: str
|
60
|
+
|
61
|
+
def __repr__(self) -> str:
|
62
|
+
return f'{self.__class__.__name__}({self.n!r})'
|
63
|
+
|
64
|
+
if _DEBUG:
|
65
|
+
def __post_init__(self) -> None:
|
66
|
+
check.non_empty_str(self.n)
|
67
|
+
|
68
|
+
|
69
|
+
#
|
70
|
+
|
71
|
+
|
72
|
+
@dc.dataclass(frozen=True)
|
73
|
+
class Collection(Value, lang.Abstract):
|
74
|
+
pass
|
75
|
+
|
76
|
+
|
77
|
+
@dataclass_cache_hash()
|
78
|
+
@dc.dataclass(frozen=True)
|
79
|
+
class List(Collection, lang.Final):
|
80
|
+
items: ta.Sequence[ta.Any]
|
81
|
+
|
82
|
+
def __repr__(self) -> str:
|
83
|
+
return f'{self.__class__.__name__}({self.items!r})'
|
84
|
+
|
85
|
+
if _DEBUG:
|
86
|
+
def __post_init__(self) -> None:
|
87
|
+
check.isinstance(self.items, tuple)
|
88
|
+
|
89
|
+
@classmethod
|
90
|
+
def new(cls, items: ta.Iterable[ta.Any]) -> 'List':
|
91
|
+
return cls(tuple(items))
|
92
|
+
|
93
|
+
|
94
|
+
@dataclass_cache_hash()
|
95
|
+
@dc.dataclass(frozen=True)
|
96
|
+
class Vector(Collection, lang.Final):
|
97
|
+
items: ta.Sequence[ta.Any]
|
98
|
+
|
99
|
+
def __repr__(self) -> str:
|
100
|
+
return f'{self.__class__.__name__}({self.items!r})'
|
101
|
+
|
102
|
+
if _DEBUG:
|
103
|
+
def __post_init__(self) -> None:
|
104
|
+
check.isinstance(self.items, tuple)
|
105
|
+
|
106
|
+
@classmethod
|
107
|
+
def new(cls, items: ta.Iterable[ta.Any]) -> 'Vector':
|
108
|
+
return cls(tuple(items))
|
109
|
+
|
110
|
+
|
111
|
+
@dataclass_cache_hash()
|
112
|
+
@dc.dataclass(frozen=True)
|
113
|
+
class Set(Collection, lang.Final):
|
114
|
+
items: ta.Sequence[ta.Any]
|
115
|
+
|
116
|
+
def __repr__(self) -> str:
|
117
|
+
return f'{self.__class__.__name__}({self.items!r})'
|
118
|
+
|
119
|
+
if _DEBUG:
|
120
|
+
def __post_init__(self) -> None:
|
121
|
+
check.isinstance(self.items, tuple)
|
122
|
+
|
123
|
+
@classmethod
|
124
|
+
def new(cls, items: ta.Iterable[ta.Any]) -> 'Set':
|
125
|
+
return cls(tuple(items))
|
126
|
+
|
127
|
+
|
128
|
+
@dataclass_cache_hash()
|
129
|
+
@dc.dataclass(frozen=True)
|
130
|
+
class Map(Collection, lang.Final):
|
131
|
+
items: ta.Sequence[tuple[ta.Any, ta.Any]]
|
132
|
+
|
133
|
+
def __repr__(self) -> str:
|
134
|
+
return f'{self.__class__.__name__}({self.items!r})'
|
135
|
+
|
136
|
+
if _DEBUG:
|
137
|
+
def __post_init__(self) -> None:
|
138
|
+
check.isinstance(self.items, tuple)
|
139
|
+
for t in self.items:
|
140
|
+
check.isinstance(t, tuple)
|
141
|
+
check.equal(len(t), 2)
|
142
|
+
|
143
|
+
@classmethod
|
144
|
+
def new(cls, items: ta.Iterable[ta.Iterable[ta.Any]]) -> 'Map':
|
145
|
+
return cls(tuple((k, v) for k, v in items))
|
146
|
+
|
147
|
+
|
148
|
+
#
|
149
|
+
|
150
|
+
|
151
|
+
@dataclass_cache_hash()
|
152
|
+
@dc.dataclass(frozen=True)
|
153
|
+
class TaggedVal(Value, lang.Final):
|
154
|
+
t: str
|
155
|
+
v: ta.Any
|
156
|
+
|
157
|
+
def __repr__(self) -> str:
|
158
|
+
return f'{self.__class__.__name__}({self.t!r}, {self.v!r})'
|
159
|
+
|
160
|
+
if _DEBUG:
|
161
|
+
def __post_init__(self) -> None:
|
162
|
+
check.non_empty_str(self.t)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev306
|
4
4
|
Summary: omlish
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -40,7 +40,7 @@ Requires-Dist: aiomysql~=0.2; extra == "all"
|
|
40
40
|
Requires-Dist: aiosqlite~=0.21; extra == "all"
|
41
41
|
Requires-Dist: asyncpg~=0.30; extra == "all"
|
42
42
|
Requires-Dist: apsw~=3.49; extra == "all"
|
43
|
-
Requires-Dist: sqlean.py~=3.
|
43
|
+
Requires-Dist: sqlean.py~=3.49; extra == "all"
|
44
44
|
Requires-Dist: duckdb~=1.2; extra == "all"
|
45
45
|
Requires-Dist: markupsafe~=3.0; extra == "all"
|
46
46
|
Requires-Dist: jinja2~=3.1; extra == "all"
|
@@ -88,7 +88,7 @@ Requires-Dist: aiomysql~=0.2; extra == "sqldrivers"
|
|
88
88
|
Requires-Dist: aiosqlite~=0.21; extra == "sqldrivers"
|
89
89
|
Requires-Dist: asyncpg~=0.30; extra == "sqldrivers"
|
90
90
|
Requires-Dist: apsw~=3.49; extra == "sqldrivers"
|
91
|
-
Requires-Dist: sqlean.py~=3.
|
91
|
+
Requires-Dist: sqlean.py~=3.49; extra == "sqldrivers"
|
92
92
|
Requires-Dist: duckdb~=1.2; extra == "sqldrivers"
|
93
93
|
Provides-Extra: templates
|
94
94
|
Requires-Dist: markupsafe~=3.0; extra == "templates"
|
@@ -1,5 +1,5 @@
|
|
1
|
-
omlish/.manifests.json,sha256=
|
2
|
-
omlish/__about__.py,sha256=
|
1
|
+
omlish/.manifests.json,sha256=orgsRvtpHu8tdhaCvlP9v3P495OJopYYiHKjK68WtWg,8587
|
2
|
+
omlish/__about__.py,sha256=GhIrDhTYihc0evLBX7furXS9SiYupCmrYNe-MrlOL0w,3478
|
3
3
|
omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
|
4
4
|
omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
|
5
5
|
omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
|
@@ -319,6 +319,11 @@ omlish/formats/props.py,sha256=auCv-Jx79KGlWfyG1-Qo0ou-Ex0W_mF3r_lDFdsVkWI,18920
|
|
319
319
|
omlish/formats/repr.py,sha256=kYrNs4o-ji8nOdp6u_L3aMgBMWN1ZAZJSAWgQQfStSQ,414
|
320
320
|
omlish/formats/xml.py,sha256=VJfqHR60dhAtjeG8WXFMozFqesTBSGvv264d67eDFXc,3514
|
321
321
|
omlish/formats/yaml.py,sha256=jGPQlTE0vSV-p0O7TJRNlf6o1uq4gx8PrHZe1ApJ_o8,7386
|
322
|
+
omlish/formats/edn/LICENSE,sha256=EUHM_e21AO5QuuMYXhDE81wmeBxbxeEk_i8oToZhiJo,1078
|
323
|
+
omlish/formats/edn/__init__.py,sha256=JXHN8RlPAl-l2OnOQOQgYO8-f2zrYy-bGS2uaHiD9x0,183
|
324
|
+
omlish/formats/edn/codec.py,sha256=k6-Ra3P3Rlv6JA69-jPLI4nCe5XVes_QJbcsj5DYzMM,454
|
325
|
+
omlish/formats/edn/parsing.py,sha256=EtpFdeU1DPAh9pvPjEQSBwZJ9OESeonRkUFQdjmIh2Y,11212
|
326
|
+
omlish/formats/edn/values.py,sha256=m2mDkX0BP63-e81cBbZnB-S5zPzc-J-tYrFzycqL7AI,3488
|
322
327
|
omlish/formats/ini/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
323
328
|
omlish/formats/ini/codec.py,sha256=omuFg0kiDksv8rRlWd_v32ebzEcKlgmiPgGID3bRi2M,631
|
324
329
|
omlish/formats/ini/sections.py,sha256=7wYyZdVTQbMPFpjQEACKJfAEPzUBrogINsrvFgxJoZ0,1015
|
@@ -847,9 +852,9 @@ omlish/typedvalues/holder.py,sha256=ZTnHiw-K38ciOBLEdwgrltr7Xp8jjEs_0Lp69DH-G-o,
|
|
847
852
|
omlish/typedvalues/marshal.py,sha256=hWHRLcrGav7lvXJDtb9bNI0ickl4SKPQ6F4BbTpqw3A,4219
|
848
853
|
omlish/typedvalues/reflect.py,sha256=Ih1YgU-srUjsvBn_P7C66f73_VCvcwqE3ffeBnZBgt4,674
|
849
854
|
omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
|
850
|
-
omlish-0.0.0.
|
851
|
-
omlish-0.0.0.
|
852
|
-
omlish-0.0.0.
|
853
|
-
omlish-0.0.0.
|
854
|
-
omlish-0.0.0.
|
855
|
-
omlish-0.0.0.
|
855
|
+
omlish-0.0.0.dev306.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
856
|
+
omlish-0.0.0.dev306.dist-info/METADATA,sha256=GvMQ6j9pDWhBIlo-FffGTPzRwn6QSfgLdBRQ62RIshY,4416
|
857
|
+
omlish-0.0.0.dev306.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
|
858
|
+
omlish-0.0.0.dev306.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
859
|
+
omlish-0.0.0.dev306.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
860
|
+
omlish-0.0.0.dev306.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|