tangle-cli 0.1.18__tar.gz → 0.1.19__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.
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/PKG-INFO +29 -1
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/README.md +28 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/__init__.py +1 -1
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_compiler.py +38 -2
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipelines.py +11 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/compiler_context.py +8 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/errors.py +11 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/schema_validation.py +158 -8
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/pyproject.toml +1 -1
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/pyproject.toml.orig +1 -1
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/api_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/api_schema.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/api_transport.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/args_container.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/artifacts.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/artifacts_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/authenticated_identity.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/cli_helpers.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/cli_options.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/client.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_from_func.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_generator.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_inspector.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_publisher.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/components_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/dynamic_discovery_client.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/generated_model_extensions.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/handler.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/hydration_trust.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/logger.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/models.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/module_bundler.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/openapi/parser.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_annotations.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_spec_utils.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_validation.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipelines_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/published_components_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/py.typed +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/__init__.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/cfg.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/dynamic_data.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/emit.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/graph.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/ids.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/pipeline.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/placeholders.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/publish.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/raw.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/ref.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/registered.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/subpipeline.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/task.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/task_env.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/trace.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/types.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/quickstart.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/schemas/__init__.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/schemas/dehydrated_pipeline_schema.json +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/schemas/pipeline_schema.json +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/secrets.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/secrets_cli.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/utils.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/version_manager.py +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/OSS-CONVENTIONS.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/PORT-README.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/SKILL.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/auth-wizard.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/builder.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/debugger.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/reporter.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/researcher.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/reviewer.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/agents/scenario-builder.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/data-sources.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/event-log.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/example-scenarios/01-mslr-ranking.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/example-scenarios/02-text-classification.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/example-scenarios/INDEX.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/iterating-on-runs.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/knowledge-corpus.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/secrets.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/setup.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-0-initialize.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-1-analyze.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-2-hypothesize.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-3-submit.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-4-monitor.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-5-evaluate.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-6-synthesize.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/step-7-decide.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/tangle-tools.md +0 -0
- {tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/uploading-artifacts.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: tangle-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.19
|
|
4
4
|
Summary: CLI for Tangle, the open-source ML pipeline orchestration platform
|
|
5
5
|
Author: Alexey Volkov, Tangle authors, Volv Grebennikov
|
|
6
6
|
Author-email: Alexey Volkov <alexey.volkov@ark-kun.com>, Volv Grebennikov <volv.grebennikov@shopify.com>
|
|
@@ -537,6 +537,34 @@ def greeting_pipeline(who: In[str], cfg) -> Out[str]:
|
|
|
537
537
|
|
|
538
538
|
Task IDs default from the left-hand variable name at the call site, converted to title case. If there is no simple left-hand variable, or if you want a stable explicit label, call `.named("Task Id")` before invoking the task. Use `.bind(...)` to pre-fill task arguments and `.with_annotations({...})` to add per-task annotations.
|
|
539
539
|
|
|
540
|
+
##### Root pipeline annotations
|
|
541
|
+
|
|
542
|
+
`@pipeline(annotations={...})` writes the compiled pipeline's root `metadata.annotations` block. A caller that compiles programmatically can supply the block instead — typically from its own per-environment config file, so the values do not have to be hard-coded in source:
|
|
543
|
+
|
|
544
|
+
```python
|
|
545
|
+
from tangle_cli.pipelines import compile_pipeline_file
|
|
546
|
+
|
|
547
|
+
compile_pipeline_file(
|
|
548
|
+
"pipeline.py",
|
|
549
|
+
"pipeline.yaml",
|
|
550
|
+
pipeline_annotations={"environment": "staging", "owner": "search-platform"},
|
|
551
|
+
)
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
The same keyword exists on `tangle_cli.pipeline_compiler.compile_pipeline` and on `PipelineCompiler.compile_file`. There is no CLI flag: the source route already exists, and what the keyword adds is a programmatic/config route for the part of the block that varies by environment.
|
|
555
|
+
|
|
556
|
+
Semantics:
|
|
557
|
+
|
|
558
|
+
- **Per-key merge, caller wins.** `@pipeline(annotations={"author": "a", "version": "1.0"})` compiled with `pipeline_annotations={"version": "2.0", "environment": "staging"}` emits all three keys, with `version: "2.0"`. Source keys the caller does not mention are preserved, so invariants stay in source and only the varying subset is passed in.
|
|
559
|
+
- **Omitted or `{}` is a no-op**, byte for byte — an empty mapping is not a destructive clear of the source block.
|
|
560
|
+
- **Root only.** `subpipeline` children never inherit it, so child subgraph sidecar names, bytes, and component digests are unaffected. A child that wants annotations declares its own.
|
|
561
|
+
- **Descriptive only.** Root metadata is not read by the orchestrator, so it cannot influence placement, routing, scheduling, or run identity. Use pipeline-run annotations for anything execution-bearing.
|
|
562
|
+
- **`str -> str`, validated up front.** A non-mapping argument, a non-string key or value, an empty key, a `system/`-prefixed key (reserved by Tangle), or a template delimiter (`{{`, `{%`, `{#`) in a key or value raises `InvalidPipelineAnnotationsError` (a `CompileError`) before anything is imported or written. Annotations usually come from an untrusted config file, so the diagnostics name the key and the type and never echo a value. Values are baked into the compiled YAML and the stored pipeline definition: labels only, never secrets.
|
|
563
|
+
|
|
564
|
+
The rules live in one place, `tangle_cli.schema_validation`: `check_annotations(mapping, policy=..., error_cls=...)` applied under a named `AnnotationPolicy`. `CALLER_ANNOTATION_POLICY` is the strict input policy described above; `DOCUMENT_ANNOTATION_POLICY` is the lenient policy every pipeline document is validated against (scalar-or-null values, no key rules), matching the schema and hand-authored YAML. Only the caller-supplied input surface is strict: existing documents are accepted exactly as before, and the document check still runs on the merged result, so annotations reaching the output by any route are validated.
|
|
565
|
+
|
|
566
|
+
A distribution that reads these annotations from its own config file should call `check_annotations(mapping, policy=CALLER_ANNOTATION_POLICY, error_cls=...)` at config-parse time — passing its own error type and adding the config path and key to the message — so one user mistake produces one diagnostic instead of two competing ones. The compiler's own call is then the backstop for anything arriving by another route.
|
|
567
|
+
|
|
540
568
|
##### Conditional task execution
|
|
541
569
|
|
|
542
570
|
Pipeline inputs used as conditions are ordinary `In[str]` values; there is no special conditional input annotation. Pass the value through the reserved task-call metadata keyword `is_enabled=`:
|
|
@@ -511,6 +511,34 @@ def greeting_pipeline(who: In[str], cfg) -> Out[str]:
|
|
|
511
511
|
|
|
512
512
|
Task IDs default from the left-hand variable name at the call site, converted to title case. If there is no simple left-hand variable, or if you want a stable explicit label, call `.named("Task Id")` before invoking the task. Use `.bind(...)` to pre-fill task arguments and `.with_annotations({...})` to add per-task annotations.
|
|
513
513
|
|
|
514
|
+
##### Root pipeline annotations
|
|
515
|
+
|
|
516
|
+
`@pipeline(annotations={...})` writes the compiled pipeline's root `metadata.annotations` block. A caller that compiles programmatically can supply the block instead — typically from its own per-environment config file, so the values do not have to be hard-coded in source:
|
|
517
|
+
|
|
518
|
+
```python
|
|
519
|
+
from tangle_cli.pipelines import compile_pipeline_file
|
|
520
|
+
|
|
521
|
+
compile_pipeline_file(
|
|
522
|
+
"pipeline.py",
|
|
523
|
+
"pipeline.yaml",
|
|
524
|
+
pipeline_annotations={"environment": "staging", "owner": "search-platform"},
|
|
525
|
+
)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
The same keyword exists on `tangle_cli.pipeline_compiler.compile_pipeline` and on `PipelineCompiler.compile_file`. There is no CLI flag: the source route already exists, and what the keyword adds is a programmatic/config route for the part of the block that varies by environment.
|
|
529
|
+
|
|
530
|
+
Semantics:
|
|
531
|
+
|
|
532
|
+
- **Per-key merge, caller wins.** `@pipeline(annotations={"author": "a", "version": "1.0"})` compiled with `pipeline_annotations={"version": "2.0", "environment": "staging"}` emits all three keys, with `version: "2.0"`. Source keys the caller does not mention are preserved, so invariants stay in source and only the varying subset is passed in.
|
|
533
|
+
- **Omitted or `{}` is a no-op**, byte for byte — an empty mapping is not a destructive clear of the source block.
|
|
534
|
+
- **Root only.** `subpipeline` children never inherit it, so child subgraph sidecar names, bytes, and component digests are unaffected. A child that wants annotations declares its own.
|
|
535
|
+
- **Descriptive only.** Root metadata is not read by the orchestrator, so it cannot influence placement, routing, scheduling, or run identity. Use pipeline-run annotations for anything execution-bearing.
|
|
536
|
+
- **`str -> str`, validated up front.** A non-mapping argument, a non-string key or value, an empty key, a `system/`-prefixed key (reserved by Tangle), or a template delimiter (`{{`, `{%`, `{#`) in a key or value raises `InvalidPipelineAnnotationsError` (a `CompileError`) before anything is imported or written. Annotations usually come from an untrusted config file, so the diagnostics name the key and the type and never echo a value. Values are baked into the compiled YAML and the stored pipeline definition: labels only, never secrets.
|
|
537
|
+
|
|
538
|
+
The rules live in one place, `tangle_cli.schema_validation`: `check_annotations(mapping, policy=..., error_cls=...)` applied under a named `AnnotationPolicy`. `CALLER_ANNOTATION_POLICY` is the strict input policy described above; `DOCUMENT_ANNOTATION_POLICY` is the lenient policy every pipeline document is validated against (scalar-or-null values, no key rules), matching the schema and hand-authored YAML. Only the caller-supplied input surface is strict: existing documents are accepted exactly as before, and the document check still runs on the merged result, so annotations reaching the output by any route are validated.
|
|
539
|
+
|
|
540
|
+
A distribution that reads these annotations from its own config file should call `check_annotations(mapping, policy=CALLER_ANNOTATION_POLICY, error_cls=...)` at config-parse time — passing its own error type and adding the config path and key to the message — so one user mistake produces one diagnostic instead of two competing ones. The compiler's own call is then the backstop for anything arriving by another route.
|
|
541
|
+
|
|
514
542
|
##### Conditional task execution
|
|
515
543
|
|
|
516
544
|
Pipeline inputs used as conditions are ordinary `In[str]` values; there is no special conditional input annotation. Pass the value through the reserved task-call metadata keyword `is_enabled=`:
|
|
@@ -14,6 +14,6 @@ from tangle_cli.dynamic_discovery_client import TangleDynamicDiscoveryClient
|
|
|
14
14
|
try:
|
|
15
15
|
__version__ = metadata_version("tangle-cli")
|
|
16
16
|
except PackageNotFoundError:
|
|
17
|
-
__version__ = "0.1.
|
|
17
|
+
__version__ = "0.1.19"
|
|
18
18
|
|
|
19
19
|
__all__ = ["TangleDynamicDiscoveryClient", "__version__"]
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_compiler.py
RENAMED
|
@@ -65,14 +65,19 @@ from .python_pipeline.compiler_context import (
|
|
|
65
65
|
overrides_fingerprint,
|
|
66
66
|
)
|
|
67
67
|
from .python_pipeline.emit import _TASK_URL_PLACEHOLDER, emit_pipeline
|
|
68
|
-
from .python_pipeline.errors import CompileError
|
|
68
|
+
from .python_pipeline.errors import CompileError, InvalidPipelineAnnotationsError
|
|
69
69
|
from .python_pipeline.pipeline import PipelineFn
|
|
70
70
|
from .python_pipeline.ref import CallableRef
|
|
71
71
|
from .python_pipeline.registered import _REGISTERED_URL_PLACEHOLDER
|
|
72
72
|
from .python_pipeline.subpipeline import _SUBPIPELINE_URL_PLACEHOLDER, SubpipelineRef
|
|
73
73
|
from .python_pipeline.trace import trace_pipeline
|
|
74
74
|
from .python_pipeline.types import In
|
|
75
|
-
from .schema_validation import
|
|
75
|
+
from .schema_validation import (
|
|
76
|
+
CALLER_ANNOTATION_POLICY,
|
|
77
|
+
SchemaValidationError,
|
|
78
|
+
check_annotations,
|
|
79
|
+
validate_dehydrated_pipeline,
|
|
80
|
+
)
|
|
76
81
|
from .utils import dump_yaml
|
|
77
82
|
|
|
78
83
|
|
|
@@ -141,6 +146,7 @@ def compile_pipeline(
|
|
|
141
146
|
pipeline_name: str | None = None,
|
|
142
147
|
emit_components_sidecar: bool = True,
|
|
143
148
|
image_overrides: Mapping[str, str] | None = None,
|
|
149
|
+
pipeline_annotations: Mapping[str, str] | None = None,
|
|
144
150
|
) -> CompileResult:
|
|
145
151
|
"""Compile ``script`` to a single pipeline YAML at ``output``.
|
|
146
152
|
|
|
@@ -174,6 +180,18 @@ def compile_pipeline(
|
|
|
174
180
|
image_overrides: Compile-time image-id overrides from ``--image
|
|
175
181
|
ID=REF``. They apply only to ``@task(image_id=...)`` refs that do
|
|
176
182
|
not also set an explicit ``image=``.
|
|
183
|
+
pipeline_annotations: Caller-supplied ROOT ``metadata.annotations``
|
|
184
|
+
(``str -> str``), typically read from a downstream config file so
|
|
185
|
+
the block can vary per environment. Merged PER KEY over the root
|
|
186
|
+
``@pipeline(annotations=...)`` block, caller winning on collision;
|
|
187
|
+
``None`` / ``{}`` is a no-op that leaves the compiled bytes
|
|
188
|
+
identical. ROOT ONLY — ``subpipeline`` children do not inherit it,
|
|
189
|
+
so their sidecar names, bytes, and digests are unaffected. Root
|
|
190
|
+
metadata is descriptive: it is not read by the orchestrator and
|
|
191
|
+
cannot influence placement, routing, scheduling, or identity. See
|
|
192
|
+
:data:`tangle_cli.schema_validation.CALLER_ANNOTATION_POLICY`
|
|
193
|
+
for the accepted shape; a malformed mapping raises
|
|
194
|
+
:class:`~tangle_cli.python_pipeline.errors.InvalidPipelineAnnotationsError`.
|
|
177
195
|
|
|
178
196
|
Returns:
|
|
179
197
|
A :class:`CompileResult`. ``components_path`` is the sidecar path
|
|
@@ -186,6 +204,15 @@ def compile_pipeline(
|
|
|
186
204
|
"""
|
|
187
205
|
overrides = dict(overrides or {})
|
|
188
206
|
image_overrides = dict(image_overrides or {})
|
|
207
|
+
# Validated up front, by the shared validation layer, so a hostile or
|
|
208
|
+
# malformed annotation mapping fails before any module is imported or any
|
|
209
|
+
# file is written. The compiler owns no annotation rules of its own; it
|
|
210
|
+
# only chooses the caller-facing error type.
|
|
211
|
+
root_annotations = check_annotations(
|
|
212
|
+
pipeline_annotations,
|
|
213
|
+
policy=CALLER_ANNOTATION_POLICY,
|
|
214
|
+
error_cls=InvalidPipelineAnnotationsError,
|
|
215
|
+
)
|
|
189
216
|
|
|
190
217
|
# 1. Validate the script path.
|
|
191
218
|
script_path = Path(script).resolve()
|
|
@@ -241,6 +268,7 @@ def compile_pipeline(
|
|
|
241
268
|
emit_components_sidecar=emit_components_sidecar,
|
|
242
269
|
source_dirs=purge_dirs,
|
|
243
270
|
image_overrides=image_overrides,
|
|
271
|
+
pipeline_annotations=root_annotations,
|
|
244
272
|
)
|
|
245
273
|
|
|
246
274
|
# 5. Compile the root (and, recursively, all children) into in-memory
|
|
@@ -445,6 +473,12 @@ def _compile_pipeline_fn(
|
|
|
445
473
|
# output guard must skip for THIS artifact's body.
|
|
446
474
|
with _temp_sys_path(base_dir):
|
|
447
475
|
builder = trace_pipeline(pipeline_fn, cfg=cfg, inputs={})
|
|
476
|
+
# Caller-supplied root annotations: ROOT ONLY (a child keeps exactly what
|
|
477
|
+
# its own ``@pipeline`` declared), merged PER KEY with the caller winning
|
|
478
|
+
# on collision, before emit so they pass the same emit-time guards as
|
|
479
|
+
# authored ones. ``update`` keeps the emitted order source-first.
|
|
480
|
+
if is_root and ctx.pipeline_annotations:
|
|
481
|
+
builder.annotations.update(ctx.pipeline_annotations)
|
|
448
482
|
body_dict, exempt_paths = emit_pipeline(builder)
|
|
449
483
|
|
|
450
484
|
# 3. The canonical compile key for dedup / cycle detection. A child is
|
|
@@ -2785,6 +2819,7 @@ class PipelineCompiler(TangleCliHandler):
|
|
|
2785
2819
|
pipeline_name: str | None = None,
|
|
2786
2820
|
emit_components_sidecar: bool = True,
|
|
2787
2821
|
image_overrides: Mapping[str, str] | None = None,
|
|
2822
|
+
pipeline_annotations: Mapping[str, str] | None = None,
|
|
2788
2823
|
) -> CompileResult:
|
|
2789
2824
|
"""Compile ``script`` to a single dehydrated pipeline YAML at ``output``.
|
|
2790
2825
|
|
|
@@ -2804,6 +2839,7 @@ class PipelineCompiler(TangleCliHandler):
|
|
|
2804
2839
|
pipeline_name=pipeline_name,
|
|
2805
2840
|
emit_components_sidecar=emit_components_sidecar,
|
|
2806
2841
|
image_overrides=image_overrides,
|
|
2842
|
+
pipeline_annotations=pipeline_annotations,
|
|
2807
2843
|
)
|
|
2808
2844
|
self.log.info(f"wrote {result.pipeline_path}")
|
|
2809
2845
|
if result.components_path is not None:
|
|
@@ -259,6 +259,7 @@ def compile_pipeline_file(
|
|
|
259
259
|
pipeline_name: str | None = None,
|
|
260
260
|
emit_components_sidecar: bool = True,
|
|
261
261
|
image_overrides: Mapping[str, str] | None = None,
|
|
262
|
+
pipeline_annotations: Mapping[str, str] | None = None,
|
|
262
263
|
logger: Any | None = None,
|
|
263
264
|
) -> CompileResult:
|
|
264
265
|
"""Compile a Python-authored pipeline to a dehydrated YAML bundle.
|
|
@@ -271,6 +272,12 @@ def compile_pipeline_file(
|
|
|
271
272
|
The :class:`~tangle_cli.pipeline_compiler.CompileResult` is returned as-is —
|
|
272
273
|
unlike hydrate, the compiler already exposes its public result type, so there
|
|
273
274
|
is nothing to repackage.
|
|
275
|
+
|
|
276
|
+
``pipeline_annotations`` supplies ROOT ``metadata.annotations`` (``str ->
|
|
277
|
+
str``) merged per key over the root ``@pipeline(annotations=...)`` block,
|
|
278
|
+
caller winning on collision; it applies to the root only and is a no-op
|
|
279
|
+
when omitted or empty. See
|
|
280
|
+
:func:`~tangle_cli.pipeline_compiler.compile_pipeline`.
|
|
274
281
|
"""
|
|
275
282
|
|
|
276
283
|
from .pipeline_compiler import PipelineCompiler
|
|
@@ -286,6 +293,10 @@ def compile_pipeline_file(
|
|
|
286
293
|
pipeline_name=pipeline_name,
|
|
287
294
|
emit_components_sidecar=emit_components_sidecar,
|
|
288
295
|
image_overrides=dict(image_overrides) if image_overrides else None,
|
|
296
|
+
# Passed through unconverted: the compiler validates the shape and
|
|
297
|
+
# takes its own copy, so a malformed mapping fails with the
|
|
298
|
+
# compiler's value-free CompileError instead of a bare TypeError.
|
|
299
|
+
pipeline_annotations=pipeline_annotations,
|
|
289
300
|
)
|
|
290
301
|
except (CompileError, SchemaValidationError) as exc:
|
|
291
302
|
raise PipelineValidationError(str(exc)) from exc
|
|
@@ -253,6 +253,14 @@ class CompileContext:
|
|
|
253
253
|
root_overrides: dict[str, str] = field(default_factory=dict)
|
|
254
254
|
emit_components_sidecar: bool = True
|
|
255
255
|
image_overrides: dict[str, str] = field(default_factory=dict)
|
|
256
|
+
# Caller-supplied ROOT ``metadata.annotations`` (already validated),
|
|
257
|
+
# merged PER KEY over the root ``@pipeline(annotations=...)`` block just
|
|
258
|
+
# before emit. ROOT ONLY: children never inherit it, so a child sidecar's
|
|
259
|
+
# bytes — and therefore its component digest — are untouched by it. It is
|
|
260
|
+
# deliberately absent from :class:`PipelineCompileKey` /
|
|
261
|
+
# ``overrides_fingerprint`` (as ``image_overrides`` is), so sidecar
|
|
262
|
+
# filenames stay identity-derived rather than content-derived.
|
|
263
|
+
pipeline_annotations: dict[str, str] = field(default_factory=dict)
|
|
256
264
|
max_depth: int = 32
|
|
257
265
|
# Compiled CHILD artifacts keyed by compile key (Decision M dedup).
|
|
258
266
|
# The root is NOT stored here; it is returned directly.
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/errors.py
RENAMED
|
@@ -27,3 +27,14 @@ class AmbiguousTaskIdError(CompileError):
|
|
|
27
27
|
|
|
28
28
|
class InvalidArgumentTypeError(CompileError):
|
|
29
29
|
"""Raised on an argument value with no supported emit dispatch."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class InvalidPipelineAnnotationsError(CompileError):
|
|
33
|
+
"""Raised on a malformed caller-supplied ``pipeline_annotations`` mapping.
|
|
34
|
+
|
|
35
|
+
A dedicated type because these annotations usually originate in a
|
|
36
|
+
downstream CONFIG file: a caller that reads such a file can catch this
|
|
37
|
+
precisely and re-raise with the config path and key attached, without
|
|
38
|
+
broadly catching :class:`CompileError` and swallowing unrelated compile
|
|
39
|
+
failures. Messages never echo an annotation value.
|
|
40
|
+
"""
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/schema_validation.py
RENAMED
|
@@ -25,6 +25,12 @@ Public surface:
|
|
|
25
25
|
``taskOutput.taskId``, undeclared ``graphInput.inputName``,
|
|
26
26
|
``outputValues`` ↔ ``outputs`` correspondence, scalar metadata
|
|
27
27
|
annotations, pure componentRefs) and the no-template-delimiter scan.
|
|
28
|
+
* :func:`check_annotations` plus :data:`DOCUMENT_ANNOTATION_POLICY` /
|
|
29
|
+
:data:`CALLER_ANNOTATION_POLICY` — the ONE place that says what a
|
|
30
|
+
``metadata.annotations`` mapping may contain. Both the lenient check
|
|
31
|
+
applied to every pipeline DOCUMENT and the strict check applied to a
|
|
32
|
+
caller/config-supplied mapping are the same function under different
|
|
33
|
+
policies, so the two can never drift apart.
|
|
28
34
|
|
|
29
35
|
Everything here is standalone — it never changes ``PipelineHydrator``
|
|
30
36
|
behavior. ``compile_pipeline`` uses :func:`validate_dehydrated_pipeline`
|
|
@@ -34,6 +40,7 @@ from __future__ import annotations
|
|
|
34
40
|
|
|
35
41
|
import json
|
|
36
42
|
from collections.abc import Collection, Iterator, Mapping
|
|
43
|
+
from dataclasses import dataclass
|
|
37
44
|
from functools import lru_cache
|
|
38
45
|
from pathlib import Path
|
|
39
46
|
from typing import Any
|
|
@@ -195,6 +202,152 @@ def assert_no_template_delimiters(
|
|
|
195
202
|
)
|
|
196
203
|
|
|
197
204
|
|
|
205
|
+
# ---------------------------------------------------------------------------
|
|
206
|
+
# Annotation policy: the one definition of what an annotations mapping may
|
|
207
|
+
# contain, applied at two documented strictness levels.
|
|
208
|
+
|
|
209
|
+
#: Annotation-key prefix Tangle reserves for its own annotations.
|
|
210
|
+
RESERVED_ANNOTATION_KEY_PREFIX = "system/"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@dataclass(frozen=True)
|
|
214
|
+
class AnnotationPolicy:
|
|
215
|
+
"""Which rules :func:`check_annotations` applies, and how it names the
|
|
216
|
+
mapping in diagnostics (``label``).
|
|
217
|
+
|
|
218
|
+
Every flag defaults to off, so a policy opts IN to strictness. With
|
|
219
|
+
``require_string_values`` off, values fall back to the legacy
|
|
220
|
+
scalar-or-null rule rather than being unchecked.
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
label: str
|
|
224
|
+
require_string_values: bool = False
|
|
225
|
+
require_string_keys: bool = False
|
|
226
|
+
require_non_empty_keys: bool = False
|
|
227
|
+
reject_reserved_key_prefix: bool = False
|
|
228
|
+
reject_template_delimiters: bool = False
|
|
229
|
+
reject_non_mapping: bool = False
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
#: Applied to every pipeline document validated by
|
|
233
|
+
#: :func:`validate_dehydrated_pipeline`. Deliberately lenient: hand-authored
|
|
234
|
+
#: and legacy YAML reaches this path, and any flag enabled here would reject
|
|
235
|
+
#: documents that compile and run today.
|
|
236
|
+
DOCUMENT_ANNOTATION_POLICY = AnnotationPolicy(label="metadata.annotations")
|
|
237
|
+
|
|
238
|
+
#: Applied to a caller/config-supplied root annotations mapping (the
|
|
239
|
+
#: ``pipeline_annotations`` compile argument, and any downstream config reader
|
|
240
|
+
#: that wants to refuse a bad mapping early with its own file/key provenance:
|
|
241
|
+
#: ``check_annotations(mapping, policy=CALLER_ANNOTATION_POLICY,
|
|
242
|
+
#: error_cls=...)``). Strict ``str -> str`` because that input surface is new,
|
|
243
|
+
#: has no legacy, and is usually an untrusted config file — hence also
|
|
244
|
+
#: :func:`check_annotations`'s rule that a diagnostic names the key and the
|
|
245
|
+
#: type or delimiter but never echoes a value. ``None`` / ``{}`` means nothing
|
|
246
|
+
#: supplied and is a no-op, not a clear. ``reject_template_delimiters`` adds no
|
|
247
|
+
#: rule the output lacks — :func:`assert_no_template_delimiters` scans the
|
|
248
|
+
#: compiled output regardless; it moves the failure earlier, onto a message
|
|
249
|
+
#: that names the offending annotation key.
|
|
250
|
+
CALLER_ANNOTATION_POLICY = AnnotationPolicy(
|
|
251
|
+
label="pipeline_annotations",
|
|
252
|
+
require_string_values=True,
|
|
253
|
+
require_string_keys=True,
|
|
254
|
+
require_non_empty_keys=True,
|
|
255
|
+
reject_reserved_key_prefix=True,
|
|
256
|
+
reject_template_delimiters=True,
|
|
257
|
+
reject_non_mapping=True,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def check_annotations(
|
|
262
|
+
annotations: Any,
|
|
263
|
+
*,
|
|
264
|
+
policy: AnnotationPolicy,
|
|
265
|
+
error_cls: type[Exception] = SchemaValidationError,
|
|
266
|
+
) -> dict[Any, Any]:
|
|
267
|
+
"""Check an annotations mapping against ``policy`` and copy it.
|
|
268
|
+
|
|
269
|
+
Annotations are frequently UNTRUSTED input (a config file, a checked-in
|
|
270
|
+
YAML document), so every diagnostic names the offending KEY and the
|
|
271
|
+
offending TYPE or delimiter and NEVER echoes a value.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
annotations: The mapping to check. ``None`` means "nothing supplied"
|
|
275
|
+
and is always accepted.
|
|
276
|
+
policy: Which rules apply — :data:`DOCUMENT_ANNOTATION_POLICY` or
|
|
277
|
+
:data:`CALLER_ANNOTATION_POLICY`.
|
|
278
|
+
error_cls: Exception type to raise, so a caller-input path can raise
|
|
279
|
+
its own precise type (``InvalidPipelineAnnotationsError``) while
|
|
280
|
+
the document path keeps raising
|
|
281
|
+
:class:`SchemaValidationError`. This module deliberately does
|
|
282
|
+
not import the authoring-layer error hierarchy.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
A plain ``dict`` copy in the caller's key order (empty for ``None``),
|
|
286
|
+
so later mutation of the supplied mapping cannot reach the compile.
|
|
287
|
+
No value is coerced or normalized — this function only accepts or
|
|
288
|
+
rejects.
|
|
289
|
+
|
|
290
|
+
Raises:
|
|
291
|
+
error_cls: on the first violation found.
|
|
292
|
+
"""
|
|
293
|
+
if annotations is None:
|
|
294
|
+
return {}
|
|
295
|
+
if not isinstance(annotations, Mapping):
|
|
296
|
+
if not policy.reject_non_mapping:
|
|
297
|
+
return {}
|
|
298
|
+
raise error_cls(
|
|
299
|
+
f"{policy.label} must be a mapping of string keys to string "
|
|
300
|
+
f"values; got {type(annotations).__name__}."
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
checked: dict[Any, Any] = {}
|
|
304
|
+
for key, value in annotations.items():
|
|
305
|
+
if policy.require_string_keys and not isinstance(key, str):
|
|
306
|
+
raise error_cls(
|
|
307
|
+
f"{policy.label} keys must be strings; got a key of type "
|
|
308
|
+
f"{type(key).__name__}."
|
|
309
|
+
)
|
|
310
|
+
if policy.require_non_empty_keys and key == "":
|
|
311
|
+
raise error_cls(f"{policy.label} keys must not be empty.")
|
|
312
|
+
if policy.require_string_values:
|
|
313
|
+
# Report the type only — a rejected value may be untrusted.
|
|
314
|
+
if not isinstance(value, str):
|
|
315
|
+
raise error_cls(
|
|
316
|
+
f"{policy.label} value for key {key!r} must be a string; "
|
|
317
|
+
f"got {type(value).__name__}."
|
|
318
|
+
)
|
|
319
|
+
# bool is a subclass of int, so it is covered by int.
|
|
320
|
+
elif not (value is None or isinstance(value, (str, int, float))):
|
|
321
|
+
raise error_cls(
|
|
322
|
+
f"{policy.label}[{key!r}] must be a scalar (str/number/bool) "
|
|
323
|
+
f"or null, got {type(value).__name__!r}."
|
|
324
|
+
)
|
|
325
|
+
if policy.reject_reserved_key_prefix and isinstance(key, str):
|
|
326
|
+
if key.startswith(RESERVED_ANNOTATION_KEY_PREFIX):
|
|
327
|
+
raise error_cls(
|
|
328
|
+
f"{policy.label} key {key!r} uses the reserved "
|
|
329
|
+
f"{RESERVED_ANNOTATION_KEY_PREFIX!r} prefix, which Tangle "
|
|
330
|
+
"keeps for its own annotations. Choose a different key."
|
|
331
|
+
)
|
|
332
|
+
if policy.reject_template_delimiters:
|
|
333
|
+
# Scanned with the SAME tokens the compiled-output guard uses, so
|
|
334
|
+
# an input check and the output contract can never disagree.
|
|
335
|
+
for where, text in ((f"key {key!r}", key), (f"value for key {key!r}", value)):
|
|
336
|
+
if not isinstance(text, str):
|
|
337
|
+
continue
|
|
338
|
+
delim = next((d for _p, d in iter_template_delimiters(text)), None)
|
|
339
|
+
if delim is None:
|
|
340
|
+
continue
|
|
341
|
+
raise error_cls(
|
|
342
|
+
f"{policy.label} {where} contains the template delimiter "
|
|
343
|
+
f"{delim!r}. Annotations are literal metadata written "
|
|
344
|
+
"verbatim into the compiled pipeline, which must be fully "
|
|
345
|
+
"rendered — resolve the template before passing the value."
|
|
346
|
+
)
|
|
347
|
+
checked[key] = value
|
|
348
|
+
return checked
|
|
349
|
+
|
|
350
|
+
|
|
198
351
|
# ---------------------------------------------------------------------------
|
|
199
352
|
# Phase 5: dehydrated-pipeline shape detection + semantic validation.
|
|
200
353
|
#
|
|
@@ -411,15 +564,12 @@ def _validate_semantics(data: Mapping[str, Any]) -> None:
|
|
|
411
564
|
metadata = data.get("metadata")
|
|
412
565
|
if isinstance(metadata, Mapping):
|
|
413
566
|
annotations = metadata.get("annotations")
|
|
567
|
+
# A non-mapping ``annotations`` is left to JSON-Schema, exactly as
|
|
568
|
+
# before. Everything a DOCUMENT's annotations may contain is decided
|
|
569
|
+
# by the shared policy below, so this backstop and the strict
|
|
570
|
+
# caller-input check can never disagree about a shared rule.
|
|
414
571
|
if isinstance(annotations, Mapping):
|
|
415
|
-
|
|
416
|
-
# bool is a subclass of int, so it is covered by int.
|
|
417
|
-
if not (value is None or isinstance(value, (str, int, float))):
|
|
418
|
-
raise SchemaValidationError(
|
|
419
|
-
f"metadata.annotations[{key!r}] must be a scalar "
|
|
420
|
-
f"(str/number/bool) or null, got "
|
|
421
|
-
f"{type(value).__name__!r}."
|
|
422
|
-
)
|
|
572
|
+
check_annotations(annotations, policy=DOCUMENT_ANNOTATION_POLICY)
|
|
423
573
|
|
|
424
574
|
|
|
425
575
|
def validate_dehydrated_pipeline(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/args_container.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/authenticated_identity.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_from_func.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_generator.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_inspector.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/component_publisher.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/components_cli.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/hydration_trust.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/module_bundler.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/openapi/parser.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_spec_utils.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/pipeline_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/cfg.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/emit.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/graph.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/ids.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/raw.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/ref.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/task.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/trace.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/python_pipeline/types.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/schemas/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/packages/tangle-cli/src/tangle_cli/version_manager.py
RENAMED
|
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
|
{tangle_cli-0.1.18 → tangle_cli-0.1.19}/skills/tangent/references/example-scenarios/INDEX.md
RENAMED
|
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
|