tigrbl-core 0.4.2.dev4__tar.gz → 0.4.3.dev4__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.4.2.dev4 → tigrbl_core-0.4.3.dev4}/PKG-INFO +85 -4
- tigrbl_core-0.4.3.dev4/README.md +238 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/pyproject.toml +3 -1
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/__init__.py +36 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/app_spec.py +38 -1
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/binding_spec.py +28 -11
- tigrbl_core-0.4.3.dev4/tigrbl_core/_spec/exceptions.py +16 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/_spec/exposure_policy.py +112 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/hook_types.py +2 -2
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/op_spec.py +9 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/path_spec.py +17 -1
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/router_spec.py +7 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/_spec/table_profile_bindings.py +466 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/_spec/table_profile_spec.py +536 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/table_spec.py +25 -1
- tigrbl_core-0.4.3.dev4/tigrbl_core/_spec/transport_stack.py +120 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/_spec/well_known_spec.py +69 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/config/constants.py +3 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/__init__.py +28 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/schema/provenance.py +191 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/schema/provenance_inventory.py +249 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/schema/spec_json.py +19 -0
- tigrbl_core-0.4.3.dev4/tigrbl_core/schema/surface_chains.json +2842 -0
- tigrbl_core-0.4.2.dev4/README.md +0 -158
- tigrbl_core-0.4.2.dev4/tigrbl_core/schema/spec_json.py +0 -807
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/LICENSE +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/NOTICE +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/alias_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/column_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/datatypes.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/docs_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/engine_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/field_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/hook_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/io_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/middleware_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/monotone.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/op_utils.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/plugins.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/registry.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/request_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/response_resolver.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/response_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/response_types.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/schema_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/serde.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/session_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/storage_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/_spec/table_registry_spec.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/canonical_json.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/config/__init__.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/config/defaults.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/config/engine_traversal.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/config/resolver.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/core/__init__.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/op/__init__.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/op/canonical.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/op/collect.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/op/types.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/__init__.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/build_schema.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/cache.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/extras.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/helpers.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/list_params.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/builder/strip_parent_fields.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/get_schema.py +0 -0
- {tigrbl_core-0.4.2.dev4 → tigrbl_core-0.4.3.dev4}/tigrbl_core/schema/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrbl-core
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3.dev4
|
|
4
4
|
Summary: Core Tigrbl framework specifications, decorators, schemas, hooks, operations, and primitives for schema-first APIs.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -228,6 +228,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
228
228
|
Requires-Dist: pydantic (>=2.10,<3)
|
|
229
229
|
Requires-Dist: pyyaml
|
|
230
230
|
Requires-Dist: tigrbl-typing
|
|
231
|
+
Requires-Dist: tigrbl_spec
|
|
231
232
|
Requires-Dist: tomli (>=2.0.1) ; python_version < "3.11"
|
|
232
233
|
Requires-Dist: tomli-w
|
|
233
234
|
Project-URL: Discord, https://discord.gg/K4YTAPapjR
|
|
@@ -246,7 +247,7 @@ Description-Content-Type: text/markdown
|
|
|
246
247
|
<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-core"/></a>
|
|
247
248
|
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_core/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_core/README.md.svg?label=hits" alt="Repository hits for tigrbl-core README"/></a>
|
|
248
249
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
|
|
249
|
-
<a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%
|
|
250
|
+
<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-core"/></a>
|
|
250
251
|
<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-core"/></a>
|
|
251
252
|
</div>
|
|
252
253
|
|
|
@@ -303,7 +304,7 @@ pip install tigrbl-core
|
|
|
303
304
|
| Entry points | none declared |
|
|
304
305
|
| Optional extras | none declared |
|
|
305
306
|
| Legal files | `LICENSE`, `NOTICE` |
|
|
306
|
-
| Supported Python | `3.10
|
|
307
|
+
| Supported Python | `3.10, 3.11, 3.12, 3.13, 3.14` |
|
|
307
308
|
|
|
308
309
|
## What It Owns
|
|
309
310
|
|
|
@@ -312,6 +313,13 @@ pip install tigrbl-core
|
|
|
312
313
|
Implementation orientation:
|
|
313
314
|
- `tigrbl_core`: _spec/, canonical_json, config/, core/, op/, schema/
|
|
314
315
|
|
|
316
|
+
Package catalog:
|
|
317
|
+
- `tigrbl_core/_spec/`: typed, serializable specifications for aliases, apps, bindings, columns, data types, docs, engines, fields, hooks, IO, middleware, operations, paths, requests, responses, routers, schemas, sessions, storage, tables, and table registries.
|
|
318
|
+
- `tigrbl_core/config/`: constants, defaults, resolver logic, and engine traversal helpers used when app, router, table, column, op, and request layers are merged.
|
|
319
|
+
- `tigrbl_core/op/`: canonical operation names, operation collection, and operation typing helpers.
|
|
320
|
+
- `tigrbl_core/schema/`: dynamic schema construction, schema cache helpers, extras handling, list-parameter support, schema JSON helpers, and `get_schema` access.
|
|
321
|
+
- `tigrbl_core/canonical_json.py`: deterministic JSON output used by docs, registry-like payloads, tests, and conformance artifacts.
|
|
322
|
+
|
|
315
323
|
## Public API and Import Surface
|
|
316
324
|
|
|
317
325
|
- Import roots: `tigrbl_core`.
|
|
@@ -319,6 +327,77 @@ Implementation orientation:
|
|
|
319
327
|
- Workspace dependencies: [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/).
|
|
320
328
|
- External runtime dependencies: `pydantic>=2.10,<3`, `pyyaml`, `tomli-w`, `tomli>=2.0.1; python_version < '3.11'`.
|
|
321
329
|
|
|
330
|
+
## Specification Model
|
|
331
|
+
|
|
332
|
+
The core package is the contract layer. It defines the vocabulary consumed by base abstractions, concrete adapters, atoms, kernel planning, runtime routing, docs generation, and the public facade. Most application code should not construct these specs manually; application code should normally use facade decorators and shortcuts. Extension packages use the specs when they need deterministic, testable configuration objects.
|
|
333
|
+
|
|
334
|
+
| Spec family | What it describes |
|
|
335
|
+
|---|---|
|
|
336
|
+
| `AppSpec`, `RouterSpec`, `TableSpec` | Container-level framework configuration and inheritance points. |
|
|
337
|
+
| `ColumnSpec`, `FieldSpec`, data type specs | Field semantics, validation, storage, schema projection, and data-type lowering. |
|
|
338
|
+
| `OpSpec` and op utilities | Operation name, alias, arity, binding, handler, schema, hook, response, and runtime intent. |
|
|
339
|
+
| `HookSpec` and hook types | Hook targets, phases, predicates, ordering, and callable registration shape. |
|
|
340
|
+
| `SchemaSpec`, `RequestSpec`, `ResponseSpec`, `IoSpec` | Input/output envelope behavior, request extraction, response shaping, and Pydantic model generation. |
|
|
341
|
+
| `BindingSpec` | REST, JSON-RPC, stream, SSE, WebSocket, WSS, and WebTransport binding metadata. |
|
|
342
|
+
| `EngineSpec`, `SessionSpec`, `StorageSpec` | Engine/provider/session/storage configuration without importing concrete engine implementations. |
|
|
343
|
+
| `DocsSpec`, `PathSpec`, `MiddlewareSpec` | Documentation projection, route paths, and middleware configuration. |
|
|
344
|
+
|
|
345
|
+
## Operation Semantics
|
|
346
|
+
|
|
347
|
+
`tigrbl_core.op.canonical.DEFAULT_CANON_VERBS` is the default CRUD set:
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
create, read, update, replace, delete, list, clear
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Tables can change canonical wiring through mode/include/exclude attributes or a `should_wire_canonical(op)` helper. Core only decides whether an operation is part of the desired specification. Concrete packages and operation packs supply the actual handlers and routing behavior.
|
|
354
|
+
|
|
355
|
+
Use this package when you need to inspect or build operation specs before runtime compilation. Use `tigrbl` when you simply want a working app surface.
|
|
356
|
+
|
|
357
|
+
## Binding and Transport Semantics
|
|
358
|
+
|
|
359
|
+
`BindingSpec` keeps four concerns distinct:
|
|
360
|
+
|
|
361
|
+
- protocol or binding kind, such as HTTP REST, HTTP JSON-RPC, HTTP stream, SSE, WebSocket, WSS, or WebTransport;
|
|
362
|
+
- exchange shape, such as request/response, server stream, bidirectional stream, client stream, server stream, session, or datagram;
|
|
363
|
+
- framing, such as JSON, JSON-RPC, SSE, WebSocket text, stream framing, or WebTransport outer framing;
|
|
364
|
+
- runtime lane metadata, especially for WebTransport session, stream, and datagram behavior.
|
|
365
|
+
|
|
366
|
+
This separation is deliberate. Extension authors should not collapse protocol support into a single string or infer framing from the transport name. Invalid combinations should remain explicit validation failures so runtime behavior is fail-closed.
|
|
367
|
+
|
|
368
|
+
## Configuration Precedence
|
|
369
|
+
|
|
370
|
+
Core resolvers use this precedence pattern:
|
|
371
|
+
|
|
372
|
+
```text
|
|
373
|
+
request override > operation spec > column spec > table spec > router spec > app spec > defaults
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
The most specific layer wins. Keep default policy broad, then narrow behavior by table, column, and operation. Avoid hidden mutation of spec objects after a runtime plan has been compiled; build a fresh spec or invalidate the relevant cache when behavior truly changes.
|
|
377
|
+
|
|
378
|
+
## Schema Construction
|
|
379
|
+
|
|
380
|
+
Schema helpers build operation-specific request and response models from table metadata, column specs, request/response extras, list-parameter rules, and op-level configuration. `get_schema(...)` is the stable way to retrieve the generated model for a table operation and direction. Prefer it over hand-writing duplicate Pydantic envelopes when data belongs to a Tigrbl operation.
|
|
381
|
+
|
|
382
|
+
Best practices for schema work:
|
|
383
|
+
- Keep storage fields, wire fields, and virtual extras separate.
|
|
384
|
+
- Put reusable schema behavior in table or column specs; reserve op specs for operation-specific differences.
|
|
385
|
+
- Use canonical JSON helpers when writing deterministic docs or evidence artifacts.
|
|
386
|
+
- Treat generated schemas as projections of the specs, not as the source of truth.
|
|
387
|
+
|
|
388
|
+
## Extension Guidance
|
|
389
|
+
|
|
390
|
+
- Depend on `tigrbl-core` when you need spec classes, op collection, schema generation, or config resolution without concrete app/router/runtime imports.
|
|
391
|
+
- Keep specs serializable and deterministic. Do not attach live database sessions, request objects, or transport handles to core specs.
|
|
392
|
+
- Validate protocol and binding assumptions in core or kernel-facing tests before adding runtime behavior.
|
|
393
|
+
- Keep application-facing convenience APIs in `tigrbl` or `tigrbl-concrete`; keep cross-package contracts here.
|
|
394
|
+
|
|
395
|
+
Authoring BCP for this boundary:
|
|
396
|
+
- Do treat `ColumnSpec`, `FieldSpec`, `OpSpec`, `HookSpec`, `SchemaSpec`, `BindingSpec`, `EngineSpec`, `SessionSpec`, and related specs as the contract vocabulary that other Tigrbl packages consume.
|
|
397
|
+
- Do keep specs independent of FastAPI, Starlette, SQLAlchemy sessions, live request objects, and transport handles.
|
|
398
|
+
- Do not move application route authoring, direct database calls, concrete engine creation, or runtime dispatch side effects into `tigrbl-core`.
|
|
399
|
+
- Avoid duplicating spec fields in helper classes or generated schemas. Specs should remain the source that schema, docs, kernel, runtime, base, concrete, and facade layers project from.
|
|
400
|
+
|
|
322
401
|
## Usage Examples
|
|
323
402
|
|
|
324
403
|
### Verify the installed package
|
|
@@ -379,6 +458,8 @@ Choose `tigrbl-core` when the quick-answer table matches your use case. Choose [
|
|
|
379
458
|
- [Package layout](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_LAYOUT.md)
|
|
380
459
|
- [Current target](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_TARGET.md)
|
|
381
460
|
- [Current state](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_STATE.md)
|
|
461
|
+
- [Next steps](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/NEXT_STEPS.md)
|
|
462
|
+
- [Documentation pointers](https://github.com/tigrbl/tigrbl/blob/master/docs/governance/DOC_POINTERS.md)
|
|
382
463
|
- [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json)
|
|
383
464
|
- [Release workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml)
|
|
384
465
|
|
|
@@ -390,7 +471,7 @@ Choose `tigrbl-core` when the quick-answer table matches your use case. Choose [
|
|
|
390
471
|
|
|
391
472
|
## Package-local Boundary
|
|
392
473
|
|
|
393
|
-
This README is the package-local distribution entry point for `tigrbl-core`. It answers install, usage, API, ownership, and certification-orientation questions for this package. Broader architectural decisions, release status, and cross-package proof chains remain in the repository-level docs and SSOT registry.
|
|
474
|
+
This file is a package-local distribution entry point. This README is the package-local distribution entry point for `tigrbl-core`. It answers install, usage, API, ownership, and certification-orientation questions for this package. Broader architectural decisions, release status, and cross-package proof chains remain in the repository-level docs and SSOT registry.
|
|
394
475
|
|
|
395
476
|
## License
|
|
396
477
|
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>tigrbl-core</h1>
|
|
3
|
+
<img src="https://raw.githubusercontent.com/swarmauri/swarmauri-sdk/master/assets/tigrbl_full_logo.png" alt="Tigrbl logo" width="140"/>
|
|
4
|
+
<p><strong>Core Tigrbl framework specifications, decorators, schemas, hooks, operations, and primitives for schema-first APIs.</strong></p>
|
|
5
|
+
<a href="https://pypi.org/project/tigrbl-core/"><img src="https://img.shields.io/pypi/v/tigrbl-core?label=PyPI" alt="PyPI version for tigrbl-core"/></a>
|
|
6
|
+
<a href="https://pypi.org/project/tigrbl-core/"><img src="https://static.pepy.tech/badge/tigrbl-core" alt="Downloads for tigrbl-core"/></a>
|
|
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-core"/></a>
|
|
8
|
+
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_core/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/core/tigrbl_core/README.md.svg?label=hits" alt="Repository hits for tigrbl-core README"/></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
|
|
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-core"/></a>
|
|
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-core"/></a>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
## What is tigrbl-core?
|
|
15
|
+
|
|
16
|
+
Core Tigrbl framework specifications, decorators, schemas, hooks, operations, and primitives for schema-first APIs.
|
|
17
|
+
|
|
18
|
+
## Why use tigrbl-core?
|
|
19
|
+
|
|
20
|
+
Use it when you need this foundational Tigrbl layer directly as a small, focused dependency.
|
|
21
|
+
|
|
22
|
+
## When should I install tigrbl-core?
|
|
23
|
+
|
|
24
|
+
Install it for extension packages, package-local tests, or internals that need this boundary without the whole facade.
|
|
25
|
+
|
|
26
|
+
## Who is tigrbl-core for?
|
|
27
|
+
|
|
28
|
+
Framework maintainers, extension authors, and advanced users composing Tigrbl from split packages.
|
|
29
|
+
|
|
30
|
+
## Where does tigrbl-core fit?
|
|
31
|
+
|
|
32
|
+
`tigrbl-core` lives at `pkgs/core/tigrbl_core` and serves a focused layer in the split Tigrbl framework.
|
|
33
|
+
|
|
34
|
+
## How does tigrbl-core work?
|
|
35
|
+
|
|
36
|
+
It owns a narrow layer in the split workspace and is consumed by higher-level packages through explicit dependencies.
|
|
37
|
+
|
|
38
|
+
## Certification Status
|
|
39
|
+
|
|
40
|
+
- Package status: governed package in the `tigrbl/tigrbl` workspace.
|
|
41
|
+
- Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
|
|
42
|
+
- 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.
|
|
43
|
+
- Local certification guard: `pkgs/core/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`.
|
|
44
|
+
- Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv add tigrbl-core
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install tigrbl-core
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Surface Coverage
|
|
57
|
+
|
|
58
|
+
| Surface | Value |
|
|
59
|
+
|---|---|
|
|
60
|
+
| PyPI package | [`tigrbl-core`](https://pypi.org/project/tigrbl-core/) |
|
|
61
|
+
| Repository path | [`pkgs/core/tigrbl_core`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_core) |
|
|
62
|
+
| Python import root | `tigrbl_core` |
|
|
63
|
+
| Console scripts | none declared |
|
|
64
|
+
| Entry points | none declared |
|
|
65
|
+
| Optional extras | none declared |
|
|
66
|
+
| Legal files | `LICENSE`, `NOTICE` |
|
|
67
|
+
| Supported Python | `3.10, 3.11, 3.12, 3.13, 3.14` |
|
|
68
|
+
|
|
69
|
+
## What It Owns
|
|
70
|
+
|
|
71
|
+
`tigrbl-core` owns the `foundational framework package` boundary. It should be installed when you need this package's focused responsibility without assuming every other Tigrbl workspace package is present.
|
|
72
|
+
|
|
73
|
+
Implementation orientation:
|
|
74
|
+
- `tigrbl_core`: _spec/, canonical_json, config/, core/, op/, schema/
|
|
75
|
+
|
|
76
|
+
Package catalog:
|
|
77
|
+
- `tigrbl_core/_spec/`: typed, serializable specifications for aliases, apps, bindings, columns, data types, docs, engines, fields, hooks, IO, middleware, operations, paths, requests, responses, routers, schemas, sessions, storage, tables, and table registries.
|
|
78
|
+
- `tigrbl_core/config/`: constants, defaults, resolver logic, and engine traversal helpers used when app, router, table, column, op, and request layers are merged.
|
|
79
|
+
- `tigrbl_core/op/`: canonical operation names, operation collection, and operation typing helpers.
|
|
80
|
+
- `tigrbl_core/schema/`: dynamic schema construction, schema cache helpers, extras handling, list-parameter support, schema JSON helpers, and `get_schema` access.
|
|
81
|
+
- `tigrbl_core/canonical_json.py`: deterministic JSON output used by docs, registry-like payloads, tests, and conformance artifacts.
|
|
82
|
+
|
|
83
|
+
## Public API and Import Surface
|
|
84
|
+
|
|
85
|
+
- Import roots: `tigrbl_core`.
|
|
86
|
+
- Public symbols: public surface is module-oriented; import the package boundary and inspect submodules as needed.
|
|
87
|
+
- Workspace dependencies: [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/).
|
|
88
|
+
- External runtime dependencies: `pydantic>=2.10,<3`, `pyyaml`, `tomli-w`, `tomli>=2.0.1; python_version < '3.11'`.
|
|
89
|
+
|
|
90
|
+
## Specification Model
|
|
91
|
+
|
|
92
|
+
The core package is the contract layer. It defines the vocabulary consumed by base abstractions, concrete adapters, atoms, kernel planning, runtime routing, docs generation, and the public facade. Most application code should not construct these specs manually; application code should normally use facade decorators and shortcuts. Extension packages use the specs when they need deterministic, testable configuration objects.
|
|
93
|
+
|
|
94
|
+
| Spec family | What it describes |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `AppSpec`, `RouterSpec`, `TableSpec` | Container-level framework configuration and inheritance points. |
|
|
97
|
+
| `ColumnSpec`, `FieldSpec`, data type specs | Field semantics, validation, storage, schema projection, and data-type lowering. |
|
|
98
|
+
| `OpSpec` and op utilities | Operation name, alias, arity, binding, handler, schema, hook, response, and runtime intent. |
|
|
99
|
+
| `HookSpec` and hook types | Hook targets, phases, predicates, ordering, and callable registration shape. |
|
|
100
|
+
| `SchemaSpec`, `RequestSpec`, `ResponseSpec`, `IoSpec` | Input/output envelope behavior, request extraction, response shaping, and Pydantic model generation. |
|
|
101
|
+
| `BindingSpec` | REST, JSON-RPC, stream, SSE, WebSocket, WSS, and WebTransport binding metadata. |
|
|
102
|
+
| `EngineSpec`, `SessionSpec`, `StorageSpec` | Engine/provider/session/storage configuration without importing concrete engine implementations. |
|
|
103
|
+
| `DocsSpec`, `PathSpec`, `MiddlewareSpec` | Documentation projection, route paths, and middleware configuration. |
|
|
104
|
+
|
|
105
|
+
## Operation Semantics
|
|
106
|
+
|
|
107
|
+
`tigrbl_core.op.canonical.DEFAULT_CANON_VERBS` is the default CRUD set:
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
create, read, update, replace, delete, list, clear
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Tables can change canonical wiring through mode/include/exclude attributes or a `should_wire_canonical(op)` helper. Core only decides whether an operation is part of the desired specification. Concrete packages and operation packs supply the actual handlers and routing behavior.
|
|
114
|
+
|
|
115
|
+
Use this package when you need to inspect or build operation specs before runtime compilation. Use `tigrbl` when you simply want a working app surface.
|
|
116
|
+
|
|
117
|
+
## Binding and Transport Semantics
|
|
118
|
+
|
|
119
|
+
`BindingSpec` keeps four concerns distinct:
|
|
120
|
+
|
|
121
|
+
- protocol or binding kind, such as HTTP REST, HTTP JSON-RPC, HTTP stream, SSE, WebSocket, WSS, or WebTransport;
|
|
122
|
+
- exchange shape, such as request/response, server stream, bidirectional stream, client stream, server stream, session, or datagram;
|
|
123
|
+
- framing, such as JSON, JSON-RPC, SSE, WebSocket text, stream framing, or WebTransport outer framing;
|
|
124
|
+
- runtime lane metadata, especially for WebTransport session, stream, and datagram behavior.
|
|
125
|
+
|
|
126
|
+
This separation is deliberate. Extension authors should not collapse protocol support into a single string or infer framing from the transport name. Invalid combinations should remain explicit validation failures so runtime behavior is fail-closed.
|
|
127
|
+
|
|
128
|
+
## Configuration Precedence
|
|
129
|
+
|
|
130
|
+
Core resolvers use this precedence pattern:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
request override > operation spec > column spec > table spec > router spec > app spec > defaults
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The most specific layer wins. Keep default policy broad, then narrow behavior by table, column, and operation. Avoid hidden mutation of spec objects after a runtime plan has been compiled; build a fresh spec or invalidate the relevant cache when behavior truly changes.
|
|
137
|
+
|
|
138
|
+
## Schema Construction
|
|
139
|
+
|
|
140
|
+
Schema helpers build operation-specific request and response models from table metadata, column specs, request/response extras, list-parameter rules, and op-level configuration. `get_schema(...)` is the stable way to retrieve the generated model for a table operation and direction. Prefer it over hand-writing duplicate Pydantic envelopes when data belongs to a Tigrbl operation.
|
|
141
|
+
|
|
142
|
+
Best practices for schema work:
|
|
143
|
+
- Keep storage fields, wire fields, and virtual extras separate.
|
|
144
|
+
- Put reusable schema behavior in table or column specs; reserve op specs for operation-specific differences.
|
|
145
|
+
- Use canonical JSON helpers when writing deterministic docs or evidence artifacts.
|
|
146
|
+
- Treat generated schemas as projections of the specs, not as the source of truth.
|
|
147
|
+
|
|
148
|
+
## Extension Guidance
|
|
149
|
+
|
|
150
|
+
- Depend on `tigrbl-core` when you need spec classes, op collection, schema generation, or config resolution without concrete app/router/runtime imports.
|
|
151
|
+
- Keep specs serializable and deterministic. Do not attach live database sessions, request objects, or transport handles to core specs.
|
|
152
|
+
- Validate protocol and binding assumptions in core or kernel-facing tests before adding runtime behavior.
|
|
153
|
+
- Keep application-facing convenience APIs in `tigrbl` or `tigrbl-concrete`; keep cross-package contracts here.
|
|
154
|
+
|
|
155
|
+
Authoring BCP for this boundary:
|
|
156
|
+
- Do treat `ColumnSpec`, `FieldSpec`, `OpSpec`, `HookSpec`, `SchemaSpec`, `BindingSpec`, `EngineSpec`, `SessionSpec`, and related specs as the contract vocabulary that other Tigrbl packages consume.
|
|
157
|
+
- Do keep specs independent of FastAPI, Starlette, SQLAlchemy sessions, live request objects, and transport handles.
|
|
158
|
+
- Do not move application route authoring, direct database calls, concrete engine creation, or runtime dispatch side effects into `tigrbl-core`.
|
|
159
|
+
- Avoid duplicating spec fields in helper classes or generated schemas. Specs should remain the source that schema, docs, kernel, runtime, base, concrete, and facade layers project from.
|
|
160
|
+
|
|
161
|
+
## Usage Examples
|
|
162
|
+
|
|
163
|
+
### Verify the installed package
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python -m pip show tigrbl-core
|
|
167
|
+
python - <<'PY'
|
|
168
|
+
from importlib.metadata import version
|
|
169
|
+
print(version("tigrbl-core"))
|
|
170
|
+
PY
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Import the package boundary
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
import importlib
|
|
177
|
+
|
|
178
|
+
module = importlib.import_module("tigrbl_core._spec")
|
|
179
|
+
print(module.__name__)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Inspect available modules
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
import importlib
|
|
186
|
+
import pkgutil
|
|
187
|
+
|
|
188
|
+
module = importlib.import_module("tigrbl_core._spec")
|
|
189
|
+
for info in pkgutil.iter_modules(getattr(module, "__path__", [])):
|
|
190
|
+
print(info.name)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Use with the facade when building applications
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
uv add tigrbl tigrbl-core
|
|
197
|
+
python - <<'PY'
|
|
198
|
+
import tigrbl
|
|
199
|
+
print(tigrbl.__name__)
|
|
200
|
+
PY
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## How To Choose This Package
|
|
204
|
+
|
|
205
|
+
Choose `tigrbl-core` when the quick-answer table matches your use case. Choose [`tigrbl`](https://pypi.org/project/tigrbl/) instead when you want the full public facade. Choose a lower-level package such as [`tigrbl-core`](https://pypi.org/project/tigrbl-core/), [`tigrbl-base`](https://pypi.org/project/tigrbl-base/), or [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/) when you are building framework extensions or testing a specific internal boundary.
|
|
206
|
+
|
|
207
|
+
## Related Packages
|
|
208
|
+
|
|
209
|
+
- [`tigrbl-typing`](https://pypi.org/project/tigrbl-typing/)
|
|
210
|
+
- [`tigrbl`](https://pypi.org/project/tigrbl/)
|
|
211
|
+
- [`tigrbl-base`](https://pypi.org/project/tigrbl-base/)
|
|
212
|
+
- [`tigrbl-runtime`](https://pypi.org/project/tigrbl-runtime/)
|
|
213
|
+
|
|
214
|
+
## Documentation Links
|
|
215
|
+
|
|
216
|
+
- [Workspace docs](https://github.com/tigrbl/tigrbl/blob/master/docs/README.md)
|
|
217
|
+
- [Package catalog](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_CATALOG.md)
|
|
218
|
+
- [Package layout](https://github.com/tigrbl/tigrbl/blob/master/docs/developer/PACKAGE_LAYOUT.md)
|
|
219
|
+
- [Current target](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_TARGET.md)
|
|
220
|
+
- [Current state](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/CURRENT_STATE.md)
|
|
221
|
+
- [Next steps](https://github.com/tigrbl/tigrbl/blob/master/docs/conformance/NEXT_STEPS.md)
|
|
222
|
+
- [Documentation pointers](https://github.com/tigrbl/tigrbl/blob/master/docs/governance/DOC_POINTERS.md)
|
|
223
|
+
- [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json)
|
|
224
|
+
- [Release workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml)
|
|
225
|
+
|
|
226
|
+
## Support
|
|
227
|
+
|
|
228
|
+
- Community: [Discord](https://discord.gg/K4YTAPapjR).
|
|
229
|
+
- Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
|
|
230
|
+
- Repository: [pkgs/core/tigrbl_core](https://github.com/tigrbl/tigrbl/tree/master/pkgs/core/tigrbl_core).
|
|
231
|
+
|
|
232
|
+
## Package-local Boundary
|
|
233
|
+
|
|
234
|
+
This file is a package-local distribution entry point. This README is the package-local distribution entry point for `tigrbl-core`. It answers install, usage, API, ownership, and certification-orientation questions for this package. Broader architectural decisions, release status, and cross-package proof chains remain in the repository-level docs and SSOT registry.
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
Licensed under the Apache License, Version 2.0. See `LICENSE`, `NOTICE`, and the official [Apache 2.0 license text](https://www.apache.org/licenses/LICENSE-2.0).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tigrbl-core"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.3.dev4"
|
|
4
4
|
description = "Core Tigrbl framework specifications, decorators, schemas, hooks, operations, and primitives for schema-first APIs."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { file = "LICENSE" }
|
|
@@ -42,6 +42,7 @@ requires-python = ">=3.10,<3.15"
|
|
|
42
42
|
authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
43
43
|
|
|
44
44
|
dependencies = [
|
|
45
|
+
"tigrbl_spec",
|
|
45
46
|
"tigrbl-typing",
|
|
46
47
|
"pydantic>=2.10,<3",
|
|
47
48
|
"pyyaml",
|
|
@@ -59,6 +60,7 @@ Issues = "https://github.com/tigrbl/tigrbl/issues"
|
|
|
59
60
|
|
|
60
61
|
[tool.uv.sources]
|
|
61
62
|
"tigrbl-typing" = { workspace = true }
|
|
63
|
+
"tigrbl_spec" = { workspace = true }
|
|
62
64
|
|
|
63
65
|
[build-system]
|
|
64
66
|
requires = ["poetry-core>=1.0.0"]
|
|
@@ -29,6 +29,8 @@ _EXPORTS = {
|
|
|
29
29
|
"HttpStreamBindingSpec": "binding_spec",
|
|
30
30
|
"SseBindingSpec": "binding_spec",
|
|
31
31
|
"WebTransportBindingSpec": "binding_spec",
|
|
32
|
+
"WELL_KNOWN_PREFIX": "well_known_spec",
|
|
33
|
+
"WellKnownResourceSpec": "well_known_spec",
|
|
32
34
|
"WsBindingSpec": "binding_spec",
|
|
33
35
|
"resolve_rest_nested_prefix": "binding_spec",
|
|
34
36
|
"ColumnSpec": "column_spec",
|
|
@@ -80,6 +82,8 @@ _EXPORTS = {
|
|
|
80
82
|
"validate_app_framing_for_binding": "binding_spec",
|
|
81
83
|
"validate_binding_profile_exchange": "binding_spec",
|
|
82
84
|
"validate_path_binding": "path_spec",
|
|
85
|
+
"normalize_well_known_name": "well_known_spec",
|
|
86
|
+
"well_known_path": "well_known_spec",
|
|
83
87
|
"PHASE": "op_spec",
|
|
84
88
|
"PHASES": "op_spec",
|
|
85
89
|
"HookPhase": "hook_spec",
|
|
@@ -106,7 +110,39 @@ _EXPORTS = {
|
|
|
106
110
|
"TypeAdapter": "datatypes",
|
|
107
111
|
"TypeRegistry": "datatypes",
|
|
108
112
|
"TableSpec": "table_spec",
|
|
113
|
+
"BindingToken": "table_profile_bindings",
|
|
114
|
+
"LoweredBinding": "table_profile_bindings",
|
|
115
|
+
"lower_binding_tokens_for_ops": "table_profile_bindings",
|
|
116
|
+
"lower_default_bindings_for_op": "table_profile_bindings",
|
|
117
|
+
"lower_table_profile_bindings": "table_profile_bindings",
|
|
118
|
+
"TableProfileSpec": "table_profile_spec",
|
|
119
|
+
"BuiltinTableProfile": "table_profile_spec",
|
|
120
|
+
"BUILTIN_TABLE_PROFILE_DEFINITIONS": "table_profile_spec",
|
|
121
|
+
"BUILTIN_TABLE_PROFILE_KINDS": "table_profile_spec",
|
|
122
|
+
"TableProfileError": "table_profile_spec",
|
|
123
|
+
"TableProfileBindingFamily": "table_profile_spec",
|
|
124
|
+
"TableProfileRole": "table_profile_spec",
|
|
125
|
+
"PLAIN_TABLE_PROFILE": "table_profile_spec",
|
|
126
|
+
"CRUD_TABLE_PROFILE": "table_profile_spec",
|
|
127
|
+
"REALTIME_TABLE_PROFILE": "table_profile_spec",
|
|
128
|
+
"coerce_table_profile": "table_profile_spec",
|
|
129
|
+
"get_builtin_table_profile_definition": "table_profile_spec",
|
|
130
|
+
"get_table_profile": "table_profile_spec",
|
|
131
|
+
"iter_builtin_table_profile_definitions": "table_profile_spec",
|
|
132
|
+
"make_builtin_table_profile": "table_profile_spec",
|
|
133
|
+
"register_table_profile": "table_profile_spec",
|
|
109
134
|
"TableRegistrySpec": "table_registry_spec",
|
|
135
|
+
"BINDING_STACK_PROJECTIONS": "transport_stack",
|
|
136
|
+
"BindingStackError": "transport_stack",
|
|
137
|
+
"BindingStackProjection": "transport_stack",
|
|
138
|
+
"binding_stack_maturity": "transport_stack",
|
|
139
|
+
"classify_binding_stack": "transport_stack",
|
|
140
|
+
"compose_h3_binding_projections": "transport_stack",
|
|
141
|
+
"require_binding_stack": "transport_stack",
|
|
142
|
+
"ExposureDecision": "exposure_policy",
|
|
143
|
+
"ExposurePolicyError": "exposure_policy",
|
|
144
|
+
"exposed_surfaces": "exposure_policy",
|
|
145
|
+
"resolve_exposure_policy": "exposure_policy",
|
|
110
146
|
}
|
|
111
147
|
|
|
112
148
|
__all__ = list(_EXPORTS)
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import Any, Callable, Optional, Sequence
|
|
5
|
+
import warnings
|
|
5
6
|
|
|
6
7
|
from .._spec.engine_spec import EngineCfg, EngineSpec
|
|
7
8
|
from .._spec.monotone import as_tuple, merge_mro_sequence_attr
|
|
8
9
|
from .._spec.response_spec import ResponseSpec
|
|
10
|
+
from .._spec.well_known_spec import WellKnownResourceSpec
|
|
9
11
|
from .serde import SerdeMixin
|
|
10
12
|
|
|
11
13
|
|
|
@@ -45,12 +47,15 @@ def normalize_app_spec(spec: "AppSpec") -> "AppSpec":
|
|
|
45
47
|
title=str(spec.title or "Tigrbl"),
|
|
46
48
|
description=spec.description,
|
|
47
49
|
version=str(spec.version or "0.1.0"),
|
|
48
|
-
execution_backend=
|
|
50
|
+
execution_backend=normalize_execution_backend(
|
|
51
|
+
getattr(spec, "execution_backend", None),
|
|
52
|
+
),
|
|
49
53
|
engine=spec.engine,
|
|
50
54
|
engine_name=spec.engine_name,
|
|
51
55
|
engines=_seqify(spec.engines),
|
|
52
56
|
routers=routers,
|
|
53
57
|
ops=ops,
|
|
58
|
+
well_known=_seqify(spec.well_known),
|
|
54
59
|
tables=tables,
|
|
55
60
|
schemas=_seqify(spec.schemas),
|
|
56
61
|
hooks=_seqify(spec.hooks),
|
|
@@ -64,6 +69,23 @@ def normalize_app_spec(spec: "AppSpec") -> "AppSpec":
|
|
|
64
69
|
)
|
|
65
70
|
|
|
66
71
|
|
|
72
|
+
def normalize_execution_backend(value: Any) -> str:
|
|
73
|
+
lowered = str(value or "auto").strip().lower()
|
|
74
|
+
if not lowered:
|
|
75
|
+
return "auto"
|
|
76
|
+
if lowered == "rust":
|
|
77
|
+
warnings.warn(
|
|
78
|
+
"AppSpec.execution_backend='rust' is deprecated; "
|
|
79
|
+
"Tigrbl runtime execution is Python-only.",
|
|
80
|
+
DeprecationWarning,
|
|
81
|
+
stacklevel=2,
|
|
82
|
+
)
|
|
83
|
+
return "python"
|
|
84
|
+
if lowered in {"auto", "python"}:
|
|
85
|
+
return lowered
|
|
86
|
+
raise ValueError(f"unsupported execution backend: {value!r}")
|
|
87
|
+
|
|
88
|
+
|
|
67
89
|
@dataclass(eq=False)
|
|
68
90
|
class AppSpec(SerdeMixin):
|
|
69
91
|
"""
|
|
@@ -83,6 +105,7 @@ class AppSpec(SerdeMixin):
|
|
|
83
105
|
|
|
84
106
|
# NEW: orchestration/topology knobs
|
|
85
107
|
ops: Sequence[Any] = field(default_factory=tuple) # op descriptors or specs
|
|
108
|
+
well_known: Sequence[WellKnownResourceSpec] = field(default_factory=tuple)
|
|
86
109
|
tables: Sequence[Any] = field(default_factory=tuple) # table refs owned by app
|
|
87
110
|
schemas: Sequence[Any] = field(default_factory=tuple) # schema classes/defs
|
|
88
111
|
hooks: Sequence[Callable[..., Any]] = field(default_factory=tuple)
|
|
@@ -103,9 +126,11 @@ class AppSpec(SerdeMixin):
|
|
|
103
126
|
lifespan: Optional[Callable[..., Any]] = None
|
|
104
127
|
|
|
105
128
|
def __post_init__(self) -> None:
|
|
129
|
+
self.execution_backend = normalize_execution_backend(self.execution_backend)
|
|
106
130
|
self.engines = _seqify(self.engines)
|
|
107
131
|
self.routers = _seqify(self.routers)
|
|
108
132
|
self.ops = _seqify(self.ops)
|
|
133
|
+
self.well_known = _seqify(self.well_known)
|
|
109
134
|
self.tables = _seqify(self.tables)
|
|
110
135
|
self.schemas = _seqify(self.schemas)
|
|
111
136
|
self.hooks = _seqify(self.hooks)
|
|
@@ -113,6 +138,14 @@ class AppSpec(SerdeMixin):
|
|
|
113
138
|
self.deps = _seqify(self.deps)
|
|
114
139
|
self.middlewares = _seqify(self.middlewares)
|
|
115
140
|
|
|
141
|
+
for resource in self.well_known:
|
|
142
|
+
if isinstance(resource, str):
|
|
143
|
+
raise TypeError("AppSpec.well_known entries must be nested specs, not strings.")
|
|
144
|
+
if not isinstance(resource, WellKnownResourceSpec):
|
|
145
|
+
raise TypeError(
|
|
146
|
+
"AppSpec.well_known entries must be WellKnownResourceSpec; "
|
|
147
|
+
f"got {type(resource).__name__}."
|
|
148
|
+
)
|
|
116
149
|
validate_engine_inventory(self.engines)
|
|
117
150
|
validate_engine_name_binding(
|
|
118
151
|
self.engine_name,
|
|
@@ -172,6 +205,8 @@ class AppSpec(SerdeMixin):
|
|
|
172
205
|
|
|
173
206
|
@classmethod
|
|
174
207
|
def from_dict(cls, payload: dict[str, Any]) -> "AppSpec":
|
|
208
|
+
if "routes" in payload:
|
|
209
|
+
raise ValueError("AppSpec does not accept 'routes'; use path-owned specs.")
|
|
175
210
|
return super().from_dict(payload)
|
|
176
211
|
|
|
177
212
|
@classmethod
|
|
@@ -255,6 +290,7 @@ class AppSpec(SerdeMixin):
|
|
|
255
290
|
or ()
|
|
256
291
|
),
|
|
257
292
|
ops=tuple(merge_seq_attr(app, "OPS") or ()),
|
|
293
|
+
well_known=tuple(merge_seq_attr(app, "WELL_KNOWN") or ()),
|
|
258
294
|
tables=tuple(merge_seq_attr(app, "TABLES") or ()),
|
|
259
295
|
schemas=tuple(merge_seq_attr(app, "SCHEMAS") or ()),
|
|
260
296
|
hooks=tuple(merge_seq_attr(app, "HOOKS") or ()),
|
|
@@ -277,6 +313,7 @@ class AppSpec(SerdeMixin):
|
|
|
277
313
|
engines=tuple(spec.engines or ()),
|
|
278
314
|
routers=tuple(spec.routers or ()),
|
|
279
315
|
ops=tuple(spec.ops or ()),
|
|
316
|
+
well_known=tuple(spec.well_known or ()),
|
|
280
317
|
tables=tuple(spec.tables or ()),
|
|
281
318
|
schemas=tuple(spec.schemas or ()),
|
|
282
319
|
hooks=tuple(spec.hooks or ()),
|