tigrbl-kernel 0.4.5.dev4__tar.gz → 0.4.5.dev6__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_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/PKG-INFO +9 -9
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/README.md +5 -5
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/pyproject.toml +4 -4
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/__init__.py +2 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/_build.py +19 -1
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/_compile.py +35 -7
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/models.py +8 -0
- tigrbl_kernel-0.4.5.dev6/tigrbl_kernel/opview_compiler.py +312 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/packed_selectors.py +145 -5
- tigrbl_kernel-0.4.5.dev6/tigrbl_kernel/protocol_chains/websocket.py +528 -0
- tigrbl_kernel-0.4.5.dev6/tigrbl_kernel/webtransport_session_plan.py +92 -0
- tigrbl_kernel-0.4.5.dev4/tigrbl_kernel/opview_compiler.py +0 -136
- tigrbl_kernel-0.4.5.dev4/tigrbl_kernel/protocol_chains/websocket.py +0 -41
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/LICENSE +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/NOTICE +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/atoms.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/cache.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/callbacks.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/channel_taxonomy.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/contract_classification.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/core.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/cross_transport.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/dispatch_taxonomy.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/eventkey.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/eventkey_hooks.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/events.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/helpers.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/hook_types.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/labels.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/lifecycle_matrix.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/loop_modes.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/loop_regions.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/measure.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/opchannel_capabilities.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/ordering.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/packed_access.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/payload.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_anchors.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_bindings.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_chains/__init__.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_chains/http_stream.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_chains/http_unary.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_chains/lifespan.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_chains/sse.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_chains/static_files.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_completion.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_fusion.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_legality_matrix.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_phase_tree.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/protocol_streams.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/resume_policy.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/runtime_contracts.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/segment_fusion.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/subevent_handlers.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/subevent_taxonomy.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/trace.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/transaction_units.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/transport_atoms.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/transport_events.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/types.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/utils.py +0 -0
- {tigrbl_kernel-0.4.5.dev4 → tigrbl_kernel-0.4.5.dev6}/tigrbl_kernel/webtransport_events.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrbl-kernel
|
|
3
|
-
Version: 0.4.5.
|
|
3
|
+
Version: 0.4.5.dev6
|
|
4
4
|
Summary: Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -225,14 +225,14 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
225
225
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
226
226
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
227
227
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
228
|
-
Requires-Dist: tigrbl-atoms
|
|
229
|
-
Requires-Dist: tigrbl-core
|
|
228
|
+
Requires-Dist: tigrbl-atoms (>=0.4.5.dev5)
|
|
229
|
+
Requires-Dist: tigrbl-core (>=0.4.5.dev6)
|
|
230
230
|
Requires-Dist: tigrbl-typing
|
|
231
231
|
Project-URL: Discord, https://discord.gg/K4YTAPapjR
|
|
232
232
|
Project-URL: Homepage, https://github.com/tigrbl/tigrbl
|
|
233
233
|
Project-URL: Issues, https://github.com/tigrbl/tigrbl/issues
|
|
234
234
|
Project-URL: Organization, https://github.com/tigrbl
|
|
235
|
-
Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/
|
|
235
|
+
Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel
|
|
236
236
|
Description-Content-Type: text/markdown
|
|
237
237
|
|
|
238
238
|
<div align="center">
|
|
@@ -242,7 +242,7 @@ Description-Content-Type: text/markdown
|
|
|
242
242
|
<a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://img.shields.io/pypi/v/tigrbl-kernel?label=PyPI" alt="PyPI version for tigrbl-kernel"/></a>
|
|
243
243
|
<a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://static.pepy.tech/badge/tigrbl-kernel" alt="Downloads for tigrbl-kernel"/></a>
|
|
244
244
|
<a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-kernel"/></a>
|
|
245
|
-
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/
|
|
245
|
+
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md.svg?label=hits" alt="Repository hits for tigrbl-kernel README"/></a>
|
|
246
246
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
|
|
247
247
|
<a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%2C%203.11%2C%203.12%2C%203.13%2C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-kernel"/></a>
|
|
248
248
|
<a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-kernel"/></a>
|
|
@@ -266,7 +266,7 @@ Framework maintainers, extension authors, and advanced users composing Tigrbl fr
|
|
|
266
266
|
|
|
267
267
|
## Where does tigrbl-kernel fit?
|
|
268
268
|
|
|
269
|
-
`tigrbl-kernel` lives at `pkgs/
|
|
269
|
+
`tigrbl-kernel` lives at `pkgs/45_kernel/tigrbl_kernel` and serves a focused layer in the split Tigrbl framework.
|
|
270
270
|
|
|
271
271
|
## How does tigrbl-kernel work?
|
|
272
272
|
|
|
@@ -288,7 +288,7 @@ pip install tigrbl-kernel
|
|
|
288
288
|
| Surface | Value |
|
|
289
289
|
|---|---|
|
|
290
290
|
| PyPI package | [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/) |
|
|
291
|
-
| Repository path | [`pkgs/
|
|
291
|
+
| Repository path | [`pkgs/45_kernel/tigrbl_kernel`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel) |
|
|
292
292
|
| Python import root | `tigrbl_kernel` |
|
|
293
293
|
| Console scripts | none declared |
|
|
294
294
|
| Entry points | none declared |
|
|
@@ -444,7 +444,7 @@ Choose `tigrbl-kernel` when the quick-answer table matches your use case. Choose
|
|
|
444
444
|
|
|
445
445
|
- Community: [Discord](https://discord.gg/K4YTAPapjR).
|
|
446
446
|
- Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
|
|
447
|
-
- Repository: [pkgs/
|
|
447
|
+
- Repository: [pkgs/45_kernel/tigrbl_kernel](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel).
|
|
448
448
|
|
|
449
449
|
## Package-local Boundary
|
|
450
450
|
|
|
@@ -455,7 +455,7 @@ This file is a package-local distribution entry point. This README is the packag
|
|
|
455
455
|
- Package status: governed package in the `tigrbl/tigrbl` workspace.
|
|
456
456
|
- Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
|
|
457
457
|
- Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
|
|
458
|
-
- Local certification guard: `pkgs/
|
|
458
|
+
- Local certification guard: `pkgs/97_tests/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
|
|
459
459
|
- Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
|
|
460
460
|
|
|
461
461
|
## License
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://img.shields.io/pypi/v/tigrbl-kernel?label=PyPI" alt="PyPI version for tigrbl-kernel"/></a>
|
|
6
6
|
<a href="https://pypi.org/project/tigrbl-kernel/"><img src="https://static.pepy.tech/badge/tigrbl-kernel" alt="Downloads for tigrbl-kernel"/></a>
|
|
7
7
|
<a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-kernel"/></a>
|
|
8
|
-
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/
|
|
8
|
+
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/45_kernel/tigrbl_kernel/README.md.svg?label=hits" alt="Repository hits for tigrbl-kernel README"/></a>
|
|
9
9
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
|
|
10
10
|
<a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%2C%203.11%2C%203.12%2C%203.13%2C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-kernel"/></a>
|
|
11
11
|
<a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-kernel"/></a>
|
|
@@ -29,7 +29,7 @@ Framework maintainers, extension authors, and advanced users composing Tigrbl fr
|
|
|
29
29
|
|
|
30
30
|
## Where does tigrbl-kernel fit?
|
|
31
31
|
|
|
32
|
-
`tigrbl-kernel` lives at `pkgs/
|
|
32
|
+
`tigrbl-kernel` lives at `pkgs/45_kernel/tigrbl_kernel` and serves a focused layer in the split Tigrbl framework.
|
|
33
33
|
|
|
34
34
|
## How does tigrbl-kernel work?
|
|
35
35
|
|
|
@@ -51,7 +51,7 @@ pip install tigrbl-kernel
|
|
|
51
51
|
| Surface | Value |
|
|
52
52
|
|---|---|
|
|
53
53
|
| PyPI package | [`tigrbl-kernel`](https://pypi.org/project/tigrbl-kernel/) |
|
|
54
|
-
| Repository path | [`pkgs/
|
|
54
|
+
| Repository path | [`pkgs/45_kernel/tigrbl_kernel`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel) |
|
|
55
55
|
| Python import root | `tigrbl_kernel` |
|
|
56
56
|
| Console scripts | none declared |
|
|
57
57
|
| Entry points | none declared |
|
|
@@ -207,7 +207,7 @@ Choose `tigrbl-kernel` when the quick-answer table matches your use case. Choose
|
|
|
207
207
|
|
|
208
208
|
- Community: [Discord](https://discord.gg/K4YTAPapjR).
|
|
209
209
|
- Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
|
|
210
|
-
- Repository: [pkgs/
|
|
210
|
+
- Repository: [pkgs/45_kernel/tigrbl_kernel](https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel).
|
|
211
211
|
|
|
212
212
|
## Package-local Boundary
|
|
213
213
|
|
|
@@ -218,7 +218,7 @@ This file is a package-local distribution entry point. This README is the packag
|
|
|
218
218
|
- Package status: governed package in the `tigrbl/tigrbl` workspace.
|
|
219
219
|
- Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
|
|
220
220
|
- Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
|
|
221
|
-
- Local certification guard: `pkgs/
|
|
221
|
+
- Local certification guard: `pkgs/97_tests/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
|
|
222
222
|
- Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
|
|
223
223
|
|
|
224
224
|
## License
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tigrbl-kernel"
|
|
3
|
-
version = "0.4.5.
|
|
3
|
+
version = "0.4.5.dev6"
|
|
4
4
|
description = "Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { file = "LICENSE" }
|
|
@@ -42,8 +42,8 @@ authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
|
42
42
|
|
|
43
43
|
dependencies = [
|
|
44
44
|
"tigrbl-typing",
|
|
45
|
-
"tigrbl-atoms",
|
|
46
|
-
"tigrbl-core",
|
|
45
|
+
"tigrbl-atoms>=0.4.5.dev5",
|
|
46
|
+
"tigrbl-core>=0.4.5.dev6",
|
|
47
47
|
]
|
|
48
48
|
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ dependencies = [
|
|
|
51
51
|
Organization = "https://github.com/tigrbl"
|
|
52
52
|
Discord = "https://discord.gg/K4YTAPapjR"
|
|
53
53
|
Homepage = "https://github.com/tigrbl/tigrbl"
|
|
54
|
-
Repository = "https://github.com/tigrbl/tigrbl/tree/master/pkgs/
|
|
54
|
+
Repository = "https://github.com/tigrbl/tigrbl/tree/master/pkgs/45_kernel/tigrbl_kernel"
|
|
55
55
|
Issues = "https://github.com/tigrbl/tigrbl/issues"
|
|
56
56
|
|
|
57
57
|
[tool.uv.sources]
|
|
@@ -18,6 +18,7 @@ _LAZY_EXPORTS = {
|
|
|
18
18
|
"PackedKernel": "models",
|
|
19
19
|
"SchemaIn": "models",
|
|
20
20
|
"SchemaOut": "models",
|
|
21
|
+
"SchemaStored": "models",
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
_default_kernel = None
|
|
@@ -73,6 +74,7 @@ __all__ = [
|
|
|
73
74
|
"PackedKernel",
|
|
74
75
|
"SchemaIn",
|
|
75
76
|
"SchemaOut",
|
|
77
|
+
"SchemaStored",
|
|
76
78
|
"build_kernel_plan",
|
|
77
79
|
"build_packed_kernel",
|
|
78
80
|
"build_packed_kernel_measurement_view",
|
|
@@ -91,6 +91,12 @@ _DECODER_TIME = 9
|
|
|
91
91
|
_WS_FAST_PATH_BYPASS_ATOM_NAMES = frozenset(
|
|
92
92
|
{
|
|
93
93
|
"ingress.ctx_init",
|
|
94
|
+
"ingress.transport_extract",
|
|
95
|
+
"transport.sink_bind",
|
|
96
|
+
"ingress.input_prepare",
|
|
97
|
+
"dispatch.binding_match",
|
|
98
|
+
"dispatch.binding_parse",
|
|
99
|
+
"dispatch.input_normalize",
|
|
94
100
|
"dispatch.op_resolve",
|
|
95
101
|
"schema.collect_in",
|
|
96
102
|
"handler.custom",
|
|
@@ -213,6 +219,8 @@ def _is_batch_domain_run(run: Any) -> bool:
|
|
|
213
219
|
except ValueError:
|
|
214
220
|
return False
|
|
215
221
|
domain = parts[index + 1] if index + 1 < len(parts) else None
|
|
222
|
+
if domain == "transport" and parts[-1] == "sink_bind":
|
|
223
|
+
return False
|
|
216
224
|
return domain in {"transport", "intent", "batch", "fanout"}
|
|
217
225
|
|
|
218
226
|
|
|
@@ -1156,8 +1164,18 @@ def _pack_kernel_plan(
|
|
|
1156
1164
|
)
|
|
1157
1165
|
alias_name = str(getattr(meta, "alias", "") or "")
|
|
1158
1166
|
target_name = str(getattr(meta, "target", "") or "")
|
|
1167
|
+
opview = opviews[program_id] if program_id < len(opviews) else None
|
|
1159
1168
|
compiled_param_eligible = not (
|
|
1160
|
-
alias_name.startswith("bulk_")
|
|
1169
|
+
alias_name.startswith("bulk_")
|
|
1170
|
+
or target_name.startswith("bulk_")
|
|
1171
|
+
# Selector aliases and URL precedence are validated by wire.validate_in.
|
|
1172
|
+
# The scalar compiled decoder does not implement that contract yet.
|
|
1173
|
+
or any(
|
|
1174
|
+
entry.get("selector")
|
|
1175
|
+
for entry in (
|
|
1176
|
+
getattr(getattr(opview, "schema_in", None), "by_field", {}) or {}
|
|
1177
|
+
).values()
|
|
1178
|
+
)
|
|
1161
1179
|
)
|
|
1162
1180
|
compiled_param_phase_steps = (
|
|
1163
1181
|
program_compiled_param_phase_steps[program_id]
|
|
@@ -95,6 +95,7 @@ def _route_metadata_for_binding(binding: Any) -> dict[str, Any]:
|
|
|
95
95
|
metadata["lane"] = lane
|
|
96
96
|
metadata["inner_framing"] = framing_kind(inner_framing)
|
|
97
97
|
metadata["inner_framing_spec"] = framing_spec_name(inner_framing)
|
|
98
|
+
metadata["rpc_method"] = getattr(binding, "rpc_method", None)
|
|
98
99
|
if inner_framing is not None:
|
|
99
100
|
metadata["inner_framing_kind"] = str(inner_framing)
|
|
100
101
|
metadata["inner_framing_spec"] = framing_spec_name(inner_framing)
|
|
@@ -206,8 +207,6 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
206
207
|
from tigrbl_core._spec.binding_spec import (
|
|
207
208
|
HttpJsonRpcBindingSpec,
|
|
208
209
|
HttpRestBindingSpec,
|
|
209
|
-
HttpJsonRpcProtocolBindingSpec,
|
|
210
|
-
HttpRestProtocolBindingSpec,
|
|
211
210
|
HttpStreamBindingSpec,
|
|
212
211
|
SseBindingSpec,
|
|
213
212
|
WebSocketProtocolBindingSpec,
|
|
@@ -281,7 +280,9 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
281
280
|
meta_index
|
|
282
281
|
)
|
|
283
282
|
|
|
284
|
-
elif isinstance(
|
|
283
|
+
elif isinstance(
|
|
284
|
+
binding, (HttpJsonRpcBindingSpec, HttpJsonRpcProtocolBindingSpec)
|
|
285
|
+
):
|
|
285
286
|
rpc_path = str(
|
|
286
287
|
getattr(
|
|
287
288
|
binding,
|
|
@@ -302,8 +303,12 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
302
303
|
proto_bucket = route_data.setdefault(
|
|
303
304
|
binding.proto, {"paths": {}, "endpoints": {}}
|
|
304
305
|
)
|
|
305
|
-
path_bucket = proto_bucket.setdefault("paths", {}).setdefault(
|
|
306
|
-
|
|
306
|
+
path_bucket = proto_bucket.setdefault("paths", {}).setdefault(
|
|
307
|
+
rpc_path, {}
|
|
308
|
+
)
|
|
309
|
+
endpoint_bucket = proto_bucket.setdefault(
|
|
310
|
+
"endpoints", {}
|
|
311
|
+
).setdefault(rpc_path, {})
|
|
307
312
|
proto_bucket[rpc_method] = meta_index
|
|
308
313
|
row = {
|
|
309
314
|
"meta_index": meta_index,
|
|
@@ -326,6 +331,17 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
326
331
|
bucket = route_data.setdefault(
|
|
327
332
|
binding.proto, {"exact": {}, "templated": []}
|
|
328
333
|
)
|
|
334
|
+
if (
|
|
335
|
+
isinstance(
|
|
336
|
+
binding, (WsBindingSpec, WebSocketProtocolBindingSpec)
|
|
337
|
+
)
|
|
338
|
+
and framing_kind(getattr(binding, "framing", None)) == "jsonrpc"
|
|
339
|
+
and bool(getattr(sp, "expose_method", True))
|
|
340
|
+
):
|
|
341
|
+
# JSON-RPC method operations are dispatched inside the
|
|
342
|
+
# framework-owned WebSocket session. Only the hidden
|
|
343
|
+
# transport operation may own the socket path itself.
|
|
344
|
+
continue
|
|
329
345
|
selector = binding.path
|
|
330
346
|
route_metadata = _route_metadata_for_binding(binding)
|
|
331
347
|
opkey_to_meta[OpKey(proto=binding.proto, selector=selector)] = (
|
|
@@ -345,13 +361,25 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
345
361
|
}
|
|
346
362
|
)
|
|
347
363
|
else:
|
|
348
|
-
|
|
349
|
-
bucket.setdefault("exact_metadata", {})[selector] = {
|
|
364
|
+
route_row = {
|
|
350
365
|
"path": binding.path,
|
|
351
366
|
"meta_index": meta_index,
|
|
352
367
|
"selector": selector,
|
|
353
368
|
**route_metadata,
|
|
354
369
|
}
|
|
370
|
+
if binding.proto == "webtransport":
|
|
371
|
+
bucket["exact"].setdefault(selector, meta_index)
|
|
372
|
+
bucket.setdefault("routes", {}).setdefault(
|
|
373
|
+
selector, []
|
|
374
|
+
).append(route_row)
|
|
375
|
+
bucket.setdefault("exact_metadata", {}).setdefault(
|
|
376
|
+
selector, route_row
|
|
377
|
+
)
|
|
378
|
+
else:
|
|
379
|
+
bucket["exact"][selector] = meta_index
|
|
380
|
+
bucket.setdefault("exact_metadata", {})[selector] = (
|
|
381
|
+
route_row
|
|
382
|
+
)
|
|
355
383
|
|
|
356
384
|
semantic = KernelPlan(
|
|
357
385
|
proto_indices=route_data,
|
|
@@ -51,6 +51,13 @@ class SchemaOut:
|
|
|
51
51
|
expose: Tuple[str, ...]
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
@dataclass(frozen=True)
|
|
55
|
+
class SchemaStored:
|
|
56
|
+
fields: Tuple[str, ...]
|
|
57
|
+
by_field: Dict[str, Dict[str, object]]
|
|
58
|
+
required_from_client: Tuple[str, ...] = ()
|
|
59
|
+
|
|
60
|
+
|
|
54
61
|
@dataclass(frozen=True)
|
|
55
62
|
class OpView:
|
|
56
63
|
schema_in: SchemaIn
|
|
@@ -59,6 +66,7 @@ class OpView:
|
|
|
59
66
|
virtual_producers: Dict[str, Callable[[object, dict], object]]
|
|
60
67
|
to_stored_transforms: Dict[str, Callable[[object, dict], object]]
|
|
61
68
|
refresh_hints: Tuple[str, ...]
|
|
69
|
+
schema_stored: SchemaStored | None = None
|
|
62
70
|
|
|
63
71
|
|
|
64
72
|
@dataclass(frozen=True, slots=True)
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Mapping
|
|
4
|
+
|
|
5
|
+
from tigrbl_core.schema.builder.helpers import (
|
|
6
|
+
_normalize_py_type,
|
|
7
|
+
_storage_python_type,
|
|
8
|
+
_spec_python_type,
|
|
9
|
+
_input_selector_entries,
|
|
10
|
+
_input_filter_entries,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .models import OpView, SchemaIn, SchemaOut, SchemaStored
|
|
14
|
+
|
|
15
|
+
_READ_ONLY_TARGETS = frozenset(
|
|
16
|
+
{
|
|
17
|
+
"read",
|
|
18
|
+
"list",
|
|
19
|
+
"count",
|
|
20
|
+
"exists",
|
|
21
|
+
"aggregate",
|
|
22
|
+
"group_by",
|
|
23
|
+
"subscribe",
|
|
24
|
+
"tail",
|
|
25
|
+
"download",
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
_NON_PERSISTING_TARGETS = frozenset(
|
|
29
|
+
{
|
|
30
|
+
"delete",
|
|
31
|
+
"clear",
|
|
32
|
+
"bulk_delete",
|
|
33
|
+
"close_stream",
|
|
34
|
+
"close_session",
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
_CREATE_LIKE_TARGETS = frozenset({"create", "bulk_create"})
|
|
38
|
+
_UPDATE_LIKE_TARGETS = frozenset({"update", "merge", "bulk_update", "bulk_merge"})
|
|
39
|
+
_REPLACE_LIKE_TARGETS = frozenset({"replace", "bulk_replace"})
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _storage_requires_input(storage: Any, alias: str) -> bool:
|
|
43
|
+
if storage is None or alias == "update":
|
|
44
|
+
return False
|
|
45
|
+
if bool(getattr(storage, "primary_key", False)):
|
|
46
|
+
if alias in {"replace", "delete"}:
|
|
47
|
+
return True
|
|
48
|
+
auto = getattr(storage, "autoincrement", False)
|
|
49
|
+
if auto not in (False, None) or getattr(storage, "identity", None) is not None:
|
|
50
|
+
return False
|
|
51
|
+
has_default = (
|
|
52
|
+
getattr(storage, "default", None) is not None
|
|
53
|
+
or getattr(storage, "server_default", None) is not None
|
|
54
|
+
or callable(getattr(storage, "default_factory", None))
|
|
55
|
+
)
|
|
56
|
+
return not bool(getattr(storage, "nullable", True)) and not has_default
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _storage_has_server_default(spec: Any, storage: Any) -> bool:
|
|
60
|
+
return bool(
|
|
61
|
+
getattr(storage, "default", None) is not None
|
|
62
|
+
or getattr(storage, "server_default", None) is not None
|
|
63
|
+
or callable(getattr(storage, "default_factory", None))
|
|
64
|
+
or callable(getattr(spec, "default_factory", None))
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _supports_stored_shape(target: str) -> bool:
|
|
69
|
+
lowered = str(target or "").lower()
|
|
70
|
+
return lowered not in _READ_ONLY_TARGETS and lowered not in _NON_PERSISTING_TARGETS
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _is_input_enabled(io: Any, semantic_verbs: tuple[str, ...]) -> bool:
|
|
74
|
+
in_verbs = set(getattr(io, "in_verbs", ()) or ())
|
|
75
|
+
return any(name in in_verbs for name in semantic_verbs)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _is_paired_enabled(io: Any, semantic_verbs: tuple[str, ...]) -> bool:
|
|
79
|
+
cfg = getattr(io, "_paired", None)
|
|
80
|
+
if cfg is None:
|
|
81
|
+
return False
|
|
82
|
+
paired_verbs = set(getattr(cfg, "verbs", ()) or ())
|
|
83
|
+
return any(name in paired_verbs for name in semantic_verbs)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _include_in_stored_schema(
|
|
87
|
+
*,
|
|
88
|
+
spec: Any,
|
|
89
|
+
io: Any,
|
|
90
|
+
storage: Any,
|
|
91
|
+
semantic_verbs: tuple[str, ...],
|
|
92
|
+
target: str,
|
|
93
|
+
) -> bool:
|
|
94
|
+
lowered = str(target or "").lower()
|
|
95
|
+
if storage is None or not _supports_stored_shape(lowered):
|
|
96
|
+
return False
|
|
97
|
+
if _is_input_enabled(io, semantic_verbs) or _is_paired_enabled(io, semantic_verbs):
|
|
98
|
+
return True
|
|
99
|
+
if lowered in _CREATE_LIKE_TARGETS or lowered in _UPDATE_LIKE_TARGETS:
|
|
100
|
+
return True
|
|
101
|
+
if lowered in _REPLACE_LIKE_TARGETS:
|
|
102
|
+
return True
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _stored_required(storage: Any, spec: Any, target: str, *, derived: bool) -> bool:
|
|
107
|
+
lowered = str(target or "").lower()
|
|
108
|
+
if lowered in _UPDATE_LIKE_TARGETS:
|
|
109
|
+
return False
|
|
110
|
+
if lowered in _NON_PERSISTING_TARGETS or lowered in _READ_ONLY_TARGETS:
|
|
111
|
+
return False
|
|
112
|
+
if derived:
|
|
113
|
+
return True
|
|
114
|
+
return not bool(
|
|
115
|
+
getattr(storage, "nullable", True)
|
|
116
|
+
) and not _storage_has_server_default(
|
|
117
|
+
spec,
|
|
118
|
+
storage,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def compile_opview_from_specs(specs: Mapping[str, Any], sp: Any) -> OpView:
|
|
123
|
+
"""Build a basic OpView from collected specs when no app/model is present."""
|
|
124
|
+
alias = str(getattr(sp, "alias", "") or "")
|
|
125
|
+
target = str(getattr(sp, "target", alias) or alias)
|
|
126
|
+
semantic_verbs = tuple(
|
|
127
|
+
dict.fromkeys(
|
|
128
|
+
name for name in (alias, target) if isinstance(name, str) and name
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
in_fields: list[str] = []
|
|
133
|
+
out_fields: list[str] = []
|
|
134
|
+
stored_fields: list[str] = []
|
|
135
|
+
by_field_in: Dict[str, Dict[str, object]] = {}
|
|
136
|
+
by_field_out: Dict[str, Dict[str, object]] = {}
|
|
137
|
+
by_field_stored: Dict[str, Dict[str, object]] = {}
|
|
138
|
+
required_from_client: list[str] = []
|
|
139
|
+
to_stored_transforms: Dict[str, Any] = {}
|
|
140
|
+
|
|
141
|
+
for name, spec in specs.items():
|
|
142
|
+
io = getattr(spec, "io", None)
|
|
143
|
+
fs = getattr(spec, "field", None)
|
|
144
|
+
storage = getattr(spec, "storage", None)
|
|
145
|
+
in_verbs = set(getattr(io, "in_verbs", ()) or ())
|
|
146
|
+
out_verbs = set(getattr(io, "out_verbs", ()) or ())
|
|
147
|
+
|
|
148
|
+
if any(name in in_verbs for name in semantic_verbs):
|
|
149
|
+
in_fields.append(name)
|
|
150
|
+
meta: Dict[str, object] = {"in_enabled": True}
|
|
151
|
+
if storage is None:
|
|
152
|
+
meta["virtual"] = True
|
|
153
|
+
py_type = _spec_python_type(spec)
|
|
154
|
+
if py_type is not None and py_type is not Any:
|
|
155
|
+
meta["py_type"] = py_type
|
|
156
|
+
constraints = getattr(fs, "constraints", {}) or {}
|
|
157
|
+
if isinstance(constraints, Mapping):
|
|
158
|
+
max_length = constraints.get("max_length")
|
|
159
|
+
if isinstance(max_length, int) and max_length > 0:
|
|
160
|
+
meta["max_length"] = max_length
|
|
161
|
+
default_factory = getattr(spec, "default_factory", None)
|
|
162
|
+
if callable(default_factory):
|
|
163
|
+
meta["default_factory"] = default_factory
|
|
164
|
+
alias_in = getattr(io, "alias_in", None)
|
|
165
|
+
if alias_in:
|
|
166
|
+
meta["alias_in"] = alias_in
|
|
167
|
+
header_in = getattr(io, "header_in", None)
|
|
168
|
+
if header_in:
|
|
169
|
+
meta["header_in"] = header_in
|
|
170
|
+
meta["header_required_in"] = bool(
|
|
171
|
+
getattr(io, "header_required_in", False)
|
|
172
|
+
)
|
|
173
|
+
required = bool(
|
|
174
|
+
(
|
|
175
|
+
fs
|
|
176
|
+
and any(
|
|
177
|
+
name in getattr(fs, "required_in", ())
|
|
178
|
+
for name in semantic_verbs
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
or _storage_requires_input(storage, target)
|
|
182
|
+
)
|
|
183
|
+
meta["required"] = required
|
|
184
|
+
base_nullable = (
|
|
185
|
+
True if storage is None else getattr(storage, "nullable", True)
|
|
186
|
+
)
|
|
187
|
+
meta["nullable"] = base_nullable
|
|
188
|
+
meta["coerce"] = True
|
|
189
|
+
by_field_in[name] = meta
|
|
190
|
+
|
|
191
|
+
if any(name in out_verbs for name in semantic_verbs):
|
|
192
|
+
out_fields.append(name)
|
|
193
|
+
meta_out: Dict[str, object] = {}
|
|
194
|
+
alias_out = getattr(io, "alias_out", None)
|
|
195
|
+
if alias_out:
|
|
196
|
+
meta_out["alias_out"] = alias_out
|
|
197
|
+
if storage is None:
|
|
198
|
+
meta_out["virtual"] = True
|
|
199
|
+
py_type = getattr(getattr(fs, "py_type", None), "__name__", None)
|
|
200
|
+
if py_type:
|
|
201
|
+
meta_out["py_type"] = py_type
|
|
202
|
+
by_field_out[name] = meta_out
|
|
203
|
+
|
|
204
|
+
if _include_in_stored_schema(
|
|
205
|
+
spec=spec,
|
|
206
|
+
io=io,
|
|
207
|
+
storage=storage,
|
|
208
|
+
semantic_verbs=semantic_verbs,
|
|
209
|
+
target=target,
|
|
210
|
+
):
|
|
211
|
+
stored_fields.append(name)
|
|
212
|
+
input_enabled = _is_input_enabled(io, semantic_verbs)
|
|
213
|
+
paired_enabled = _is_paired_enabled(io, semantic_verbs)
|
|
214
|
+
server_default = _storage_has_server_default(spec, storage)
|
|
215
|
+
py_type = getattr(fs, "py_type", None)
|
|
216
|
+
if py_type is None or py_type is Any:
|
|
217
|
+
py_type = _storage_python_type(getattr(storage, "type_", None))
|
|
218
|
+
else:
|
|
219
|
+
py_type = _normalize_py_type(py_type)
|
|
220
|
+
stored_meta: Dict[str, object] = {
|
|
221
|
+
"nullable": bool(getattr(storage, "nullable", True)),
|
|
222
|
+
"from_client": input_enabled,
|
|
223
|
+
"required_from_client": bool(
|
|
224
|
+
input_enabled and _storage_requires_input(storage, target)
|
|
225
|
+
),
|
|
226
|
+
"server_default": server_default,
|
|
227
|
+
}
|
|
228
|
+
if py_type is not Any:
|
|
229
|
+
stored_meta["py_type"] = py_type
|
|
230
|
+
constraints = getattr(fs, "constraints", {}) or {}
|
|
231
|
+
if isinstance(constraints, Mapping):
|
|
232
|
+
max_length = constraints.get("max_length")
|
|
233
|
+
if isinstance(max_length, int) and max_length > 0:
|
|
234
|
+
stored_meta["max_length"] = max_length
|
|
235
|
+
|
|
236
|
+
transform = getattr(getattr(storage, "transform", None), "to_stored", None)
|
|
237
|
+
if callable(transform):
|
|
238
|
+
to_stored_transforms[name] = transform
|
|
239
|
+
|
|
240
|
+
derived = paired_enabled or callable(transform)
|
|
241
|
+
stored_meta["derived"] = derived
|
|
242
|
+
stored_meta["required"] = _stored_required(
|
|
243
|
+
storage,
|
|
244
|
+
spec,
|
|
245
|
+
target,
|
|
246
|
+
derived=derived,
|
|
247
|
+
)
|
|
248
|
+
if stored_meta["required_from_client"]:
|
|
249
|
+
required_from_client.append(name)
|
|
250
|
+
by_field_stored[name] = stored_meta
|
|
251
|
+
|
|
252
|
+
for name, meta in {
|
|
253
|
+
**_input_filter_entries(specs, target),
|
|
254
|
+
**_input_selector_entries(specs, target),
|
|
255
|
+
}.items():
|
|
256
|
+
if name not in by_field_in:
|
|
257
|
+
in_fields.append(name)
|
|
258
|
+
by_field_in[name] = meta
|
|
259
|
+
elif meta.get("selector"):
|
|
260
|
+
by_field_in[name] = {**meta, **by_field_in[name], "selector": True}
|
|
261
|
+
|
|
262
|
+
schema_in = SchemaIn(
|
|
263
|
+
fields=tuple(sorted(in_fields)),
|
|
264
|
+
by_field={field: by_field_in.get(field, {}) for field in sorted(in_fields)},
|
|
265
|
+
)
|
|
266
|
+
schema_out = SchemaOut(
|
|
267
|
+
fields=tuple(sorted(out_fields)),
|
|
268
|
+
by_field={field: by_field_out.get(field, {}) for field in sorted(out_fields)},
|
|
269
|
+
expose=tuple(sorted(out_fields)),
|
|
270
|
+
)
|
|
271
|
+
stored_fields_sorted = tuple(sorted(stored_fields))
|
|
272
|
+
schema_stored = (
|
|
273
|
+
SchemaStored(
|
|
274
|
+
fields=stored_fields_sorted,
|
|
275
|
+
by_field={
|
|
276
|
+
field: by_field_stored.get(field, {}) for field in stored_fields_sorted
|
|
277
|
+
},
|
|
278
|
+
required_from_client=tuple(sorted(required_from_client)),
|
|
279
|
+
)
|
|
280
|
+
if stored_fields_sorted
|
|
281
|
+
else None
|
|
282
|
+
)
|
|
283
|
+
paired_index: Dict[str, Dict[str, object]] = {}
|
|
284
|
+
for field, col in specs.items():
|
|
285
|
+
io = getattr(col, "io", None)
|
|
286
|
+
cfg = getattr(io, "_paired", None)
|
|
287
|
+
if cfg and any(name in getattr(cfg, "verbs", ()) for name in semantic_verbs): # type: ignore[attr-defined]
|
|
288
|
+
field_spec = getattr(col, "field", None)
|
|
289
|
+
max_length = None
|
|
290
|
+
if field_spec is not None:
|
|
291
|
+
max_length = getattr(
|
|
292
|
+
getattr(field_spec, "constraints", {}),
|
|
293
|
+
"get",
|
|
294
|
+
lambda k, d=None: None,
|
|
295
|
+
)("max_length")
|
|
296
|
+
paired_index[field] = {
|
|
297
|
+
"alias": cfg.alias,
|
|
298
|
+
"gen": cfg.gen,
|
|
299
|
+
"store": cfg.store,
|
|
300
|
+
"mask_last": cfg.mask_last,
|
|
301
|
+
"max_length": max_length,
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return OpView(
|
|
305
|
+
schema_in=schema_in,
|
|
306
|
+
schema_out=schema_out,
|
|
307
|
+
paired_index=paired_index,
|
|
308
|
+
virtual_producers={},
|
|
309
|
+
to_stored_transforms=to_stored_transforms,
|
|
310
|
+
refresh_hints=(),
|
|
311
|
+
schema_stored=schema_stored,
|
|
312
|
+
)
|