tigrbl-core 0.1.0.dev13__tar.gz → 0.1.10.dev1__tar.gz
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.
- tigrbl_core-0.1.10.dev1/PKG-INFO +48 -0
- tigrbl_core-0.1.10.dev1/README.md +23 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/pyproject.toml +3 -3
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/__init__.py +27 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/app_spec.py +22 -33
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/binding_spec.py +56 -1
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/column_spec.py +61 -3
- tigrbl_core-0.1.10.dev1/tigrbl_core/_spec/datatypes.py +536 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/hook_spec.py +7 -1
- tigrbl_core-0.1.10.dev1/tigrbl_core/_spec/monotone.py +155 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/op_spec.py +63 -6
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/storage_spec.py +2 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/table_spec.py +22 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/config/constants.py +60 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/__init__.py +14 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/build_schema.py +8 -5
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/helpers.py +27 -1
- tigrbl_core-0.1.10.dev1/tigrbl_core/schema/spec_json.py +804 -0
- tigrbl_core-0.1.0.dev13/PKG-INFO +0 -54
- tigrbl_core-0.1.0.dev13/README.md +0 -29
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/alias_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/engine_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/field_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/hook_types.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/io_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/middleware_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/op_utils.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/plugins.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/registry.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/request_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/response_resolver.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/response_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/response_types.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/router_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/schema_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/serde.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/session_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/_spec/table_registry_spec.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/config/__init__.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/config/defaults.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/config/engine_traversal.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/config/resolver.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/core/__init__.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/op/__init__.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/op/canonical.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/op/collect.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/op/types.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/__init__.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/cache.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/extras.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/list_params.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/builder/strip_parent_fields.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/get_schema.py +0 -0
- {tigrbl_core-0.1.0.dev13 → tigrbl_core-0.1.10.dev1}/tigrbl_core/schema/utils.py +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tigrbl-core
|
|
3
|
+
Version: 0.1.10.dev1
|
|
4
|
+
Summary: Core specifications and primitives for the Tigrbl framework.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Keywords: tigrbl,sdk,standards,framework
|
|
7
|
+
Author: Jacob Stewart
|
|
8
|
+
Author-email: jacob@swarmauri.com
|
|
9
|
+
Requires-Python: >=3.10,<3.14
|
|
10
|
+
Classifier: Development Status :: 1 - Planning
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Requires-Dist: pydantic (>=2.10,<3)
|
|
19
|
+
Requires-Dist: pyyaml
|
|
20
|
+
Requires-Dist: tigrbl-typing
|
|
21
|
+
Requires-Dist: tomli (>=2.0.1) ; python_version < "3.11"
|
|
22
|
+
Requires-Dist: tomli-w
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# tigrbl_core
|
|
26
|
+
|
|
27
|
+
This file is a package-local distribution entry point.
|
|
28
|
+
It is not the authoritative location for repository governance, current target status, current state reporting, certification claims, or release evidence.
|
|
29
|
+
|
|
30
|
+
## Canonical repository docs
|
|
31
|
+
|
|
32
|
+
- `README.md`
|
|
33
|
+
- `docs/README.md`
|
|
34
|
+
- `docs/conformance/CURRENT_TARGET.md`
|
|
35
|
+
- `docs/conformance/CURRENT_STATE.md`
|
|
36
|
+
- `docs/conformance/NEXT_STEPS.md`
|
|
37
|
+
- `docs/governance/DOC_POINTERS.md`
|
|
38
|
+
- `docs/developer/PACKAGE_CATALOG.md`
|
|
39
|
+
- `docs/developer/PACKAGE_LAYOUT.md`
|
|
40
|
+
|
|
41
|
+
## Package identity
|
|
42
|
+
|
|
43
|
+
- workspace path: `pkgs/core/tigrbl_core`
|
|
44
|
+
- workspace class: core Python package
|
|
45
|
+
- implementation layout: `tigrbl_core/`
|
|
46
|
+
|
|
47
|
+
Long-form repository documentation is governed from `docs/`.
|
|
48
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# tigrbl_core
|
|
2
|
+
|
|
3
|
+
This file is a package-local distribution entry point.
|
|
4
|
+
It is not the authoritative location for repository governance, current target status, current state reporting, certification claims, or release evidence.
|
|
5
|
+
|
|
6
|
+
## Canonical repository docs
|
|
7
|
+
|
|
8
|
+
- `README.md`
|
|
9
|
+
- `docs/README.md`
|
|
10
|
+
- `docs/conformance/CURRENT_TARGET.md`
|
|
11
|
+
- `docs/conformance/CURRENT_STATE.md`
|
|
12
|
+
- `docs/conformance/NEXT_STEPS.md`
|
|
13
|
+
- `docs/governance/DOC_POINTERS.md`
|
|
14
|
+
- `docs/developer/PACKAGE_CATALOG.md`
|
|
15
|
+
- `docs/developer/PACKAGE_LAYOUT.md`
|
|
16
|
+
|
|
17
|
+
## Package identity
|
|
18
|
+
|
|
19
|
+
- workspace path: `pkgs/core/tigrbl_core`
|
|
20
|
+
- workspace class: core Python package
|
|
21
|
+
- implementation layout: `tigrbl_core/`
|
|
22
|
+
|
|
23
|
+
Long-form repository documentation is governed from `docs/`.
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tigrbl-core"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.10.dev1"
|
|
4
4
|
description = "Core specifications and primitives for the Tigrbl framework."
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
repository = "http://github.com/swarmauri/swarmauri-sdk"
|
|
8
|
-
requires-python = ">=3.10,<3.
|
|
8
|
+
requires-python = ">=3.10,<3.14"
|
|
9
9
|
classifiers = [
|
|
10
|
-
"License :: OSI Approved :: Apache Software License",
|
|
11
10
|
"Development Status :: 1 - Planning",
|
|
12
11
|
"Programming Language :: Python :: 3.10",
|
|
13
12
|
"Programming Language :: Python :: 3.11",
|
|
14
13
|
"Programming Language :: Python :: 3.12",
|
|
14
|
+
"Programming Language :: Python :: 3.13",
|
|
15
15
|
"Programming Language :: Python",
|
|
16
16
|
"Programming Language :: Python :: 3",
|
|
17
17
|
"Programming Language :: Python :: 3 :: Only",
|
|
@@ -13,24 +13,48 @@ _EXPORTS = {
|
|
|
13
13
|
"AppSpec": "app_spec",
|
|
14
14
|
"BindingSpec": "binding_spec",
|
|
15
15
|
"BindingRegistrySpec": "binding_spec",
|
|
16
|
+
"Exchange": "binding_spec",
|
|
17
|
+
"Framing": "binding_spec",
|
|
16
18
|
"TransportBindingSpec": "binding_spec",
|
|
17
19
|
"HttpRestBindingSpec": "binding_spec",
|
|
18
20
|
"HttpJsonRpcBindingSpec": "binding_spec",
|
|
21
|
+
"HttpStreamBindingSpec": "binding_spec",
|
|
22
|
+
"SseBindingSpec": "binding_spec",
|
|
23
|
+
"WebTransportBindingSpec": "binding_spec",
|
|
19
24
|
"WsBindingSpec": "binding_spec",
|
|
20
25
|
"resolve_rest_nested_prefix": "binding_spec",
|
|
21
26
|
"ColumnSpec": "column_spec",
|
|
27
|
+
"CANONICAL_DATATYPES": "datatypes",
|
|
28
|
+
"DataTypeSpec": "datatypes",
|
|
22
29
|
"EngineSpec": "engine_spec",
|
|
23
30
|
"EngineProviderSpec": "engine_spec",
|
|
31
|
+
"EngineDatatypeBridge": "datatypes",
|
|
32
|
+
"EngineRegistry": "datatypes",
|
|
33
|
+
"EngineTypeLowerer": "datatypes",
|
|
24
34
|
"FieldSpec": "field_spec",
|
|
25
35
|
"F": "field_spec",
|
|
36
|
+
"BaseTypeAdapter": "datatypes",
|
|
26
37
|
"HookSpec": "hook_spec",
|
|
27
38
|
"IOSpec": "io_spec",
|
|
28
39
|
"IO": "io_spec",
|
|
40
|
+
"ReflectedDatatype": "datatypes",
|
|
41
|
+
"ReflectedTypeMapper": "datatypes",
|
|
42
|
+
"StaticEngineLowerer": "datatypes",
|
|
43
|
+
"as_tuple": "monotone",
|
|
29
44
|
"MiddlewareSpec": "middleware_spec",
|
|
45
|
+
"highest_precedence": "monotone",
|
|
46
|
+
"keyed_overlay": "monotone",
|
|
47
|
+
"mapping_overlay": "monotone",
|
|
48
|
+
"merge_mro_mapping_attr": "monotone",
|
|
49
|
+
"merge_mro_sequence_attr": "monotone",
|
|
30
50
|
"OpSpec": "op_spec",
|
|
51
|
+
"sequence_union": "monotone",
|
|
52
|
+
"stable_keyed_overlay": "monotone",
|
|
53
|
+
"stable_unique": "monotone",
|
|
31
54
|
"Arity": "op_spec",
|
|
32
55
|
"TargetOp": "op_spec",
|
|
33
56
|
"PersistPolicy": "op_spec",
|
|
57
|
+
"TxScope": "op_spec",
|
|
34
58
|
"PHASE": "op_spec",
|
|
35
59
|
"PHASES": "op_spec",
|
|
36
60
|
"HookPhase": "hook_spec",
|
|
@@ -48,11 +72,14 @@ _EXPORTS = {
|
|
|
48
72
|
"tx_repeatable_read": "session_spec",
|
|
49
73
|
"tx_serializable": "session_spec",
|
|
50
74
|
"readonly": "session_spec",
|
|
75
|
+
"StorageTypeRef": "datatypes",
|
|
51
76
|
"StorageSpec": "storage_spec",
|
|
52
77
|
"S": "storage_spec",
|
|
53
78
|
"StorageTransformSpec": "storage_spec",
|
|
54
79
|
"StorageTransform": "storage_spec",
|
|
55
80
|
"ForeignKeySpec": "storage_spec",
|
|
81
|
+
"TypeAdapter": "datatypes",
|
|
82
|
+
"TypeRegistry": "datatypes",
|
|
56
83
|
"TableSpec": "table_spec",
|
|
57
84
|
"TableRegistrySpec": "table_registry_spec",
|
|
58
85
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# pkgs/standards/tigrbl_core/tigrbl/_spec/app_spec.py
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import Any, Callable,
|
|
4
|
+
from typing import Any, Callable, Optional, Sequence
|
|
5
5
|
|
|
6
6
|
from .._spec.engine_spec import EngineCfg
|
|
7
|
+
from .._spec.monotone import as_tuple, merge_mro_sequence_attr
|
|
7
8
|
from .._spec.response_spec import ResponseSpec
|
|
8
9
|
from .serde import SerdeMixin
|
|
9
10
|
|
|
@@ -11,17 +12,7 @@ from .serde import SerdeMixin
|
|
|
11
12
|
def _seqify(value: Any) -> tuple[Any, ...]:
|
|
12
13
|
"""Normalize sequence-like inputs while treating scalars as a single item."""
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
return ()
|
|
16
|
-
if isinstance(value, tuple):
|
|
17
|
-
return value
|
|
18
|
-
if isinstance(value, (str, bytes, bytearray)):
|
|
19
|
-
return (value,)
|
|
20
|
-
if isinstance(value, Mapping):
|
|
21
|
-
return (value,)
|
|
22
|
-
if isinstance(value, Iterable):
|
|
23
|
-
return tuple(value)
|
|
24
|
-
return (value,)
|
|
15
|
+
return as_tuple(value)
|
|
25
16
|
|
|
26
17
|
|
|
27
18
|
def merge_seq_attr(
|
|
@@ -34,27 +25,13 @@ def merge_seq_attr(
|
|
|
34
25
|
) -> tuple[Any, ...]:
|
|
35
26
|
"""Merge sequence-like class attributes over the MRO."""
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
seq = getattr(base, attr) or ()
|
|
45
|
-
else:
|
|
46
|
-
seq = base.__dict__.get(attr, ()) or ()
|
|
47
|
-
for item in _seqify(seq):
|
|
48
|
-
if dedupe:
|
|
49
|
-
try:
|
|
50
|
-
if item in seen_hashable:
|
|
51
|
-
continue
|
|
52
|
-
seen_hashable.add(item)
|
|
53
|
-
except TypeError:
|
|
54
|
-
if any(item == existing for existing in values):
|
|
55
|
-
continue
|
|
56
|
-
values.append(item)
|
|
57
|
-
return tuple(values)
|
|
28
|
+
return merge_mro_sequence_attr(
|
|
29
|
+
owner,
|
|
30
|
+
attr,
|
|
31
|
+
include_inherited=include_inherited,
|
|
32
|
+
reverse=reverse,
|
|
33
|
+
dedupe=dedupe,
|
|
34
|
+
)
|
|
58
35
|
|
|
59
36
|
|
|
60
37
|
def normalize_app_spec(spec: "AppSpec") -> "AppSpec":
|
|
@@ -68,6 +45,7 @@ def normalize_app_spec(spec: "AppSpec") -> "AppSpec":
|
|
|
68
45
|
title=str(spec.title or "Tigrbl"),
|
|
69
46
|
description=spec.description,
|
|
70
47
|
version=str(spec.version or "0.1.0"),
|
|
48
|
+
execution_backend=str(getattr(spec, "execution_backend", None) or "auto"),
|
|
71
49
|
engine=spec.engine,
|
|
72
50
|
routers=routers,
|
|
73
51
|
ops=ops,
|
|
@@ -93,6 +71,7 @@ class AppSpec(SerdeMixin):
|
|
|
93
71
|
title: str = "Tigrbl"
|
|
94
72
|
description: str | None = None
|
|
95
73
|
version: str = "0.1.0"
|
|
74
|
+
execution_backend: str = "auto"
|
|
96
75
|
engine: Optional[EngineCfg] = None
|
|
97
76
|
|
|
98
77
|
# NEW: multi-Router composition (store Router classes or instances)
|
|
@@ -128,6 +107,7 @@ class AppSpec(SerdeMixin):
|
|
|
128
107
|
sentinel = object()
|
|
129
108
|
title: Any = sentinel
|
|
130
109
|
version: Any = sentinel
|
|
110
|
+
execution_backend: Any = sentinel
|
|
131
111
|
engine: Any | None = sentinel # type: ignore[assignment]
|
|
132
112
|
response: Any = sentinel
|
|
133
113
|
jsonrpc_prefix: Any = sentinel
|
|
@@ -139,6 +119,11 @@ class AppSpec(SerdeMixin):
|
|
|
139
119
|
title = base.__dict__["TITLE"]
|
|
140
120
|
if "VERSION" in base.__dict__ and version is sentinel:
|
|
141
121
|
version = base.__dict__["VERSION"]
|
|
122
|
+
if (
|
|
123
|
+
"EXECUTION_BACKEND" in base.__dict__
|
|
124
|
+
and execution_backend is sentinel
|
|
125
|
+
):
|
|
126
|
+
execution_backend = base.__dict__["EXECUTION_BACKEND"]
|
|
142
127
|
if "ENGINE" in base.__dict__ and engine is sentinel:
|
|
143
128
|
engine = base.__dict__["ENGINE"]
|
|
144
129
|
if "RESPONSE" in base.__dict__ and response is sentinel:
|
|
@@ -154,6 +139,8 @@ class AppSpec(SerdeMixin):
|
|
|
154
139
|
title = "Tigrbl"
|
|
155
140
|
if version is sentinel:
|
|
156
141
|
version = "0.1.0"
|
|
142
|
+
if execution_backend is sentinel:
|
|
143
|
+
execution_backend = "auto"
|
|
157
144
|
if engine is sentinel:
|
|
158
145
|
engine = None
|
|
159
146
|
if response is sentinel:
|
|
@@ -171,6 +158,7 @@ class AppSpec(SerdeMixin):
|
|
|
171
158
|
title=title,
|
|
172
159
|
description=description,
|
|
173
160
|
version=version,
|
|
161
|
+
execution_backend=execution_backend,
|
|
174
162
|
engine=engine,
|
|
175
163
|
routers=tuple(
|
|
176
164
|
merge_seq_attr(
|
|
@@ -199,6 +187,7 @@ class AppSpec(SerdeMixin):
|
|
|
199
187
|
title=spec.title,
|
|
200
188
|
description=spec.description,
|
|
201
189
|
version=spec.version,
|
|
190
|
+
execution_backend=spec.execution_backend,
|
|
202
191
|
engine=spec.engine,
|
|
203
192
|
routers=tuple(spec.routers or ()),
|
|
204
193
|
ops=tuple(spec.ops or ()),
|
|
@@ -3,21 +3,58 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import Literal, Optional, Type, Union
|
|
5
5
|
|
|
6
|
-
from ..config.constants import
|
|
6
|
+
from ..config.constants import (
|
|
7
|
+
TIGRBL_NESTED_PATHS_ATTR,
|
|
8
|
+
__JSONRPC_DEFAULT_ENDPOINT__,
|
|
9
|
+
)
|
|
7
10
|
from .serde import SerdeMixin
|
|
8
11
|
|
|
12
|
+
Exchange = Literal[
|
|
13
|
+
"request_response",
|
|
14
|
+
"server_stream",
|
|
15
|
+
"event_stream",
|
|
16
|
+
"client_stream",
|
|
17
|
+
"bidirectional",
|
|
18
|
+
"bidirectional_stream",
|
|
19
|
+
"fire_and_forget",
|
|
20
|
+
]
|
|
21
|
+
Framing = Literal["json", "jsonrpc", "sse", "stream", "text", "bytes", "webtransport"]
|
|
22
|
+
|
|
9
23
|
|
|
10
24
|
@dataclass(frozen=True, slots=True)
|
|
11
25
|
class HttpRestBindingSpec(SerdeMixin):
|
|
12
26
|
proto: Literal["http.rest", "https.rest"]
|
|
13
27
|
methods: tuple[str, ...]
|
|
14
28
|
path: str
|
|
29
|
+
exchange: Exchange = "request_response"
|
|
30
|
+
framing: Framing = "json"
|
|
15
31
|
|
|
16
32
|
|
|
17
33
|
@dataclass(frozen=True, slots=True)
|
|
18
34
|
class HttpJsonRpcBindingSpec(SerdeMixin):
|
|
19
35
|
proto: Literal["http.jsonrpc", "https.jsonrpc"]
|
|
20
36
|
rpc_method: str
|
|
37
|
+
endpoint: str = __JSONRPC_DEFAULT_ENDPOINT__
|
|
38
|
+
exchange: Exchange = "request_response"
|
|
39
|
+
framing: Framing = "jsonrpc"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True, slots=True)
|
|
43
|
+
class HttpStreamBindingSpec(SerdeMixin):
|
|
44
|
+
proto: Literal["http.stream", "https.stream"]
|
|
45
|
+
path: str
|
|
46
|
+
methods: tuple[str, ...] = ("GET",)
|
|
47
|
+
exchange: Exchange = "server_stream"
|
|
48
|
+
framing: Framing = "stream"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True, slots=True)
|
|
52
|
+
class SseBindingSpec(SerdeMixin):
|
|
53
|
+
proto: Literal["http.sse", "https.sse"] = "http.sse"
|
|
54
|
+
path: str = "/"
|
|
55
|
+
methods: tuple[str, ...] = ("GET",)
|
|
56
|
+
exchange: Exchange = "server_stream"
|
|
57
|
+
framing: Framing = "sse"
|
|
21
58
|
|
|
22
59
|
|
|
23
60
|
@dataclass(frozen=True, slots=True)
|
|
@@ -25,12 +62,25 @@ class WsBindingSpec(SerdeMixin):
|
|
|
25
62
|
proto: Literal["ws", "wss"]
|
|
26
63
|
path: str
|
|
27
64
|
subprotocols: tuple[str, ...] = ()
|
|
65
|
+
exchange: Exchange = "bidirectional_stream"
|
|
66
|
+
framing: Framing = "text"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(frozen=True, slots=True)
|
|
70
|
+
class WebTransportBindingSpec(SerdeMixin):
|
|
71
|
+
proto: Literal["webtransport"] = "webtransport"
|
|
72
|
+
path: str = "/"
|
|
73
|
+
exchange: Exchange = "bidirectional_stream"
|
|
74
|
+
framing: Framing = "webtransport"
|
|
28
75
|
|
|
29
76
|
|
|
30
77
|
TransportBindingSpec = Union[
|
|
31
78
|
HttpRestBindingSpec,
|
|
32
79
|
HttpJsonRpcBindingSpec,
|
|
80
|
+
HttpStreamBindingSpec,
|
|
81
|
+
SseBindingSpec,
|
|
33
82
|
WsBindingSpec,
|
|
83
|
+
WebTransportBindingSpec,
|
|
34
84
|
]
|
|
35
85
|
|
|
36
86
|
|
|
@@ -70,9 +120,14 @@ def resolve_rest_nested_prefix(model: Type) -> Optional[str]:
|
|
|
70
120
|
__all__ = [
|
|
71
121
|
"BindingSpec",
|
|
72
122
|
"BindingRegistrySpec",
|
|
123
|
+
"Exchange",
|
|
124
|
+
"Framing",
|
|
73
125
|
"HttpJsonRpcBindingSpec",
|
|
74
126
|
"HttpRestBindingSpec",
|
|
127
|
+
"HttpStreamBindingSpec",
|
|
128
|
+
"SseBindingSpec",
|
|
75
129
|
"TransportBindingSpec",
|
|
130
|
+
"WebTransportBindingSpec",
|
|
76
131
|
"WsBindingSpec",
|
|
77
132
|
"resolve_rest_nested_prefix",
|
|
78
133
|
]
|
|
@@ -5,9 +5,10 @@ from functools import lru_cache
|
|
|
5
5
|
from types import SimpleNamespace
|
|
6
6
|
from typing import Any, Callable, Dict, Optional
|
|
7
7
|
|
|
8
|
+
from .datatypes import DataTypeSpec, StorageTypeRef, infer_datatype
|
|
8
9
|
from .._spec.field_spec import FieldSpec as F
|
|
9
10
|
from .._spec.io_spec import IOSpec as IO
|
|
10
|
-
from .._spec.storage_spec import StorageSpec as S
|
|
11
|
+
from .._spec.storage_spec import ForeignKeySpec, StorageSpec as S
|
|
11
12
|
from .serde import SerdeMixin
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger("uvicorn")
|
|
@@ -34,6 +35,7 @@ class ColumnSpec(SerdeMixin):
|
|
|
34
35
|
self,
|
|
35
36
|
*,
|
|
36
37
|
storage: S | None,
|
|
38
|
+
datatype: DataTypeSpec | None = None,
|
|
37
39
|
field: F | None = None,
|
|
38
40
|
io: IO | None = None,
|
|
39
41
|
default_factory: Optional[Callable[[dict], Any]] = None,
|
|
@@ -42,6 +44,12 @@ class ColumnSpec(SerdeMixin):
|
|
|
42
44
|
self.storage = storage
|
|
43
45
|
self.field = field if field is not None else F()
|
|
44
46
|
self.io = io if io is not None else IO()
|
|
47
|
+
self.datatype = datatype or infer_datatype(
|
|
48
|
+
field_py_type=self.field.py_type,
|
|
49
|
+
storage_type=getattr(storage, "type_", None),
|
|
50
|
+
nullable=getattr(storage, "nullable", None),
|
|
51
|
+
constraints=getattr(self.field, "constraints", {}),
|
|
52
|
+
)
|
|
45
53
|
self.default_factory = default_factory
|
|
46
54
|
self.read_producer = read_producer
|
|
47
55
|
|
|
@@ -85,6 +93,49 @@ class ColumnSpec(SerdeMixin):
|
|
|
85
93
|
except TypeError:
|
|
86
94
|
return ()
|
|
87
95
|
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _storage_spec_from_column(column: object) -> S:
|
|
98
|
+
fk_spec = None
|
|
99
|
+
foreign_keys = tuple(getattr(column, "foreign_keys", ()) or ())
|
|
100
|
+
if foreign_keys:
|
|
101
|
+
fk = foreign_keys[0]
|
|
102
|
+
target = str(getattr(fk, "target_fullname", "") or "")
|
|
103
|
+
if target:
|
|
104
|
+
fk_spec = ForeignKeySpec(
|
|
105
|
+
target=target,
|
|
106
|
+
on_delete=str(getattr(fk, "ondelete", None) or "RESTRICT"),
|
|
107
|
+
on_update=str(getattr(fk, "onupdate", None) or "RESTRICT"),
|
|
108
|
+
deferrable=bool(getattr(fk, "deferrable", False)),
|
|
109
|
+
initially_deferred=(
|
|
110
|
+
str(getattr(fk, "initially", "") or "").upper() == "DEFERRED"
|
|
111
|
+
),
|
|
112
|
+
match=str(getattr(fk, "match", None) or "SIMPLE"),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
type_obj = getattr(column, "type", None)
|
|
116
|
+
physical_name = None
|
|
117
|
+
if type_obj is not None:
|
|
118
|
+
physical_name = getattr(type_obj, "__visit_name__", None) or type(type_obj).__name__
|
|
119
|
+
|
|
120
|
+
return S(
|
|
121
|
+
type_=type_obj,
|
|
122
|
+
physical_type=(
|
|
123
|
+
StorageTypeRef(physical_name=str(physical_name))
|
|
124
|
+
if physical_name is not None
|
|
125
|
+
else None
|
|
126
|
+
),
|
|
127
|
+
nullable=getattr(column, "nullable", None),
|
|
128
|
+
unique=bool(getattr(column, "unique", False)),
|
|
129
|
+
index=bool(getattr(column, "index", False)),
|
|
130
|
+
primary_key=bool(getattr(column, "primary_key", False)),
|
|
131
|
+
autoincrement=getattr(column, "autoincrement", None),
|
|
132
|
+
default=getattr(getattr(column, "default", None), "arg", None),
|
|
133
|
+
onupdate=getattr(getattr(column, "onupdate", None), "arg", None),
|
|
134
|
+
server_default=getattr(getattr(column, "server_default", None), "arg", None),
|
|
135
|
+
fk=fk_spec,
|
|
136
|
+
comment=getattr(column, "comment", None),
|
|
137
|
+
)
|
|
138
|
+
|
|
88
139
|
@staticmethod
|
|
89
140
|
@lru_cache(maxsize=None)
|
|
90
141
|
def _mro_collect_columns_cached(
|
|
@@ -121,7 +172,13 @@ class ColumnSpec(SerdeMixin):
|
|
|
121
172
|
name = getattr(col, "key", None) or getattr(col, "name", None)
|
|
122
173
|
if not isinstance(name, str):
|
|
123
174
|
continue
|
|
124
|
-
out.setdefault(
|
|
175
|
+
out.setdefault(
|
|
176
|
+
name,
|
|
177
|
+
ColumnSpec(
|
|
178
|
+
storage=ColumnSpec._storage_spec_from_column(col),
|
|
179
|
+
io=ColumnSpec._DEFAULT_IO,
|
|
180
|
+
),
|
|
181
|
+
)
|
|
125
182
|
else:
|
|
126
183
|
# Declarative models can be inspected before SQLAlchemy finishes
|
|
127
184
|
# materializing ``__table__``. In that transient state plain
|
|
@@ -133,7 +190,8 @@ class ColumnSpec(SerdeMixin):
|
|
|
133
190
|
continue
|
|
134
191
|
if hasattr(value, "type") and hasattr(value, "nullable"):
|
|
135
192
|
out[attr_name] = ColumnSpec(
|
|
136
|
-
storage=
|
|
193
|
+
storage=ColumnSpec._storage_spec_from_column(value),
|
|
194
|
+
io=ColumnSpec._DEFAULT_IO,
|
|
137
195
|
)
|
|
138
196
|
|
|
139
197
|
logger.debug(
|