omlish 0.0.0.dev132__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/.manifests.json +265 -7
- omlish/__about__.py +7 -5
- omlish/antlr/_runtime/__init__.py +0 -22
- omlish/antlr/_runtime/_all.py +24 -0
- omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
- omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
- omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
- omlish/antlr/_runtime/xpath/XPath.py +7 -1
- omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
- omlish/antlr/delimit.py +106 -0
- omlish/antlr/dot.py +31 -0
- omlish/antlr/errors.py +11 -0
- omlish/antlr/input.py +96 -0
- omlish/antlr/parsing.py +19 -0
- omlish/antlr/runtime.py +102 -0
- omlish/antlr/utils.py +38 -0
- omlish/argparse/all.py +45 -0
- omlish/{argparse.py → argparse/cli.py} +112 -107
- omlish/asyncs/__init__.py +0 -35
- omlish/asyncs/all.py +35 -0
- omlish/asyncs/asyncio/all.py +7 -0
- omlish/asyncs/asyncio/channels.py +40 -0
- omlish/asyncs/asyncio/streams.py +45 -0
- omlish/asyncs/asyncio/subprocesses.py +238 -0
- omlish/asyncs/asyncio/timeouts.py +16 -0
- omlish/asyncs/bluelet/LICENSE +6 -0
- omlish/asyncs/bluelet/all.py +67 -0
- omlish/asyncs/bluelet/api.py +23 -0
- omlish/asyncs/bluelet/core.py +178 -0
- omlish/asyncs/bluelet/events.py +78 -0
- omlish/asyncs/bluelet/files.py +80 -0
- omlish/asyncs/bluelet/runner.py +416 -0
- omlish/asyncs/bluelet/sockets.py +214 -0
- omlish/bootstrap/sys.py +3 -3
- omlish/cached.py +2 -2
- omlish/check.py +49 -460
- omlish/codecs/__init__.py +72 -0
- omlish/codecs/base.py +106 -0
- omlish/codecs/bytes.py +119 -0
- omlish/codecs/chain.py +23 -0
- omlish/codecs/funcs.py +39 -0
- omlish/codecs/registry.py +139 -0
- omlish/codecs/standard.py +4 -0
- omlish/codecs/text.py +217 -0
- omlish/collections/cache/impl.py +50 -57
- omlish/collections/coerce.py +1 -0
- omlish/collections/mappings.py +1 -1
- omlish/configs/flattening.py +1 -1
- omlish/defs.py +1 -1
- omlish/diag/_pycharm/runhack.py +8 -2
- omlish/diag/procfs.py +8 -8
- omlish/docker/__init__.py +0 -36
- omlish/docker/all.py +31 -0
- omlish/docker/consts.py +4 -0
- omlish/{lite/docker.py → docker/detect.py} +18 -0
- omlish/docker/{helpers.py → timebomb.py} +0 -21
- omlish/formats/cbor.py +31 -0
- omlish/formats/cloudpickle.py +31 -0
- omlish/formats/codecs.py +93 -0
- omlish/formats/json/codecs.py +29 -0
- omlish/formats/json/delimted.py +4 -0
- omlish/formats/json/stream/errors.py +2 -0
- omlish/formats/json/stream/lex.py +12 -6
- omlish/formats/json/stream/parse.py +38 -22
- omlish/formats/json5.py +31 -0
- omlish/formats/pickle.py +31 -0
- omlish/formats/repr.py +25 -0
- omlish/formats/toml.py +17 -0
- omlish/formats/yaml.py +25 -0
- omlish/funcs/__init__.py +0 -0
- omlish/{genmachine.py → funcs/genmachine.py} +5 -4
- omlish/{matchfns.py → funcs/match.py} +1 -1
- omlish/funcs/pairs.py +215 -0
- omlish/http/__init__.py +0 -48
- omlish/http/all.py +48 -0
- omlish/http/coro/__init__.py +0 -0
- omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
- omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
- omlish/{lite/http → http}/handlers.py +3 -2
- omlish/{lite/http → http}/parsing.py +1 -0
- omlish/http/sessions.py +1 -1
- omlish/{lite/http → http}/versions.py +1 -0
- omlish/inject/managed.py +2 -2
- omlish/io/__init__.py +0 -3
- omlish/{lite/io.py → io/buffers.py} +8 -9
- omlish/io/compress/__init__.py +9 -0
- omlish/io/compress/abc.py +104 -0
- omlish/io/compress/adapters.py +148 -0
- omlish/io/compress/base.py +24 -0
- omlish/io/compress/brotli.py +47 -0
- omlish/io/compress/bz2.py +61 -0
- omlish/io/compress/codecs.py +78 -0
- omlish/io/compress/gzip.py +350 -0
- omlish/io/compress/lz4.py +91 -0
- omlish/io/compress/lzma.py +81 -0
- omlish/io/compress/snappy.py +34 -0
- omlish/io/compress/zlib.py +74 -0
- omlish/io/compress/zstd.py +44 -0
- omlish/io/fdio/__init__.py +1 -0
- omlish/{lite → io}/fdio/handlers.py +5 -5
- omlish/{lite → io}/fdio/kqueue.py +8 -8
- omlish/{lite → io}/fdio/manager.py +7 -7
- omlish/{lite → io}/fdio/pollers.py +13 -13
- omlish/io/generators/__init__.py +56 -0
- omlish/io/generators/consts.py +1 -0
- omlish/io/generators/direct.py +13 -0
- omlish/io/generators/readers.py +189 -0
- omlish/io/generators/stepped.py +191 -0
- omlish/io/pyio.py +5 -2
- omlish/iterators/__init__.py +24 -0
- omlish/iterators/iterators.py +132 -0
- omlish/iterators/recipes.py +18 -0
- omlish/iterators/tools.py +96 -0
- omlish/iterators/unique.py +67 -0
- omlish/lang/__init__.py +13 -1
- omlish/lang/functions.py +11 -2
- omlish/lang/generators.py +243 -0
- omlish/lang/iterables.py +46 -49
- omlish/lang/maybes.py +4 -4
- omlish/lite/cached.py +39 -6
- omlish/lite/check.py +438 -75
- omlish/lite/contextmanagers.py +17 -4
- omlish/lite/dataclasses.py +42 -0
- omlish/lite/inject.py +28 -45
- omlish/lite/logs.py +0 -270
- omlish/lite/marshal.py +309 -144
- omlish/lite/pycharm.py +47 -0
- omlish/lite/reflect.py +33 -0
- omlish/lite/resources.py +8 -0
- omlish/lite/runtime.py +4 -4
- omlish/lite/shlex.py +12 -0
- omlish/lite/socketserver.py +2 -2
- omlish/lite/strings.py +31 -0
- omlish/logs/__init__.py +0 -32
- omlish/logs/{_abc.py → abc.py} +0 -1
- omlish/logs/all.py +37 -0
- omlish/logs/{formatters.py → color.py} +1 -2
- omlish/logs/configs.py +7 -38
- omlish/logs/filters.py +10 -0
- omlish/logs/handlers.py +4 -1
- omlish/logs/json.py +56 -0
- omlish/logs/proxy.py +99 -0
- omlish/logs/standard.py +128 -0
- omlish/logs/utils.py +2 -2
- omlish/manifests/__init__.py +2 -0
- omlish/manifests/load.py +209 -0
- omlish/manifests/types.py +17 -0
- omlish/marshal/base.py +1 -1
- omlish/marshal/factories.py +1 -1
- omlish/marshal/forbidden.py +1 -1
- omlish/marshal/iterables.py +1 -1
- omlish/marshal/literals.py +50 -0
- omlish/marshal/mappings.py +1 -1
- omlish/marshal/maybes.py +1 -1
- omlish/marshal/standard.py +5 -1
- omlish/marshal/unions.py +1 -1
- omlish/os/__init__.py +0 -0
- omlish/os/atomics.py +205 -0
- omlish/os/deathsig.py +23 -0
- omlish/{os.py → os/files.py} +0 -9
- omlish/{lite → os}/journald.py +2 -1
- omlish/os/linux.py +484 -0
- omlish/os/paths.py +36 -0
- omlish/{lite → os}/pidfile.py +1 -0
- omlish/os/sizes.py +9 -0
- omlish/reflect/__init__.py +3 -0
- omlish/reflect/subst.py +2 -1
- omlish/reflect/types.py +126 -44
- omlish/secrets/pwhash.py +1 -1
- omlish/secrets/subprocesses.py +3 -1
- omlish/specs/jsonrpc/marshal.py +1 -1
- omlish/specs/openapi/marshal.py +1 -1
- omlish/sql/alchemy/asyncs.py +1 -1
- omlish/sql/queries/__init__.py +9 -1
- omlish/sql/queries/building.py +3 -0
- omlish/sql/queries/exprs.py +10 -27
- omlish/sql/queries/idents.py +48 -10
- omlish/sql/queries/names.py +80 -13
- omlish/sql/queries/params.py +64 -0
- omlish/sql/queries/rendering.py +1 -1
- omlish/subprocesses.py +340 -0
- omlish/term.py +29 -14
- omlish/testing/pytest/marks.py +2 -2
- omlish/testing/pytest/plugins/asyncs.py +6 -1
- omlish/testing/pytest/plugins/logging.py +1 -1
- omlish/testing/pytest/plugins/switches.py +1 -1
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +13 -11
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
- omlish/fnpairs.py +0 -496
- omlish/formats/json/cli/__main__.py +0 -11
- omlish/formats/json/cli/cli.py +0 -298
- omlish/formats/json/cli/formats.py +0 -71
- omlish/formats/json/cli/io.py +0 -74
- omlish/formats/json/cli/parsing.py +0 -82
- omlish/formats/json/cli/processing.py +0 -48
- omlish/formats/json/cli/rendering.py +0 -92
- omlish/iterators.py +0 -300
- omlish/lite/subprocesses.py +0 -130
- /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
- /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
- /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
- /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
- /omlish/collections/{_abc.py → abc.py} +0 -0
- /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
- /omlish/io/{_abc.py → abc.py} +0 -0
- /omlish/sql/{_abc.py → abc.py} +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
omlish/reflect/types.py
CHANGED
@@ -7,6 +7,7 @@ TODO:
|
|
7
7
|
- cache this shit, esp generic_mro shit
|
8
8
|
- cache __hash__ in Generic/Union
|
9
9
|
"""
|
10
|
+
import abc
|
10
11
|
import dataclasses as dc
|
11
12
|
import types
|
12
13
|
import typing as ta
|
@@ -17,11 +18,12 @@ _NoneType = types.NoneType # type: ignore
|
|
17
18
|
_NONE_TYPE_FROZENSET: frozenset['Type'] = frozenset([_NoneType])
|
18
19
|
|
19
20
|
|
20
|
-
|
21
|
+
_AnnotatedAlias = ta._AnnotatedAlias # type: ignore # noqa
|
21
22
|
_CallableGenericAlias = ta._CallableGenericAlias # type: ignore # noqa
|
23
|
+
_GenericAlias = ta._GenericAlias # type: ignore # noqa
|
24
|
+
_LiteralGenericAlias = ta._LiteralGenericAlias # type: ignore # noqa
|
22
25
|
_SpecialGenericAlias = ta._SpecialGenericAlias # type: ignore # noqa
|
23
26
|
_UnionGenericAlias = ta._UnionGenericAlias # type: ignore # noqa
|
24
|
-
_AnnotatedAlias = ta._AnnotatedAlias # type: ignore # noqa
|
25
27
|
|
26
28
|
|
27
29
|
##
|
@@ -116,19 +118,29 @@ def get_newtype_supertype(obj: ta.Any) -> ta.Any:
|
|
116
118
|
##
|
117
119
|
|
118
120
|
|
119
|
-
|
121
|
+
class TypeInfo(abc.ABC): # noqa
|
122
|
+
pass
|
123
|
+
|
124
|
+
|
125
|
+
Type: ta.TypeAlias = ta.Union[ # noqa
|
120
126
|
type,
|
121
127
|
ta.TypeVar,
|
122
|
-
|
123
|
-
'Generic',
|
124
|
-
'NewType',
|
125
|
-
'Annotated',
|
126
|
-
'Any',
|
128
|
+
TypeInfo,
|
127
129
|
]
|
128
130
|
|
129
131
|
|
132
|
+
TYPES: tuple[type, ...] = (
|
133
|
+
type,
|
134
|
+
ta.TypeVar,
|
135
|
+
TypeInfo,
|
136
|
+
)
|
137
|
+
|
138
|
+
|
139
|
+
##
|
140
|
+
|
141
|
+
|
130
142
|
@dc.dataclass(frozen=True)
|
131
|
-
class Union:
|
143
|
+
class Union(TypeInfo):
|
132
144
|
args: frozenset[Type]
|
133
145
|
|
134
146
|
@property
|
@@ -144,8 +156,11 @@ class Union:
|
|
144
156
|
return Union(rem)
|
145
157
|
|
146
158
|
|
159
|
+
#
|
160
|
+
|
161
|
+
|
147
162
|
@dc.dataclass(frozen=True)
|
148
|
-
class Generic:
|
163
|
+
class Generic(TypeInfo):
|
149
164
|
cls: type
|
150
165
|
args: tuple[Type, ...] # map[int, V] = (int, V) | map[T, T] = (T, T)
|
151
166
|
|
@@ -167,39 +182,51 @@ class Generic:
|
|
167
182
|
)
|
168
183
|
|
169
184
|
|
185
|
+
#
|
186
|
+
|
187
|
+
|
170
188
|
@dc.dataclass(frozen=True)
|
171
|
-
class NewType:
|
189
|
+
class NewType(TypeInfo):
|
172
190
|
obj: ta.Any
|
173
191
|
ty: Type
|
174
192
|
|
175
193
|
|
194
|
+
#
|
195
|
+
|
196
|
+
|
176
197
|
@dc.dataclass(frozen=True)
|
177
|
-
class Annotated:
|
198
|
+
class Annotated(TypeInfo):
|
178
199
|
ty: Type
|
179
200
|
md: ta.Sequence[ta.Any]
|
180
201
|
|
181
202
|
obj: ta.Any = dc.field(compare=False, repr=False)
|
182
203
|
|
183
204
|
|
184
|
-
|
205
|
+
#
|
206
|
+
|
207
|
+
|
208
|
+
@dc.dataclass(frozen=True)
|
209
|
+
class Literal(TypeInfo):
|
210
|
+
args: tuple[ta.Any, ...]
|
211
|
+
|
212
|
+
obj: ta.Any = dc.field(compare=False, repr=False)
|
213
|
+
|
214
|
+
|
215
|
+
#
|
216
|
+
|
217
|
+
|
218
|
+
class Any(TypeInfo):
|
185
219
|
pass
|
186
220
|
|
187
221
|
|
188
222
|
ANY = Any()
|
189
223
|
|
190
224
|
|
191
|
-
|
192
|
-
type,
|
193
|
-
ta.TypeVar,
|
194
|
-
Union,
|
195
|
-
Generic,
|
196
|
-
NewType,
|
197
|
-
Annotated,
|
198
|
-
Any,
|
199
|
-
)
|
225
|
+
##
|
200
226
|
|
201
227
|
|
202
|
-
|
228
|
+
class ReflectTypeError(TypeError):
|
229
|
+
pass
|
203
230
|
|
204
231
|
|
205
232
|
class Reflector:
|
@@ -212,57 +239,80 @@ class Reflector:
|
|
212
239
|
|
213
240
|
self._override = override
|
214
241
|
|
242
|
+
#
|
243
|
+
|
215
244
|
def is_type(self, obj: ta.Any) -> bool:
|
216
|
-
|
245
|
+
try:
|
246
|
+
self._type(obj, check_only=True)
|
247
|
+
except ReflectTypeError:
|
248
|
+
return False
|
249
|
+
else:
|
217
250
|
return True
|
218
251
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
isinstance(obj, ta.NewType) or # noqa
|
225
|
-
|
226
|
-
(
|
227
|
-
is_simple_generic_alias_type(oty) or
|
228
|
-
oty is _CallableGenericAlias
|
229
|
-
) or
|
252
|
+
def type(self, obj: ta.Any) -> Type:
|
253
|
+
if (ty := self._type(obj, check_only=False)) is None:
|
254
|
+
raise RuntimeError(obj)
|
255
|
+
return ty
|
230
256
|
|
231
|
-
|
257
|
+
#
|
232
258
|
|
233
|
-
|
234
|
-
|
259
|
+
def _type(self, obj: ta.Any, *, check_only: bool) -> Type | None:
|
260
|
+
##
|
261
|
+
# Overrides beat everything
|
235
262
|
|
236
|
-
def type(self, obj: ta.Any) -> Type:
|
237
263
|
if self._override is not None:
|
238
264
|
if (ovr := self._override(obj)) is not None:
|
239
265
|
return ovr
|
240
266
|
|
267
|
+
##
|
268
|
+
# Any
|
269
|
+
|
241
270
|
if obj is ta.Any:
|
242
271
|
return ANY
|
243
272
|
|
244
|
-
|
273
|
+
##
|
274
|
+
# Already a Type?
|
275
|
+
|
276
|
+
if isinstance(obj, (ta.TypeVar, TypeInfo)): # noqa
|
245
277
|
return obj
|
246
278
|
|
247
279
|
oty = type(obj)
|
248
280
|
|
281
|
+
##
|
282
|
+
# Union
|
283
|
+
|
249
284
|
if oty is _UnionGenericAlias or oty is types.UnionType:
|
285
|
+
if check_only:
|
286
|
+
return None
|
287
|
+
|
250
288
|
return Union(frozenset(self.type(a) for a in ta.get_args(obj)))
|
251
289
|
|
290
|
+
##
|
291
|
+
# NewType
|
292
|
+
|
252
293
|
if isinstance(obj, ta.NewType): # noqa
|
294
|
+
if check_only:
|
295
|
+
return None
|
296
|
+
|
253
297
|
return NewType(obj, get_newtype_supertype(obj))
|
254
298
|
|
299
|
+
##
|
300
|
+
# Simple Generic
|
301
|
+
|
255
302
|
if (
|
256
303
|
is_simple_generic_alias_type(oty) or
|
257
304
|
oty is _CallableGenericAlias
|
258
305
|
):
|
306
|
+
if check_only:
|
307
|
+
return None
|
308
|
+
|
259
309
|
origin = ta.get_origin(obj)
|
260
310
|
args = ta.get_args(obj)
|
261
311
|
|
262
312
|
if oty is _CallableGenericAlias:
|
263
313
|
p, r = args
|
264
314
|
if p is Ellipsis or isinstance(p, ta.ParamSpec):
|
265
|
-
raise
|
315
|
+
raise ReflectTypeError(f'Callable argument not yet supported for {obj=}')
|
266
316
|
args = (*p, r)
|
267
317
|
params = _KNOWN_SPECIAL_TYPE_VARS[:len(args)]
|
268
318
|
|
@@ -276,7 +326,7 @@ class Reflector:
|
|
276
326
|
params = get_params(origin)
|
277
327
|
|
278
328
|
if len(args) != len(params):
|
279
|
-
raise
|
329
|
+
raise ReflectTypeError(f'Mismatched {args=} and {params=} for {obj=}')
|
280
330
|
|
281
331
|
return Generic(
|
282
332
|
origin,
|
@@ -285,7 +335,13 @@ class Reflector:
|
|
285
335
|
obj,
|
286
336
|
)
|
287
337
|
|
338
|
+
##
|
339
|
+
# Full Generic
|
340
|
+
|
288
341
|
if isinstance(obj, type):
|
342
|
+
if check_only:
|
343
|
+
return None
|
344
|
+
|
289
345
|
if issubclass(obj, ta.Generic): # type: ignore
|
290
346
|
params = get_params(obj)
|
291
347
|
if params:
|
@@ -295,12 +351,20 @@ class Reflector:
|
|
295
351
|
params,
|
296
352
|
obj,
|
297
353
|
)
|
354
|
+
|
298
355
|
return obj
|
299
356
|
|
357
|
+
##
|
358
|
+
# Special Generic
|
359
|
+
|
300
360
|
if isinstance(obj, _SpecialGenericAlias):
|
301
361
|
if (ks := _KNOWN_SPECIALS_BY_ALIAS.get(obj)) is not None:
|
362
|
+
if check_only:
|
363
|
+
return None
|
364
|
+
|
302
365
|
if (np := ks.nparams) < 0:
|
303
|
-
raise
|
366
|
+
raise ReflectTypeError(obj)
|
367
|
+
|
304
368
|
params = _KNOWN_SPECIAL_TYPE_VARS[:np]
|
305
369
|
return Generic(
|
306
370
|
ks.origin,
|
@@ -309,11 +373,29 @@ class Reflector:
|
|
309
373
|
obj,
|
310
374
|
)
|
311
375
|
|
376
|
+
##
|
377
|
+
# Annotated
|
378
|
+
|
312
379
|
if isinstance(obj, _AnnotatedAlias):
|
380
|
+
if check_only:
|
381
|
+
return None
|
382
|
+
|
313
383
|
o = ta.get_args(obj)[0]
|
314
384
|
return Annotated(self.type(o), md=obj.__metadata__, obj=obj)
|
315
385
|
|
316
|
-
|
386
|
+
##
|
387
|
+
# Literal
|
388
|
+
|
389
|
+
if isinstance(obj, _LiteralGenericAlias):
|
390
|
+
if check_only:
|
391
|
+
return None
|
392
|
+
|
393
|
+
return Literal(ta.get_args(obj), obj=obj)
|
394
|
+
|
395
|
+
##
|
396
|
+
# Failure
|
397
|
+
|
398
|
+
raise ReflectTypeError(obj)
|
317
399
|
|
318
400
|
|
319
401
|
DEFAULT_REFLECTOR = Reflector()
|
omlish/secrets/pwhash.py
CHANGED
omlish/secrets/subprocesses.py
CHANGED
@@ -32,7 +32,9 @@ def pipe_fd_subprocess_file_input(buf: bytes) -> ta.Iterator[SubprocessFileInput
|
|
32
32
|
try:
|
33
33
|
if hasattr(fcntl, 'F_SETPIPE_SZ'):
|
34
34
|
fcntl.fcntl(wfd, fcntl.F_SETPIPE_SZ, max(len(buf), 0x1000))
|
35
|
-
os.write(wfd, buf)
|
35
|
+
n = os.write(wfd, buf)
|
36
|
+
if n != len(buf):
|
37
|
+
raise OSError(f'Failed to write data to pipe: {n=} {len(buf)=}')
|
36
38
|
os.close(wfd)
|
37
39
|
closed_wfd = True
|
38
40
|
yield SubprocessFileInput(f'/dev/fd/{rfd}', [rfd])
|
omlish/specs/jsonrpc/marshal.py
CHANGED
omlish/specs/openapi/marshal.py
CHANGED
omlish/sql/alchemy/asyncs.py
CHANGED
omlish/sql/queries/__init__.py
CHANGED
@@ -22,13 +22,13 @@ from .exprs import ( # noqa
|
|
22
22
|
ExprBuilder,
|
23
23
|
Literal,
|
24
24
|
NameExpr,
|
25
|
-
Param,
|
26
25
|
)
|
27
26
|
|
28
27
|
from .idents import ( # noqa
|
29
28
|
CanIdent,
|
30
29
|
Ident,
|
31
30
|
IdentBuilder,
|
31
|
+
IdentLike,
|
32
32
|
)
|
33
33
|
|
34
34
|
from .multi import ( # noqa
|
@@ -41,12 +41,20 @@ from .names import ( # noqa
|
|
41
41
|
CanName,
|
42
42
|
Name,
|
43
43
|
NameBuilder,
|
44
|
+
NameLike,
|
44
45
|
)
|
45
46
|
|
46
47
|
from .ops import ( # noqa
|
47
48
|
OpKind,
|
48
49
|
)
|
49
50
|
|
51
|
+
from .params import ( # noqa
|
52
|
+
CanParam,
|
53
|
+
Param,
|
54
|
+
ParamBuilder,
|
55
|
+
as_param,
|
56
|
+
)
|
57
|
+
|
50
58
|
from .relations import ( # noqa
|
51
59
|
CanRelation,
|
52
60
|
CanTable,
|
omlish/sql/queries/building.py
CHANGED
@@ -5,6 +5,7 @@ from .idents import IdentBuilder
|
|
5
5
|
from .inserts import InsertBuilder
|
6
6
|
from .multi import MultiBuilder
|
7
7
|
from .names import NameBuilder
|
8
|
+
from .params import ParamBuilder
|
8
9
|
from .relations import RelationBuilder
|
9
10
|
from .selects import SelectBuilder
|
10
11
|
from .stmts import StmtBuilder
|
@@ -23,6 +24,8 @@ class StdBuilder(
|
|
23
24
|
|
24
25
|
RelationBuilder,
|
25
26
|
|
27
|
+
ParamBuilder,
|
28
|
+
|
26
29
|
NameBuilder,
|
27
30
|
IdentBuilder,
|
28
31
|
|
omlish/sql/queries/exprs.py
CHANGED
@@ -8,10 +8,11 @@ import typing as ta
|
|
8
8
|
from ... import lang
|
9
9
|
from .base import Node
|
10
10
|
from .base import Value
|
11
|
-
from .idents import
|
11
|
+
from .idents import IdentLike
|
12
12
|
from .names import CanName
|
13
13
|
from .names import Name
|
14
14
|
from .names import NameBuilder
|
15
|
+
from .names import NameLike
|
15
16
|
|
16
17
|
|
17
18
|
##
|
@@ -21,30 +22,21 @@ class Expr(Node, lang.Abstract):
|
|
21
22
|
pass
|
22
23
|
|
23
24
|
|
25
|
+
#
|
26
|
+
|
27
|
+
|
24
28
|
class Literal(Expr, lang.Final):
|
25
29
|
v: Value
|
26
30
|
|
27
31
|
|
28
|
-
|
29
|
-
n: Name
|
32
|
+
#
|
30
33
|
|
31
34
|
|
32
|
-
class
|
33
|
-
n:
|
35
|
+
class NameExpr(Expr, lang.Final):
|
36
|
+
n: Name
|
34
37
|
|
35
|
-
def __repr__(self) -> str:
|
36
|
-
if self.n is not None:
|
37
|
-
return f'{self.__class__.__name__}({self.n!r})'
|
38
|
-
else:
|
39
|
-
return f'{self.__class__.__name__}(@{hex(id(self))[2:]})'
|
40
38
|
|
41
|
-
|
42
|
-
if not isinstance(other, Param):
|
43
|
-
return False
|
44
|
-
if self.n is None and other.n is None:
|
45
|
-
return self is other
|
46
|
-
else:
|
47
|
-
return self.n == other.n
|
39
|
+
##
|
48
40
|
|
49
41
|
|
50
42
|
CanLiteral: ta.TypeAlias = Literal | Value
|
@@ -69,7 +61,7 @@ class ExprBuilder(NameBuilder):
|
|
69
61
|
def expr(self, o: CanExpr) -> Expr:
|
70
62
|
if isinstance(o, Expr):
|
71
63
|
return o
|
72
|
-
elif isinstance(o, (
|
64
|
+
elif isinstance(o, (NameLike, IdentLike)):
|
73
65
|
return NameExpr(self.name(o))
|
74
66
|
else:
|
75
67
|
return self.literal(o)
|
@@ -77,12 +69,3 @@ class ExprBuilder(NameBuilder):
|
|
77
69
|
@ta.final
|
78
70
|
def e(self, o: CanExpr) -> Expr:
|
79
71
|
return self.expr(o)
|
80
|
-
|
81
|
-
#
|
82
|
-
|
83
|
-
def param(self, n: str | None = None) -> Param:
|
84
|
-
return Param(n)
|
85
|
-
|
86
|
-
@ta.final
|
87
|
-
def p(self, n: str | None = None) -> Param:
|
88
|
-
return self.param(n)
|
omlish/sql/queries/idents.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import abc
|
2
|
+
import functools
|
1
3
|
import typing as ta
|
2
4
|
|
3
5
|
from ... import lang
|
@@ -8,22 +10,58 @@ from .base import Node
|
|
8
10
|
##
|
9
11
|
|
10
12
|
|
11
|
-
class
|
13
|
+
class IdentLike(abc.ABC): # noqa
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
|
19
|
+
|
20
|
+
class Ident(Node, IdentLike, lang.Final):
|
12
21
|
s: str
|
13
22
|
|
14
23
|
|
15
|
-
|
24
|
+
##
|
25
|
+
|
26
|
+
|
27
|
+
@functools.singledispatch
|
28
|
+
def as_ident(o: ta.Any) -> Ident:
|
29
|
+
raise TypeError(o)
|
30
|
+
|
31
|
+
|
32
|
+
@as_ident.register
|
33
|
+
def _(i: Ident) -> Ident:
|
34
|
+
return i
|
35
|
+
|
36
|
+
|
37
|
+
@as_ident.register
|
38
|
+
def _(s: str) -> Ident:
|
39
|
+
return Ident(s)
|
40
|
+
|
41
|
+
|
42
|
+
##
|
43
|
+
|
44
|
+
|
45
|
+
CanIdent: ta.TypeAlias = IdentLike | Ident | str
|
46
|
+
|
47
|
+
|
48
|
+
class IdentAccessor(lang.Final):
|
49
|
+
def __getattr__(self, s: str) -> Ident:
|
50
|
+
return Ident(s)
|
51
|
+
|
52
|
+
def __call__(self, o: CanIdent) -> Ident:
|
53
|
+
return as_ident(o)
|
54
|
+
|
55
|
+
|
56
|
+
##
|
16
57
|
|
17
58
|
|
18
59
|
class IdentBuilder(Builder):
|
60
|
+
@ta.final
|
19
61
|
def ident(self, o: CanIdent) -> Ident:
|
20
|
-
|
21
|
-
return o
|
22
|
-
elif isinstance(o, str):
|
23
|
-
return Ident(o)
|
24
|
-
else:
|
25
|
-
raise TypeError(o)
|
62
|
+
return as_ident(o)
|
26
63
|
|
27
64
|
@ta.final
|
28
|
-
|
29
|
-
|
65
|
+
@property
|
66
|
+
def i(self) -> IdentAccessor:
|
67
|
+
return IdentAccessor()
|
omlish/sql/queries/names.py
CHANGED
@@ -1,34 +1,101 @@
|
|
1
|
+
import abc
|
2
|
+
import functools
|
1
3
|
import typing as ta
|
2
4
|
|
5
|
+
from ... import check
|
3
6
|
from ... import dataclasses as dc
|
4
7
|
from ... import lang
|
5
8
|
from .base import Node
|
6
9
|
from .idents import CanIdent
|
7
10
|
from .idents import Ident
|
8
11
|
from .idents import IdentBuilder
|
12
|
+
from .idents import as_ident
|
9
13
|
|
10
14
|
|
11
15
|
##
|
12
16
|
|
13
17
|
|
14
|
-
class
|
15
|
-
|
18
|
+
class NameLike(abc.ABC): # noqa
|
19
|
+
pass
|
16
20
|
|
17
21
|
|
18
|
-
|
22
|
+
##
|
23
|
+
|
24
|
+
|
25
|
+
def _coerce_name_parts(o: ta.Iterable[Ident]) -> ta.Sequence[Ident]:
|
26
|
+
check.not_isinstance(o, str)
|
27
|
+
return check.not_empty(tuple(check.isinstance(e, Ident) for e in o))
|
28
|
+
|
29
|
+
|
30
|
+
class Name(Node, NameLike, lang.Final):
|
31
|
+
ps: ta.Sequence[Ident] = dc.xfield(coerce=_coerce_name_parts)
|
32
|
+
|
33
|
+
|
34
|
+
##
|
35
|
+
|
36
|
+
|
37
|
+
@functools.singledispatch
|
38
|
+
def as_name(o: ta.Any) -> Name:
|
39
|
+
if isinstance(o, ta.Sequence):
|
40
|
+
return Name([as_ident(p) for p in o])
|
41
|
+
else:
|
42
|
+
raise TypeError(o)
|
43
|
+
|
44
|
+
|
45
|
+
@as_name.register
|
46
|
+
def _(n: Name) -> Name:
|
47
|
+
return n
|
48
|
+
|
49
|
+
|
50
|
+
@as_name.register
|
51
|
+
def _(o: Ident | str) -> Name:
|
52
|
+
return Name([as_ident(o)])
|
53
|
+
|
54
|
+
|
55
|
+
##
|
56
|
+
|
57
|
+
|
58
|
+
CanName: ta.TypeAlias = ta.Union[
|
59
|
+
NameLike,
|
60
|
+
Name,
|
61
|
+
CanIdent,
|
62
|
+
ta.Sequence[CanIdent],
|
63
|
+
'NameAccessor',
|
64
|
+
]
|
65
|
+
|
66
|
+
|
67
|
+
class NameAccessor(NameLike, lang.Final):
|
68
|
+
def __init__(self, ps: tuple[str, ...] = ()) -> None:
|
69
|
+
super().__init__()
|
70
|
+
self.__query_name_parts__ = ps
|
71
|
+
|
72
|
+
def __repr__(self) -> str:
|
73
|
+
return f'{self.__class__.__name__}({self.__query_name_parts__!r})'
|
74
|
+
|
75
|
+
def __getattr__(self, s: str) -> 'NameAccessor':
|
76
|
+
return NameAccessor((*self.__query_name_parts__, s))
|
77
|
+
|
78
|
+
def __call__(self, o: CanName) -> Name:
|
79
|
+
n = as_name(o)
|
80
|
+
if (ps := self.__query_name_parts__):
|
81
|
+
n = Name(tuple(*tuple(Ident(p) for p in ps), *n.ps)) # type: ignore[arg-type]
|
82
|
+
return n
|
83
|
+
|
84
|
+
|
85
|
+
@as_name.register
|
86
|
+
def _(a: NameAccessor) -> Name:
|
87
|
+
return Name(tuple(Ident(p) for p in a.__query_name_parts__))
|
88
|
+
|
89
|
+
|
90
|
+
##
|
19
91
|
|
20
92
|
|
21
93
|
class NameBuilder(IdentBuilder):
|
94
|
+
@ta.final
|
22
95
|
def name(self, o: CanName) -> Name:
|
23
|
-
|
24
|
-
return o
|
25
|
-
elif isinstance(o, (Ident, str)):
|
26
|
-
return Name([self.ident(o)])
|
27
|
-
elif isinstance(o, ta.Sequence):
|
28
|
-
return Name([self.ident(p) for p in o])
|
29
|
-
else:
|
30
|
-
raise TypeError(o)
|
96
|
+
return as_name(o)
|
31
97
|
|
32
98
|
@ta.final
|
33
|
-
|
34
|
-
|
99
|
+
@property
|
100
|
+
def n(self) -> NameAccessor:
|
101
|
+
return NameAccessor()
|