krons 0.1.1__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- krons/__init__.py +49 -0
- krons/agent/__init__.py +144 -0
- krons/agent/mcps/__init__.py +14 -0
- krons/agent/mcps/loader.py +287 -0
- krons/agent/mcps/wrapper.py +799 -0
- krons/agent/message/__init__.py +20 -0
- krons/agent/message/action.py +69 -0
- krons/agent/message/assistant.py +52 -0
- krons/agent/message/common.py +49 -0
- krons/agent/message/instruction.py +130 -0
- krons/agent/message/prepare_msg.py +187 -0
- krons/agent/message/role.py +53 -0
- krons/agent/message/system.py +53 -0
- krons/agent/operations/__init__.py +82 -0
- krons/agent/operations/act.py +100 -0
- krons/agent/operations/generate.py +145 -0
- krons/agent/operations/llm_reparse.py +89 -0
- krons/agent/operations/operate.py +247 -0
- krons/agent/operations/parse.py +243 -0
- krons/agent/operations/react.py +286 -0
- krons/agent/operations/specs.py +235 -0
- krons/agent/operations/structure.py +151 -0
- krons/agent/operations/utils.py +79 -0
- krons/agent/providers/__init__.py +17 -0
- krons/agent/providers/anthropic_messages.py +146 -0
- krons/agent/providers/claude_code.py +276 -0
- krons/agent/providers/gemini.py +268 -0
- krons/agent/providers/match.py +75 -0
- krons/agent/providers/oai_chat.py +174 -0
- krons/agent/third_party/__init__.py +2 -0
- krons/agent/third_party/anthropic_models.py +154 -0
- krons/agent/third_party/claude_code.py +682 -0
- krons/agent/third_party/gemini_models.py +508 -0
- krons/agent/third_party/openai_models.py +295 -0
- krons/agent/tool.py +291 -0
- krons/core/__init__.py +56 -74
- krons/core/base/__init__.py +121 -0
- krons/core/{broadcaster.py → base/broadcaster.py} +7 -3
- krons/core/{element.py → base/element.py} +13 -5
- krons/core/{event.py → base/event.py} +39 -6
- krons/core/{eventbus.py → base/eventbus.py} +3 -1
- krons/core/{flow.py → base/flow.py} +11 -4
- krons/core/{graph.py → base/graph.py} +24 -8
- krons/core/{node.py → base/node.py} +44 -19
- krons/core/{pile.py → base/pile.py} +22 -8
- krons/core/{processor.py → base/processor.py} +21 -7
- krons/core/{progression.py → base/progression.py} +3 -1
- krons/{specs → core/specs}/__init__.py +0 -5
- krons/{specs → core/specs}/adapters/dataclass_field.py +16 -8
- krons/{specs → core/specs}/adapters/pydantic_adapter.py +11 -5
- krons/{specs → core/specs}/adapters/sql_ddl.py +14 -8
- krons/{specs → core/specs}/catalog/__init__.py +2 -2
- krons/{specs → core/specs}/catalog/_audit.py +2 -2
- krons/{specs → core/specs}/catalog/_common.py +2 -2
- krons/{specs → core/specs}/catalog/_content.py +4 -4
- krons/{specs → core/specs}/catalog/_enforcement.py +3 -3
- krons/{specs → core/specs}/factory.py +5 -5
- krons/{specs → core/specs}/operable.py +8 -2
- krons/{specs → core/specs}/protocol.py +4 -2
- krons/{specs → core/specs}/spec.py +23 -11
- krons/{types → core/types}/base.py +4 -2
- krons/{types → core/types}/db_types.py +2 -2
- krons/errors.py +13 -13
- krons/protocols.py +9 -4
- krons/resource/__init__.py +89 -0
- krons/{services → resource}/backend.py +48 -22
- krons/{services → resource}/endpoint.py +28 -14
- krons/{services → resource}/hook.py +20 -7
- krons/{services → resource}/imodel.py +46 -28
- krons/{services → resource}/registry.py +26 -24
- krons/{services → resource}/utilities/rate_limited_executor.py +7 -3
- krons/{services → resource}/utilities/rate_limiter.py +3 -1
- krons/{services → resource}/utilities/resilience.py +15 -5
- krons/resource/utilities/token_calculator.py +185 -0
- krons/session/__init__.py +12 -17
- krons/session/constraints.py +70 -0
- krons/session/exchange.py +11 -3
- krons/session/message.py +3 -1
- krons/session/registry.py +35 -0
- krons/session/session.py +165 -174
- krons/utils/__init__.py +45 -0
- krons/utils/_function_arg_parser.py +99 -0
- krons/utils/_pythonic_function_call.py +249 -0
- krons/utils/_to_list.py +9 -3
- krons/utils/_utils.py +6 -2
- krons/utils/concurrency/_async_call.py +4 -2
- krons/utils/concurrency/_errors.py +3 -1
- krons/utils/concurrency/_patterns.py +3 -1
- krons/utils/concurrency/_resource_tracker.py +6 -2
- krons/utils/display.py +257 -0
- krons/utils/fuzzy/__init__.py +6 -1
- krons/utils/fuzzy/_fuzzy_match.py +14 -8
- krons/utils/fuzzy/_string_similarity.py +3 -1
- krons/utils/fuzzy/_to_dict.py +3 -1
- krons/utils/schemas/__init__.py +26 -0
- krons/utils/schemas/_breakdown_pydantic_annotation.py +131 -0
- krons/utils/schemas/_formatter.py +72 -0
- krons/utils/schemas/_minimal_yaml.py +151 -0
- krons/utils/schemas/_typescript.py +153 -0
- krons/utils/validators/__init__.py +3 -0
- krons/utils/validators/_validate_image_url.py +56 -0
- krons/work/__init__.py +115 -0
- krons/work/engine.py +333 -0
- krons/work/form.py +242 -0
- krons/{operations → work/operations}/__init__.py +7 -4
- krons/{operations → work/operations}/builder.py +1 -1
- krons/{enforcement → work/operations}/context.py +36 -5
- krons/{operations → work/operations}/flow.py +13 -5
- krons/{operations → work/operations}/node.py +45 -43
- krons/work/operations/registry.py +103 -0
- krons/work/report.py +268 -0
- krons/work/rules/__init__.py +47 -0
- krons/{enforcement → work/rules}/common/boolean.py +3 -1
- krons/{enforcement → work/rules}/common/choice.py +9 -3
- krons/{enforcement → work/rules}/common/number.py +3 -1
- krons/{enforcement → work/rules}/common/string.py +9 -3
- krons/{enforcement → work/rules}/rule.py +1 -1
- krons/{enforcement → work/rules}/validator.py +20 -5
- krons/work/worker.py +266 -0
- {krons-0.1.1.dist-info → krons-0.2.1.dist-info}/METADATA +15 -1
- krons-0.2.1.dist-info/RECORD +151 -0
- krons/enforcement/__init__.py +0 -57
- krons/enforcement/policy.py +0 -80
- krons/enforcement/service.py +0 -370
- krons/operations/registry.py +0 -92
- krons/services/__init__.py +0 -81
- krons/specs/phrase.py +0 -405
- krons-0.1.1.dist-info/RECORD +0 -101
- /krons/{specs → core/specs}/adapters/__init__.py +0 -0
- /krons/{specs → core/specs}/adapters/_utils.py +0 -0
- /krons/{specs → core/specs}/adapters/factory.py +0 -0
- /krons/{types → core/types}/__init__.py +0 -0
- /krons/{types → core/types}/_sentinel.py +0 -0
- /krons/{types → core/types}/identity.py +0 -0
- /krons/{services → resource}/utilities/__init__.py +0 -0
- /krons/{services → resource}/utilities/header_factory.py +0 -0
- /krons/{enforcement → work/rules}/common/__init__.py +0 -0
- /krons/{enforcement → work/rules}/common/mapping.py +0 -0
- /krons/{enforcement → work/rules}/common/model.py +0 -0
- /krons/{enforcement → work/rules}/registry.py +0 -0
- {krons-0.1.1.dist-info → krons-0.2.1.dist-info}/WHEEL +0 -0
- {krons-0.1.1.dist-info → krons-0.2.1.dist-info}/licenses/LICENSE +0 -0
krons/specs/phrase.py
DELETED
|
@@ -1,405 +0,0 @@
|
|
|
1
|
-
"""Phrase - typed operation template with auto-generated Options/Result types.
|
|
2
|
-
|
|
3
|
-
A Phrase wraps an async handler with:
|
|
4
|
-
- Typed inputs (auto-generates FrozenOptions dataclass)
|
|
5
|
-
- Typed outputs (auto-generates FrozenResult dataclass)
|
|
6
|
-
- Validation via Operable
|
|
7
|
-
|
|
8
|
-
Usage with decorator (custom handler):
|
|
9
|
-
from krons.specs import Operable, phrase
|
|
10
|
-
|
|
11
|
-
consent_operable = Operable([
|
|
12
|
-
Spec("subject_id", UUID),
|
|
13
|
-
Spec("scope", str),
|
|
14
|
-
Spec("has_consent", bool),
|
|
15
|
-
Spec("token_id", UUID | None),
|
|
16
|
-
])
|
|
17
|
-
|
|
18
|
-
@phrase(consent_operable, inputs={"subject_id", "scope"}, outputs={"has_consent", "token_id"})
|
|
19
|
-
async def verify_consent(options, ctx):
|
|
20
|
-
# options is VerifyConsentOptions (frozen dataclass)
|
|
21
|
-
# return dict with output fields
|
|
22
|
-
return {"has_consent": True, "token_id": some_id}
|
|
23
|
-
|
|
24
|
-
# Call it
|
|
25
|
-
result = await verify_consent({"subject_id": id, "scope": "background"}, ctx)
|
|
26
|
-
|
|
27
|
-
Usage with CrudPattern (declarative):
|
|
28
|
-
from krons.specs import Operable, phrase, CrudPattern
|
|
29
|
-
|
|
30
|
-
def check_has_consent(row):
|
|
31
|
-
return {"has_consent": row["status"] in {"active"} if row else False}
|
|
32
|
-
|
|
33
|
-
verify_consent = phrase(
|
|
34
|
-
consent_operable,
|
|
35
|
-
inputs={"subject_id", "scope"},
|
|
36
|
-
outputs={"has_consent", "token_id"},
|
|
37
|
-
crud=CrudPattern(
|
|
38
|
-
table="consent_tokens",
|
|
39
|
-
operation="read",
|
|
40
|
-
lookup={"subject_id", "scope"},
|
|
41
|
-
),
|
|
42
|
-
result_parser=check_has_consent,
|
|
43
|
-
name="verify_consent",
|
|
44
|
-
)
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
from collections.abc import Awaitable, Callable, Mapping
|
|
48
|
-
from dataclasses import dataclass
|
|
49
|
-
from enum import Enum
|
|
50
|
-
from types import MappingProxyType
|
|
51
|
-
from typing import Any
|
|
52
|
-
|
|
53
|
-
from krons.types import Unset, is_unset
|
|
54
|
-
from krons.utils.sql import validate_identifier
|
|
55
|
-
|
|
56
|
-
from .operable import Operable
|
|
57
|
-
|
|
58
|
-
__all__ = ("CrudPattern", "CrudOperation", "Phrase", "phrase")
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class CrudOperation(str, Enum):
|
|
62
|
-
"""CRUD operation types for declarative phrases."""
|
|
63
|
-
|
|
64
|
-
READ = "read"
|
|
65
|
-
INSERT = "insert"
|
|
66
|
-
UPDATE = "update"
|
|
67
|
-
SOFT_DELETE = "soft_delete"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
_EMPTY_MAP: MappingProxyType = MappingProxyType({})
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@dataclass(frozen=True, slots=True)
|
|
74
|
-
class CrudPattern:
|
|
75
|
-
"""Declarative CRUD pattern for auto-generating phrase handlers.
|
|
76
|
-
|
|
77
|
-
Attributes:
|
|
78
|
-
table: Validated database table name (alphanumeric + underscores).
|
|
79
|
-
operation: CRUD operation type (read, insert, update, soft_delete).
|
|
80
|
-
lookup: Fields from options used in WHERE clause (for read/update/delete).
|
|
81
|
-
filters: Static key-value pairs added to WHERE clause. Use for
|
|
82
|
-
hardcoded filters like {"status": "active"}.
|
|
83
|
-
set_fields: Explicit field mappings for update. Values can be:
|
|
84
|
-
- Field name (str): copy from options
|
|
85
|
-
- "ctx.{attr}": read from context (e.g., "ctx.now", "ctx.user_id")
|
|
86
|
-
- Literal value: use directly
|
|
87
|
-
defaults: Static default values for insert.
|
|
88
|
-
|
|
89
|
-
The auto-handler resolves output fields in order:
|
|
90
|
-
1. ctx metadata attribute (e.g., tenant_id — only if explicitly set)
|
|
91
|
-
2. options pass-through (if field in inputs)
|
|
92
|
-
3. row column (direct from query result)
|
|
93
|
-
4. result_parser (for computed fields)
|
|
94
|
-
"""
|
|
95
|
-
|
|
96
|
-
table: str
|
|
97
|
-
operation: CrudOperation | str = CrudOperation.READ
|
|
98
|
-
lookup: frozenset[str] = frozenset()
|
|
99
|
-
filters: Mapping[str, Any] = None # type: ignore[assignment]
|
|
100
|
-
set_fields: Mapping[str, Any] = None # type: ignore[assignment]
|
|
101
|
-
defaults: Mapping[str, Any] = None # type: ignore[assignment]
|
|
102
|
-
|
|
103
|
-
def __post_init__(self):
|
|
104
|
-
# Validate table name against SQL injection
|
|
105
|
-
validate_identifier(self.table, "table")
|
|
106
|
-
# Normalize operation to enum
|
|
107
|
-
if isinstance(self.operation, str):
|
|
108
|
-
object.__setattr__(self, "operation", CrudOperation(self.operation))
|
|
109
|
-
# Normalize lookup to frozenset
|
|
110
|
-
if not isinstance(self.lookup, frozenset):
|
|
111
|
-
object.__setattr__(self, "lookup", frozenset(self.lookup))
|
|
112
|
-
# Normalize None mappings to immutable empty maps; freeze mutable dicts
|
|
113
|
-
object.__setattr__(
|
|
114
|
-
self, "filters",
|
|
115
|
-
_EMPTY_MAP if self.filters is None else MappingProxyType(dict(self.filters)),
|
|
116
|
-
)
|
|
117
|
-
object.__setattr__(
|
|
118
|
-
self, "set_fields",
|
|
119
|
-
_EMPTY_MAP if self.set_fields is None
|
|
120
|
-
else MappingProxyType(dict(self.set_fields)),
|
|
121
|
-
)
|
|
122
|
-
object.__setattr__(
|
|
123
|
-
self, "defaults",
|
|
124
|
-
_EMPTY_MAP if self.defaults is None
|
|
125
|
-
else MappingProxyType(dict(self.defaults)),
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
class Phrase:
|
|
130
|
-
"""A typed operation template with auto-generated Options/Result types.
|
|
131
|
-
|
|
132
|
-
Phrases can be created two ways:
|
|
133
|
-
1. With a custom handler (decorator pattern)
|
|
134
|
-
2. With a CrudPattern (declarative pattern, auto-generates handler)
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
def __init__(
|
|
138
|
-
self,
|
|
139
|
-
name: str,
|
|
140
|
-
operable: Operable,
|
|
141
|
-
inputs: set[str],
|
|
142
|
-
outputs: set[str],
|
|
143
|
-
handler: Callable[..., Awaitable] | None = None,
|
|
144
|
-
crud: CrudPattern | None = None,
|
|
145
|
-
result_parser: Callable[[dict | None], dict] | None = None,
|
|
146
|
-
):
|
|
147
|
-
"""
|
|
148
|
-
Args:
|
|
149
|
-
name: Snake_case phrase name.
|
|
150
|
-
operable: Operable defining field specs for inputs/outputs.
|
|
151
|
-
inputs: Set of field names that form the options type.
|
|
152
|
-
outputs: Set of field names that form the result type.
|
|
153
|
-
handler: Async function (options, ctx) -> result dict. Required if no crud.
|
|
154
|
-
crud: CrudPattern for declarative CRUD operations. If provided, handler
|
|
155
|
-
is auto-generated.
|
|
156
|
-
result_parser: Function (row) -> dict for computed output fields.
|
|
157
|
-
Only used with crud pattern. Row may be None if not found.
|
|
158
|
-
"""
|
|
159
|
-
if handler is None and crud is None:
|
|
160
|
-
raise ValueError("Either handler or crud must be provided")
|
|
161
|
-
|
|
162
|
-
self.name = name
|
|
163
|
-
self.operable = Operable(operable.get_specs(), adapter="dataclass")
|
|
164
|
-
self.inputs = tuple(inputs)
|
|
165
|
-
self.outputs = tuple(outputs)
|
|
166
|
-
self.crud = crud
|
|
167
|
-
self.result_parser = result_parser
|
|
168
|
-
self._options_type: Any = Unset
|
|
169
|
-
self._result_type: Any = Unset
|
|
170
|
-
|
|
171
|
-
# Use provided handler or generate from crud
|
|
172
|
-
if handler is not None:
|
|
173
|
-
self.handler = handler
|
|
174
|
-
else:
|
|
175
|
-
self.handler = self._make_crud_handler()
|
|
176
|
-
|
|
177
|
-
def _make_crud_handler(self) -> Callable[..., Awaitable]:
|
|
178
|
-
"""Generate handler from CrudPattern."""
|
|
179
|
-
crud = self.crud
|
|
180
|
-
inputs = set(self.inputs)
|
|
181
|
-
outputs = set(self.outputs)
|
|
182
|
-
result_parser = self.result_parser
|
|
183
|
-
|
|
184
|
-
async def _crud_handler(options: Any, ctx: Any) -> dict:
|
|
185
|
-
# Get the query backend from context
|
|
186
|
-
query_fn = getattr(ctx, "query_fn", None)
|
|
187
|
-
if query_fn is None:
|
|
188
|
-
raise RuntimeError(
|
|
189
|
-
"Context must provide query_fn for crud patterns. "
|
|
190
|
-
"Ensure ctx.query_fn is set."
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
# Helper: check ctx metadata for a key
|
|
194
|
-
_meta = getattr(ctx, "metadata", {})
|
|
195
|
-
|
|
196
|
-
row = None
|
|
197
|
-
|
|
198
|
-
if crud.operation == CrudOperation.READ:
|
|
199
|
-
# Build WHERE from lookup fields + filters + tenant_id
|
|
200
|
-
where = {field: getattr(options, field) for field in crud.lookup}
|
|
201
|
-
where.update(crud.filters)
|
|
202
|
-
if "tenant_id" in _meta:
|
|
203
|
-
where["tenant_id"] = _meta["tenant_id"]
|
|
204
|
-
row = await query_fn(crud.table, "select_one", where, None, ctx)
|
|
205
|
-
|
|
206
|
-
elif crud.operation == CrudOperation.INSERT:
|
|
207
|
-
# Build data from input fields + defaults
|
|
208
|
-
data = {}
|
|
209
|
-
for field in inputs:
|
|
210
|
-
if hasattr(options, field):
|
|
211
|
-
data[field] = getattr(options, field)
|
|
212
|
-
# Add defaults
|
|
213
|
-
for key, value in crud.defaults.items():
|
|
214
|
-
if key not in data:
|
|
215
|
-
data[key] = value
|
|
216
|
-
# Add tenant_id
|
|
217
|
-
if "tenant_id" in _meta:
|
|
218
|
-
data["tenant_id"] = _meta["tenant_id"]
|
|
219
|
-
row = await query_fn(crud.table, "insert", None, data, ctx)
|
|
220
|
-
|
|
221
|
-
elif crud.operation == CrudOperation.UPDATE:
|
|
222
|
-
# Build WHERE from lookup fields
|
|
223
|
-
where = {field: getattr(options, field) for field in crud.lookup}
|
|
224
|
-
if "tenant_id" in _meta:
|
|
225
|
-
where["tenant_id"] = _meta["tenant_id"]
|
|
226
|
-
# Build SET data
|
|
227
|
-
data = {}
|
|
228
|
-
for key, value in crud.set_fields.items():
|
|
229
|
-
if isinstance(value, str) and value.startswith("ctx."):
|
|
230
|
-
attr_name = value[4:]
|
|
231
|
-
if attr_name in _meta:
|
|
232
|
-
data[key] = _meta[attr_name]
|
|
233
|
-
else:
|
|
234
|
-
data[key] = getattr(ctx, attr_name)
|
|
235
|
-
elif isinstance(value, str) and hasattr(options, value):
|
|
236
|
-
data[key] = getattr(options, value)
|
|
237
|
-
else:
|
|
238
|
-
data[key] = value
|
|
239
|
-
row = await query_fn(crud.table, "update", where, data, ctx)
|
|
240
|
-
|
|
241
|
-
elif crud.operation == CrudOperation.SOFT_DELETE:
|
|
242
|
-
# Build WHERE from lookup fields
|
|
243
|
-
where = {field: getattr(options, field) for field in crud.lookup}
|
|
244
|
-
if "tenant_id" in _meta:
|
|
245
|
-
where["tenant_id"] = _meta["tenant_id"]
|
|
246
|
-
# Soft delete sets is_deleted=True, deleted_at=now
|
|
247
|
-
data = {"is_deleted": True}
|
|
248
|
-
if ctx.now is not None:
|
|
249
|
-
data["deleted_at"] = ctx.now
|
|
250
|
-
row = await query_fn(crud.table, "update", where, data, ctx)
|
|
251
|
-
|
|
252
|
-
# Build result from auto-mapping + result_parser
|
|
253
|
-
result = {}
|
|
254
|
-
|
|
255
|
-
for field in outputs:
|
|
256
|
-
# Priority 1: ctx metadata attribute (only if explicitly set)
|
|
257
|
-
if field in _meta:
|
|
258
|
-
result[field] = _meta[field]
|
|
259
|
-
# Priority 2: pass-through from options
|
|
260
|
-
elif field in inputs and hasattr(options, field):
|
|
261
|
-
result[field] = getattr(options, field)
|
|
262
|
-
# Priority 3: direct from row
|
|
263
|
-
elif row and field in row:
|
|
264
|
-
result[field] = row[field]
|
|
265
|
-
|
|
266
|
-
# Priority 4: computed fields from result_parser
|
|
267
|
-
if result_parser is not None:
|
|
268
|
-
computed = result_parser(row)
|
|
269
|
-
if computed:
|
|
270
|
-
result.update(computed)
|
|
271
|
-
|
|
272
|
-
return result
|
|
273
|
-
|
|
274
|
-
return _crud_handler
|
|
275
|
-
|
|
276
|
-
async def __call__(self, options: Any, ctx: Any) -> Any:
|
|
277
|
-
# If options is already the correct type, use it directly
|
|
278
|
-
# Otherwise validate/construct from dict
|
|
279
|
-
if not isinstance(options, self.options_type):
|
|
280
|
-
options = self.operable.validate_instance(self.options_type, options)
|
|
281
|
-
result = await self.handler(options, ctx)
|
|
282
|
-
return self.operable.validate_instance(self.result_type, result)
|
|
283
|
-
|
|
284
|
-
@property
|
|
285
|
-
def options_type(self) -> Any:
|
|
286
|
-
if not is_unset(self._options_type):
|
|
287
|
-
return self._options_type
|
|
288
|
-
|
|
289
|
-
_opt_type_name = _to_pascal(self.name) + "Options"
|
|
290
|
-
self._options_type = self.operable.compose_structure(
|
|
291
|
-
_opt_type_name,
|
|
292
|
-
include=set(self.inputs),
|
|
293
|
-
frozen=True,
|
|
294
|
-
)
|
|
295
|
-
return self._options_type
|
|
296
|
-
|
|
297
|
-
@property
|
|
298
|
-
def result_type(self) -> Any:
|
|
299
|
-
if not is_unset(self._result_type):
|
|
300
|
-
return self._result_type
|
|
301
|
-
|
|
302
|
-
_res_type_name = _to_pascal(self.name) + "Result"
|
|
303
|
-
self._result_type = self.operable.compose_structure(
|
|
304
|
-
_res_type_name,
|
|
305
|
-
include=set(self.outputs),
|
|
306
|
-
frozen=True,
|
|
307
|
-
)
|
|
308
|
-
return self._result_type
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
def _to_pascal(snake_name: str) -> str:
|
|
312
|
-
"""Convert snake_case name to PascalCase.
|
|
313
|
-
|
|
314
|
-
Examples:
|
|
315
|
-
require_monitoring_active -> RequireMonitoringActive
|
|
316
|
-
verify_consent_token -> VerifyConsentToken
|
|
317
|
-
"""
|
|
318
|
-
return "".join(word.capitalize() for word in snake_name.split("_"))
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
def phrase(
|
|
322
|
-
operable: Operable,
|
|
323
|
-
*,
|
|
324
|
-
inputs: set[str],
|
|
325
|
-
outputs: set[str],
|
|
326
|
-
name: str | None = None,
|
|
327
|
-
crud: CrudPattern | None = None,
|
|
328
|
-
result_parser: Callable[[dict | None], dict] | None = None,
|
|
329
|
-
) -> Phrase | Callable[[Callable[..., Awaitable]], Phrase]:
|
|
330
|
-
"""Create a Phrase, either as decorator or directly with CrudPattern.
|
|
331
|
-
|
|
332
|
-
Two usage modes:
|
|
333
|
-
|
|
334
|
-
1. Decorator mode (custom handler):
|
|
335
|
-
@phrase(operable, inputs={...}, outputs={...})
|
|
336
|
-
async def my_phrase(options, ctx):
|
|
337
|
-
return {...}
|
|
338
|
-
|
|
339
|
-
2. Direct mode (declarative crud):
|
|
340
|
-
my_phrase = phrase(
|
|
341
|
-
operable,
|
|
342
|
-
inputs={...},
|
|
343
|
-
outputs={...},
|
|
344
|
-
crud=CrudPattern(table="...", operation="read", lookup={...}),
|
|
345
|
-
result_parser=lambda row: {...},
|
|
346
|
-
name="my_phrase",
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
Args:
|
|
350
|
-
operable: Operable defining the field specs for inputs/outputs.
|
|
351
|
-
inputs: Set of field names that form the options type.
|
|
352
|
-
outputs: Set of field names that form the result type.
|
|
353
|
-
name: Phrase name. Required for direct mode, optional for decorator mode.
|
|
354
|
-
crud: CrudPattern for declarative CRUD. If provided, returns Phrase directly.
|
|
355
|
-
result_parser: Function (row) -> dict for computed fields. Only with crud.
|
|
356
|
-
|
|
357
|
-
Returns:
|
|
358
|
-
- If crud provided: Phrase instance directly
|
|
359
|
-
- If no crud: Decorator that wraps async function into Phrase
|
|
360
|
-
|
|
361
|
-
Examples:
|
|
362
|
-
# Decorator mode
|
|
363
|
-
@phrase(my_operable, inputs={"subject_id", "scope"}, outputs={"valid", "reason"})
|
|
364
|
-
async def verify_consent(options, ctx):
|
|
365
|
-
return {"valid": True, "reason": None}
|
|
366
|
-
|
|
367
|
-
# Direct mode with CrudPattern
|
|
368
|
-
verify_consent = phrase(
|
|
369
|
-
my_operable,
|
|
370
|
-
inputs={"subject_id", "scope"},
|
|
371
|
-
outputs={"has_consent", "token_id"},
|
|
372
|
-
crud=CrudPattern(
|
|
373
|
-
table="consent_tokens",
|
|
374
|
-
operation="read",
|
|
375
|
-
lookup={"subject_id", "scope"},
|
|
376
|
-
),
|
|
377
|
-
result_parser=lambda row: {"has_consent": row["status"] == "active" if row else False},
|
|
378
|
-
name="verify_consent",
|
|
379
|
-
)
|
|
380
|
-
"""
|
|
381
|
-
# Direct mode: crud provided, return Phrase immediately
|
|
382
|
-
if crud is not None:
|
|
383
|
-
if name is None:
|
|
384
|
-
raise ValueError("name is required when using crud pattern")
|
|
385
|
-
return Phrase(
|
|
386
|
-
name=name,
|
|
387
|
-
operable=operable,
|
|
388
|
-
inputs=inputs,
|
|
389
|
-
outputs=outputs,
|
|
390
|
-
crud=crud,
|
|
391
|
-
result_parser=result_parser,
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
# Decorator mode: return decorator function
|
|
395
|
-
def decorator(func: Callable[..., Awaitable]) -> Phrase:
|
|
396
|
-
phrase_name = name or func.__name__
|
|
397
|
-
return Phrase(
|
|
398
|
-
name=phrase_name,
|
|
399
|
-
operable=operable,
|
|
400
|
-
inputs=inputs,
|
|
401
|
-
outputs=outputs,
|
|
402
|
-
handler=func,
|
|
403
|
-
)
|
|
404
|
-
|
|
405
|
-
return decorator
|
krons-0.1.1.dist-info/RECORD
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
krons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
krons/errors.py,sha256=qzedv7hxB66-1hxNZYooetp-x-Yo71g_NquJH931YsQ,4038
|
|
3
|
-
krons/protocols.py,sha256=J7mMmBIk-sS5CPwYk1tPo-W8UAnau8_v6wruDhDelbs,15239
|
|
4
|
-
krons/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
krons/core/__init__.py,sha256=cR62yVsNyF8lu3gkiHJMnvew1Jj8HqnMBzA7rFzlVzs,4187
|
|
6
|
-
krons/core/broadcaster.py,sha256=oSfr1ESB8DJdCnzwDmOuVr2QKtisFxQh7OldVzwPKKI,3965
|
|
7
|
-
krons/core/element.py,sha256=ouSNYvryb7TzgRuwW-ETVOvrfomTlrVp8AqLQ8NEJSg,7533
|
|
8
|
-
krons/core/event.py,sha256=hOXOjrug9C8GqMAdT44iQVC3oSRnXFnOx7-TEbNcaKs,10601
|
|
9
|
-
krons/core/eventbus.py,sha256=cSi2PGRIUh9t2RpN92fjP73mDoIinngBYDbEbA3bv4s,3731
|
|
10
|
-
krons/core/flow.py,sha256=h2Ug-u7DWNDgLOYwSjIZjNVLI4iuNzV1wZ4RSdp6ba0,12271
|
|
11
|
-
krons/core/graph.py,sha256=hk8pp5vt_aI6L-PLopzd3tGrV4XnyYqzDPWQ58VK0E8,15797
|
|
12
|
-
krons/core/node.py,sha256=3DEIsNVrR5WOnh_JZzShSPbX0dNnUo02pxngJgZ4cTM,34330
|
|
13
|
-
krons/core/pile.py,sha256=MiTyajAOVNtv1bFcZQYX2P4PL07kTWZDBATr2DFm034,20893
|
|
14
|
-
krons/core/processor.py,sha256=O4Fv7gQzytD4Fmjw8JHdSfuPA85r30z9RfcB021nn0E,18484
|
|
15
|
-
krons/core/progression.py,sha256=85Dy-cMLy2UGFr5eZxqiuBh53lKaCQYjIyCZdyQ690M,9806
|
|
16
|
-
krons/enforcement/__init__.py,sha256=Y1V7OCqYQF3S02VHt0mRcjktLYNFH_ef-71u7hh4IDg,1653
|
|
17
|
-
krons/enforcement/context.py,sha256=b5f653m55NhxqYEDqKT5ZdEqIyqdSWdbGFwMw-cIt7c,4239
|
|
18
|
-
krons/enforcement/policy.py,sha256=GYTbSG8ibo2x1eeGr_ot8wGRZBURd9wjyHuUZb6tcGE,2132
|
|
19
|
-
krons/enforcement/registry.py,sha256=JFdwcIVtysntj6wMY3bO7-hqwNU7QIoIbEQuhsy5O4U,4742
|
|
20
|
-
krons/enforcement/rule.py,sha256=ks2nHFmcwCwPn306k8ra_WFpdj5R3a3W3pyO1fpNeMk,9466
|
|
21
|
-
krons/enforcement/service.py,sha256=x5xClQ2uysKYepAZti7ICqrWXTbYjGYtFaC6tzsY_CI,11849
|
|
22
|
-
krons/enforcement/validator.py,sha256=mipoSCpk57vOiPDx0UzReYyp2QuD5tOjH_muLnaDWgc,6759
|
|
23
|
-
krons/enforcement/common/__init__.py,sha256=U0rEcHOxLftR4-xJNuuXMSDYFAvbs0KzwV3GhlZcUrY,1026
|
|
24
|
-
krons/enforcement/common/boolean.py,sha256=vUmOpCMr7kW0tkS5zdvmgY6RouJ_8Xl9Yd0MTCbItz8,2614
|
|
25
|
-
krons/enforcement/common/choice.py,sha256=hbziQjfc60Azq-4P5PSEw3KYWm80JPhBg6rgVl3MXaE,3190
|
|
26
|
-
krons/enforcement/common/mapping.py,sha256=Loq54MNEtwpnHN0aypTjFOqwoOKLEysddHh-JESedvs,3824
|
|
27
|
-
krons/enforcement/common/model.py,sha256=xmM6coEThf_fgIiqJiyDgvdfib_FpVeY6LgWPVcWSwU,3026
|
|
28
|
-
krons/enforcement/common/number.py,sha256=_WM_LGSsU1D-HHE6O0nd4tRV20tTw06sOyhaevwoZu4,3132
|
|
29
|
-
krons/enforcement/common/string.py,sha256=PAknCSgCPTld1niSsZjljc5_j-cDZVr8S3OvNYFEXJM,4992
|
|
30
|
-
krons/operations/__init__.py,sha256=ARzm5ywMn3YzW8vIWfKcy8CeN5DSxi_mGxtyxty03gk,917
|
|
31
|
-
krons/operations/builder.py,sha256=wtnlcCpngE5tK0pnwCNjniCi3HFJrWtwpULGzMcddIg,7774
|
|
32
|
-
krons/operations/flow.py,sha256=QstfNqntodU7MaVyHva89Rlu1xbdThZwlIqYtLmQVjE,14696
|
|
33
|
-
krons/operations/node.py,sha256=499BVq2BnCBM4hLEmYrBsUuWmDhtISgMelUQlEvOtCM,3166
|
|
34
|
-
krons/operations/registry.py,sha256=kEE484Q3J4CvcOuP-1AUPQg5i-ff8WcSjQntOXhgqgg,3046
|
|
35
|
-
krons/services/__init__.py,sha256=ltUHcKZIWXMk5T11HRJrf_-XjX3eZdwEx02qrID44Nc,2574
|
|
36
|
-
krons/services/backend.py,sha256=txvySl_7NLbBJy0b_ZlkxaMhRfPQ1x2_NVrarkxhmew,10251
|
|
37
|
-
krons/services/endpoint.py,sha256=FCn3fn9bNZ_lohL8wHPRKYVh3cGbsDE9Un75VXaCE0c,22076
|
|
38
|
-
krons/services/hook.py,sha256=Ni1kIe-D-cbb6isjK2_jsy3X2AH0WFXgXOcq75aTRJM,16910
|
|
39
|
-
krons/services/imodel.py,sha256=qPd77SAbN3PX0e5dcm-A6UK8fn2eWTAIJ6mBqduQXnQ,18190
|
|
40
|
-
krons/services/registry.py,sha256=uHlHJZEYFrV3fL8V61eYAG0geUm3VmT3Be1oJaF8KbY,3788
|
|
41
|
-
krons/services/utilities/__init__.py,sha256=-ycdoYgtXrliJwbtQGMHBRvZL0qX2xLzooL3RNV99x4,1013
|
|
42
|
-
krons/services/utilities/header_factory.py,sha256=WZCCZMh9EJVi8tnY7dJD07FcTOrrUMvecJmzy8P65Os,2992
|
|
43
|
-
krons/services/utilities/rate_limited_executor.py,sha256=KSAYvVce24O7B0BlOgCX6jnYTpGwzjnPHLvbNZ5IvHo,9650
|
|
44
|
-
krons/services/utilities/rate_limiter.py,sha256=lquGaLRjQGIIcTysUtsJJ6ZJEqFQyUmbAP7JBCIT93E,5957
|
|
45
|
-
krons/services/utilities/resilience.py,sha256=LpcUSx4zGkWECkrgoSKJKyTFkirpoknrgbD1zjwYuco,14239
|
|
46
|
-
krons/session/__init__.py,sha256=EZDOlXoGcJ5VT9NPpx5fV_vIpRF_DsavQPcmeG7xiFQ,1210
|
|
47
|
-
krons/session/exchange.py,sha256=uE7d2ai5zom64bIA-RmAZy6SUpydCHwZc1e0eROLN6c,9025
|
|
48
|
-
krons/session/message.py,sha256=eVP2-4xwMTBaRtATfG7SD4UkdooN-FlRSx0hKsjkFNM,1993
|
|
49
|
-
krons/session/session.py,sha256=lWy5ACVFDaUiuFPUSR4kSbcpDB7GI2x4CXP5VoRnL3I,14245
|
|
50
|
-
krons/specs/__init__.py,sha256=F6QOVdo1EK5jK6b17rgQqX8i8PWURUxkFzBSz3g0L0A,631
|
|
51
|
-
krons/specs/factory.py,sha256=R0vp4ATRZAHhinBFcldyGp1Tt6I44tp-r2GznrxTWZs,3337
|
|
52
|
-
krons/specs/operable.py,sha256=lhQ4K3mpHeHPgSSLODnhzJhTYEjSRkxOSqESxVpUBRk,11043
|
|
53
|
-
krons/specs/phrase.py,sha256=Zyx-u1vySLHFL5PP1bkHL4AQq7jVa3wag6kDucPT1ck,15125
|
|
54
|
-
krons/specs/protocol.py,sha256=ugYVjN6kV-rjXqvxdoTSaQmK9AP_8rXzKY4gN26xfyk,4365
|
|
55
|
-
krons/specs/spec.py,sha256=6aB_XGPF6zQfn0g-Pn0IBweC-6xQUqGB1RVhSq-TsBw,18512
|
|
56
|
-
krons/specs/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
-
krons/specs/adapters/_utils.py,sha256=ChWH-C2LRXaXiWM3n7P0DZ8Oci5dSDq59DIJtHx2h-g,1365
|
|
58
|
-
krons/specs/adapters/dataclass_field.py,sha256=2mdmqdn5aUV1Y8i1q6IQErmdo4NRP-002y3ZKK424BI,8678
|
|
59
|
-
krons/specs/adapters/factory.py,sha256=_LoSMCtHNkK5kNL5LUDjHvJJ2BtDHAaW1gly5LpNPXQ,1572
|
|
60
|
-
krons/specs/adapters/pydantic_adapter.py,sha256=L5e0Kg_picNiGyxdvbJil96zAzNGIoHUHTuxcQmcXZk,10360
|
|
61
|
-
krons/specs/adapters/sql_ddl.py,sha256=HxvZDYri4GzUgSFf6SDsdI_5w44SOZSRMkqD23LDLVg,31332
|
|
62
|
-
krons/specs/catalog/__init__.py,sha256=Sdxl3HDK5LpjDZ0Cf-eBsErPLEGYJRiigMky719lRYY,1221
|
|
63
|
-
krons/specs/catalog/_audit.py,sha256=YYrIvEBsAHmRXiIUQrrp_qE6NmnUJq5rexxD5r3radw,1250
|
|
64
|
-
krons/specs/catalog/_common.py,sha256=-LyBKV1MMEE0QlrKjlqs9JBmJi_kCehB2Cr743jl94I,1197
|
|
65
|
-
krons/specs/catalog/_content.py,sha256=aG01G_X_AHPyYMg7ELdgVUPFLDjqM2BIuaxjKR3zDAs,1952
|
|
66
|
-
krons/specs/catalog/_enforcement.py,sha256=NmBwqXQxojBNkIECvPSy1kg1375sijhOXezwCPTa6LM,2111
|
|
67
|
-
krons/types/__init__.py,sha256=pJ6kuop7vSLZp5jMBs-CQ7CHRjvUuO8kHhpZ34KM85I,1049
|
|
68
|
-
krons/types/_sentinel.py,sha256=QJGyRAYNkJ2ylw6dhxPHJNgmxqBdorBd-xx7pNrUykw,8855
|
|
69
|
-
krons/types/base.py,sha256=1wE3Sjxt46cTkqgDT_35Go_1nM2qwVQGv-HJ58e8ATM,12307
|
|
70
|
-
krons/types/db_types.py,sha256=78nH6N5hwlwZv69jgBR5bVwpZx82P0mi893THebG-Gg,8126
|
|
71
|
-
krons/types/identity.py,sha256=Ccb5oJArC1PEzdzNPlLi_oK87uKx7BFevX9rvY9y-14,1949
|
|
72
|
-
krons/utils/__init__.py,sha256=BUQLqQoZ6Bz9eA0nEz9urPTVVS-FSOUWXZe3LMbhEj4,847
|
|
73
|
-
krons/utils/_hash.py,sha256=W2Ma9v8-INPaGkur7GTtbF8KwuXSJNSwk8DCNPRvx8Q,6859
|
|
74
|
-
krons/utils/_json_dump.py,sha256=rpBmr0NCmIKRdmpgn1nSWIHI3FTsGYsQjOa3YTxCi3M,12482
|
|
75
|
-
krons/utils/_lazy_init.py,sha256=bCx_W3dfzirB5KnAt6_jmbnwOk2xbU7-kgOhMQqzW70,1806
|
|
76
|
-
krons/utils/_to_list.py,sha256=LmGMwAhxP0RRr-pEYG01_nWVvb7ei95xn_ZlAJUquqc,6031
|
|
77
|
-
krons/utils/_to_num.py,sha256=NyyIL9Az1EaW6QFh9R7AeJdaUPoSRBNVBX9yj78wpok,3102
|
|
78
|
-
krons/utils/_utils.py,sha256=533D_1yTDURzn5QrnADT99_AEvK4P5g4FUYs3Ohkx6M,11089
|
|
79
|
-
krons/utils/concurrency/__init__.py,sha256=1HD-aY4Hevde0Hm0-VYa0eheT5OiwhlnDJtofIuV9wk,6754
|
|
80
|
-
krons/utils/concurrency/_async_call.py,sha256=T1YN7hh2vvG9hdheRlEVvXsGRU0p3v0GTisoMeLzx7g,10206
|
|
81
|
-
krons/utils/concurrency/_cancel.py,sha256=b9f6yT8gObS6Y3EWKoGzNfYxqM1ZrN_8ctfyIjT1m1U,3326
|
|
82
|
-
krons/utils/concurrency/_errors.py,sha256=tmszbwq7NPy3VTqJpvXxQ_2IVE024KkCqC27Bsoo4ZU,2597
|
|
83
|
-
krons/utils/concurrency/_patterns.py,sha256=OGCLd5ndMV7fZxKxTT6lPJTIgwu8euEBbhopIt6_Ijs,11534
|
|
84
|
-
krons/utils/concurrency/_primitives.py,sha256=D1Rl1hujXXPdL4Mw6eW5EN8utM3bh8vmmFtXmuvsDw0,9024
|
|
85
|
-
krons/utils/concurrency/_priority_queue.py,sha256=wGi6ESS6AIZ0QNRBQR5UwcSQI5GhKjATBC_aEw6c0aQ,4342
|
|
86
|
-
krons/utils/concurrency/_resource_tracker.py,sha256=hTn0PmxWbQ0uwTGB1YuPUKhtso2VyY7SVWtl4dkzZSU,3151
|
|
87
|
-
krons/utils/concurrency/_run_async.py,sha256=A_vuPi9-wWRr3oXiAMnv3l7MV2B76jkBXoVztX_Vcgo,1940
|
|
88
|
-
krons/utils/concurrency/_task.py,sha256=4ivkiUUbutheoYZ-G8-mTfHX4YgWguGIy1v5hSU871w,2528
|
|
89
|
-
krons/utils/concurrency/_utils.py,sha256=CyH_z4prYFeCFgwk4Pc3q0m5NRzDB2TP-G2oxdM_-C0,2136
|
|
90
|
-
krons/utils/fuzzy/__init__.py,sha256=0dZRhC7sgH0b3oiNFdnUpPq7Jgsb84sFXtCsxCFkdss,354
|
|
91
|
-
krons/utils/fuzzy/_extract_json.py,sha256=6Y-QEfXrTBdaNmlbMfVm6xJPBKI0RBbr_t0VYGE7nMo,2922
|
|
92
|
-
krons/utils/fuzzy/_fuzzy_json.py,sha256=hV6v9YkQpGxwOnhpLM6jkrG5fZKYluMTxgdqsk5sTew,9151
|
|
93
|
-
krons/utils/fuzzy/_fuzzy_match.py,sha256=rL_YuoAUVbnLxFCAZlXgPxeCmKjxH90r06mzuZ-jXk4,4855
|
|
94
|
-
krons/utils/fuzzy/_string_similarity.py,sha256=ZwAerTdXDen-6Q3Kg46ckXF_T69xFLYBEVdt8EZq95M,6141
|
|
95
|
-
krons/utils/fuzzy/_to_dict.py,sha256=ORQy-_6snt6TmVJZI-MHDoDO7jFYg-xlaxU_pBbfk7s,12911
|
|
96
|
-
krons/utils/sql/__init__.py,sha256=yNjm9Dr-ZjrZSD3Lext7fPR80qX5svGT2PnXqlb5qXs,264
|
|
97
|
-
krons/utils/sql/_sql_validation.py,sha256=smxNU3HjPhQuRK5ehG9Fl4DeljKK9tqUQIvRUopgvc8,4229
|
|
98
|
-
krons-0.1.1.dist-info/METADATA,sha256=88PmVejjLNnaSX-xRgqkSaP15gpLiladDaE6XvhbJiE,1997
|
|
99
|
-
krons-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
100
|
-
krons-0.1.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
101
|
-
krons-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|