tigrbl-concrete 0.1.0.dev5__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_concrete-0.1.0.dev5/PKG-INFO +79 -0
- tigrbl_concrete-0.1.0.dev5/README.md +49 -0
- tigrbl_concrete-0.1.0.dev5/pyproject.toml +59 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/__init__.py +67 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/__init__.py +59 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_alias.py +10 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_allow_anon.py +42 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_app.py +212 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_background.py +29 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_binding.py +14 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_body.py +27 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_column.py +10 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_cors_middleware.py +103 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_engine.py +267 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_file_response.py +26 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_headers.py +142 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_hook.py +12 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_html_response.py +18 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_httpx.py +25 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_json_response.py +24 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_middleware.py +45 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_op.py +31 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_op_registry.py +301 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_plain_text_response.py +18 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_redirect_response.py +19 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_request.py +270 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_request_adapters.py +68 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_response.py +359 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_route.py +122 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_router.py +273 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_routing.py +141 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_schema.py +28 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_security/__init__.py +7 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_security/api_key.py +57 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_security/http_bearer.py +74 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_security/mutual_tls.py +27 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_security/oauth2.py +28 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_security/openid_connect.py +31 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_session.py +124 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_storage.py +18 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_streaming_response.py +35 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_table.py +108 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/_table_registry.py +10 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/dependencies.py +21 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/engine_resolver.py +400 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/tigrbl_app.py +972 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_concrete/tigrbl_router.py +428 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/__init__.py +52 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/allow_anon.py +5 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/engine.py +110 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/hook.py +40 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/middlewares.py +32 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/op.py +257 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/response.py +45 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/rest.py +30 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/router.py +115 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/schema.py +96 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_decorators/session.py +43 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/__init__.py +1 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/column_mro_collect.py +3 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/core_resolver.py +95 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/model.py +861 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/model_helpers.py +151 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/op_resolver.py +3 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/rest/__init__.py +1 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/rest/helpers.py +11 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/router/__init__.py +1 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/router/common.py +78 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/router/include.py +475 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/router/resource_proxy.py +121 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/router/rpc.py +423 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/_mapping/rpc.py +11 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/ddl/__init__.py +411 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/decorators.py +45 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/__init__.py +179 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/bind.py +53 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/builders.py +250 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/capabilities.py +28 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/collect.py +11 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/plugins.py +15 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/registry.py +15 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/engine/resolver.py +8 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/resolve/__init__.py +3 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/resolve/handlers.py +58 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/security/__init__.py +5 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/security/dependencies.py +5 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/shortcuts/__init__.py +3 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/shortcuts/app.py +67 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/__init__.py +98 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/__init__.py +26 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/healthz.py +70 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/hookz.py +50 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/kernelz.py +57 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/methodz.py +43 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/router.py +217 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/diagnostics/utils.py +63 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/__init__.py +63 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/lens.py +109 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/openapi/__init__.py +34 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/openapi/helpers.py +223 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/openapi/metadata.py +21 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/openapi/mount.py +47 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/openapi/schema.py +188 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/openrpc.py +272 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/runtime_ops.py +164 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/docs/swagger.py +87 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/favicon/__init__.py +203 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/favicon/assets/favicon.svg +4 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/system/uvicorn.py +60 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/transport/__init__.py +3 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/transport/jsonrpc/__init__.py +2 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/transport/jsonrpc/helpers.py +56 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/transport/jsonrpc/models.py +41 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/transport/rest/__init__.py +30 -0
- tigrbl_concrete-0.1.0.dev5/tigrbl_concrete/transport/rest/aggregator.py +118 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tigrbl-concrete
|
|
3
|
+
Version: 0.1.0.dev5
|
|
4
|
+
Summary: Concrete implementations of Tigrbl base abstractions.
|
|
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.13
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Development Status :: 1 - Planning
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Requires-Dist: orjson
|
|
19
|
+
Requires-Dist: pydantic (>=2.0)
|
|
20
|
+
Requires-Dist: sqlalchemy
|
|
21
|
+
Requires-Dist: tigrbl-atoms
|
|
22
|
+
Requires-Dist: tigrbl-base
|
|
23
|
+
Requires-Dist: tigrbl-core
|
|
24
|
+
Requires-Dist: tigrbl-ops-oltp
|
|
25
|
+
Requires-Dist: tigrbl-runtime
|
|
26
|
+
Requires-Dist: tigrbl-typing
|
|
27
|
+
Requires-Dist: uvicorn
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
# tigrbl-concrete
|
|
33
|
+
|
|
34
|
+
    
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- Modular package in the Tigrbl namespace.
|
|
39
|
+
- Supports Python 3.10 through 3.12.
|
|
40
|
+
- Distributed as part of the swarmauri-sdk workspace.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### uv
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv add tigrbl-concrete
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### pip
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install tigrbl-concrete
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
Import from the shared package-specific module namespaces after installation in your environment.
|
|
59
|
+
|
|
60
|
+
### Runtime-visible operation metadata
|
|
61
|
+
|
|
62
|
+
Runtime-visible operations are defined by collected specs (`RouterSpec.collect(...)`,
|
|
63
|
+
`OpSpec.collect(...)`) and then installed through binding on the live graph.
|
|
64
|
+
Mounted routes are not backfilled into runtime metadata after the fact.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from tigrbl_concrete import TigrblApp, TigrblRouter
|
|
68
|
+
|
|
69
|
+
app = TigrblApp()
|
|
70
|
+
router = TigrblRouter()
|
|
71
|
+
|
|
72
|
+
@router.get("/health")
|
|
73
|
+
def health_check():
|
|
74
|
+
return {"ok": True}
|
|
75
|
+
|
|
76
|
+
# include_router(...) mounts already-bound operations
|
|
77
|
+
app.include_router(router, prefix="/api")
|
|
78
|
+
```
|
|
79
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# tigrbl-concrete
|
|
4
|
+
|
|
5
|
+
    
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Modular package in the Tigrbl namespace.
|
|
10
|
+
- Supports Python 3.10 through 3.12.
|
|
11
|
+
- Distributed as part of the swarmauri-sdk workspace.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### uv
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv add tigrbl-concrete
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### pip
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install tigrbl-concrete
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Import from the shared package-specific module namespaces after installation in your environment.
|
|
30
|
+
|
|
31
|
+
### Runtime-visible operation metadata
|
|
32
|
+
|
|
33
|
+
Runtime-visible operations are defined by collected specs (`RouterSpec.collect(...)`,
|
|
34
|
+
`OpSpec.collect(...)`) and then installed through binding on the live graph.
|
|
35
|
+
Mounted routes are not backfilled into runtime metadata after the fact.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from tigrbl_concrete import TigrblApp, TigrblRouter
|
|
39
|
+
|
|
40
|
+
app = TigrblApp()
|
|
41
|
+
router = TigrblRouter()
|
|
42
|
+
|
|
43
|
+
@router.get("/health")
|
|
44
|
+
def health_check():
|
|
45
|
+
return {"ok": True}
|
|
46
|
+
|
|
47
|
+
# include_router(...) mounts already-bound operations
|
|
48
|
+
app.include_router(router, prefix="/api")
|
|
49
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tigrbl-concrete"
|
|
3
|
+
version = "0.1.0.dev5"
|
|
4
|
+
description = "Concrete implementations of Tigrbl base abstractions."
|
|
5
|
+
license = "Apache-2.0"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
repository = "http://github.com/swarmauri/swarmauri-sdk"
|
|
8
|
+
requires-python = ">=3.10,<3.13"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"License :: OSI Approved :: Apache Software License",
|
|
11
|
+
"Development Status :: 1 - Planning",
|
|
12
|
+
"Programming Language :: Python :: 3.10",
|
|
13
|
+
"Programming Language :: Python :: 3.11",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"Programming Language :: Python",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
]
|
|
19
|
+
authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"orjson",
|
|
22
|
+
"pydantic>=2.0",
|
|
23
|
+
"sqlalchemy",
|
|
24
|
+
"tigrbl-atoms",
|
|
25
|
+
"tigrbl-base",
|
|
26
|
+
"tigrbl-core",
|
|
27
|
+
"tigrbl-ops-oltp",
|
|
28
|
+
"tigrbl-runtime",
|
|
29
|
+
"tigrbl-typing",
|
|
30
|
+
"uvicorn",
|
|
31
|
+
]
|
|
32
|
+
keywords = ["tigrbl", "sdk", "standards", "framework"]
|
|
33
|
+
|
|
34
|
+
[tool.uv.sources]
|
|
35
|
+
"tigrbl-atoms" = { workspace = true }
|
|
36
|
+
"tigrbl-base" = { workspace = true }
|
|
37
|
+
"tigrbl-core" = { workspace = true }
|
|
38
|
+
"tigrbl-ops-oltp" = { workspace = true }
|
|
39
|
+
"tigrbl-runtime" = { workspace = true }
|
|
40
|
+
"tigrbl-typing" = { workspace = true }
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["poetry-core>=1.0.0"]
|
|
44
|
+
build-backend = "poetry.core.masonry.api"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
[tool.poetry]
|
|
48
|
+
packages = [
|
|
49
|
+
{ include = "tigrbl_concrete" },
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[dependency-groups]
|
|
53
|
+
dev = [
|
|
54
|
+
"pytest>=8.0",
|
|
55
|
+
"ruff>=0.9",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.entry-points."tigrbl.engine_plugins"]
|
|
59
|
+
concrete = "tigrbl_concrete.engine.plugins:register"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""tigrbl_concrete compatibility facade.
|
|
2
|
+
|
|
3
|
+
This package provides concrete implementations while preserving legacy
|
|
4
|
+
submodule paths that still live in ``tigrbl``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from importlib import import_module
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
_COMPAT_ALIASES = {
|
|
14
|
+
"ddl": "tigrbl.ddl",
|
|
15
|
+
"system": "tigrbl.system",
|
|
16
|
+
"op": "tigrbl.op",
|
|
17
|
+
"config": "tigrbl.config",
|
|
18
|
+
"schema": "tigrbl.schema",
|
|
19
|
+
"security": "tigrbl.security",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _optional_import(path: str):
|
|
24
|
+
try:
|
|
25
|
+
return import_module(path)
|
|
26
|
+
except ImportError:
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
for alias, target in _COMPAT_ALIASES.items():
|
|
31
|
+
module = _optional_import(target)
|
|
32
|
+
if module is not None:
|
|
33
|
+
sys.modules.setdefault(f"{__name__}.{alias}", module)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build_handlers(*args, **kwargs):
|
|
37
|
+
return import_module("tigrbl_concrete._mapping.model")._materialize_handlers(
|
|
38
|
+
*args, **kwargs
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def build_hooks(*args, **kwargs):
|
|
43
|
+
return import_module("tigrbl_concrete._mapping.model")._bind_model_hooks(
|
|
44
|
+
*args, **kwargs
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def build_schemas(*args, **kwargs):
|
|
49
|
+
return import_module("tigrbl_concrete._mapping.model")._materialize_schemas(
|
|
50
|
+
*args, **kwargs
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def build_rest_router(*args, **kwargs):
|
|
55
|
+
if "router" not in kwargs:
|
|
56
|
+
kwargs["router"] = None
|
|
57
|
+
return import_module("tigrbl_concrete._mapping.model")._materialize_rest_router(
|
|
58
|
+
*args, **kwargs
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
__all__ = [
|
|
63
|
+
"build_handlers",
|
|
64
|
+
"build_hooks",
|
|
65
|
+
"build_schemas",
|
|
66
|
+
"build_rest_router",
|
|
67
|
+
]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Concrete generic class implementations for tigrbl."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib import import_module
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
_EXPORTS = {
|
|
9
|
+
"Alias": "_alias",
|
|
10
|
+
"Binding": "_binding",
|
|
11
|
+
"BindingRegistry": "_binding",
|
|
12
|
+
"App": "_app",
|
|
13
|
+
"Column": "_column",
|
|
14
|
+
"Engine": "_engine",
|
|
15
|
+
"Hook": "_hook",
|
|
16
|
+
"Op": "_op",
|
|
17
|
+
"Route": "_route",
|
|
18
|
+
"Router": "_router",
|
|
19
|
+
"Schema": "_schema",
|
|
20
|
+
"ForeignKey": "_storage",
|
|
21
|
+
"StorageTransform": "_storage",
|
|
22
|
+
"Table": "_table",
|
|
23
|
+
"Template": "_response",
|
|
24
|
+
"TableRegistry": "_table_registry",
|
|
25
|
+
"Response": "_response",
|
|
26
|
+
"TransportResponse": "_response",
|
|
27
|
+
"JSONResponse": "_json_response",
|
|
28
|
+
"HTMLResponse": "_html_response",
|
|
29
|
+
"PlainTextResponse": "_plain_text_response",
|
|
30
|
+
"StreamingResponse": "_streaming_response",
|
|
31
|
+
"DefaultSession": "_session",
|
|
32
|
+
"FileResponse": "_file_response",
|
|
33
|
+
"RedirectResponse": "_redirect_response",
|
|
34
|
+
"Request": "_request",
|
|
35
|
+
"Body": "_body",
|
|
36
|
+
"Depends": "dependencies",
|
|
37
|
+
"APIKey": "_security",
|
|
38
|
+
"HTTPBearer": "_security",
|
|
39
|
+
"OAuth2": "_security",
|
|
40
|
+
"OpenIdConnect": "_security",
|
|
41
|
+
"MutualTLS": "_security",
|
|
42
|
+
"TigrblApp": "tigrbl_app",
|
|
43
|
+
"TigrblRouter": "tigrbl_router",
|
|
44
|
+
"BackgroundTask": "_background",
|
|
45
|
+
"wrap_sessionmaker": "_session",
|
|
46
|
+
"allow_anon": "_allow_anon",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
__all__ = list(_EXPORTS)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def __getattr__(name: str) -> Any:
|
|
53
|
+
module_name = _EXPORTS.get(name)
|
|
54
|
+
if module_name is None:
|
|
55
|
+
raise AttributeError(name)
|
|
56
|
+
module = import_module(f"{__name__}.{module_name}")
|
|
57
|
+
value = getattr(module, name)
|
|
58
|
+
globals()[name] = value
|
|
59
|
+
return value
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Decorator helpers for anonymous route authorization metadata."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from typing import TypeVar
|
|
7
|
+
|
|
8
|
+
from tigrbl_core.config.constants import TIGRBL_ALLOW_ANON_ATTR
|
|
9
|
+
|
|
10
|
+
_TableT = TypeVar("_TableT", bound=type)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _normalize_ops(ops: Iterable[str]) -> tuple[str, ...]:
|
|
14
|
+
normalized = [op.strip() for op in ops if isinstance(op, str) and op.strip()]
|
|
15
|
+
seen: set[str] = set()
|
|
16
|
+
deduped: list[str] = []
|
|
17
|
+
for op in normalized:
|
|
18
|
+
if op not in seen:
|
|
19
|
+
seen.add(op)
|
|
20
|
+
deduped.append(op)
|
|
21
|
+
return tuple(deduped)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def allow_anon(*ops: str):
|
|
25
|
+
"""Attach anonymous-allowed operation names to a table class.
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
@allow_anon("list", "read")
|
|
29
|
+
class Item(TableBase):
|
|
30
|
+
...
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
normalized = _normalize_ops(ops)
|
|
34
|
+
|
|
35
|
+
def _decorator(table_cls: _TableT) -> _TableT:
|
|
36
|
+
setattr(table_cls, TIGRBL_ALLOW_ANON_ATTR, normalized)
|
|
37
|
+
return table_cls
|
|
38
|
+
|
|
39
|
+
return _decorator
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = ["allow_anon"]
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ._table_registry import TableRegistry
|
|
6
|
+
from tigrbl_base._base import AppBase
|
|
7
|
+
from tigrbl_concrete.ddl import initialize as _ddl_initialize
|
|
8
|
+
from ._engine import Engine
|
|
9
|
+
from tigrbl_concrete._concrete import engine_resolver as _resolver
|
|
10
|
+
from tigrbl_core._spec.app_spec import AppSpec
|
|
11
|
+
from tigrbl_core._spec.engine_spec import EngineCfg
|
|
12
|
+
from ._routing import (
|
|
13
|
+
include_router as _include_router_impl,
|
|
14
|
+
merge_tags as _merge_tags_impl,
|
|
15
|
+
normalize_prefix as _normalize_prefix_impl,
|
|
16
|
+
)
|
|
17
|
+
from tigrbl_runtime.runtime import Runtime
|
|
18
|
+
from tigrbl_typing.gw.raw import GwRawEnvelope
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class App(AppBase):
|
|
22
|
+
@classmethod
|
|
23
|
+
def collect(cls) -> AppSpec:
|
|
24
|
+
"""Collect and normalize AppSpec configuration for this App class."""
|
|
25
|
+
return AppSpec.collect(cls)
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def _collect_mro_spec(cls) -> AppSpec:
|
|
29
|
+
return cls.collect()
|
|
30
|
+
|
|
31
|
+
TITLE = "Tigrbl"
|
|
32
|
+
VERSION = "0.1.0"
|
|
33
|
+
LIFESPAN = None
|
|
34
|
+
ROUTERS = ()
|
|
35
|
+
OPS = ()
|
|
36
|
+
TABLES = ()
|
|
37
|
+
SCHEMAS = ()
|
|
38
|
+
HOOKS = ()
|
|
39
|
+
DESCRIPTION = None
|
|
40
|
+
OPENAPI_URL = "/openapi.json"
|
|
41
|
+
DOCS_URL = "/docs"
|
|
42
|
+
DEBUG = False
|
|
43
|
+
SWAGGER_UI_VERSION = "5.31.0"
|
|
44
|
+
SECURITY_DEPS = ()
|
|
45
|
+
DEPS = ()
|
|
46
|
+
RESPONSE = None
|
|
47
|
+
JSONRPC_PREFIX = "/rpc"
|
|
48
|
+
SYSTEM_PREFIX = "/system"
|
|
49
|
+
|
|
50
|
+
def __init__(self, *, engine: EngineCfg | None = None, **asgi_kwargs: Any) -> None:
|
|
51
|
+
collected_spec = self.__class__._collect_mro_spec()
|
|
52
|
+
collected_spec = self.__class__.bind_spec(collected_spec, parent=self)
|
|
53
|
+
|
|
54
|
+
title = asgi_kwargs.pop("title", None)
|
|
55
|
+
if title is not None:
|
|
56
|
+
self.TITLE = title
|
|
57
|
+
else:
|
|
58
|
+
title = collected_spec.title
|
|
59
|
+
version = asgi_kwargs.pop("version", None)
|
|
60
|
+
if version is not None:
|
|
61
|
+
self.VERSION = version
|
|
62
|
+
else:
|
|
63
|
+
version = collected_spec.version
|
|
64
|
+
lifespan = asgi_kwargs.pop("lifespan", None)
|
|
65
|
+
if lifespan is not None:
|
|
66
|
+
self.LIFESPAN = lifespan
|
|
67
|
+
else:
|
|
68
|
+
lifespan = collected_spec.lifespan
|
|
69
|
+
get_db = asgi_kwargs.pop("get_db", None)
|
|
70
|
+
if get_db is not None:
|
|
71
|
+
self.get_db = get_db
|
|
72
|
+
description = asgi_kwargs.pop("description", None)
|
|
73
|
+
if description is None:
|
|
74
|
+
description = getattr(self, "DESCRIPTION", None)
|
|
75
|
+
openapi_url = asgi_kwargs.pop("openapi_url", None)
|
|
76
|
+
if openapi_url is None:
|
|
77
|
+
openapi_url = getattr(self, "OPENAPI_URL", "/openapi.json")
|
|
78
|
+
docs_url = asgi_kwargs.pop("docs_url", None)
|
|
79
|
+
if docs_url is None:
|
|
80
|
+
docs_url = getattr(self, "DOCS_URL", "/docs")
|
|
81
|
+
debug = asgi_kwargs.pop("debug", None)
|
|
82
|
+
if debug is None:
|
|
83
|
+
debug = bool(getattr(self, "DEBUG", False))
|
|
84
|
+
swagger_ui_version = asgi_kwargs.pop("swagger_ui_version", None)
|
|
85
|
+
if swagger_ui_version is None:
|
|
86
|
+
swagger_ui_version = getattr(self, "SWAGGER_UI_VERSION", "5.31.0")
|
|
87
|
+
include_docs = asgi_kwargs.pop("include_docs", None)
|
|
88
|
+
if include_docs is None:
|
|
89
|
+
include_docs = bool(getattr(self, "INCLUDE_DOCS", False))
|
|
90
|
+
self.title = title
|
|
91
|
+
self.version = version
|
|
92
|
+
self.description = description
|
|
93
|
+
self.openapi_url = openapi_url
|
|
94
|
+
self.docs_url = docs_url
|
|
95
|
+
self.debug = debug
|
|
96
|
+
self.swagger_ui_version = swagger_ui_version
|
|
97
|
+
self.engine = engine if engine is not None else collected_spec.engine
|
|
98
|
+
self.routers = tuple(collected_spec.routers)
|
|
99
|
+
self.ops = tuple(collected_spec.ops)
|
|
100
|
+
self.tables = TableRegistry(tables=collected_spec.tables)
|
|
101
|
+
self.schemas = tuple(collected_spec.schemas)
|
|
102
|
+
self.hooks = tuple(collected_spec.hooks)
|
|
103
|
+
self.security_deps = tuple(collected_spec.security_deps)
|
|
104
|
+
self.deps = tuple(collected_spec.deps)
|
|
105
|
+
self.response = collected_spec.response
|
|
106
|
+
self.jsonrpc_prefix = collected_spec.jsonrpc_prefix
|
|
107
|
+
self.system_prefix = collected_spec.system_prefix
|
|
108
|
+
self.lifespan = lifespan
|
|
109
|
+
|
|
110
|
+
from ._router import Router
|
|
111
|
+
|
|
112
|
+
Router.__init__(
|
|
113
|
+
self,
|
|
114
|
+
engine=self.engine,
|
|
115
|
+
title=self.title,
|
|
116
|
+
version=self.version,
|
|
117
|
+
description=self.description,
|
|
118
|
+
openapi_url=self.openapi_url,
|
|
119
|
+
docs_url=self.docs_url,
|
|
120
|
+
debug=self.debug,
|
|
121
|
+
swagger_ui_version=self.swagger_ui_version,
|
|
122
|
+
include_docs=include_docs,
|
|
123
|
+
**asgi_kwargs,
|
|
124
|
+
)
|
|
125
|
+
# Router.__init__ seeds several attributes from class-level defaults.
|
|
126
|
+
# Re-apply merged AppSpec values so MRO-collected app configuration
|
|
127
|
+
# remains the source of truth for the app instance.
|
|
128
|
+
self.routers = tuple(collected_spec.routers)
|
|
129
|
+
self.ops = tuple(collected_spec.ops)
|
|
130
|
+
self.tables = TableRegistry(tables=collected_spec.tables)
|
|
131
|
+
self.schemas = tuple(collected_spec.schemas)
|
|
132
|
+
self.hooks = tuple(collected_spec.hooks)
|
|
133
|
+
self.security_deps = tuple(collected_spec.security_deps)
|
|
134
|
+
self.deps = tuple(collected_spec.deps)
|
|
135
|
+
self.response = collected_spec.response
|
|
136
|
+
self.jsonrpc_prefix = collected_spec.jsonrpc_prefix
|
|
137
|
+
self.system_prefix = collected_spec.system_prefix
|
|
138
|
+
|
|
139
|
+
_engine_ctx = self.engine
|
|
140
|
+
if _engine_ctx is not None:
|
|
141
|
+
_resolver.set_default(_engine_ctx)
|
|
142
|
+
_resolver.resolve_provider()
|
|
143
|
+
|
|
144
|
+
self.runtime = Runtime(
|
|
145
|
+
default_executor=getattr(self, "DEFAULT_EXECUTOR", "packed")
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def router(self) -> "App":
|
|
150
|
+
return self
|
|
151
|
+
|
|
152
|
+
def install_engines(
|
|
153
|
+
self, *, router: Any = None, tables: tuple[Any, ...] | None = None
|
|
154
|
+
) -> None:
|
|
155
|
+
routers = (router,) if router is not None else self.ROUTERS
|
|
156
|
+
tables = tables if tables is not None else self.TABLES
|
|
157
|
+
install_app = self if (routers or tuple(tables)) else None
|
|
158
|
+
if routers:
|
|
159
|
+
for a in routers:
|
|
160
|
+
Engine.install_from_objects(
|
|
161
|
+
app=install_app, router=a, tables=tuple(tables)
|
|
162
|
+
)
|
|
163
|
+
else:
|
|
164
|
+
Engine.install_from_objects(
|
|
165
|
+
app=install_app, router=None, tables=tuple(tables)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
async def invoke(self, env: GwRawEnvelope) -> None:
|
|
169
|
+
plan, packed_plan = self.runtime.compile(self)
|
|
170
|
+
ctx: dict[str, Any] = {
|
|
171
|
+
"app": self,
|
|
172
|
+
"router": self,
|
|
173
|
+
"raw": env,
|
|
174
|
+
"env": env,
|
|
175
|
+
"kernel_plan": plan,
|
|
176
|
+
"plan": plan,
|
|
177
|
+
"packed_plan": packed_plan,
|
|
178
|
+
"temp": {},
|
|
179
|
+
}
|
|
180
|
+
await self.runtime.invoke(
|
|
181
|
+
env=env,
|
|
182
|
+
ctx=ctx,
|
|
183
|
+
plan=plan,
|
|
184
|
+
packed_plan=packed_plan,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
async def __call__(self, scope: dict[str, Any], receive: Any, send: Any) -> None:
|
|
188
|
+
path = scope.get("path")
|
|
189
|
+
if isinstance(path, str):
|
|
190
|
+
seen_paths = getattr(self, "_seen_paths", None)
|
|
191
|
+
if not isinstance(seen_paths, set):
|
|
192
|
+
seen_paths = set()
|
|
193
|
+
setattr(self, "_seen_paths", seen_paths)
|
|
194
|
+
seen_paths.add(path)
|
|
195
|
+
env = GwRawEnvelope(kind="asgi3", scope=scope, receive=receive, send=send)
|
|
196
|
+
await self.invoke(env)
|
|
197
|
+
|
|
198
|
+
def _normalize_prefix(self, prefix: str) -> str:
|
|
199
|
+
return _normalize_prefix_impl(prefix)
|
|
200
|
+
|
|
201
|
+
def _merge_tags(self, tags: list[str] | None) -> list[str] | None:
|
|
202
|
+
return _merge_tags_impl(getattr(self, "tags", None), tags)
|
|
203
|
+
|
|
204
|
+
def include_router(self, router: Any, *, prefix: str | None = None) -> Any:
|
|
205
|
+
routed = getattr(router, "router", router)
|
|
206
|
+
_include_router_impl(self, routed, prefix=prefix or "")
|
|
207
|
+
bump = getattr(self, "_bump_runtime_plan_revision", None)
|
|
208
|
+
if callable(bump):
|
|
209
|
+
bump()
|
|
210
|
+
return router
|
|
211
|
+
|
|
212
|
+
initialize = _ddl_initialize
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Background task helpers with Starlette-compatible call behavior."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Callable
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class BackgroundTask:
|
|
12
|
+
"""Run a callable after response handling, matching Starlette semantics."""
|
|
13
|
+
|
|
14
|
+
func: Callable[..., Any]
|
|
15
|
+
args: tuple[Any, ...] = ()
|
|
16
|
+
kwargs: dict[str, Any] | None = None
|
|
17
|
+
|
|
18
|
+
def __init__(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> None:
|
|
19
|
+
self.func = func
|
|
20
|
+
self.args = args
|
|
21
|
+
self.kwargs = kwargs
|
|
22
|
+
|
|
23
|
+
async def __call__(self) -> None:
|
|
24
|
+
result = self.func(*self.args, **(self.kwargs or {}))
|
|
25
|
+
if inspect.isawaitable(result):
|
|
26
|
+
await result
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__ = ["BackgroundTask"]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tigrbl_base._base import BindingBase, BindingRegistryBase
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Binding(BindingBase):
|
|
7
|
+
"""Concrete named binding declaration."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BindingRegistry(BindingRegistryBase):
|
|
11
|
+
"""Concrete named binding registry."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ["Binding", "BindingRegistry"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class Body:
|
|
10
|
+
"""Lightweight wrapper for response/request payload bytes."""
|
|
11
|
+
|
|
12
|
+
value: bytes | str | None
|
|
13
|
+
|
|
14
|
+
def decode(self, encoding: str = "utf-8") -> str:
|
|
15
|
+
"""Decode the wrapped payload into text."""
|
|
16
|
+
if self.value is None:
|
|
17
|
+
return ""
|
|
18
|
+
if isinstance(self.value, bytes):
|
|
19
|
+
return self.value.decode(encoding)
|
|
20
|
+
return self.value
|
|
21
|
+
|
|
22
|
+
def json(self) -> Any:
|
|
23
|
+
"""Parse the wrapped payload as JSON."""
|
|
24
|
+
text = self.decode()
|
|
25
|
+
if not text:
|
|
26
|
+
return None
|
|
27
|
+
return json.loads(text)
|