omlish 0.0.0.dev73__py3-none-any.whl → 0.0.0.dev75__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/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev73'
2
- __revision__ = '1fa2fcb99d4ea871fe3f5aa5c094ae37d0b1090c'
1
+ __version__ = '0.0.0.dev75'
2
+ __revision__ = 'dcdc82976a464689890fe99f9aaf5fc596ddd563'
3
3
 
4
4
 
5
5
  #
@@ -1,3 +1,7 @@
1
+ """
2
+ TODO:
3
+ - point validate / check exceptions to lambdas
4
+ """
1
5
  import dataclasses as dc
2
6
  import types
3
7
  import typing as ta
@@ -108,7 +108,11 @@ class DataMeta(abc.ABCMeta):
108
108
 
109
109
 
110
110
  # @ta.dataclass_transform(field_specifiers=(field,)) # FIXME: ctor
111
- class Data(metaclass=DataMeta):
111
+ class Data(
112
+ eq=False,
113
+ order=False,
114
+ metaclass=DataMeta,
115
+ ):
112
116
  def __init__(self, *args, **kwargs):
113
117
  super().__init__(*args, **kwargs)
114
118
 
@@ -125,6 +129,8 @@ class Data(metaclass=DataMeta):
125
129
  class Frozen(
126
130
  Data,
127
131
  frozen=True,
132
+ eq=False,
133
+ order=False,
128
134
  confer=frozenset([
129
135
  'frozen',
130
136
  'cache_hash',
omlish/http/clients.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """
2
2
  TODO:
3
+ - httpx catch
3
4
  - check=False
4
5
  - return non-200 HttpResponses
5
6
  - async
omlish/http/sse.py ADDED
@@ -0,0 +1,96 @@
1
+ """
2
+ TODO:
3
+ - end-of-line = ( cr lf / cr / lf )
4
+ """
5
+ import string
6
+ import typing as ta
7
+
8
+ from .. import dataclasses as dc
9
+ from .. import lang
10
+
11
+
12
+ class SseDecoderOutput(lang.Abstract):
13
+ pass
14
+
15
+
16
+ @dc.dataclass(frozen=True)
17
+ class SseComment(SseDecoderOutput, lang.Final):
18
+ data: bytes
19
+
20
+
21
+ SseEventId: ta.TypeAlias = bytes
22
+
23
+
24
+ @dc.dataclass(frozen=True)
25
+ class SseEvent(SseDecoderOutput, lang.Final):
26
+ type: bytes
27
+ data: bytes
28
+ last_id: SseEventId = dc.xfield(b'', repr_fn=dc.truthy_repr)
29
+
30
+
31
+ _DIGIT_BYTES = string.digits.encode('ascii')
32
+
33
+
34
+ class SseDecoder:
35
+ """https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation"""
36
+
37
+ def __init__(self) -> None:
38
+ super().__init__()
39
+
40
+ self._reset()
41
+ self._last_event_id = b''
42
+ self._reconnection_time: int | None = None
43
+
44
+ _event_type: bytes
45
+ _data: list[bytes]
46
+
47
+ def _reset(self) -> None:
48
+ self._event_type = b'message'
49
+ self._data = []
50
+
51
+ def _process_field(self, name: bytes, value: bytes) -> None:
52
+ if name == b'event':
53
+ self._event_type = value
54
+
55
+ elif name == b'data':
56
+ self._data.append(value)
57
+
58
+ elif name == b'id':
59
+ if 0 not in value:
60
+ self._last_event_id = value
61
+
62
+ elif name == b'retry':
63
+ if all(c in _DIGIT_BYTES for c in value):
64
+ self._reconnection_time = int(value)
65
+
66
+ def _dispatch_event(self) -> SseEvent:
67
+ data = b''.join(lang.interleave(self._data, b'\n'))
68
+
69
+ e = SseEvent(
70
+ type=self._event_type,
71
+ data=data,
72
+ last_id=self._last_event_id,
73
+ )
74
+
75
+ self._reset()
76
+
77
+ return e
78
+
79
+ def process_line(self, line: bytes) -> ta.Iterable[SseDecoderOutput]:
80
+ if b'\r' in line or b'\n' in line:
81
+ raise ValueError(line)
82
+
83
+ if not line:
84
+ yield self._dispatch_event()
85
+
86
+ elif line[0] == b':'[0]:
87
+ yield SseComment(line)
88
+
89
+ elif (c := line.find(b':')) >= 0:
90
+ d = c + 1
91
+ if len(line) > d and line[d] == b' '[0]:
92
+ d += 1
93
+ self._process_field(line[:c], line[d:])
94
+
95
+ else:
96
+ self._process_field(line, b'')
omlish/io.py ADDED
@@ -0,0 +1,142 @@
1
+ import dataclasses as dc
2
+ import io
3
+ import typing as ta
4
+
5
+ from . import check
6
+
7
+
8
+ @dc.dataclass(frozen=True)
9
+ class DelimitingBufferError(Exception):
10
+ buffer: 'DelimitingBuffer'
11
+
12
+
13
+ class ClosedDelimitingBufferError(DelimitingBufferError):
14
+ pass
15
+
16
+
17
+ class FullDelimitingBufferError(DelimitingBufferError):
18
+ pass
19
+
20
+
21
+ class IncompleteDelimitingBufferError(DelimitingBufferError):
22
+ pass
23
+
24
+
25
+ class DelimitingBuffer:
26
+ """
27
+ https://github.com/python-trio/trio/issues/796 :|
28
+ """
29
+
30
+ DEFAULT_DELIMITERS: bytes = b'\n'
31
+
32
+ def __init__(
33
+ self,
34
+ delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
35
+ *,
36
+ keep_ends: bool = False,
37
+ max_size: int | None = None,
38
+ on_full: ta.Literal['raise', 'yield'] = 'raise',
39
+ on_incomplete: ta.Literal['raise', 'yield'] = 'yield',
40
+ ) -> None:
41
+ super().__init__()
42
+
43
+ self._delimiters = frozenset(check.isinstance(d, int) for d in delimiters)
44
+ self._keep_ends = keep_ends
45
+ self._max_size = max_size
46
+ self._on_full = on_full
47
+ self._on_incomplete = on_incomplete
48
+
49
+ self._buf: io.BytesIO | None = io.BytesIO()
50
+
51
+ @property
52
+ def is_closed(self) -> bool:
53
+ return self._buf is None
54
+
55
+ def tell(self) -> int:
56
+ if (buf := self._buf) is None:
57
+ raise ClosedDelimitingBufferError(self)
58
+ return buf.tell()
59
+
60
+ def peek(self) -> bytes:
61
+ if (buf := self._buf) is None:
62
+ raise ClosedDelimitingBufferError(self)
63
+ return buf.getvalue()
64
+
65
+ def _find_delim(self, data: bytes | bytearray, i: int) -> int | None:
66
+ r = None # type: int | None
67
+ for d in self._delimiters:
68
+ if (p := data.find(d, i)) >= 0:
69
+ if r is None or p < r:
70
+ r = p
71
+ return r
72
+
73
+ def _append_and_reset(self, chunk: bytes) -> bytes:
74
+ buf = check.not_none(self._buf)
75
+ if not buf.tell():
76
+ return chunk
77
+
78
+ buf.write(chunk)
79
+ ret = buf.getvalue()
80
+ buf.seek(0)
81
+ return ret
82
+
83
+ def feed(self, data: bytes | bytearray) -> ta.Generator[bytes, None, None]:
84
+ if (buf := self._buf) is None:
85
+ raise ClosedDelimitingBufferError(self)
86
+
87
+ if not data:
88
+ self._buf = None
89
+
90
+ if buf.tell():
91
+ if self._on_incomplete == 'raise':
92
+ raise IncompleteDelimitingBufferError(self)
93
+
94
+ elif self._on_incomplete == 'yield':
95
+ yield buf.getvalue()
96
+
97
+ else:
98
+ raise ValueError(f'Unknown on_incomplete value: {self._on_incomplete!r}')
99
+
100
+ return
101
+
102
+ l = len(data)
103
+ i = 0
104
+ while i < l:
105
+ if (p := self._find_delim(data, i)) is None:
106
+ break
107
+
108
+ n = p + 1
109
+ if self._keep_ends:
110
+ p = n
111
+
112
+ yield self._append_and_reset(data[i:p])
113
+
114
+ i = n
115
+
116
+ if i >= l:
117
+ return
118
+
119
+ if self._max_size is None:
120
+ buf.write(data[i:])
121
+ return
122
+
123
+ while i < l:
124
+ remaining_data_len = l - i
125
+ remaining_buf_capacity = self._max_size - buf.tell()
126
+
127
+ if remaining_data_len < remaining_buf_capacity:
128
+ buf.write(data[i:])
129
+ return
130
+
131
+ if self._on_full == 'raise':
132
+ raise FullDelimitingBufferError(self)
133
+
134
+ elif self._on_full == 'yield':
135
+ p = i + remaining_buf_capacity
136
+
137
+ yield self._append_and_reset(data[i:p])
138
+
139
+ i = p
140
+
141
+ else:
142
+ raise ValueError(f'Unknown on_full value: {self._on_full!r}')
omlish/lang/__init__.py CHANGED
@@ -140,6 +140,7 @@ from .iterables import ( # noqa
140
140
  flatmap,
141
141
  flatten,
142
142
  ilen,
143
+ interleave,
143
144
  itergen,
144
145
  peek,
145
146
  prodrange,
omlish/lang/iterables.py CHANGED
@@ -37,6 +37,13 @@ def peek(vs: ta.Iterable[T]) -> tuple[T, ta.Iterator[T]]:
37
37
  return v, itertools.chain(iter((v,)), it)
38
38
 
39
39
 
40
+ def interleave(vs: ta.Iterable[T], d: T) -> ta.Iterable[T]:
41
+ for i, v in enumerate(vs):
42
+ if i:
43
+ yield d
44
+ yield v
45
+
46
+
40
47
  Rangeable: ta.TypeAlias = ta.Union[ # noqa
41
48
  int,
42
49
  tuple[int],
omlish/marshal/enums.py CHANGED
@@ -28,7 +28,7 @@ class EnumMarshalerFactory(MarshalerFactory):
28
28
  def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
29
29
  ty = check.isinstance(rty, type)
30
30
  check.state(issubclass(ty, enum.Enum))
31
- return EnumMarshaler(ty)
31
+ return EnumMarshaler(ty) # noqa
32
32
 
33
33
 
34
34
  @dc.dataclass(frozen=True)
@@ -11,6 +11,10 @@ from .binary import ( # noqa
11
11
  BinaryOps,
12
12
  )
13
13
 
14
+ from .building import ( # noqa
15
+ StdBuilder,
16
+ )
17
+
14
18
  from .exprs import ( # noqa
15
19
  CanExpr,
16
20
  CanLiteral,
@@ -18,6 +22,7 @@ from .exprs import ( # noqa
18
22
  ExprBuilder,
19
23
  Literal,
20
24
  NameExpr,
25
+ Param,
21
26
  )
22
27
 
23
28
  from .idents import ( # noqa
@@ -29,8 +34,7 @@ from .idents import ( # noqa
29
34
  from .multi import ( # noqa
30
35
  Multi,
31
36
  MultiBuilder,
32
- MultiOp,
33
- MultiOps,
37
+ MultiKind,
34
38
  )
35
39
 
36
40
  from .names import ( # noqa
@@ -39,6 +43,10 @@ from .names import ( # noqa
39
43
  NameBuilder,
40
44
  )
41
45
 
46
+ from .ops import ( # noqa
47
+ OpKind,
48
+ )
49
+
42
50
  from .relations import ( # noqa
43
51
  CanRelation,
44
52
  CanTable,
@@ -47,6 +55,12 @@ from .relations import ( # noqa
47
55
  Table,
48
56
  )
49
57
 
58
+ from .rendering import ( # noqa
59
+ Renderer,
60
+ StdRenderer,
61
+ render,
62
+ )
63
+
50
64
  from .selects import ( # noqa
51
65
  CanRelation,
52
66
  Select,
@@ -54,10 +68,6 @@ from .selects import ( # noqa
54
68
  SelectItem,
55
69
  )
56
70
 
57
- from .std import ( # noqa
58
- StdBuilder,
59
- )
60
-
61
71
  from .stmts import ( # noqa
62
72
  CanExpr,
63
73
  ExprStmt,
@@ -77,3 +87,11 @@ from .unary import ( # noqa
77
87
 
78
88
 
79
89
  Q = StdBuilder()
90
+
91
+
92
+ ##
93
+
94
+
95
+ from ...lang.imports import _register_conditional_import # noqa
96
+
97
+ _register_conditional_import('...marshal', '.marshal', __package__)
@@ -1,33 +1,41 @@
1
- import enum
2
-
1
+ """
2
+ TODO:
3
+ - in_
4
+ - like
5
+ - no this is a dedicated node, escape / negation in grammar
6
+ """
3
7
  from ... import check
4
8
  from ... import dataclasses as dc
5
9
  from ... import lang
6
10
  from .exprs import CanExpr
7
11
  from .exprs import Expr
8
12
  from .exprs import ExprBuilder
13
+ from .ops import OpKind
9
14
 
10
15
 
11
16
  ##
12
17
 
13
18
 
14
- class BinaryOpKind(enum.Enum):
15
- ARITH = enum.auto()
16
- BIT = enum.auto()
17
- CMP = enum.auto()
18
-
19
-
20
19
  class BinaryOp(dc.Frozen, lang.Final, eq=False):
21
20
  name: str
22
- kind: BinaryOpKind
21
+ kind: OpKind
23
22
 
24
23
 
25
24
  class BinaryOps(lang.Namespace):
26
- ADD = BinaryOp('add', BinaryOpKind.ARITH)
27
- SUB = BinaryOp('sub', BinaryOpKind.ARITH)
25
+ EQ = BinaryOp('eq', OpKind.CMP)
26
+ NE = BinaryOp('ne', OpKind.CMP)
27
+ LT = BinaryOp('lt', OpKind.CMP)
28
+ LE = BinaryOp('le', OpKind.CMP)
29
+ GT = BinaryOp('gt', OpKind.CMP)
30
+ GE = BinaryOp('ge', OpKind.CMP)
28
31
 
29
- EQ = BinaryOp('eq', BinaryOpKind.CMP)
30
- NE = BinaryOp('ne', BinaryOpKind.CMP)
32
+ ADD = BinaryOp('add', OpKind.ARITH)
33
+ SUB = BinaryOp('sub', OpKind.ARITH)
34
+ MUL = BinaryOp('mul', OpKind.ARITH)
35
+ DIV = BinaryOp('div', OpKind.ARITH)
36
+ MOD = BinaryOp('mod', OpKind.ARITH)
37
+
38
+ CONCAT = BinaryOp('concat', OpKind.STR)
31
39
 
32
40
 
33
41
  class Binary(Expr, lang.Final):
@@ -44,14 +52,44 @@ class BinaryBuilder(ExprBuilder):
44
52
  l = Binary(op, l, self.expr(r))
45
53
  return l
46
54
 
55
+ #
56
+
57
+ def eq(self, *es: CanExpr) -> Expr:
58
+ return self.binary(BinaryOps.EQ, *es)
59
+
60
+ def ne(self, *es: CanExpr) -> Expr:
61
+ return self.binary(BinaryOps.NE, *es)
62
+
63
+ def lt(self, *es: CanExpr) -> Expr:
64
+ return self.binary(BinaryOps.LT, *es)
65
+
66
+ def le(self, *es: CanExpr) -> Expr:
67
+ return self.binary(BinaryOps.LE, *es)
68
+
69
+ def gt(self, *es: CanExpr) -> Expr:
70
+ return self.binary(BinaryOps.GT, *es)
71
+
72
+ def ge(self, *es: CanExpr) -> Expr:
73
+ return self.binary(BinaryOps.GE, *es)
74
+
75
+ #
76
+
47
77
  def add(self, *es: CanExpr) -> Expr:
48
78
  return self.binary(BinaryOps.ADD, *es)
49
79
 
50
80
  def sub(self, *es: CanExpr) -> Expr:
51
81
  return self.binary(BinaryOps.SUB, *es)
52
82
 
53
- def eq(self, *es: CanExpr) -> Expr:
54
- return self.binary(BinaryOps.EQ, *es)
83
+ def mul(self, *es: CanExpr) -> Expr:
84
+ return self.binary(BinaryOps.MUL, *es)
55
85
 
56
- def ne(self, *es: CanExpr) -> Expr:
57
- return self.binary(BinaryOps.NE, *es)
86
+ def div(self, *es: CanExpr) -> Expr:
87
+ return self.binary(BinaryOps.DIV, *es)
88
+
89
+ def mod(self, *es: CanExpr) -> Expr:
90
+ return self.binary(BinaryOps.MOD, *es)
91
+
92
+ #
93
+
94
+ def concat(self, *es: CanExpr) -> Expr:
95
+ return self.binary(BinaryOps.CONCAT, *es)
@@ -1,3 +1,8 @@
1
+ """
2
+ TODO:
3
+ - case
4
+ - cast / ::
5
+ """
1
6
  import typing as ta
2
7
 
3
8
  from ... import lang
@@ -24,6 +29,24 @@ class NameExpr(Expr, lang.Final):
24
29
  n: Name
25
30
 
26
31
 
32
+ class Param(Expr, lang.Final):
33
+ n: str | None = None
34
+
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
+
41
+ def __eq__(self, other):
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
48
+
49
+
27
50
  CanLiteral: ta.TypeAlias = Literal | Value
28
51
  CanExpr: ta.TypeAlias = Expr | CanName | CanLiteral
29
52
 
@@ -41,6 +64,8 @@ class ExprBuilder(NameBuilder):
41
64
  def l(self, o: CanLiteral) -> Literal: # noqa
42
65
  return self.literal(o)
43
66
 
67
+ #
68
+
44
69
  def expr(self, o: CanExpr) -> Expr:
45
70
  if isinstance(o, Expr):
46
71
  return o
@@ -52,3 +77,12 @@ class ExprBuilder(NameBuilder):
52
77
  @ta.final
53
78
  def e(self, o: CanExpr) -> Expr:
54
79
  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)
@@ -0,0 +1,74 @@
1
+ import enum
2
+ import typing as ta
3
+
4
+ from ... import cached
5
+ from ... import check
6
+ from ... import collections as col
7
+ from ... import dataclasses as dc
8
+ from ... import lang
9
+ from ... import marshal as msh
10
+ from .base import Node
11
+ from .binary import BinaryOp
12
+ from .binary import BinaryOps
13
+ from .exprs import Expr
14
+ from .multi import MultiKind
15
+ from .relations import Relation
16
+ from .stmts import Stmt
17
+ from .unary import UnaryOp
18
+ from .unary import UnaryOps
19
+
20
+
21
+ @dc.dataclass(frozen=True)
22
+ class OpMarshalerUnmarshaler(msh.Marshaler, msh.Unmarshaler):
23
+ ty: type
24
+ ns: type[lang.Namespace]
25
+
26
+ @cached.property
27
+ @dc.init
28
+ def by_name(self) -> ta.Mapping[str, ta.Any]:
29
+ return col.make_map(((o.name, o) for _, o in self.ns), strict=True)
30
+
31
+ def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
32
+ return check.isinstance(o, self.ty).name # type: ignore # noqa
33
+
34
+ def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
35
+ return self.by_name[check.isinstance(v, str)]
36
+
37
+
38
+ @dc.dataclass(frozen=True)
39
+ class LowerEnumMarshaler(msh.Marshaler, msh.Unmarshaler):
40
+ ty: type[enum.Enum]
41
+
42
+ @cached.property
43
+ @dc.init
44
+ def by_name(self) -> ta.Mapping[str, ta.Any]:
45
+ return col.make_map(((o.name.lower(), o) for o in self.ty), strict=True)
46
+
47
+ def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
48
+ return o.name.lower()
49
+
50
+ def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
51
+ return self.by_name[check.isinstance(v, str).lower()]
52
+
53
+
54
+ @lang.static_init
55
+ def _install_standard_marshalling() -> None:
56
+ for ty, ns in [
57
+ (BinaryOp, BinaryOps),
58
+ (UnaryOp, UnaryOps),
59
+ ]:
60
+ msh.STANDARD_MARSHALER_FACTORIES[0:0] = [msh.TypeMapMarshalerFactory({ty: OpMarshalerUnmarshaler(ty, ns)})]
61
+ msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.TypeMapUnmarshalerFactory({ty: OpMarshalerUnmarshaler(ty, ns)})]
62
+
63
+ msh.STANDARD_MARSHALER_FACTORIES[0:0] = [msh.TypeMapMarshalerFactory({MultiKind: LowerEnumMarshaler(MultiKind)})]
64
+ msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.TypeMapUnmarshalerFactory({MultiKind: LowerEnumMarshaler(MultiKind)})] # noqa
65
+
66
+ for cls in [
67
+ Expr,
68
+ Node,
69
+ Relation,
70
+ Stmt,
71
+ ]:
72
+ p = msh.polymorphism_from_subclasses(cls, naming=msh.Naming.SNAKE)
73
+ msh.STANDARD_MARSHALER_FACTORIES[0:0] = [msh.PolymorphismMarshalerFactory(p)]
74
+ msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.PolymorphismUnmarshalerFactory(p)]
@@ -1,3 +1,4 @@
1
+ import enum
1
2
  import typing as ta
2
3
 
3
4
  from ... import check
@@ -11,30 +12,26 @@ from .exprs import ExprBuilder
11
12
  ##
12
13
 
13
14
 
14
- class MultiOp(dc.Frozen, lang.Final, eq=False):
15
- name: str
16
-
17
-
18
- class MultiOps(lang.Namespace):
19
- AND = MultiOp('and')
20
- OR = MultiOp('or')
15
+ class MultiKind(enum.Enum):
16
+ AND = enum.auto()
17
+ OR = enum.auto()
21
18
 
22
19
 
23
20
  class Multi(Expr, lang.Final):
24
- op: MultiOp
25
- es: ta.Sequence[Expr] = dc.xfield(coerce=tuple)
21
+ k: MultiKind
22
+ es: ta.Sequence[Expr] = dc.xfield(coerce=tuple, validate=lambda es: len(es) > 1)
26
23
 
27
24
 
28
25
  class MultiBuilder(ExprBuilder):
29
- def multi(self, op: MultiOp, *es: CanExpr) -> Expr:
26
+ def multi(self, k: MultiKind, *es: CanExpr) -> Expr:
30
27
  check.not_empty(es)
31
28
  if len(es) == 1:
32
29
  return self.expr(es[0])
33
30
  else:
34
- return Multi(op, [self.expr(e) for e in es])
31
+ return Multi(k, [self.expr(e) for e in es])
35
32
 
36
33
  def and_(self, *es: CanExpr) -> Expr:
37
- return self.multi(MultiOps.AND, *es)
34
+ return self.multi(MultiKind.AND, *es)
38
35
 
39
36
  def or_(self, *es: CanExpr) -> Expr:
40
- return self.multi(MultiOps.OR, *es)
37
+ return self.multi(MultiKind.OR, *es)
@@ -0,0 +1,8 @@
1
+ import enum
2
+
3
+
4
+ class OpKind(enum.Enum):
5
+ CMP = enum.auto()
6
+ ARITH = enum.auto()
7
+ BIT = enum.auto()
8
+ STR = enum.auto()
@@ -1,3 +1,8 @@
1
+ """
2
+ TODO:
3
+ - join
4
+ - subquery
5
+ """
1
6
  import typing as ta
2
7
 
3
8
  from ... import dataclasses as dc
@@ -0,0 +1,180 @@
1
+ """
2
+ TODO:
3
+ - minimal parens
4
+ - text.parts
5
+ - QuoteStyle
6
+ - ParamStyle
7
+
8
+ ==
9
+
10
+ def needs_parens(self, e: Expr) -> bool:
11
+ if isinstance(e, (Literal, Ident, Name)):
12
+ return True
13
+ elif isinstance(e, Expr):
14
+ return False
15
+ else:
16
+ raise TypeError(e)
17
+ """
18
+ import io
19
+ import typing as ta
20
+
21
+ from ... import dispatch
22
+ from ... import lang
23
+ from .base import Node
24
+ from .binary import Binary
25
+ from .binary import BinaryOp
26
+ from .binary import BinaryOps
27
+ from .exprs import Literal
28
+ from .exprs import NameExpr
29
+ from .idents import Ident
30
+ from .multi import Multi
31
+ from .multi import MultiKind
32
+ from .names import Name
33
+ from .relations import Table
34
+ from .selects import Select
35
+ from .selects import SelectItem
36
+ from .unary import Unary
37
+ from .unary import UnaryOp
38
+ from .unary import UnaryOps
39
+
40
+
41
+ class Renderer(lang.Abstract):
42
+ def __init__(self, out: ta.TextIO) -> None:
43
+ super().__init__()
44
+ self._out = out
45
+
46
+ @dispatch.method
47
+ def render(self, o: ta.Any) -> None:
48
+ raise TypeError(o)
49
+
50
+ @classmethod
51
+ def render_str(cls, o: ta.Any, *args: ta.Any, **kwargs: ta.Any) -> str:
52
+ out = io.StringIO()
53
+ cls(out, *args, **kwargs).render(o)
54
+ return out.getvalue()
55
+
56
+
57
+ class StdRenderer(Renderer):
58
+ # binary
59
+
60
+ BINARY_OP_TO_STR: ta.ClassVar[ta.Mapping[BinaryOp, str]] = {
61
+ BinaryOps.EQ: '=',
62
+ BinaryOps.NE: '!=',
63
+ BinaryOps.LT: '<',
64
+ BinaryOps.LE: '<=',
65
+ BinaryOps.GT: '>',
66
+ BinaryOps.GE: '>=',
67
+
68
+ BinaryOps.ADD: '+',
69
+ BinaryOps.SUB: '-',
70
+ BinaryOps.MUL: '*',
71
+ BinaryOps.DIV: '/',
72
+ BinaryOps.MOD: '%',
73
+
74
+ BinaryOps.CONCAT: '||',
75
+ }
76
+
77
+ @Renderer.render.register
78
+ def render_binary(self, o: Binary) -> None:
79
+ self._out.write('(')
80
+ self.render(o.l)
81
+ self._out.write(f' {self.BINARY_OP_TO_STR[o.op]} ')
82
+ self.render(o.r)
83
+ self._out.write(')')
84
+
85
+ # exprs
86
+
87
+ @Renderer.render.register
88
+ def render_literal(self, o: Literal) -> None:
89
+ self._out.write(repr(o.v))
90
+
91
+ @Renderer.render.register
92
+ def render_name_expr(self, o: NameExpr) -> None:
93
+ self.render(o.n)
94
+
95
+ # idents
96
+
97
+ @Renderer.render.register
98
+ def render_ident(self, o: Ident) -> None:
99
+ self._out.write(f'"{o.s}"')
100
+
101
+ # multis
102
+
103
+ MULTI_KIND_TO_STR: ta.ClassVar[ta.Mapping[MultiKind, str]] = {
104
+ MultiKind.AND: 'and',
105
+ MultiKind.OR: 'or',
106
+
107
+ }
108
+
109
+ @Renderer.render.register
110
+ def render_multi(self, o: Multi) -> None:
111
+ d = f' {self.MULTI_KIND_TO_STR[o.k]} '
112
+ self._out.write('(')
113
+ for i, e in enumerate(o.es):
114
+ if i:
115
+ self._out.write(d)
116
+ self.render(e)
117
+ self._out.write(')')
118
+
119
+ # names
120
+
121
+ @Renderer.render.register
122
+ def render_name(self, o: Name) -> None:
123
+ for n, i in enumerate(o.ps):
124
+ if n:
125
+ self._out.write('.')
126
+ self.render(i)
127
+
128
+ # relations
129
+
130
+ @Renderer.render.register
131
+ def render_table(self, o: Table) -> None:
132
+ self.render(o.n)
133
+ if o.a is not None:
134
+ self._out.write(' as ')
135
+ self.render(o.a)
136
+
137
+ # selects
138
+
139
+ @Renderer.render.register
140
+ def render_select_item(self, o: SelectItem) -> None:
141
+ self.render(o.v)
142
+ if o.a is not None:
143
+ self._out.write(' as ')
144
+ self.render(o.a)
145
+
146
+ @Renderer.render.register
147
+ def render_select(self, o: Select) -> None:
148
+ self._out.write('select ')
149
+ for i, it in enumerate(o.items):
150
+ if i:
151
+ self._out.write(', ')
152
+ self.render(it)
153
+ if o.from_ is not None:
154
+ self._out.write(' from ')
155
+ self.render(o.from_)
156
+ if o.where:
157
+ self._out.write(' where ')
158
+ self.render(o.where)
159
+
160
+ # unary
161
+
162
+ UNARY_OP_TO_STR: ta.ClassVar[ta.Mapping[UnaryOp, tuple[str, str]]] = {
163
+ UnaryOps.NOT: ('not ', ''),
164
+ UnaryOps.IS_NULL: ('', ' is null'),
165
+ UnaryOps.IS_NOT_NULL: ('', ' is not null'),
166
+
167
+ UnaryOps.POS: ('+', ''),
168
+ UnaryOps.NEG: ('-', ''),
169
+ }
170
+
171
+ @Renderer.render.register
172
+ def render_unary(self, o: Unary) -> None:
173
+ pfx, sfx = self.UNARY_OP_TO_STR[o.op]
174
+ self._out.write(pfx)
175
+ self.render(o.v)
176
+ self._out.write(sfx)
177
+
178
+
179
+ def render(n: Node) -> str:
180
+ return StdRenderer.render_str(n)
@@ -3,6 +3,7 @@ from ... import lang
3
3
  from .exprs import CanExpr
4
4
  from .exprs import Expr
5
5
  from .exprs import ExprBuilder
6
+ from .ops import OpKind
6
7
 
7
8
 
8
9
  ##
@@ -10,10 +11,16 @@ from .exprs import ExprBuilder
10
11
 
11
12
  class UnaryOp(dc.Frozen, lang.Final, eq=False):
12
13
  name: str
14
+ kind: OpKind
13
15
 
14
16
 
15
17
  class UnaryOps(lang.Namespace):
16
- NOT = UnaryOp('not')
18
+ NOT = UnaryOp('not', OpKind.CMP)
19
+ IS_NULL = UnaryOp('is_null', OpKind.CMP)
20
+ IS_NOT_NULL = UnaryOp('is_not_null', OpKind.CMP)
21
+
22
+ POS = UnaryOp('pos', OpKind.ARITH)
23
+ NEG = UnaryOp('neg', OpKind.ARITH)
17
24
 
18
25
 
19
26
  class Unary(Expr, lang.Final):
@@ -25,5 +32,21 @@ class UnaryBuilder(ExprBuilder):
25
32
  def unary(self, op: UnaryOp, v: CanExpr) -> Unary:
26
33
  return Unary(op, self.expr(v))
27
34
 
35
+ #
36
+
28
37
  def not_(self, v: CanExpr) -> Unary:
29
38
  return self.unary(UnaryOps.NOT, v)
39
+
40
+ def is_null(self, v: CanExpr) -> Unary:
41
+ return self.unary(UnaryOps.IS_NULL, v)
42
+
43
+ def is_not_null(self, v: CanExpr) -> Unary:
44
+ return self.unary(UnaryOps.IS_NOT_NULL, v)
45
+
46
+ #
47
+
48
+ def pos(self, v: CanExpr) -> Unary:
49
+ return self.unary(UnaryOps.POS, v)
50
+
51
+ def neg(self, v: CanExpr) -> Unary:
52
+ return self.unary(UnaryOps.NEG, v)
@@ -10,10 +10,7 @@ def _install_poly(cls: type) -> None:
10
10
  msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.PolymorphismUnmarshalerFactory(p)]
11
11
 
12
12
 
13
- @lang.cached_function
13
+ @lang.static_init
14
14
  def _install_standard_marshalling() -> None:
15
15
  _install_poly(Dtype)
16
16
  _install_poly(Element)
17
-
18
-
19
- _install_standard_marshalling()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev73
3
+ Version: 0.0.0.dev75
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=TXvFdkAU0Zr2FKdo7fyvt9nr3UjCtrnAZ0diZXSAteE,1430
2
- omlish/__about__.py,sha256=yPixWBOcI8ebqG0dPVHJ2dG1M4Ec4rBKr8ehmN0d7qQ,3420
2
+ omlish/__about__.py,sha256=KmKwb6iUcg1fxhudcMoQVNM13U_ufTfnRbe5K2n-Za0,3420
3
3
  omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omlish/argparse.py,sha256=Dc73G8lyoQBLvXhMYUbzQUh4SJu_OTvKUXjSUxq_ang,7499
5
5
  omlish/c3.py,sha256=4vogWgwPb8TbNS2KkZxpoWbwjj7MuHG2lQG-hdtkvjI,8062
@@ -11,6 +11,7 @@ omlish/dynamic.py,sha256=35C_cCX_Vq2HrHzGk5T-zbrMvmUdiIiwDzDNixczoDo,6541
11
11
  omlish/fnpairs.py,sha256=Sl8CMFNyDS-1JYAjSWqnT5FmUm9Lj6o7FxSRo7g4jww,10875
12
12
  omlish/fnpipes.py,sha256=AJkgz9nvRRm7oqw7ZgYyz21klu276LWi54oYCLg-vOg,2196
13
13
  omlish/genmachine.py,sha256=LCMiqvK32dAWtrlB6lKw9tXdQFiXC8rRdk4TMQYIroU,1603
14
+ omlish/io.py,sha256=4_0naIRniQ_xGhCW44xkk3sKqgddCbtIjbs72SGqK9g,3679
14
15
  omlish/iterators.py,sha256=GGLC7RIT86uXMjhIIIqnff_Iu5SI_b9rXYywYGFyzmo,7292
15
16
  omlish/libc.py,sha256=8r7Ejyhttk9ruCfBkxNTrlzir5WPbDE2vmY7VPlceMA,15362
16
17
  omlish/matchfns.py,sha256=I1IlQGfEyk_AcFSy6ulVS3utC-uwyZM2YfUXYHc9Bw0,6152
@@ -132,13 +133,13 @@ omlish/dataclasses/impl/as_.py,sha256=CD-t7hkC1EP2F_jvZKIA_cVoDuwZ-Ln_xC4fJumPYX
132
133
  omlish/dataclasses/impl/copy.py,sha256=Tn8_n6Vohs-w4otbGdubBEvhd3TsSTaM3EfNGdS2LYo,591
133
134
  omlish/dataclasses/impl/descriptors.py,sha256=rEYE1Len99agTQCC25hSPMnM19BgPr0ZChABGi58Fdk,2476
134
135
  omlish/dataclasses/impl/exceptions.py,sha256=DeiM6rcjgncudn-XVuph9TDbVDEwBtyYb1bcbO3FFcA,193
135
- omlish/dataclasses/impl/fields.py,sha256=iXA8j3q8GFQoj-6MgAKVLGG9GSSNOLGgyVtogCQ5q1E,6459
136
+ omlish/dataclasses/impl/fields.py,sha256=mr8tnSDceHGZ6VBbeegt-iCzQJbtCXoWOUwltjRULy4,6521
136
137
  omlish/dataclasses/impl/frozen.py,sha256=x87DSM8FIMZ3c_BIUE8NooCkExFjPsabeqIueEP5qKs,2988
137
138
  omlish/dataclasses/impl/hashing.py,sha256=FKnHuXCg9ylrzK2TLGqO5yfRN4HX3F415CSLlVYXtYE,3190
138
139
  omlish/dataclasses/impl/init.py,sha256=IgxO9nwHaHF8jGrUAk-Y5xke9uV2OwzfEe-88McE1Wg,6161
139
140
  omlish/dataclasses/impl/internals.py,sha256=UvZYjrLT1S8ntyxJ_vRPIkPOF00K8HatGAygErgoXTU,2990
140
141
  omlish/dataclasses/impl/main.py,sha256=Ti0PKbFKraKvfmoPuR-G7nLVNzRC8mvEuXhCuC-M2kc,2574
141
- omlish/dataclasses/impl/metaclass.py,sha256=E0lIKGjUcQXOJEZYb6qXa2h4iYNj292OFtau3sq8cSQ,3153
142
+ omlish/dataclasses/impl/metaclass.py,sha256=Fb0ExFiyYdOpvck4ayXMr_vEVDvHLhe28Ns3F4aduM8,3222
142
143
  omlish/dataclasses/impl/metadata.py,sha256=4veWwTr-aA0KP-Y1cPEeOcXHup9EKJTYNJ0ozIxtzD4,1401
143
144
  omlish/dataclasses/impl/order.py,sha256=zWvWDkSTym8cc7vO1cLHqcBhhjOlucHOCUVJcdh4jt0,1369
144
145
  omlish/dataclasses/impl/params.py,sha256=zsobAD6QvMAZeMsohP8nKFyv_w6Q4buocARQG1y1etA,2768
@@ -202,7 +203,7 @@ omlish/graphs/dot/rendering.py,sha256=2UgXvMRN4Z9cfIqLlC7Iu_8bWbwUDEL4opHHkFfSqT
202
203
  omlish/graphs/dot/utils.py,sha256=_FMwn77WfiiAfLsRTOKWm4IYbNv5kQN22YJ5psw6CWg,801
203
204
  omlish/http/__init__.py,sha256=-ENDALr8ehHvivRD6cxIbEC94t0RHhrakf6CQRDTc8o,625
204
205
  omlish/http/asgi.py,sha256=wXhBZ21bEl32Kv9yBrRwUR_7pHEgVtHP8ZZwbasQ6-4,3307
205
- omlish/http/clients.py,sha256=eOY4bmbGdXuOOabt9NLAcTO7G49u85-HoAFW28mCXS4,6004
206
+ omlish/http/clients.py,sha256=phwWe4a6aVU2_E-Z_zSzrmAb5iX9zoCDIMa2l6Trzck,6019
206
207
  omlish/http/collections.py,sha256=s8w5s4Gewgxxhe2Ai0R45PgJYYifrLgTbU3VXVflHj4,260
207
208
  omlish/http/consts.py,sha256=FTolezLknKU6WJjk_x2T3a5LEMlnZSqv7gzTq55lxcU,2147
208
209
  omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
@@ -211,6 +212,7 @@ omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
211
212
  omlish/http/headers.py,sha256=S66wiXezBHybrnjAM15E9x4GJvPRvFQHeKaXdJ799fw,5028
212
213
  omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
213
214
  omlish/http/sessions.py,sha256=VZ_WS5uiQG5y7i3u8oKuQMqf8dPKUOjFm_qk_0OvI8c,4793
215
+ omlish/http/sse.py,sha256=T2_EXTcDfEhCF4E9B68YtEYLFb803MPnh8eCNjdPlRo,2223
214
216
  omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
215
217
  omlish/inject/__init__.py,sha256=JQ7x8l9MjU-kJ5ap7cPVq7SY7zbbCIrjyJAF0UeE5-s,1886
216
218
  omlish/inject/binder.py,sha256=H8AQ4ecmBOtDL8fMgrU1yUJl1gBADLNcdysRbvO8Wso,4167
@@ -242,7 +244,7 @@ omlish/inject/impl/privates.py,sha256=alpCYyk5VJ9lJknbRH2nLVNFYVvFhkj-VC1Vco3zCF
242
244
  omlish/inject/impl/providers.py,sha256=QnwhsujJFIHC0JTgd2Wlo1kP53i3CWTrj1nKU2DNxwg,2375
243
245
  omlish/inject/impl/proxy.py,sha256=1ko0VaKqzu9UG8bIldp9xtUrAVUOFTKWKTjOCqIGr4s,1636
244
246
  omlish/inject/impl/scopes.py,sha256=ASfULXgP_ETlsAqFJfrZmyEaZt64Zr8tNn5ScA-EoXk,5900
245
- omlish/lang/__init__.py,sha256=-DRmyoSAwSWOh7nJh4UrpR-w_hGQfe-e06S9qLjHZF8,3636
247
+ omlish/lang/__init__.py,sha256=p63qmjZwg2CjLhMaZncnZKsuLZ6B_QVfpPGZKVH8FTw,3652
246
248
  omlish/lang/cached.py,sha256=92TvRZQ6sWlm7dNn4hgl7aWKbX0J1XUEo3DRjBpgVQk,7834
247
249
  omlish/lang/clsdct.py,sha256=AjtIWLlx2E6D5rC97zQ3Lwq2SOMkbg08pdO_AxpzEHI,1744
248
250
  omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
@@ -252,7 +254,7 @@ omlish/lang/descriptors.py,sha256=RRBbkMgTzg82fFFE4D0muqobpM-ZZaOta6yB1lpX3s8,66
252
254
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
253
255
  omlish/lang/functions.py,sha256=kkPfcdocg-OmyN7skIqrFxNvqAv89Zc_kXKYAN8vw8g,3895
254
256
  omlish/lang/imports.py,sha256=Oy7iInOTqgZv6nyRbnvGrPv4cKKIAzPbhfDXCajDUcc,6626
255
- omlish/lang/iterables.py,sha256=_q6rHbdFfW3VBqez0IV3rUABoNxsA_oBv_sykm5zsbQ,2243
257
+ omlish/lang/iterables.py,sha256=xRwktm6i2RHSb_ELfAXdjITIfE69qDyMEzgeZqvQXiU,2386
256
258
  omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
257
259
  omlish/lang/objects.py,sha256=t7Pvj9ILoxfdAMy5HC7bb9LfUokW5WfpLaoH2YYyTjQ,4460
258
260
  omlish/lang/resolving.py,sha256=OuN2mDTPNyBUbcrswtvFKtj4xgH4H4WglgqSKv3MTy0,1606
@@ -299,7 +301,7 @@ omlish/marshal/base.py,sha256=_ZKSSuv6p9r86sja_jaxI09WYpjCBFi0KTsOiZCYyk0,6587
299
301
  omlish/marshal/base64.py,sha256=F-3ogJdcFCtWINRgJgWT0rErqgx6f4qahhcg8OrkqhE,1089
300
302
  omlish/marshal/dataclasses.py,sha256=G6Uh8t4vvNBAx2BhzH8ksj8Hq_bo6npFphQhyF298VU,6892
301
303
  omlish/marshal/datetimes.py,sha256=0ffg8cEvx9SMKIXZGD9b7MqpLfmgw0uKKdn6YTfoqok,3714
302
- omlish/marshal/enums.py,sha256=-0fKutBbyz8ygEaA0_P_8IOJrI9jMGigmnPbutV9Bg4,1464
304
+ omlish/marshal/enums.py,sha256=CMAbx6RI2EcQoo7SoD-5q2l-3DFKreWMiOxs6mFpl_4,1472
303
305
  omlish/marshal/exceptions.py,sha256=jwQWn4LcPnadT2KRI_1JJCOSkwWh0yHnYK9BmSkNN4U,302
304
306
  omlish/marshal/factories.py,sha256=UV2Svjok-lTWsRqKGh-CeuAhvlohw9uJe7ZLyoKMvTM,2968
305
307
  omlish/marshal/forbidden.py,sha256=BNshzm4lN5O8sUZ1YvxrSYq3WPklq9NMQCRZ7RC3DLM,865
@@ -388,24 +390,27 @@ omlish/sql/alchemy/duckdb.py,sha256=kr7pIhiBLNAuZrcigHDtFg9zHkVcrRW3LfryO9VJ4mk,
388
390
  omlish/sql/alchemy/exprs.py,sha256=gO4Fj4xEY-PuDgV-N8hBMy55glZz7O-4H7v1LWabfZY,323
389
391
  omlish/sql/alchemy/secrets.py,sha256=EMfy4EfTbEvrlv_41oOhn8qsoF-eTkY7HciPenIE6rI,178
390
392
  omlish/sql/alchemy/sqlean.py,sha256=RbkuOuFIfM4fowwKk8-sQ6Dxk-tTUwxS94nY5Kxt52s,403
391
- omlish/sql/queries/__init__.py,sha256=TEl0iNWVxPURJIRJSaKpy5EJkyVXw2Zej8jlKmeggAo,963
393
+ omlish/sql/queries/__init__.py,sha256=BdhONMw2JebX-jEgYb1WrM5L3vkJOzQRm0nt04IYKgQ,1229
392
394
  omlish/sql/queries/base.py,sha256=_8O3MbH_OEjBnhp2oIJUZ3ClaQ8l4Sj9BdPdsP0Ie-g,224
393
- omlish/sql/queries/binary.py,sha256=qqlsyW7PM4DS2MkESKV81GMue22OnftOc8VD5KFpZI8,1242
394
- omlish/sql/queries/exprs.py,sha256=tJ5gK21NKYbxKnJmrAUDkzaPqzg7hg6-z2GS4-MG05U,1092
395
+ omlish/sql/queries/binary.py,sha256=dcEzeEn104AMPuQ7QrJU2O-YCN3SUdxB5S4jaWKOUqY,2253
396
+ omlish/sql/queries/building.py,sha256=pddD8-WDDGwX97OW7MLahaZTLsO_0NLxxIIAXXq1N40,537
397
+ omlish/sql/queries/exprs.py,sha256=kAI5PmvfJ-TqEzzc9H4_womFShT1eA0jWSZH2j2Wg-c,1802
395
398
  omlish/sql/queries/idents.py,sha256=erW6fE9UapuvW1ZeLfGFz7yuW6zzktWIWmOuAHeF8_g,496
396
- omlish/sql/queries/multi.py,sha256=qlcci2wv_gDfOPuPpwFS-aV6f11T8ftmIDzx2dbI82k,857
399
+ omlish/sql/queries/marshal.py,sha256=MKZ3CVcr7mpnmg25twVgErWk1SpRBEkE1mu2fE8QwUA,2508
400
+ omlish/sql/queries/multi.py,sha256=KKHf8uS3Akk-YACPUwaqQO20NlDdrB3gbauOAejZzgU,832
397
401
  omlish/sql/queries/names.py,sha256=YiIyS6ehYMYrdLlUxMawV_Xf2zdi7RwVO9Qsxr_W4_4,772
398
- omlish/sql/queries/relations.py,sha256=zAOCJWopA3MxAE_J4wxRtuvGEOcQgOnAQaF_wT4z930,804
402
+ omlish/sql/queries/ops.py,sha256=B7IDfjr2DW5LJhWoNaY1WW90BJhe5ZtmxIELhWXbW-0,129
403
+ omlish/sql/queries/relations.py,sha256=-d3n-dN17c3TPMZmzSplhWawllUzdq12XPDAuzoeMEQ,838
404
+ omlish/sql/queries/rendering.py,sha256=AC2PSGFCLXYk38mnH7EAMV7hQOKp5x6O-ZYV8FXgnAM,4360
399
405
  omlish/sql/queries/selects.py,sha256=EcHlyKl5kGSY1d3GVxnImhGCTB6WvwQnlSA9eZanBqU,1364
400
- omlish/sql/queries/std.py,sha256=pddD8-WDDGwX97OW7MLahaZTLsO_0NLxxIIAXXq1N40,537
401
406
  omlish/sql/queries/stmts.py,sha256=pBqwD7dRlqMu6uh6vR3xaWOEgbZCcFWbOQ9ryYd17T4,441
402
- omlish/sql/queries/unary.py,sha256=lbVfsfS2zcJFchZ4sqoGMFzNEgc_Tnfj5_P1Yjs9lqs,540
407
+ omlish/sql/queries/unary.py,sha256=MEYBDZn_H0bexmUrJeONOv5-gIpYowUaXOsEHeQM4ks,1144
403
408
  omlish/sql/tabledefs/__init__.py,sha256=TvtQsp-jJu6_ZahyCOFAaElSSBcRftNyJpdiDPGYCDk,190
404
409
  omlish/sql/tabledefs/alchemy.py,sha256=MiNfVSgX_Ka6PmVTgAcCmS3ULK5mfVRXD_VC2-9TidU,485
405
410
  omlish/sql/tabledefs/dtypes.py,sha256=egZDi-A17MC-4R_ZKR_3uQf1a6mGm91Gmh0b72O85bQ,362
406
411
  omlish/sql/tabledefs/elements.py,sha256=lP_Ch19hKmiGYPQVeC8HpFaKdTYnXi2FfpfwKMxZOck,1674
407
412
  omlish/sql/tabledefs/lower.py,sha256=YQf8gl1kxD5Fm-vOxV6G0Feh_D9PP1pYwz_vz6XjTPQ,1405
408
- omlish/sql/tabledefs/marshal.py,sha256=CvjNUHD5ABz72m7MsIqhpHyz2AZHYS6ijWwJXg3_MSs,542
413
+ omlish/sql/tabledefs/marshal.py,sha256=j-Rz1HsiXmABv39-2VoJdzSSB3kbxqaVevbdkZWMyG8,504
409
414
  omlish/sql/tabledefs/tabledefs.py,sha256=lIhvlt0pk6G7RZAtDFsFXm5j0l9BvRfnP7vNGeydHtE,816
410
415
  omlish/testing/__init__.py,sha256=M_BQrcCHkoL-ZvE-UpQ8XxXNYRRawhjUz4rCJnAqM2A,152
411
416
  omlish/testing/testing.py,sha256=TT2wwSzPZ_KhIvKxpM1qc1yHKD-LHDNgGrcr_h8vs7c,2895
@@ -433,9 +438,9 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
433
438
  omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
434
439
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
435
440
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
436
- omlish-0.0.0.dev73.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
437
- omlish-0.0.0.dev73.dist-info/METADATA,sha256=8-3oSBXhJcYztmni0BLIGOG4G_Wme3JfJKM25ag5sLI,4167
438
- omlish-0.0.0.dev73.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
439
- omlish-0.0.0.dev73.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
440
- omlish-0.0.0.dev73.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
441
- omlish-0.0.0.dev73.dist-info/RECORD,,
441
+ omlish-0.0.0.dev75.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
442
+ omlish-0.0.0.dev75.dist-info/METADATA,sha256=GuYbZyayGe8TDZ3NyirRfVwE06aEFatiflv_jOd9zQI,4167
443
+ omlish-0.0.0.dev75.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
444
+ omlish-0.0.0.dev75.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
445
+ omlish-0.0.0.dev75.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
446
+ omlish-0.0.0.dev75.dist-info/RECORD,,
File without changes