omlish 0.0.0.dev70__py3-none-any.whl → 0.0.0.dev72__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.
Files changed (35) hide show
  1. omlish/__about__.py +3 -3
  2. omlish/dataclasses/impl/internals.py +1 -0
  3. omlish/dataclasses/impl/metaclass.py +22 -5
  4. omlish/dataclasses/impl/params.py +4 -2
  5. omlish/diag/_pycharm/runhack.py +9 -4
  6. omlish/formats/json/cli.py +3 -0
  7. omlish/http/__init__.py +17 -0
  8. omlish/http/clients.py +239 -0
  9. omlish/http/consts.py +4 -0
  10. omlish/http/headers.py +181 -0
  11. omlish/sql/queries/__init__.py +79 -0
  12. omlish/sql/queries/base.py +21 -0
  13. omlish/sql/queries/binary.py +48 -0
  14. omlish/sql/queries/exprs.py +54 -0
  15. omlish/sql/queries/idents.py +29 -0
  16. omlish/sql/queries/multi.py +41 -0
  17. omlish/sql/queries/names.py +34 -0
  18. omlish/sql/queries/relations.py +39 -0
  19. omlish/sql/queries/selects.py +50 -0
  20. omlish/sql/queries/std.py +29 -0
  21. omlish/sql/queries/stmts.py +28 -0
  22. omlish/sql/queries/unary.py +29 -0
  23. omlish/sql/tabledefs/__init__.py +11 -0
  24. omlish/sql/tabledefs/alchemy.py +26 -0
  25. omlish/sql/tabledefs/dtypes.py +22 -0
  26. omlish/sql/tabledefs/elements.py +88 -0
  27. omlish/sql/tabledefs/lower.py +49 -0
  28. omlish/sql/tabledefs/marshal.py +19 -0
  29. omlish/sql/tabledefs/tabledefs.py +52 -0
  30. {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/METADATA +3 -3
  31. {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/RECORD +35 -14
  32. {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/LICENSE +0 -0
  33. {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/WHEEL +0 -0
  34. {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/entry_points.txt +0 -0
  35. {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,21 @@
1
+ import typing as ta
2
+
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+
6
+
7
+ ##
8
+
9
+
10
+ Value: ta.TypeAlias = ta.Any
11
+
12
+
13
+ ##
14
+
15
+
16
+ class Node(dc.Frozen, lang.Abstract, cache_hash=True):
17
+ pass
18
+
19
+
20
+ class Builder(lang.Abstract):
21
+ pass
@@ -0,0 +1,48 @@
1
+ from ... import check
2
+ from ... import lang
3
+ from .base import Node
4
+ from .exprs import CanExpr
5
+ from .exprs import Expr
6
+ from .exprs import ExprBuilder
7
+
8
+
9
+ ##
10
+
11
+
12
+ class BinaryOp(Node, lang.Final):
13
+ name: str
14
+
15
+
16
+ class BinaryOps(lang.Namespace):
17
+ ADD = BinaryOp('add')
18
+ SUB = BinaryOp('sub')
19
+
20
+ EQ = BinaryOp('eq')
21
+ NE = BinaryOp('ne')
22
+
23
+
24
+ class Binary(Expr, lang.Final):
25
+ op: BinaryOp
26
+ l: Expr
27
+ r: Expr
28
+
29
+
30
+ class BinaryBuilder(ExprBuilder):
31
+ def binary(self, op: BinaryOp, *es: CanExpr) -> Expr:
32
+ check.not_empty(es)
33
+ l = self.expr(es[0])
34
+ for r in es[1:]:
35
+ l = Binary(op, l, self.expr(r))
36
+ return l
37
+
38
+ def add(self, *es: CanExpr) -> Expr:
39
+ return self.binary(BinaryOps.ADD, *es)
40
+
41
+ def sub(self, *es: CanExpr) -> Expr:
42
+ return self.binary(BinaryOps.SUB, *es)
43
+
44
+ def eq(self, *es: CanExpr) -> Expr:
45
+ return self.binary(BinaryOps.EQ, *es)
46
+
47
+ def ne(self, *es: CanExpr) -> Expr:
48
+ return self.binary(BinaryOps.NE, *es)
@@ -0,0 +1,54 @@
1
+ import typing as ta
2
+
3
+ from ... import lang
4
+ from .base import Node
5
+ from .base import Value
6
+ from .idents import Ident
7
+ from .names import CanName
8
+ from .names import Name
9
+ from .names import NameBuilder
10
+
11
+
12
+ ##
13
+
14
+
15
+ class Expr(Node, lang.Abstract):
16
+ pass
17
+
18
+
19
+ class Literal(Expr, lang.Final):
20
+ v: Value
21
+
22
+
23
+ class NameExpr(Expr, lang.Final):
24
+ n: Name
25
+
26
+
27
+ CanLiteral: ta.TypeAlias = Literal | Value
28
+ CanExpr: ta.TypeAlias = Expr | CanName | CanLiteral
29
+
30
+
31
+ class ExprBuilder(NameBuilder):
32
+ def literal(self, o: CanLiteral) -> Literal:
33
+ if isinstance(o, Literal):
34
+ return o
35
+ elif isinstance(o, Node):
36
+ raise TypeError(o)
37
+ else:
38
+ return Literal(o)
39
+
40
+ @ta.final
41
+ def l(self, o: CanLiteral) -> Literal: # noqa
42
+ return self.literal(o)
43
+
44
+ def expr(self, o: CanExpr) -> Expr:
45
+ if isinstance(o, Expr):
46
+ return o
47
+ elif isinstance(o, (Name, Ident)):
48
+ return NameExpr(self.name(o))
49
+ else:
50
+ return self.literal(o)
51
+
52
+ @ta.final
53
+ def e(self, o: CanExpr) -> Expr:
54
+ return self.expr(o)
@@ -0,0 +1,29 @@
1
+ import typing as ta
2
+
3
+ from ... import lang
4
+ from .base import Builder
5
+ from .base import Node
6
+
7
+
8
+ ##
9
+
10
+
11
+ class Ident(Node, lang.Final):
12
+ s: str
13
+
14
+
15
+ CanIdent: ta.TypeAlias = Ident | str
16
+
17
+
18
+ class IdentBuilder(Builder):
19
+ def ident(self, o: CanIdent) -> Ident:
20
+ if isinstance(o, Ident):
21
+ return o
22
+ elif isinstance(o, str):
23
+ return Ident(o)
24
+ else:
25
+ raise TypeError(o)
26
+
27
+ @ta.final
28
+ def i(self, o: CanIdent) -> Ident:
29
+ return self.ident(o)
@@ -0,0 +1,41 @@
1
+ import typing as ta
2
+
3
+ from ... import check
4
+ from ... import dataclasses as dc
5
+ from ... import lang
6
+ from .base import Node
7
+ from .exprs import CanExpr
8
+ from .exprs import Expr
9
+ from .exprs import ExprBuilder
10
+
11
+
12
+ ##
13
+
14
+
15
+ class MultiOp(Node, lang.Final):
16
+ name: str
17
+
18
+
19
+ class MultiOps(lang.Namespace):
20
+ AND = MultiOp('and')
21
+ OR = MultiOp('or')
22
+
23
+
24
+ class Multi(Expr, lang.Final):
25
+ op: MultiOp
26
+ es: ta.Sequence[Expr] = dc.xfield(coerce=tuple)
27
+
28
+
29
+ class MultiBuilder(ExprBuilder):
30
+ def multi(self, op: MultiOp, *es: CanExpr) -> Expr:
31
+ check.not_empty(es)
32
+ if len(es) == 1:
33
+ return self.expr(es[0])
34
+ else:
35
+ return Multi(op, [self.expr(e) for e in es])
36
+
37
+ def and_(self, *es: CanExpr) -> Expr:
38
+ return self.multi(MultiOps.AND, *es)
39
+
40
+ def or_(self, *es: CanExpr) -> Expr:
41
+ return self.multi(MultiOps.OR, *es)
@@ -0,0 +1,34 @@
1
+ import typing as ta
2
+
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+ from .base import Node
6
+ from .idents import CanIdent
7
+ from .idents import Ident
8
+ from .idents import IdentBuilder
9
+
10
+
11
+ ##
12
+
13
+
14
+ class Name(Node, lang.Final):
15
+ ps: ta.Sequence[Ident] = dc.xfield(coerce=tuple)
16
+
17
+
18
+ CanName: ta.TypeAlias = Name | CanIdent | ta.Sequence[CanIdent]
19
+
20
+
21
+ class NameBuilder(IdentBuilder):
22
+ def name(self, o: CanName) -> Name:
23
+ if isinstance(o, Name):
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)
31
+
32
+ @ta.final
33
+ def n(self, o: CanName) -> Name:
34
+ return self.name(o)
@@ -0,0 +1,39 @@
1
+ import typing as ta
2
+
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+ from .base import Node
6
+ from .idents import Ident
7
+ from .names import CanName
8
+ from .names import Name
9
+ from .names import NameBuilder
10
+
11
+
12
+ ##
13
+
14
+
15
+ class Relation(Node, lang.Abstract):
16
+ pass
17
+
18
+
19
+ class Table(Relation, lang.Final):
20
+ n: Name
21
+ a: Ident | None = dc.xfield(None, repr_fn=dc.opt_repr)
22
+
23
+
24
+ CanTable: ta.TypeAlias = Table | CanName
25
+ CanRelation: ta.TypeAlias = Relation | CanTable
26
+
27
+
28
+ class RelationBuilder(NameBuilder):
29
+ def table(self, n: CanTable) -> Table:
30
+ if isinstance(n, Table):
31
+ return n
32
+ else:
33
+ return Table(self.name(n))
34
+
35
+ def relation(self, o: CanRelation) -> Relation:
36
+ if isinstance(o, Relation):
37
+ return o
38
+ else:
39
+ return self.table(o)
@@ -0,0 +1,50 @@
1
+ import typing as ta
2
+
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+ from .base import Node
6
+ from .exprs import CanExpr
7
+ from .exprs import Expr
8
+ from .exprs import ExprBuilder
9
+ from .idents import Ident
10
+ from .relations import CanRelation
11
+ from .relations import Relation
12
+ from .relations import RelationBuilder
13
+ from .stmts import Stmt
14
+
15
+
16
+ ##
17
+
18
+
19
+ class SelectItem(Node, lang.Final):
20
+ v: Expr
21
+ a: Ident | None = dc.xfield(None, repr_fn=dc.opt_repr)
22
+
23
+
24
+ class Select(Stmt, lang.Final):
25
+ its: ta.Sequence[SelectItem] = dc.xfield(coerce=tuple)
26
+ fr: Relation | None = dc.xfield(None, repr_fn=dc.opt_repr)
27
+ wh: Expr | None = dc.xfield(None, repr_fn=dc.opt_repr)
28
+
29
+
30
+ CanSelectItem: ta.TypeAlias = SelectItem | CanExpr
31
+
32
+
33
+ class SelectBuilder(ExprBuilder, RelationBuilder):
34
+ def select_item(self, o: CanSelectItem) -> SelectItem:
35
+ if isinstance(o, SelectItem):
36
+ return o
37
+ else:
38
+ return SelectItem(self.expr(o))
39
+
40
+ def select(
41
+ self,
42
+ its: ta.Sequence[CanSelectItem],
43
+ fr: CanRelation | None = None,
44
+ wh: CanExpr | None = None,
45
+ ) -> Select:
46
+ return Select(
47
+ [self.select_item(i) for i in its],
48
+ fr=self.relation(fr) if fr is not None else None,
49
+ wh=self.expr(wh) if wh is not None else None,
50
+ )
@@ -0,0 +1,29 @@
1
+ from .base import Builder
2
+ from .binary import BinaryBuilder
3
+ from .exprs import ExprBuilder
4
+ from .idents import IdentBuilder
5
+ from .multi import MultiBuilder
6
+ from .names import NameBuilder
7
+ from .relations import RelationBuilder
8
+ from .selects import SelectBuilder
9
+ from .stmts import StmtBuilder
10
+ from .unary import UnaryBuilder
11
+
12
+
13
+ class StdBuilder(
14
+ SelectBuilder,
15
+ StmtBuilder,
16
+
17
+ MultiBuilder,
18
+ BinaryBuilder,
19
+ UnaryBuilder,
20
+ ExprBuilder,
21
+
22
+ RelationBuilder,
23
+
24
+ NameBuilder,
25
+ IdentBuilder,
26
+
27
+ Builder,
28
+ ):
29
+ pass
@@ -0,0 +1,28 @@
1
+ import typing as ta
2
+
3
+ from ... import lang
4
+ from .base import Node
5
+ from .exprs import CanExpr
6
+ from .exprs import ExprBuilder
7
+
8
+
9
+ ##
10
+
11
+
12
+ class Stmt(Node, lang.Abstract):
13
+ pass
14
+
15
+
16
+ class ExprStmt(Stmt, lang.Final):
17
+ pass
18
+
19
+
20
+ CanStmt: ta.TypeAlias = Stmt | CanExpr
21
+
22
+
23
+ class StmtBuilder(ExprBuilder):
24
+ def stmt(self, o: CanStmt) -> Stmt:
25
+ if isinstance(o, Stmt):
26
+ return o
27
+ else:
28
+ return ExprStmt(self.expr(o))
@@ -0,0 +1,29 @@
1
+ from ... import lang
2
+ from .base import Node
3
+ from .exprs import CanExpr
4
+ from .exprs import Expr
5
+ from .exprs import ExprBuilder
6
+
7
+
8
+ ##
9
+
10
+
11
+ class UnaryOp(Node, lang.Final):
12
+ name: str
13
+
14
+
15
+ class UnaryOps(lang.Namespace):
16
+ NOT = UnaryOp('not')
17
+
18
+
19
+ class Unary(Expr, lang.Final):
20
+ op: UnaryOp
21
+ v: Expr
22
+
23
+
24
+ class UnaryBuilder(ExprBuilder):
25
+ def unary(self, op: UnaryOp, v: CanExpr) -> Unary:
26
+ return Unary(op, self.expr(v))
27
+
28
+ def not_(self, v: CanExpr) -> Unary:
29
+ return self.unary(UnaryOps.NOT, v)
@@ -0,0 +1,11 @@
1
+ from .tabledefs import ( # noqa
2
+ TableDef,
3
+ )
4
+
5
+
6
+ ##
7
+
8
+
9
+ from ...lang.imports import _register_conditional_import # noqa
10
+
11
+ _register_conditional_import('...marshal', '.marshal', __package__)
@@ -0,0 +1,26 @@
1
+ """
2
+ TODO:
3
+ - move to sql/alchemy/tabledefs.py
4
+ """
5
+ import typing as ta
6
+
7
+ import sqlalchemy as sa
8
+ import sqlalchemy.sql.schema
9
+
10
+ from .tabledefs import TableDef
11
+
12
+
13
+ def build_sa_table(
14
+ td: TableDef,
15
+ *,
16
+ metadata: sa.MetaData | None = None,
17
+ **kwargs: ta.Any,
18
+ ) -> sa.Table:
19
+ items: list[sa.sql.schema.SchemaItem] = []
20
+
21
+ return sa.Table(
22
+ td.name,
23
+ metadata if metadata is not None else sa.MetaData(),
24
+ *items,
25
+ **kwargs,
26
+ )
@@ -0,0 +1,22 @@
1
+ from ... import dataclasses as dc
2
+ from ... import lang
3
+
4
+
5
+ @dc.dataclass(frozen=True)
6
+ class Dtype(lang.Abstract, lang.Sealed):
7
+ pass
8
+
9
+
10
+ @dc.dataclass(frozen=True)
11
+ class Integer(Dtype, lang.Singleton):
12
+ pass
13
+
14
+
15
+ @dc.dataclass(frozen=True)
16
+ class String(Dtype, lang.Singleton):
17
+ pass
18
+
19
+
20
+ @dc.dataclass(frozen=True)
21
+ class Datetime(Dtype, lang.Singleton):
22
+ pass
@@ -0,0 +1,88 @@
1
+ import typing as ta
2
+
3
+ from ... import check
4
+ from ... import collections as col
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from .dtypes import Dtype
8
+
9
+
10
+ ##
11
+
12
+
13
+ class Element(lang.Abstract, lang.Sealed):
14
+ pass
15
+
16
+
17
+ ##
18
+
19
+
20
+ @dc.dataclass(frozen=True)
21
+ class Column(Element, lang.Final):
22
+ name: str
23
+ type: Dtype
24
+ nullable: bool = dc.field(default=False, kw_only=True)
25
+ default: lang.Maybe[ta.Any] = dc.field(default=lang.empty(), kw_only=True)
26
+
27
+
28
+ @dc.dataclass(frozen=True)
29
+ class PrimaryKey(Element, lang.Final):
30
+ columns: ta.Sequence[str]
31
+
32
+
33
+ @dc.dataclass(frozen=True)
34
+ class Index(Element, lang.Final):
35
+ columns: ta.Sequence[str] = dc.xfield(coerce=col.seq)
36
+ name: str | None = None
37
+
38
+
39
+ ##
40
+
41
+
42
+ @dc.dataclass(frozen=True)
43
+ class IdIntegerPrimaryKey(Element, lang.Final):
44
+ pass
45
+
46
+
47
+ #
48
+
49
+
50
+ @dc.dataclass(frozen=True)
51
+ class CreatedAt(Element, lang.Final):
52
+ pass
53
+
54
+
55
+ @dc.dataclass(frozen=True)
56
+ class UpdatedAt(Element, lang.Final):
57
+ pass
58
+
59
+
60
+ @dc.dataclass(frozen=True)
61
+ class UpdatedAtTrigger(Element, lang.Final):
62
+ column: str
63
+
64
+
65
+ @dc.dataclass(frozen=True)
66
+ class CreatedAtUpdatedAt(Element, lang.Final):
67
+ pass
68
+
69
+
70
+ ##
71
+
72
+
73
+ @dc.dataclass(frozen=True)
74
+ class Elements(ta.Sequence[Element], lang.Final):
75
+ lst: ta.Sequence[Element] = dc.xfield(coerce=col.seq_of(check.of_isinstance(Element)))
76
+
77
+ def __iter__(self) -> ta.Iterator[Element]:
78
+ return iter(self.lst)
79
+
80
+ def __getitem__(self, index: ta.Any) -> Element: # type: ignore[override]
81
+ return self.lst[index]
82
+
83
+ def __len__(self) -> int:
84
+ return len(self.lst)
85
+
86
+ @lang.cached_property
87
+ def by_type(self) -> col.DynamicTypeMap[Element]:
88
+ return col.DynamicTypeMap(self.lst)
@@ -0,0 +1,49 @@
1
+ from ... import dataclasses as dc
2
+ from .dtypes import Datetime
3
+ from .dtypes import Integer
4
+ from .elements import Column
5
+ from .elements import CreatedAt
6
+ from .elements import CreatedAtUpdatedAt
7
+ from .elements import Element
8
+ from .elements import Elements
9
+ from .elements import IdIntegerPrimaryKey
10
+ from .elements import PrimaryKey
11
+ from .elements import UpdatedAt
12
+ from .elements import UpdatedAtTrigger
13
+ from .tabledefs import TableDef
14
+
15
+
16
+ def lower_table_elements(td: TableDef) -> TableDef:
17
+ todo: list[Element] = list(td.elements)[::-1]
18
+ out: list[Element] = []
19
+
20
+ while todo:
21
+ match (e := todo.pop()):
22
+ case Column() | PrimaryKey():
23
+ out.append(e)
24
+
25
+ case IdIntegerPrimaryKey():
26
+ out.extend([
27
+ Column('id', Integer()),
28
+ PrimaryKey(['id']),
29
+ ])
30
+
31
+ case CreatedAt():
32
+ out.append(Column('created_at', Datetime()))
33
+
34
+ case UpdatedAt():
35
+ out.extend([
36
+ Column('updated_at', Datetime()),
37
+ UpdatedAtTrigger('updated_at'),
38
+ ])
39
+
40
+ case CreatedAtUpdatedAt():
41
+ todo.extend([
42
+ CreatedAt(),
43
+ UpdatedAt(),
44
+ ][::-1])
45
+
46
+ case _:
47
+ raise TypeError(e)
48
+
49
+ return dc.replace(td, elements=Elements(out))
@@ -0,0 +1,19 @@
1
+ from ... import lang
2
+ from ... import marshal as msh
3
+ from .dtypes import Dtype
4
+ from .elements import Element
5
+
6
+
7
+ def _install_poly(cls: type) -> None:
8
+ p = msh.polymorphism_from_subclasses(cls, naming=msh.Naming.SNAKE)
9
+ msh.STANDARD_MARSHALER_FACTORIES[0:0] = [msh.PolymorphismMarshalerFactory(p)]
10
+ msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.PolymorphismUnmarshalerFactory(p)]
11
+
12
+
13
+ @lang.cached_function
14
+ def _install_standard_marshalling() -> None:
15
+ _install_poly(Dtype)
16
+ _install_poly(Element)
17
+
18
+
19
+ _install_standard_marshalling()
@@ -0,0 +1,52 @@
1
+ """
2
+ TODO:
3
+ - QualifiedName
4
+ - hybrid dataclass scheme
5
+ - sqlite without sqlalchemy
6
+
7
+ ==
8
+
9
+ @td.tableclass([
10
+ IdIntegerPrimaryKey(),
11
+ CreatedAtUpdatedAt(),
12
+ ])
13
+ @dc.dataclass(frozen=True)
14
+ class User(lang.Final):
15
+ id: int
16
+
17
+ created_at: datetime.datetime
18
+ updated_at: datetime.datetime
19
+
20
+ name: str
21
+
22
+ ==
23
+
24
+ @td.tableclass([
25
+ IdIntegerPrimaryKey(),
26
+ CreatedAtUpdatedAt(),
27
+ ])
28
+ @dc.dataclass(frozen=True)
29
+ class BaseTable(lang.Abstract):
30
+ id: int
31
+
32
+ created_at: datetime.datetime
33
+ updated_at: datetime.datetime
34
+
35
+ @td.tableclass('user')
36
+ @dc.dataclass(frozen=True)
37
+ class User(BaseTable, lang.Final):
38
+ name: str
39
+
40
+ """
41
+ from ... import dataclasses as dc
42
+ from ... import lang
43
+ from .elements import Elements
44
+
45
+
46
+ ##
47
+
48
+
49
+ @dc.dataclass(frozen=True)
50
+ class TableDef(lang.Final):
51
+ name: str
52
+ elements: Elements