tigrbl-core 0.1.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. tigrbl_core-0.1.0.dev1/PKG-INFO +50 -0
  2. tigrbl_core-0.1.0.dev1/README.md +29 -0
  3. tigrbl_core-0.1.0.dev1/pyproject.toml +42 -0
  4. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/__init__.py +67 -0
  5. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/alias_spec.py +35 -0
  6. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/app_spec.py +137 -0
  7. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/binding_spec.py +78 -0
  8. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/column_spec.py +40 -0
  9. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/engine_spec.py +359 -0
  10. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/field_spec.py +32 -0
  11. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/hook_spec.py +24 -0
  12. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/io_spec.py +136 -0
  13. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/middleware_spec.py +28 -0
  14. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/op_spec.py +110 -0
  15. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/request_spec.py +19 -0
  16. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/response_spec.py +34 -0
  17. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/response_types.py +12 -0
  18. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/router_spec.py +25 -0
  19. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/schema_spec.py +20 -0
  20. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/session_spec.py +160 -0
  21. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/shortcuts_spec.py +8 -0
  22. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/storage_spec.py +72 -0
  23. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/table_registry_spec.py +14 -0
  24. tigrbl_core-0.1.0.dev1/tigrbl_core/_spec/table_spec.py +73 -0
  25. tigrbl_core-0.1.0.dev1/tigrbl_core/core/__init__.py +47 -0
  26. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/__init__.py +43 -0
  27. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/bulk.py +167 -0
  28. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/helpers/__init__.py +76 -0
  29. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/helpers/db.py +91 -0
  30. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/helpers/enum.py +85 -0
  31. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/helpers/filters.py +161 -0
  32. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/helpers/model.py +136 -0
  33. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/helpers/normalize.py +98 -0
  34. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/ops.py +298 -0
  35. tigrbl_core-0.1.0.dev1/tigrbl_core/core/crud/params.py +50 -0
