pivot 0.2.3__tar.gz → 0.2.4__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.
- {pivot-0.2.3 → pivot-0.2.4}/PKG-INFO +1 -1
- {pivot-0.2.3 → pivot-0.2.4}/pyproject.toml +1 -1
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/engine.py +39 -20
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/fingerprint.py +12 -4
- {pivot-0.2.3 → pivot-0.2.4}/LICENSE +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/README.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/ast_utils.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/AGENTS.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/CLAUDE.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/_run_common.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/check_ignore.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/checkout.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/commit.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/completion.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/config.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/console.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/dag.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/data.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/decorators.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/doctor.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/errors.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/fingerprint.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/helpers.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/history.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/import_cmd.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/init.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/list.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/metrics.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/params.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/plots.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/remote.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/repro.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/run.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/status.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/targets.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/track.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/update.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/cli/verify.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/compose.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/config/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/config/io.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/config/models.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/dag/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/dag/render.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/decorators.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/discovery.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/agent_rpc.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/graph.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/scheduler.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/sinks.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/sources.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/types.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/watch.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/engine/worker_pool.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/exceptions.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/executor/AGENTS.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/executor/CLAUDE.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/executor/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/executor/commit.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/executor/core.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/executor/worker.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/explain.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/git.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/ignore.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/import_artifact.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/loaders.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/metrics.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/names.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/outputs.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/parameters.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/path_policy.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/project.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/py.typed +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/registry.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/AGENTS.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/config.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/git_archive.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/github.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/storage.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/remote/sync.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/run_history.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/show/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/show/common.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/show/data.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/show/metrics.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/show/params.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/show/plots.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/skip.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/stage_def.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/status.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/AGENTS.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/CLAUDE.md +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/__init__.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/artifact_lock.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/cache.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/lock.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/presentation.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/restore.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/state.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/store.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/storage/track.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/types.py +0 -0
- {pivot-0.2.3 → pivot-0.2.4}/src/pivot/yaml_config.py +0 -0
|
@@ -1306,26 +1306,6 @@ class Engine:
|
|
|
1306
1306
|
run_id=run_id,
|
|
1307
1307
|
)
|
|
1308
1308
|
|
|
1309
|
-
# Check cancellation
|
|
1310
|
-
if self._cancel_event.is_set():
|
|
1311
|
-
cancelled = self._scheduler.apply_cancel()
|
|
1312
|
-
for name, old_state in cancelled:
|
|
1313
|
-
await self.emit(
|
|
1314
|
-
StageStateChanged(
|
|
1315
|
-
type="stage_state_changed",
|
|
1316
|
-
stage=name,
|
|
1317
|
-
state=StageExecutionState.COMPLETED,
|
|
1318
|
-
previous_state=old_state,
|
|
1319
|
-
)
|
|
1320
|
-
)
|
|
1321
|
-
await self._emit_terminal_stage(
|
|
1322
|
-
name,
|
|
1323
|
-
StageStatus.CANCELLED,
|
|
1324
|
-
"cancelled",
|
|
1325
|
-
results,
|
|
1326
|
-
run_id=run_id,
|
|
1327
|
-
)
|
|
1328
|
-
|
|
1329
1309
|
# Start more stages if slots available
|
|
1330
1310
|
if not self._scheduler.stop_starting_new:
|
|
1331
1311
|
await self._start_ready_stages(
|
|
@@ -1389,6 +1369,9 @@ class Engine:
|
|
|
1389
1369
|
"Sentinel send failed (will rely on shutdown_event): %s", exc
|
|
1390
1370
|
)
|
|
1391
1371
|
|
|
1372
|
+
if self._cancel_event.is_set():
|
|
1373
|
+
await self._finalize_cancelled_stages(results, run_id)
|
|
1374
|
+
|
|
1392
1375
|
finally:
|
|
1393
1376
|
# Close StateDBs first (lightweight), then shut down worker pool.
|
|
1394
1377
|
with anyio.CancelScope(shield=True):
|
|
@@ -1682,6 +1665,19 @@ class Engine:
|
|
|
1682
1665
|
skipped = False
|
|
1683
1666
|
if skipped:
|
|
1684
1667
|
continue
|
|
1668
|
+
# A watch event may cancel this run while its coordinator skip check awaited.
|
|
1669
|
+
# Do not submit a stage to the pool after cancellation stopped admissions.
|
|
1670
|
+
if self._cancel_event.is_set():
|
|
1671
|
+
self._scheduler.release_resources(stage_name)
|
|
1672
|
+
await self._set_stage_state(stage_name, StageExecutionState.COMPLETED)
|
|
1673
|
+
await self._emit_terminal_stage(
|
|
1674
|
+
stage_name,
|
|
1675
|
+
StageStatus.CANCELLED,
|
|
1676
|
+
"cancelled",
|
|
1677
|
+
results,
|
|
1678
|
+
run_id=run_id,
|
|
1679
|
+
)
|
|
1680
|
+
continue
|
|
1685
1681
|
|
|
1686
1682
|
# Stage must run — lazily create pool on first dispatch
|
|
1687
1683
|
started += 1
|
|
@@ -2162,6 +2158,29 @@ class Engine:
|
|
|
2162
2158
|
|
|
2163
2159
|
return duration_ms
|
|
2164
2160
|
|
|
2161
|
+
async def _finalize_cancelled_stages(
|
|
2162
|
+
self,
|
|
2163
|
+
results: dict[str, executor_core.ExecutionSummary],
|
|
2164
|
+
run_id: str,
|
|
2165
|
+
) -> None:
|
|
2166
|
+
"""Mark every ready or pending stage cancelled exactly once."""
|
|
2167
|
+
for stage_name, old_state in self._scheduler.apply_cancel():
|
|
2168
|
+
await self.emit(
|
|
2169
|
+
StageStateChanged(
|
|
2170
|
+
type="stage_state_changed",
|
|
2171
|
+
stage=stage_name,
|
|
2172
|
+
state=StageExecutionState.COMPLETED,
|
|
2173
|
+
previous_state=old_state,
|
|
2174
|
+
)
|
|
2175
|
+
)
|
|
2176
|
+
await self._emit_terminal_stage(
|
|
2177
|
+
stage_name,
|
|
2178
|
+
StageStatus.CANCELLED,
|
|
2179
|
+
"cancelled",
|
|
2180
|
+
results,
|
|
2181
|
+
run_id=run_id,
|
|
2182
|
+
)
|
|
2183
|
+
|
|
2165
2184
|
async def _emit_terminal_stage(
|
|
2166
2185
|
self,
|
|
2167
2186
|
stage_name: str,
|
|
@@ -1217,6 +1217,11 @@ def _resolve_dotted_path(parts: tuple[str, ...], ns: dict[str, Any]) -> Any:
|
|
|
1217
1217
|
return obj
|
|
1218
1218
|
|
|
1219
1219
|
|
|
1220
|
+
def _method_function(method: Callable[..., Any]) -> Callable[..., Any]:
|
|
1221
|
+
"""Return the underlying function behind a bound method."""
|
|
1222
|
+
return cast("Callable[..., Any]", getattr(method, "__func__", method))
|
|
1223
|
+
|
|
1224
|
+
|
|
1220
1225
|
def get_loader_fingerprint(loader: "loaders.Writer[Any] | loaders.Reader[Any]") -> dict[str, str]:
|
|
1221
1226
|
"""Generate fingerprint manifest for a loader instance.
|
|
1222
1227
|
|
|
@@ -1244,13 +1249,14 @@ def get_loader_fingerprint(loader: "loaders.Writer[Any] | loaders.Reader[Any]")
|
|
|
1244
1249
|
if method is not None:
|
|
1245
1250
|
_process_callable_dependency(f"{class_name}.{method_name}", method, manifest, visited)
|
|
1246
1251
|
|
|
1247
|
-
#
|
|
1252
|
+
# Use each method definition rather than a temporary bound method so the
|
|
1253
|
+
# weak AST hash cache retains the entry across loader fingerprint calls.
|
|
1248
1254
|
if isinstance(loader, loaders_module.Writer):
|
|
1249
|
-
manifest[f"loader:{class_name}:save"] = hash_function_ast(loader.save)
|
|
1255
|
+
manifest[f"loader:{class_name}:save"] = hash_function_ast(_method_function(loader.save))
|
|
1250
1256
|
|
|
1251
1257
|
# Fingerprint load() if this is a Reader
|
|
1252
1258
|
if isinstance(loader, loaders_module.Reader):
|
|
1253
|
-
manifest[f"loader:{class_name}:load"] = hash_function_ast(loader.load)
|
|
1259
|
+
manifest[f"loader:{class_name}:load"] = hash_function_ast(_method_function(loader.load))
|
|
1254
1260
|
|
|
1255
1261
|
# Only fingerprint empty() if it's overridden in a Loader subclass
|
|
1256
1262
|
if isinstance(loader, loaders_module.Loader):
|
|
@@ -1262,7 +1268,9 @@ def get_loader_fingerprint(loader: "loaders.Writer[Any] | loaders.Reader[Any]")
|
|
|
1262
1268
|
break
|
|
1263
1269
|
if "empty" in cls.__dict__:
|
|
1264
1270
|
# Found override in a subclass
|
|
1265
|
-
manifest[f"loader:{class_name}:empty"] = hash_function_ast(
|
|
1271
|
+
manifest[f"loader:{class_name}:empty"] = hash_function_ast(
|
|
1272
|
+
_method_function(typed_loader.empty)
|
|
1273
|
+
)
|
|
1266
1274
|
break
|
|
1267
1275
|
|
|
1268
1276
|
loader_any = cast("Any", loader)
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|