dirigent-core 0.16.0__tar.gz → 0.16.2__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.
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/PKG-INFO +4 -4
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/pyproject.toml +4 -4
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/pyproject.toml.orig +4 -4
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/pipelines.py +19 -5
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/protocol.py +11 -1
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/secrets.py +6 -2
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/LICENSE +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/README.md +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/__init__.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/alembic/env.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/alembic/script.py.mako +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/alembic/versions/0001_baseline_schema.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/alerting.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/artifacts.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/auth.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/blockdocs.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/config.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/configdocs.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/database.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/directory.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/documents.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/documentschema.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/__init__.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/claim.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/context.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/definition.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/executor.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/failure.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/recovery.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/references.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/runs.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/services.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/engine/state.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/examples.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/ids.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/logging.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/migrations.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/models.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/plugins.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/py.typed +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/ratelimit.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/registry.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/reporting.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/retention.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/scheduler.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/schemas.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/storage.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/telemetry.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/trigger_documents.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/triggers/__init__.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/triggers/backfill.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/triggers/materialize.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/triggers/schedules.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/triggers/webhooks.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/types.py +0 -0
- {dirigent_core-0.16.0 → dirigent_core-0.16.2}/src/dirigent_core/worker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dirigent-core
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.2
|
|
4
4
|
Summary: Dirigent engine core: schema, configuration, and plugin host.
|
|
5
5
|
License-Expression: LicenseRef-Proprietary
|
|
6
6
|
License-File: LICENSE
|
|
@@ -10,9 +10,9 @@ Requires-Dist: argon2-cffi>=25.1.0
|
|
|
10
10
|
Requires-Dist: asyncpg>=0.31.0
|
|
11
11
|
Requires-Dist: cronsim>=2.7
|
|
12
12
|
Requires-Dist: cryptography>=46.0.5
|
|
13
|
-
Requires-Dist: dirigent-client
|
|
14
|
-
Requires-Dist: dirigent-common
|
|
15
|
-
Requires-Dist: dirigent-plugin
|
|
13
|
+
Requires-Dist: dirigent-client==0.16.2
|
|
14
|
+
Requires-Dist: dirigent-common==0.16.2
|
|
15
|
+
Requires-Dist: dirigent-plugin==0.16.2
|
|
16
16
|
Requires-Dist: jsonschema>=4.26.0
|
|
17
17
|
Requires-Dist: opentelemetry-api>=1.44.0
|
|
18
18
|
Requires-Dist: pydantic-settings>=2.15.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dirigent-core"
|
|
3
|
-
version = "0.16.
|
|
3
|
+
version = "0.16.2"
|
|
4
4
|
description = "Dirigent engine core: schema, configuration, and plugin host."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
@@ -13,9 +13,9 @@ dependencies = [
|
|
|
13
13
|
"asyncpg>=0.31.0",
|
|
14
14
|
"cronsim>=2.7",
|
|
15
15
|
"cryptography>=46.0.5",
|
|
16
|
-
"dirigent-client",
|
|
17
|
-
"dirigent-common",
|
|
18
|
-
"dirigent-plugin",
|
|
16
|
+
"dirigent-client==0.16.2",
|
|
17
|
+
"dirigent-common==0.16.2",
|
|
18
|
+
"dirigent-plugin==0.16.2",
|
|
19
19
|
"jsonschema>=4.26.0",
|
|
20
20
|
"opentelemetry-api>=1.44.0",
|
|
21
21
|
"pydantic-settings>=2.15.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dirigent-core"
|
|
3
|
-
version = "0.16.
|
|
3
|
+
version = "0.16.2"
|
|
4
4
|
description = "Dirigent engine core: schema, configuration, and plugin host."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
@@ -13,9 +13,9 @@ dependencies = [
|
|
|
13
13
|
"asyncpg>=0.31.0",
|
|
14
14
|
"cronsim>=2.7",
|
|
15
15
|
"cryptography>=46.0.5",
|
|
16
|
-
"dirigent-client",
|
|
17
|
-
"dirigent-common",
|
|
18
|
-
"dirigent-plugin",
|
|
16
|
+
"dirigent-client==0.16.2",
|
|
17
|
+
"dirigent-common==0.16.2",
|
|
18
|
+
"dirigent-plugin==0.16.2",
|
|
19
19
|
"jsonschema>=4.26.0",
|
|
20
20
|
"opentelemetry-api>=1.44.0",
|
|
21
21
|
"pydantic-settings>=2.15.0",
|
|
@@ -471,24 +471,38 @@ async def last_runs(session: AsyncSession, pipeline_ids: Sequence[UUID]) -> dict
|
|
|
471
471
|
status=row.status,
|
|
472
472
|
started_at=row.started_at,
|
|
473
473
|
finished_at=row.finished_at,
|
|
474
|
-
failed_step=failing.
|
|
474
|
+
failed_step=failing[row.id].step if row.id in failing else None,
|
|
475
475
|
)
|
|
476
476
|
for row in rows
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
|
|
480
|
-
|
|
481
|
-
"""
|
|
480
|
+
class FailedStep(NamedTuple):
|
|
481
|
+
"""A run's first failed attempt, as a listing names it: which step, and what it said."""
|
|
482
|
+
|
|
483
|
+
step: str
|
|
484
|
+
error: str | None
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
async def failing_steps(session: AsyncSession, run_ids: Sequence[UUID]) -> dict[UUID, FailedStep]:
|
|
488
|
+
"""Name the step each run's first failed attempt was of, and what that attempt said.
|
|
489
|
+
|
|
490
|
+
A run row carries no error of its own unless it was cancelled: what went wrong is written
|
|
491
|
+
on the attempt, so a listing that names the step reads its message from the same row.
|
|
492
|
+
"""
|
|
482
493
|
if not run_ids:
|
|
483
494
|
return {}
|
|
484
495
|
ranked = (
|
|
485
496
|
sa.select(
|
|
486
497
|
StepAttempt.run_id,
|
|
487
498
|
StepAttempt.step_name,
|
|
499
|
+
StepAttempt.error,
|
|
488
500
|
sa.func.row_number().over(partition_by=StepAttempt.run_id, order_by=StepAttempt.id).label("rank"),
|
|
489
501
|
)
|
|
490
502
|
.where(StepAttempt.run_id.in_(run_ids), StepAttempt.status == AttemptStatus.FAILED)
|
|
491
503
|
.subquery()
|
|
492
504
|
)
|
|
493
|
-
rows = await session.execute(
|
|
494
|
-
|
|
505
|
+
rows = await session.execute(
|
|
506
|
+
sa.select(ranked.c.run_id, ranked.c.step_name, ranked.c.error).where(ranked.c.rank == 1)
|
|
507
|
+
)
|
|
508
|
+
return {run_id: FailedStep(step, error) for run_id, step, error in rows.all()}
|
|
@@ -33,6 +33,10 @@ ABSENT: Final = "-"
|
|
|
33
33
|
LEVEL_WIDTH: Final = 8
|
|
34
34
|
MESSAGE_WIDTH: Final = 30
|
|
35
35
|
|
|
36
|
+
#: The first year a zone's offset is a whole-minute standard one everywhere. Before it, a
|
|
37
|
+
#: conversion into the reader's zone spells local mean time rather than a time.
|
|
38
|
+
STANDARD_TIME_YEAR: Final = 1900
|
|
39
|
+
|
|
36
40
|
#: Nested values are spread into ``prefix.key`` fields for the flat spellings.
|
|
37
41
|
NESTED_PREFIXES: Final[Mapping[str, str]] = {"output": "output.", "fields": ""}
|
|
38
42
|
|
|
@@ -173,13 +177,19 @@ def _pad(text: str, width: int) -> str:
|
|
|
173
177
|
|
|
174
178
|
|
|
175
179
|
def _stamp(at: str, *, local: bool) -> str:
|
|
176
|
-
"""Render an instant for a person: the same moment, in the reader's own offset.
|
|
180
|
+
"""Render an instant for a person: the same moment, in the reader's own offset.
|
|
181
|
+
|
|
182
|
+
A moment from before standard time is left in the spelling it arrived in: a zone's offset
|
|
183
|
+
that far back is its local mean time, and a line reading ``+00:53:28`` says nothing.
|
|
184
|
+
"""
|
|
177
185
|
if not local:
|
|
178
186
|
return at
|
|
179
187
|
try:
|
|
180
188
|
parsed = datetime.fromisoformat(at)
|
|
181
189
|
except ValueError:
|
|
182
190
|
return at
|
|
191
|
+
if parsed.year < STANDARD_TIME_YEAR:
|
|
192
|
+
return at
|
|
183
193
|
return parsed.astimezone().isoformat(timespec="milliseconds")
|
|
184
194
|
|
|
185
195
|
|
|
@@ -33,8 +33,7 @@ class SecretKeyMissing(SecretError):
|
|
|
33
33
|
"""Say exactly which variable to set, and how to generate a key."""
|
|
34
34
|
super().__init__(
|
|
35
35
|
"no secret key is configured: set DIRIGENT_SECRET_KEY before storing or reading "
|
|
36
|
-
"connection secrets (generate one with `
|
|
37
|
-
'"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"`)'
|
|
36
|
+
"connection secrets (generate one with `dg secret-key`)"
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
|
|
@@ -51,6 +50,11 @@ class SecretKeyMismatch(SecretError):
|
|
|
51
50
|
self.key_id = key_id
|
|
52
51
|
|
|
53
52
|
|
|
53
|
+
def generate_key() -> str:
|
|
54
|
+
"""Mint a key for DIRIGENT_SECRET_KEY."""
|
|
55
|
+
return Fernet.generate_key().decode()
|
|
56
|
+
|
|
57
|
+
|
|
54
58
|
def derive_key(material: str) -> bytes:
|
|
55
59
|
"""Turn configured key material into a Fernet key, accepting a passphrase as well.
|
|
56
60
|
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|