@@ -0,0 +1,50 @@
1
+ Metadata-Version: 2.4
2
+ Name: tigrbl-core
3
+ Version: 0.1.0.dev1
4
+ Summary: Core specifications and primitives for the Tigrbl framework.
5
+ License-Expression: Apache-2.0
6
+ Keywords: tigrbl,sdk,standards,framework
7
+ Author: Jacob Stewart
8
+ Author-email: jacob@swarmauri.com
9
+ Requires-Python: >=3.10,<3.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: tigrbl-typing
19
+ Description-Content-Type: text/markdown
20
+
21
+ ![Tigrbl branding](https://github.com/swarmauri/swarmauri-sdk/blob/a170683ecda8ca1c4f912c966d4499649ffb8224/assets/tigrbl.brand.theme.svg)
22
+
23
+ # tigrbl-core
24
+
25
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/tigrbl-core.svg) ![Hits](https://hits.sh/github.com/swarmauri/swarmauri-sdk.svg) ![Python Versions](https://img.shields.io/pypi/pyversions/tigrbl-core.svg) ![License](https://img.shields.io/pypi/l/tigrbl-core.svg) ![Version](https://img.shields.io/pypi/v/tigrbl-core.svg)
26
+
27
+ ## Features
28
+
29
+ - Modular package in the Tigrbl namespace.
30
+ - Supports Python 3.10 through 3.12.
31
+ - Distributed as part of the swarmauri-sdk workspace.
32
+
33
+ ## Installation
34
+
35
+ ### uv
36
+
37
+ ```bash
38
+ uv add tigrbl-core
39
+ ```
40
+
41
+ ### pip
42
+
43
+ ```bash
44
+ pip install tigrbl-core
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ Import from the shared package-specific module namespaces after installation in your environment.
50
+
@@ -0,0 +1,29 @@
1
+ ![Tigrbl branding](https://github.com/swarmauri/swarmauri-sdk/blob/a170683ecda8ca1c4f912c966d4499649ffb8224/assets/tigrbl.brand.theme.svg)
2
+
3
+ # tigrbl-core
4
+
5
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/tigrbl-core.svg) ![Hits](https://hits.sh/github.com/swarmauri/swarmauri-sdk.svg) ![Python Versions](https://img.shields.io/pypi/pyversions/tigrbl-core.svg) ![License](https://img.shields.io/pypi/l/tigrbl-core.svg) ![Version](https://img.shields.io/pypi/v/tigrbl-core.svg)
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-core
19
+ ```
20
+
21
+ ### pip
22
+
23
+ ```bash
24
+ pip install tigrbl-core
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Import from the shared package-specific module namespaces after installation in your environment.
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "tigrbl-core"
3
+ version = "0.1.0.dev1"
4
+ description = "Core specifications and primitives for the Tigrbl framework."
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
+ "tigrbl-typing",
22
+ ]
23
+ keywords = ["tigrbl", "sdk", "standards", "framework"]
24
+
25
+ [tool.uv.sources]
26
+ "tigrbl-typing" = { workspace = true }
27
+
28
+ [build-system]
29
+ requires = ["poetry-core>=1.0.0"]
30
+ build-backend = "poetry.core.masonry.api"
31
+
32
+
33
+ [tool.poetry]
34
+ packages = [
35
+ { include = "tigrbl_core" },
36
+ ]
37
+
38
+ [dependency-groups]
39
+ dev = [
40
+ "pytest>=8.0",
41
+ "ruff>=0.9",
42
+ ]
@@ -0,0 +1,67 @@
1
+ """Canonical spec package.
2
+
3
+ Keep this module import-light to avoid circular imports during package startup.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from importlib import import_module
9
+ from typing import Any
10
+
11
+ _EXPORTS = {
12
+ "AliasSpec": "alias_spec",
13
+ "AppSpec": "app_spec",
14
+ "Binding": "binding_spec",
15
+ "BindingRegistry": "binding_spec",
16
+ "BindingSpec": "binding_spec",
17
+ "HttpRestBindingSpec": "binding_spec",
18
+ "HttpJsonRpcBindingSpec": "binding_spec",
19
+ "WsBindingSpec": "binding_spec",
20
+ "resolve_rest_nested_prefix": "binding_spec",
21
+ "ColumnSpec": "column_spec",
22
+ "EngineSpec": "engine_spec",
23
+ "FieldSpec": "field_spec",
24
+ "HookSpec": "hook_spec",
25
+ "IOSpec": "io_spec",
26
+ "MiddlewareSpec": "middleware_spec",
27
+ "OpSpec": "op_spec",
28
+ "PHASE": "op_spec",
29
+ "PHASES": "op_spec",
30
+ "TemplateSpec": "response_spec",
31
+ "ResponseSpec": "response_spec",
32
+ "RequestSpec": "request_spec",
33
+ "RouterSpec": "router_spec",
34
+ "SchemaSpec": "schema_spec",
35
+ "SchemaRef": "schema_spec",
36
+ "SessionSpec": "session_spec",
37
+ "session_spec": "session_spec",
38
+ "tx_read_committed": "session_spec",
39
+ "tx_repeatable_read": "session_spec",
40
+ "tx_serializable": "session_spec",
41
+ "readonly": "session_spec",
42
+ "wrap_sessionmaker": "session_spec",
43
+ "StorageSpec": "storage_spec",
44
+ "StorageTransform": "storage_spec",
45
+ "ForeignKeySpec": "storage_spec",
46
+ "TableSpec": "table_spec",
47
+ "TableRegistrySpec": "table_registry_spec",
48
+ "F": "shortcuts_spec",
49
+ "IO": "shortcuts_spec",
50
+ "S": "shortcuts_spec",
51
+ "makeColumn": "shortcuts_spec",
52
+ "makeVirtualColumn": "shortcuts_spec",
53
+ "acol": "shortcuts_spec",
54
+ "vcol": "shortcuts_spec",
55
+ }
56
+
57
+ __all__ = list(_EXPORTS)
58
+
59
+
60
+ def __getattr__(name: str) -> Any:
61
+ module_name = _EXPORTS.get(name)
62
+ if module_name is None:
63
+ raise AttributeError(name)
64
+ module = import_module(f"{__name__}.{module_name}")
65
+ value = getattr(module, name)
66
+ globals()[name] = value
67
+ return value
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from .._spec.op_spec import Arity, PersistPolicy
7
+
8
+ if TYPE_CHECKING: # pragma: no cover
9
+ from ..schema.types import SchemaArg
10
+
11
+
12
+ class AliasSpec(ABC):
13
+ @property
14
+ @abstractmethod
15
+ def alias(self) -> str: ...
16
+
17
+ @property
18
+ @abstractmethod
19
+ def request_schema(self) -> Optional[SchemaArg]: ...
20
+
21
+ @property
22
+ @abstractmethod
23
+ def response_schema(self) -> Optional[SchemaArg]: ...
24
+
25
+ @property
26
+ @abstractmethod
27
+ def persist(self) -> Optional[PersistPolicy]: ...
28
+
29
+ @property
30
+ @abstractmethod
31
+ def arity(self) -> Optional[Arity]: ...
32
+
33
+ @property
34
+ @abstractmethod
35
+ def rest(self) -> Optional[bool]: ...
@@ -0,0 +1,137 @@
1
+ # pkgs/standards/tigrbl_core/tigrbl/_spec/app_spec.py
2
+ from __future__ import annotations
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, Callable, Optional, Sequence
5
+
6
+ from .._spec.engine_spec import EngineCfg
7
+ from .._spec.response_spec import ResponseSpec
8
+
9
+
10
+ @dataclass(eq=False)
11
+ class AppSpec:
12
+ """
13
+ Used to *produce an App subclass* via App.from_spec().
14
+ """
15
+
16
+ title: str = "Tigrbl"
17
+ description: str | None = None
18
+ version: str = "0.1.0"
19
+ engine: Optional[EngineCfg] = None
20
+
21
+ # NEW: multi-Router composition (store Router classes or instances)
22
+ routers: Sequence[Any] = field(default_factory=tuple)
23
+
24
+ # NEW: orchestration/topology knobs
25
+ ops: Sequence[Any] = field(default_factory=tuple) # op descriptors or specs
26
+ tables: Sequence[Any] = field(default_factory=tuple) # table refs owned by app
27
+ schemas: Sequence[Any] = field(default_factory=tuple) # schema classes/defs
28
+ hooks: Sequence[Callable[..., Any]] = field(default_factory=tuple)
29
+
30
+ # security/dep stacks (ASGI dependencies or callables)
31
+ security_deps: Sequence[Callable[..., Any]] = field(default_factory=tuple)
32
+ deps: Sequence[Callable[..., Any]] = field(default_factory=tuple)
33
+
34
+ # response defaults
35
+ response: Optional[ResponseSpec] = None
36
+
37
+ # system routing prefixes (REST/JSON-RPC namespaces)
38
+ jsonrpc_prefix: str = "/rpc"
39
+ system_prefix: str = "/system"
40
+
41
+ # optional framework bits
42
+ middlewares: Sequence[Any] = field(default_factory=tuple)
43
+ lifespan: Optional[Callable[..., Any]] = None
44
+
45
+ @classmethod
46
+ def collect(cls, app: type) -> "AppSpec":
47
+ from ..mapping.spec_normalization import merge_seq_attr, normalize_app_spec
48
+
49
+ sentinel = object()
50
+ title: Any = sentinel
51
+ version: Any = sentinel
52
+ engine: Any | None = sentinel # type: ignore[assignment]
53
+ response: Any = sentinel
54
+ jsonrpc_prefix: Any = sentinel
55
+ system_prefix: Any = sentinel
56
+ lifespan: Any = sentinel
57
+
58
+ for base in app.__mro__:
59
+ if "TITLE" in base.__dict__ and title is sentinel:
60
+ title = base.__dict__["TITLE"]
61
+ if "VERSION" in base.__dict__ and version is sentinel:
62
+ version = base.__dict__["VERSION"]
63
+ if "ENGINE" in base.__dict__ and engine is sentinel:
64
+ engine = base.__dict__["ENGINE"]
65
+ if "RESPONSE" in base.__dict__ and response is sentinel:
66
+ response = base.__dict__["RESPONSE"]
67
+ if "JSONRPC_PREFIX" in base.__dict__ and jsonrpc_prefix is sentinel:
68
+ jsonrpc_prefix = base.__dict__["JSONRPC_PREFIX"]
69
+ if "SYSTEM_PREFIX" in base.__dict__ and system_prefix is sentinel:
70
+ system_prefix = base.__dict__["SYSTEM_PREFIX"]
71
+ if "LIFESPAN" in base.__dict__ and lifespan is sentinel:
72
+ lifespan = base.__dict__["LIFESPAN"]
73
+
74
+ if title is sentinel:
75
+ title = "Tigrbl"
76
+ if version is sentinel:
77
+ version = "0.1.0"
78
+ if engine is sentinel:
79
+ engine = None
80
+ if response is sentinel:
81
+ response = None
82
+ if jsonrpc_prefix is sentinel:
83
+ jsonrpc_prefix = "/rpc"
84
+ if system_prefix is sentinel:
85
+ system_prefix = "/system"
86
+ if lifespan is sentinel:
87
+ lifespan = None
88
+
89
+ description = getattr(app, "DESCRIPTION", None)
90
+ include_inherited_routers = "ROUTERS" not in app.__dict__
91
+ spec = cls(
92
+ title=title,
93
+ description=description,
94
+ version=version,
95
+ engine=engine,
96
+ routers=tuple(
97
+ merge_seq_attr(
98
+ app,
99
+ "ROUTERS",
100
+ include_inherited=include_inherited_routers,
101
+ reverse=include_inherited_routers,
102
+ dedupe=False,
103
+ )
104
+ or ()
105
+ ),
106
+ ops=tuple(merge_seq_attr(app, "OPS") or ()),
107
+ tables=tuple(merge_seq_attr(app, "TABLES") or ()),
108
+ schemas=tuple(merge_seq_attr(app, "SCHEMAS") or ()),
109
+ hooks=tuple(merge_seq_attr(app, "HOOKS") or ()),
110
+ security_deps=tuple(merge_seq_attr(app, "SECURITY_DEPS") or ()),
111
+ deps=tuple(merge_seq_attr(app, "DEPS") or ()),
112
+ response=response,
113
+ jsonrpc_prefix=(jsonrpc_prefix or "/rpc"),
114
+ system_prefix=(system_prefix or "/system"),
115
+ middlewares=tuple(merge_seq_attr(app, "MIDDLEWARES") or ()),
116
+ lifespan=lifespan,
117
+ )
118
+ return normalize_app_spec(
119
+ cls(
120
+ title=spec.title,
121
+ description=spec.description,
122
+ version=spec.version,
123
+ engine=spec.engine,
124
+ routers=tuple(spec.routers or ()),
125
+ ops=tuple(spec.ops or ()),
126
+ tables=tuple(spec.tables or ()),
127
+ schemas=tuple(spec.schemas or ()),
128
+ hooks=tuple(spec.hooks or ()),
129
+ security_deps=tuple(spec.security_deps or ()),
130
+ deps=tuple(spec.deps or ()),
131
+ response=spec.response,
132
+ jsonrpc_prefix=(spec.jsonrpc_prefix or "/rpc"),
133
+ system_prefix=(spec.system_prefix or "/system"),
134
+ middlewares=tuple(spec.middlewares or ()),
135
+ lifespan=spec.lifespan,
136
+ )
137
+ )
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Literal, Optional, Type, Union
5
+
6
+ from ..config.constants import TIGRBL_NESTED_PATHS_ATTR
7
+
8
+
9
+ @dataclass(frozen=True, slots=True)
10
+ class HttpRestBindingSpec:
11
+ proto: Literal["http.rest", "https.rest"]
12
+ methods: tuple[str, ...]
13
+ path: str
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class HttpJsonRpcBindingSpec:
18
+ proto: Literal["http.jsonrpc", "https.jsonrpc"]
19
+ rpc_method: str
20
+
21
+
22
+ @dataclass(frozen=True, slots=True)
23
+ class WsBindingSpec:
24
+ proto: Literal["ws", "wss"]
25
+ path: str
26
+ subprotocols: tuple[str, ...] = ()
27
+
28
+
29
+ BindingSpec = Union[HttpRestBindingSpec, HttpJsonRpcBindingSpec, WsBindingSpec]
30
+
31
+
32
+ @dataclass(frozen=True, slots=True)
33
+ class Binding:
34
+ """Named binding declaration used for registry composition."""
35
+
36
+ """Named binding wrapper used by registries and planners."""
37
+
38
+ name: str
39
+ spec: BindingSpec
40
+
41
+
42
+ @dataclass(slots=True)
43
+ class BindingRegistry:
44
+ """Simple in-memory registry for named transport bindings."""
45
+
46
+ _bindings: dict[str, Binding]
47
+
48
+ def __init__(self) -> None:
49
+ self._bindings = {}
50
+
51
+ def register(self, binding: Binding) -> None:
52
+ self._bindings[binding.name] = binding
53
+
54
+ def get(self, name: str) -> Optional[Binding]:
55
+ return self._bindings.get(name)
56
+
57
+ def values(self) -> tuple[Binding, ...]:
58
+ return tuple(self._bindings.values())
59
+
60
+
61
+ def resolve_rest_nested_prefix(model: Type) -> Optional[str]:
62
+ """Return the configured nested REST prefix for ``model`` if present."""
63
+
64
+ cb = getattr(model, TIGRBL_NESTED_PATHS_ATTR, None)
65
+ if callable(cb):
66
+ return cb()
67
+ return getattr(model, "_nested_path", None)
68
+
69
+
70
+ __all__ = [
71
+ "Binding",
72
+ "BindingRegistry",
73
+ "BindingSpec",
74
+ "HttpJsonRpcBindingSpec",
75
+ "HttpRestBindingSpec",
76
+ "WsBindingSpec",
77
+ "resolve_rest_nested_prefix",
78
+ ]
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable, Optional
4
+
5
+ from .._spec.field_spec import FieldSpec as F
6
+ from .._spec.io_spec import IOSpec as IO
7
+ from .._spec.storage_spec import StorageSpec as S
8
+
9
+
10
+ class ColumnSpec:
11
+ """Aggregate configuration for a model attribute.
12
+
13
+ A :class:`ColumnSpec` brings together the three lower-level specs used by
14
+ Tigrbl's declarative column system:
15
+
16
+ - ``storage`` (:class:`~tigrbl._spec.storage_spec.StorageSpec`) controls
17
+ how the value is persisted in the database.
18
+ - ``field`` (:class:`~tigrbl._spec.field_spec.FieldSpec`) describes the
19
+ Python type and any schema metadata.
20
+ - ``io`` (:class:`~tigrbl._spec.io_spec.IOSpec`) governs inbound and
21
+ outbound API exposure.
22
+
23
+ Optional ``default_factory`` and ``read_producer`` callables allow for
24
+ programmatic defaults and virtual read-time values respectively.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ *,
30
+ storage: S | None,
31
+ field: F | None = None,
32
+ io: IO | None = None,
33
+ default_factory: Optional[Callable[[dict], Any]] = None,
34
+ read_producer: Optional[Callable[[object, dict], Any]] = None,
35
+ ) -> None:
36
+ self.storage = storage
37
+ self.field = field if field is not None else F()
38
+ self.io = io if io is not None else IO()
39
+ self.default_factory = default_factory
40
+ self.read_producer = read_producer