tangle-cli 0.1.16__tar.gz → 0.1.17__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.16 → tangle_cli-0.1.17}/PKG-INFO +56 -1
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/README.md +55 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/__init__.py +1 -1
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/args_container.py +22 -7
- tangle_cli-0.1.17/packages/tangle-cli/src/tangle_cli/python_pipeline/task_env.py +203 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/pyproject.toml +1 -1
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/pyproject.toml.orig +1 -1
- tangle_cli-0.1.16/packages/tangle-cli/src/tangle_cli/python_pipeline/task_env.py +0 -88
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/api_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/api_schema.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/api_transport.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/artifacts.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/artifacts_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/authenticated_identity.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/cli_helpers.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/cli_options.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/client.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_from_func.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_generator.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_inspector.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_publisher.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/components_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/dynamic_discovery_client.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/generated_model_extensions.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/handler.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/hydration_trust.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/logger.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/models.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/module_bundler.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/openapi/parser.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_compiler.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_annotations.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_spec_utils.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_validation.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipelines.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipelines_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/published_components_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/py.typed +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/__init__.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/cfg.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/compiler_context.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/dynamic_data.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/emit.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/errors.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/graph.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/ids.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/pipeline.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/placeholders.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/publish.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/raw.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/ref.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/registered.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/subpipeline.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/task.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/trace.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/types.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/quickstart.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/schema_validation.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/schemas/__init__.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/schemas/dehydrated_pipeline_schema.json +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/schemas/pipeline_schema.json +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/secrets.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/secrets_cli.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/utils.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/version_manager.py +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/OSS-CONVENTIONS.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/PORT-README.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/SKILL.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/auth-wizard.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/builder.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/debugger.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/reporter.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/researcher.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/reviewer.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/agents/scenario-builder.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/data-sources.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/event-log.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/example-scenarios/01-mslr-ranking.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/example-scenarios/02-text-classification.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/example-scenarios/INDEX.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/iterating-on-runs.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/knowledge-corpus.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/secrets.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/setup.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-0-initialize.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-1-analyze.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-2-hypothesize.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-3-submit.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-4-monitor.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-5-evaluate.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-6-synthesize.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/step-7-decide.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/skills/tangent/references/tangle-tools.md +0 -0
- {tangle_cli-0.1.16 → tangle_cli-0.1.17}/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.17
|
|
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>
|
|
@@ -640,6 +640,61 @@ def score(...):
|
|
|
640
640
|
...
|
|
641
641
|
```
|
|
642
642
|
|
|
643
|
+
Declare the environment in a config file instead with `TaskEnv.from_config(path)`. A relative `path` resolves against the **calling pipeline module**, never the working directory, so the same script selects the same config wherever `tangle` runs from:
|
|
644
|
+
|
|
645
|
+
```python
|
|
646
|
+
EVAL = TaskEnv.from_config("envs.yaml") # relative to THIS file
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
```yaml
|
|
650
|
+
# envs.yaml
|
|
651
|
+
image: python:3.12
|
|
652
|
+
dependencies_from: pyproject.toml # relative to THIS config file
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
The file is read with the same loader `--config` uses, so the `_select` directive works here identically — the case is chosen exactly and case-sensitively by an environment variable, and an unset or unmatched variable is a hard error unless an explicit `default` branch is authored (no implicit default, no implicit production):
|
|
656
|
+
|
|
657
|
+
```yaml
|
|
658
|
+
_select:
|
|
659
|
+
env: DEPLOY_ENVIRONMENT
|
|
660
|
+
cases:
|
|
661
|
+
production:
|
|
662
|
+
image: registry.example/scoring:prod
|
|
663
|
+
staging:
|
|
664
|
+
image: registry.example/scoring:staging
|
|
665
|
+
default:
|
|
666
|
+
image: python:3.12
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
The document must resolve to exactly one object, and its keys must be named parameters of the generated `__init__` of the class `from_config` was called on — `InitVar` pseudo-fields included, `ClassVar`s and `field(init=False)` excluded — so these files stay environment-only: pipeline concerns such as file paths, versioning, annotations, schedules, or subscriptions have no field to land in and are rejected with the allowed field names. `from_config` is generic — any `TaskEnv` dataclass subclass inherits it unchanged, returns its own type, and is validated against its own fields:
|
|
670
|
+
|
|
671
|
+
```python
|
|
672
|
+
from tangle_cli.python_pipeline import TaskEnv
|
|
673
|
+
|
|
674
|
+
@dataclass(frozen=True)
|
|
675
|
+
class GpuEnv(TaskEnv):
|
|
676
|
+
accelerator: str = ""
|
|
677
|
+
|
|
678
|
+
def __post_init__(self):
|
|
679
|
+
super().__post_init__()
|
|
680
|
+
if self.accelerator not in ("gpu", "tpu"):
|
|
681
|
+
raise ValueError("GpuEnv.accelerator must be one of: gpu, tpu")
|
|
682
|
+
|
|
683
|
+
GPU = GpuEnv.from_config("envs.yaml") # accepts image, dependencies_from, accelerator
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
Failures raise `CompileError` naming the resolved config path. A config file is untrusted input, so **no diagnostic echoes a config value**. Keys are rendered through a capped, control-character-scrubbing renderer, and a constructor's own validation text is never quoted — it could embed a value directly, nested inside a structure, or transformed (lower cased, sliced, re-encoded). The rejected exception is also kept off `__cause__`/`__context__`, since `traceback.format_exception` would otherwise print it into the same CI log. The message names the class and the fields present, and points at constructing the class directly to see the validation error:
|
|
687
|
+
|
|
688
|
+
```
|
|
689
|
+
GpuEnv.from_config: /repo/envs.yaml case is not a valid GpuEnv (fields present:
|
|
690
|
+
accelerator, image). Its validation message is withheld because it can contain
|
|
691
|
+
config values; construct GpuEnv(...) directly to see it.
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Calling `GpuEnv(...)` directly is unaffected and raises the ordinary `ValueError` with its full message.
|
|
695
|
+
|
|
696
|
+
See `examples/python_pipeline/task_env_from_config/` for a runnable example.
|
|
697
|
+
|
|
643
698
|
Use `@task(image_id="eval-slim")` when source should carry a logical image name instead of a concrete registry reference. Downstream code can register defaults with `register_image_id(...)`, and callers can override at compile time with repeatable `--image ID=REF`:
|
|
644
699
|
|
|
645
700
|
```bash
|
|
@@ -614,6 +614,61 @@ def score(...):
|
|
|
614
614
|
...
|
|
615
615
|
```
|
|
616
616
|
|
|
617
|
+
Declare the environment in a config file instead with `TaskEnv.from_config(path)`. A relative `path` resolves against the **calling pipeline module**, never the working directory, so the same script selects the same config wherever `tangle` runs from:
|
|
618
|
+
|
|
619
|
+
```python
|
|
620
|
+
EVAL = TaskEnv.from_config("envs.yaml") # relative to THIS file
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
```yaml
|
|
624
|
+
# envs.yaml
|
|
625
|
+
image: python:3.12
|
|
626
|
+
dependencies_from: pyproject.toml # relative to THIS config file
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
The file is read with the same loader `--config` uses, so the `_select` directive works here identically — the case is chosen exactly and case-sensitively by an environment variable, and an unset or unmatched variable is a hard error unless an explicit `default` branch is authored (no implicit default, no implicit production):
|
|
630
|
+
|
|
631
|
+
```yaml
|
|
632
|
+
_select:
|
|
633
|
+
env: DEPLOY_ENVIRONMENT
|
|
634
|
+
cases:
|
|
635
|
+
production:
|
|
636
|
+
image: registry.example/scoring:prod
|
|
637
|
+
staging:
|
|
638
|
+
image: registry.example/scoring:staging
|
|
639
|
+
default:
|
|
640
|
+
image: python:3.12
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
The document must resolve to exactly one object, and its keys must be named parameters of the generated `__init__` of the class `from_config` was called on — `InitVar` pseudo-fields included, `ClassVar`s and `field(init=False)` excluded — so these files stay environment-only: pipeline concerns such as file paths, versioning, annotations, schedules, or subscriptions have no field to land in and are rejected with the allowed field names. `from_config` is generic — any `TaskEnv` dataclass subclass inherits it unchanged, returns its own type, and is validated against its own fields:
|
|
644
|
+
|
|
645
|
+
```python
|
|
646
|
+
from tangle_cli.python_pipeline import TaskEnv
|
|
647
|
+
|
|
648
|
+
@dataclass(frozen=True)
|
|
649
|
+
class GpuEnv(TaskEnv):
|
|
650
|
+
accelerator: str = ""
|
|
651
|
+
|
|
652
|
+
def __post_init__(self):
|
|
653
|
+
super().__post_init__()
|
|
654
|
+
if self.accelerator not in ("gpu", "tpu"):
|
|
655
|
+
raise ValueError("GpuEnv.accelerator must be one of: gpu, tpu")
|
|
656
|
+
|
|
657
|
+
GPU = GpuEnv.from_config("envs.yaml") # accepts image, dependencies_from, accelerator
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Failures raise `CompileError` naming the resolved config path. A config file is untrusted input, so **no diagnostic echoes a config value**. Keys are rendered through a capped, control-character-scrubbing renderer, and a constructor's own validation text is never quoted — it could embed a value directly, nested inside a structure, or transformed (lower cased, sliced, re-encoded). The rejected exception is also kept off `__cause__`/`__context__`, since `traceback.format_exception` would otherwise print it into the same CI log. The message names the class and the fields present, and points at constructing the class directly to see the validation error:
|
|
661
|
+
|
|
662
|
+
```
|
|
663
|
+
GpuEnv.from_config: /repo/envs.yaml case is not a valid GpuEnv (fields present:
|
|
664
|
+
accelerator, image). Its validation message is withheld because it can contain
|
|
665
|
+
config values; construct GpuEnv(...) directly to see it.
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
Calling `GpuEnv(...)` directly is unaffected and raises the ordinary `ValueError` with its full message.
|
|
669
|
+
|
|
670
|
+
See `examples/python_pipeline/task_env_from_config/` for a runnable example.
|
|
671
|
+
|
|
617
672
|
Use `@task(image_id="eval-slim")` when source should carry a logical image name instead of a concrete registry reference. Downstream code can register defaults with `register_image_id(...)`, and callers can override at compile time with repeatable `--image ID=REF`:
|
|
618
673
|
|
|
619
674
|
```bash
|
|
@@ -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.17"
|
|
18
18
|
|
|
19
19
|
__all__ = ["TangleDynamicDiscoveryClient", "__version__"]
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/args_container.py
RENAMED
|
@@ -41,10 +41,17 @@ class ConfigFileError(Exception):
|
|
|
41
41
|
"""Raised when there is an error loading or resolving a config file."""
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
"""Render
|
|
44
|
+
def _render_config_key(key: Any) -> str:
|
|
45
|
+
"""Render a config-document key safely for a diagnostic message.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Config keys come from user files, so a diagnostic must never echo them
|
|
48
|
+
verbatim: non-printable characters are replaced and the result is length
|
|
49
|
+
capped before being quoted. Accepts non-string keys (YAML permits them) so
|
|
50
|
+
callers can report a bad key without first proving it is a string.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
text = key if isinstance(key, str) else str(key)
|
|
54
|
+
rendered = "".join(char if char.isprintable() else "?" for char in text)
|
|
48
55
|
if len(rendered) > _MAX_RENDERED_CASE_KEY_LENGTH:
|
|
49
56
|
rendered = rendered[: _MAX_RENDERED_CASE_KEY_LENGTH - 3] + "..."
|
|
50
57
|
return repr(rendered)
|
|
@@ -172,8 +179,14 @@ class ArgsContainer:
|
|
|
172
179
|
if seen is not None and depth <= seen[0]:
|
|
173
180
|
return seen[2]
|
|
174
181
|
|
|
182
|
+
# Every key reaching a diagnostic goes through the ONE capped/scrubbed
|
|
183
|
+
# renderer: these keys are user input, and an unbounded repr() would
|
|
184
|
+
# let a hostile document paste control characters or a wall of text
|
|
185
|
+
# into a compile/CI log.
|
|
175
186
|
siblings = sorted(
|
|
176
|
-
|
|
187
|
+
_render_config_key(key)
|
|
188
|
+
for key in node
|
|
189
|
+
if not (isinstance(key, str) and key.startswith("_"))
|
|
177
190
|
)
|
|
178
191
|
if siblings:
|
|
179
192
|
raise ConfigFileError(
|
|
@@ -189,7 +202,9 @@ class ArgsContainer:
|
|
|
189
202
|
selector_dict = cast(dict[Any, Any], selector)
|
|
190
203
|
|
|
191
204
|
unexpected = sorted(
|
|
192
|
-
|
|
205
|
+
_render_config_key(key)
|
|
206
|
+
for key in selector_dict
|
|
207
|
+
if key not in ("env", "cases", "default")
|
|
193
208
|
)
|
|
194
209
|
if unexpected:
|
|
195
210
|
raise ConfigFileError(
|
|
@@ -231,7 +246,7 @@ class ArgsContainer:
|
|
|
231
246
|
# Every branch document is shape-checked, not just the selected one,
|
|
232
247
|
# so a malformed selector fails identically in every environment.
|
|
233
248
|
ArgsContainer._validate_branch_document(
|
|
234
|
-
case_value, f"{SELECT_KEY} case {
|
|
249
|
+
case_value, f"{SELECT_KEY} case {_render_config_key(case_key)}", depth, memo
|
|
235
250
|
)
|
|
236
251
|
|
|
237
252
|
default_branch: Any = None
|
|
@@ -241,7 +256,7 @@ class ArgsContainer:
|
|
|
241
256
|
default_branch, f"{SELECT_KEY}.default", depth, memo
|
|
242
257
|
)
|
|
243
258
|
|
|
244
|
-
allowed = ", ".join(
|
|
259
|
+
allowed = ", ".join(_render_config_key(key) for key in sorted(cases_dict))
|
|
245
260
|
summary: _SelectorSummary = (env_name, cases_dict, default_branch, allowed)
|
|
246
261
|
if memo is not None:
|
|
247
262
|
previous = memo.get(node_id)
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""``TaskEnv`` — declare image + dependencies once, reuse across ``@task``s.
|
|
2
|
+
|
|
3
|
+
A :class:`TaskEnv` bundles the container ``image`` and an optional
|
|
4
|
+
``dependencies_from`` file so a pipeline author can declare the execution
|
|
5
|
+
environment once and reference it from many ``@task`` components via
|
|
6
|
+
``@task(env=...)``. It is the Python equivalent of a ``local_from_python``
|
|
7
|
+
YAML anchor.
|
|
8
|
+
|
|
9
|
+
``TaskEnv`` is **authoring-only**. ``@task(env=...)`` expands it at decoration
|
|
10
|
+
time into the existing ``CallableRef._task_image`` /
|
|
11
|
+
``CallableRef._task_dependencies_from`` metadata, so the compiler, hydrator,
|
|
12
|
+
and runner never see a ``TaskEnv`` object.
|
|
13
|
+
|
|
14
|
+
Example::
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from tangle_cli.python_pipeline import TaskEnv, task
|
|
18
|
+
|
|
19
|
+
TRAINING = TaskEnv(
|
|
20
|
+
image="python:3.12",
|
|
21
|
+
dependencies_from=Path(__file__).parent / "pyproject.toml",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
@task(env=TRAINING)
|
|
25
|
+
def train_model(...):
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
An environment can also live in a config file, loaded with
|
|
29
|
+
:meth:`TaskEnv.from_config`, which any ``TaskEnv`` dataclass subclass
|
|
30
|
+
inherits unchanged::
|
|
31
|
+
|
|
32
|
+
ENV = TaskEnv.from_config("tangle/envs.yaml") # relative to THIS file
|
|
33
|
+
"""
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import inspect
|
|
37
|
+
from dataclasses import dataclass
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
from typing import TypeVar
|
|
40
|
+
|
|
41
|
+
_TaskEnvT = TypeVar("_TaskEnvT", bound="TaskEnv")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class TaskEnv:
|
|
46
|
+
"""Reusable execution environment for ``@task`` components.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
image: Container image for the component. Required.
|
|
50
|
+
dependencies_from: Optional path to a ``pyproject.toml`` (or any file
|
|
51
|
+
the hydrator understands) declaring pip dependencies. A relative
|
|
52
|
+
path is resolved at the ``TaskEnv`` *definition site*, so a shared
|
|
53
|
+
``_envs.py`` resolves intuitively; pass an absolute ``Path`` to
|
|
54
|
+
avoid that. When omitted, the hydrator's existing dependency
|
|
55
|
+
discovery still applies.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
image: str
|
|
59
|
+
dependencies_from: str | Path | None = None
|
|
60
|
+
|
|
61
|
+
def __post_init__(self) -> None:
|
|
62
|
+
if not isinstance(self.image, str) or not self.image:
|
|
63
|
+
raise ValueError("TaskEnv.image must be a non-empty string")
|
|
64
|
+
if self.dependencies_from is None:
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
p = Path(self.dependencies_from)
|
|
68
|
+
if not p.is_absolute():
|
|
69
|
+
# Frames: __post_init__ -> generated __init__ -> the definition site.
|
|
70
|
+
frame = inspect.currentframe()
|
|
71
|
+
caller = (
|
|
72
|
+
frame.f_back.f_back
|
|
73
|
+
if frame and frame.f_back and frame.f_back.f_back
|
|
74
|
+
else None
|
|
75
|
+
)
|
|
76
|
+
filename = caller.f_globals.get("__file__") if caller else None
|
|
77
|
+
caller_dir = Path(filename).resolve().parent if filename else Path.cwd()
|
|
78
|
+
p = caller_dir / p
|
|
79
|
+
# Frozen dataclass: bypass __setattr__ to store the resolved Path.
|
|
80
|
+
object.__setattr__(self, "dependencies_from", p.resolve())
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def from_config(cls: type[_TaskEnvT], path: str | Path) -> _TaskEnvT:
|
|
84
|
+
"""Build the env from a config file, returning an instance of ``cls``.
|
|
85
|
+
|
|
86
|
+
Every ``TaskEnv`` dataclass subclass inherits this and is validated
|
|
87
|
+
against its own fields; nothing here is specific to one kind of
|
|
88
|
+
environment.
|
|
89
|
+
|
|
90
|
+
A relative ``path`` resolves against the **calling file's** directory,
|
|
91
|
+
never the working directory, so a pipeline script selects the same
|
|
92
|
+
config wherever the CLI is run from. Call this directly on the class —
|
|
93
|
+
a subclass that wraps or delegates to it is not supported.
|
|
94
|
+
|
|
95
|
+
The file is read with the loader ``--config`` uses, so its ``_select``
|
|
96
|
+
directive behaves identically here, and it must resolve to exactly one
|
|
97
|
+
object. The object's keys must be named parameters of ``cls``'s
|
|
98
|
+
``__init__``, which keeps an environment config environment-only:
|
|
99
|
+
pipeline concerns such as versioning or schedules have no field to land
|
|
100
|
+
in. A relative ``dependencies_from`` inside the object is anchored to
|
|
101
|
+
the config file's directory rather than to this module.
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
CompileError: for every failure — a missing file, an unresolvable
|
|
105
|
+
relative path, a load or ``_select`` error, a multi-object
|
|
106
|
+
document, an unknown or missing field, or a value the subclass
|
|
107
|
+
rejects.
|
|
108
|
+
|
|
109
|
+
Note:
|
|
110
|
+
A config file is untrusted input, so no diagnostic raised here
|
|
111
|
+
echoes a config *value* — not in the message, and not through
|
|
112
|
+
``__cause__``/``__context__``, which a rendered traceback would
|
|
113
|
+
print into the same CI log. Construct ``cls(...)`` directly to see
|
|
114
|
+
a constructor's own validation message.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
# Lazy import: the authoring surface should not pay for the YAML/CLI
|
|
118
|
+
# config stack unless a pipeline actually loads an env from a file.
|
|
119
|
+
from tangle_cli.args_container import (
|
|
120
|
+
SELECT_KEY,
|
|
121
|
+
ArgsContainer,
|
|
122
|
+
ConfigFileError,
|
|
123
|
+
_render_config_key,
|
|
124
|
+
)
|
|
125
|
+
from tangle_cli.python_pipeline.errors import CompileError
|
|
126
|
+
|
|
127
|
+
label = f"{cls.__name__}.from_config"
|
|
128
|
+
config_path = Path(path)
|
|
129
|
+
if not config_path.is_absolute():
|
|
130
|
+
frame = inspect.currentframe()
|
|
131
|
+
caller = frame.f_back if frame is not None else None
|
|
132
|
+
filename = caller.f_globals.get("__file__") if caller is not None else None
|
|
133
|
+
if not isinstance(filename, str) or not filename:
|
|
134
|
+
raise CompileError(
|
|
135
|
+
f"{label}({str(path)!r}): a relative path resolves against the "
|
|
136
|
+
"calling file, which could not be determined here — pass an "
|
|
137
|
+
"absolute path."
|
|
138
|
+
)
|
|
139
|
+
config_path = (Path(filename).resolve().parent / config_path).resolve()
|
|
140
|
+
if not config_path.exists():
|
|
141
|
+
raise CompileError(
|
|
142
|
+
f"{label}: {config_path} does not exist. Declare the environment "
|
|
143
|
+
f"there (optionally a {SELECT_KEY} over an environment variable, "
|
|
144
|
+
f"with a default case for local runs), or construct "
|
|
145
|
+
f"{cls.__name__}(...) directly."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
documents = ArgsContainer._load_config_file(config_path)
|
|
150
|
+
except ConfigFileError as exc:
|
|
151
|
+
raise CompileError(f"{label} could not resolve {config_path}: {exc}") from exc
|
|
152
|
+
if len(documents) != 1 or not isinstance(documents[0], dict):
|
|
153
|
+
raise CompileError(
|
|
154
|
+
f"{label}: {config_path} must resolve to ONE environment object "
|
|
155
|
+
f"(one {SELECT_KEY} case), got a multi-config document."
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
case = dict(documents[0])
|
|
159
|
+
# The signature, not dataclasses.fields(): it is what cls(**case)
|
|
160
|
+
# actually accepts — InitVar pseudo-fields in, ClassVar and
|
|
161
|
+
# field(init=False) out. *args/**kwargs are excluded so a typo stays
|
|
162
|
+
# fail-closed.
|
|
163
|
+
parameters = {
|
|
164
|
+
name: parameter
|
|
165
|
+
for name, parameter in inspect.signature(cls).parameters.items()
|
|
166
|
+
if parameter.kind
|
|
167
|
+
in (parameter.POSITIONAL_OR_KEYWORD, parameter.KEYWORD_ONLY)
|
|
168
|
+
}
|
|
169
|
+
unknown = sorted(_render_config_key(key) for key in set(case) - set(parameters))
|
|
170
|
+
if unknown:
|
|
171
|
+
raise CompileError(
|
|
172
|
+
f"{label}: {config_path} case has unknown field(s) "
|
|
173
|
+
f"{', '.join(unknown)}. Allowed fields: {', '.join(parameters)}."
|
|
174
|
+
)
|
|
175
|
+
missing = sorted(
|
|
176
|
+
name
|
|
177
|
+
for name, parameter in parameters.items()
|
|
178
|
+
if parameter.default is parameter.empty and name not in case
|
|
179
|
+
)
|
|
180
|
+
if missing:
|
|
181
|
+
raise CompileError(
|
|
182
|
+
f"{label}: {config_path} case is missing required field(s): "
|
|
183
|
+
f"{', '.join(missing)}."
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
dependencies = case.get("dependencies_from")
|
|
187
|
+
if isinstance(dependencies, (str, Path)) and not Path(dependencies).is_absolute():
|
|
188
|
+
case["dependencies_from"] = (config_path.parent / Path(dependencies)).resolve()
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
return cls(**case)
|
|
192
|
+
except (TypeError, ValueError):
|
|
193
|
+
# Re-raised below, OUTSIDE this handler: the constructor's message
|
|
194
|
+
# may quote a config value, and `from exc` would publish it on
|
|
195
|
+
# __cause__ while a raise in-handler would publish it on
|
|
196
|
+
# __context__ — both get printed by traceback.format_exception.
|
|
197
|
+
pass
|
|
198
|
+
raise CompileError(
|
|
199
|
+
f"{label}: {config_path} case is not a valid {cls.__name__} "
|
|
200
|
+
f"(fields present: {', '.join(sorted(case))}). Its validation "
|
|
201
|
+
f"message is withheld because it can contain config values; "
|
|
202
|
+
f"construct {cls.__name__}(...) directly to see it."
|
|
203
|
+
)
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"""``TaskEnv`` — declare image + dependencies once, reuse across ``@task``s.
|
|
2
|
-
|
|
3
|
-
A :class:`TaskEnv` bundles the container ``image`` and an optional
|
|
4
|
-
``dependencies_from`` file so a pipeline author can declare the execution
|
|
5
|
-
environment once and reference it from many ``@task`` components via
|
|
6
|
-
``@task(env=...)``. It is the Python equivalent of a ``local_from_python``
|
|
7
|
-
YAML anchor.
|
|
8
|
-
|
|
9
|
-
``TaskEnv`` is **authoring-only**. ``@task(env=...)`` expands it at
|
|
10
|
-
decoration time into the existing ``CallableRef._task_image`` /
|
|
11
|
-
``CallableRef._task_dependencies_from`` metadata. The compiler, hydrator,
|
|
12
|
-
and downstream runner never see a ``TaskEnv`` object — no downstream
|
|
13
|
-
component learns the word ``env``.
|
|
14
|
-
|
|
15
|
-
Example::
|
|
16
|
-
|
|
17
|
-
from pathlib import Path
|
|
18
|
-
from tangle_cli.python_pipeline import TaskEnv, task
|
|
19
|
-
|
|
20
|
-
TRAINING = TaskEnv(
|
|
21
|
-
image="python:3.12",
|
|
22
|
-
dependencies_from=Path(__file__).parent / "pyproject.toml",
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
@task(env=TRAINING)
|
|
26
|
-
def train_model(...):
|
|
27
|
-
# docstring carries: Metadata / Name: Train Model
|
|
28
|
-
...
|
|
29
|
-
|
|
30
|
-
The component name comes from the function's docstring ``Metadata: Name:``
|
|
31
|
-
block (auto-derived from the function name if absent); the pipeline block name
|
|
32
|
-
(task id) comes from the call-site variable name, or ``.named("Block Name")``
|
|
33
|
-
for an explicit label.
|
|
34
|
-
"""
|
|
35
|
-
from __future__ import annotations
|
|
36
|
-
|
|
37
|
-
import inspect
|
|
38
|
-
from dataclasses import dataclass
|
|
39
|
-
from pathlib import Path
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@dataclass(frozen=True)
|
|
43
|
-
class TaskEnv:
|
|
44
|
-
"""Reusable execution environment for ``@task`` components.
|
|
45
|
-
|
|
46
|
-
Bundles the container image and optional dependencies file so a
|
|
47
|
-
pipeline author can declare them once and reference the env from many
|
|
48
|
-
tasks. This is the Python equivalent of a ``local_from_python`` YAML
|
|
49
|
-
anchor.
|
|
50
|
-
|
|
51
|
-
Attributes:
|
|
52
|
-
image: Container image for the component. Required — naming the
|
|
53
|
-
image once is the main point of ``TaskEnv``.
|
|
54
|
-
dependencies_from: Optional path to a ``pyproject.toml`` (or any
|
|
55
|
-
file the hydrator understands) declaring pip
|
|
56
|
-
dependencies. A relative path is resolved at the ``TaskEnv``
|
|
57
|
-
*definition site* (the module where ``TaskEnv(...)`` is
|
|
58
|
-
written), so a shared ``_envs.py`` resolves intuitively.
|
|
59
|
-
Authors can pass an absolute ``Path`` to avoid frame-based
|
|
60
|
-
ambiguity. When omitted, the existing hydrator/generator
|
|
61
|
-
dependency discovery still applies.
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
image: str
|
|
65
|
-
dependencies_from: str | Path | None = None
|
|
66
|
-
|
|
67
|
-
def __post_init__(self) -> None:
|
|
68
|
-
if not isinstance(self.image, str) or not self.image:
|
|
69
|
-
raise ValueError("TaskEnv.image must be a non-empty string")
|
|
70
|
-
if self.dependencies_from is None:
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
p = Path(self.dependencies_from)
|
|
74
|
-
if not p.is_absolute():
|
|
75
|
-
# Resolve a relative ``dependencies_from`` at the TaskEnv
|
|
76
|
-
# DEFINITION SITE. Walk frames: __post_init__ -> generated
|
|
77
|
-
# dataclass __init__ -> the caller that wrote ``TaskEnv(...)``.
|
|
78
|
-
frame = inspect.currentframe()
|
|
79
|
-
caller = (
|
|
80
|
-
frame.f_back.f_back
|
|
81
|
-
if frame and frame.f_back and frame.f_back.f_back
|
|
82
|
-
else None
|
|
83
|
-
)
|
|
84
|
-
filename = caller.f_globals.get("__file__") if caller else None
|
|
85
|
-
caller_dir = Path(filename).resolve().parent if filename else Path.cwd()
|
|
86
|
-
p = caller_dir / p
|
|
87
|
-
# Frozen dataclass: bypass __setattr__ to store the resolved Path.
|
|
88
|
-
object.__setattr__(self, "dependencies_from", p.resolve())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/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.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_from_func.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_generator.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_inspector.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/component_publisher.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/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.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/hydration_trust.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/module_bundler.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/openapi/parser.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_compiler.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/pipeline_spec_utils.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/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
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/cfg.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/emit.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/errors.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/graph.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/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.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/raw.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/ref.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/task.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/trace.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/python_pipeline/types.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/packages/tangle-cli/src/tangle_cli/schema_validation.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.16 → tangle_cli-0.1.17}/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.16 → tangle_cli-0.1.17}/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.16 → tangle_cli-0.1.17}/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
|