tangle-cli 0.1.12__tar.gz → 0.1.13__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.12 → tangle_cli-0.1.13}/PKG-INFO +1 -1
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/__init__.py +1 -1
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_validation.py +166 -11
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/pyproject.toml +1 -1
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/pyproject.toml.orig +1 -1
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/README.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/api_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/api_schema.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/api_transport.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/args_container.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/artifacts.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/artifacts_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/cli_helpers.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/cli_options.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/client.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_from_func.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_generator.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_inspector.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_publisher.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/components_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/dynamic_discovery_client.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/generated_model_extensions.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/handler.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/hydration_trust.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/logger.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/models.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/module_bundler.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/openapi/parser.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_compiler.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_annotations.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_spec_utils.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipelines.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipelines_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/published_components_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/py.typed +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/__init__.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/cfg.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/compiler_context.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/dynamic_data.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/emit.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/errors.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/graph.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/ids.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/pipeline.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/placeholders.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/raw.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/ref.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/registered.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/subpipeline.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/task.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/task_env.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/trace.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/types.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/quickstart.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/schema_validation.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/schemas/__init__.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/schemas/dehydrated_pipeline_schema.json +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/schemas/pipeline_schema.json +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/secrets.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/secrets_cli.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/utils.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/version_manager.py +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/OSS-CONVENTIONS.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/PORT-README.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/SKILL.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/auth-wizard.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/builder.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/debugger.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/reporter.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/researcher.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/reviewer.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/agents/scenario-builder.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/data-sources.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/event-log.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/example-scenarios/01-mslr-ranking.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/example-scenarios/02-text-classification.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/example-scenarios/INDEX.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/iterating-on-runs.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/knowledge-corpus.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/secrets.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/setup.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-0-initialize.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-1-analyze.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-2-hypothesize.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-3-submit.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-4-monitor.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-5-evaluate.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-6-synthesize.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/step-7-decide.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/skills/tangent/references/tangle-tools.md +0 -0
- {tangle_cli-0.1.12 → tangle_cli-0.1.13}/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.13
|
|
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>
|
|
@@ -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.13"
|
|
18
18
|
|
|
19
19
|
__all__ = ["TangleDynamicDiscoveryClient", "__version__"]
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_validation.py
RENAMED
|
@@ -8,7 +8,9 @@ Validation covers:
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import difflib
|
|
11
12
|
import json
|
|
13
|
+
import os
|
|
12
14
|
from functools import lru_cache
|
|
13
15
|
from importlib import resources
|
|
14
16
|
from typing import Any, Iterable, Mapping
|
|
@@ -20,7 +22,15 @@ from .pipeline_spec_utils import _extract_task_output_refs
|
|
|
20
22
|
PIPELINE_GRAPH_PATH = "implementation.graph"
|
|
21
23
|
TASKS_PATH = f"{PIPELINE_GRAPH_PATH}.tasks"
|
|
22
24
|
|
|
25
|
+
# Escape hatch for repositories that still carry undeclared task arguments.
|
|
26
|
+
# Set to a truthy value to downgrade the undeclared-argument check to a no-op.
|
|
27
|
+
# Follows the ``TANGLE_*`` boolean env-var convention used elsewhere in the CLI
|
|
28
|
+
# (see ``tangle_verbose_enabled`` / ``TANGLE_TRUSTED_HYDRATION_ALLOW_ALL``).
|
|
29
|
+
ALLOW_UNDECLARED_TASK_ARGUMENTS_ENV = "TANGLE_ALLOW_UNDECLARED_TASK_ARGUMENTS"
|
|
30
|
+
_TRUTHY_ENV_VALUES = ("1", "true", "yes", "on")
|
|
31
|
+
|
|
23
32
|
__all__ = [
|
|
33
|
+
"ALLOW_UNDECLARED_TASK_ARGUMENTS_ENV",
|
|
24
34
|
"PipelineValidationError",
|
|
25
35
|
"collect_pipeline_spec_errors",
|
|
26
36
|
"load_pipeline_schema",
|
|
@@ -186,6 +196,138 @@ def _get_component_spec(task: Mapping[str, Any]) -> Mapping[str, Any] | None:
|
|
|
186
196
|
return None
|
|
187
197
|
|
|
188
198
|
|
|
199
|
+
def _undeclared_arguments_allowed() -> bool:
|
|
200
|
+
"""Return True when the undeclared-argument check is disabled by env var."""
|
|
201
|
+
|
|
202
|
+
value = os.environ.get(ALLOW_UNDECLARED_TASK_ARGUMENTS_ENV, "")
|
|
203
|
+
return value.strip().lower() in _TRUTHY_ENV_VALUES
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _name_tokens(name: str) -> list[str]:
|
|
207
|
+
"""Split an input name into lowercase alphanumeric tokens.
|
|
208
|
+
|
|
209
|
+
Component authors mix ``snake_case``, ``kebab-case`` and spaces for the
|
|
210
|
+
same concept, so tokenizing lets the hint survive separator drift.
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
token = ""
|
|
214
|
+
tokens: list[str] = []
|
|
215
|
+
for char in name:
|
|
216
|
+
if char.isalnum():
|
|
217
|
+
token += char.lower()
|
|
218
|
+
elif token:
|
|
219
|
+
tokens.append(token)
|
|
220
|
+
token = ""
|
|
221
|
+
if token:
|
|
222
|
+
tokens.append(token)
|
|
223
|
+
return tokens
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _contains_tokens(haystack: list[str], needle: list[str]) -> bool:
|
|
227
|
+
"""Return True when needle appears as a contiguous run inside haystack."""
|
|
228
|
+
|
|
229
|
+
if not needle or len(needle) > len(haystack):
|
|
230
|
+
return False
|
|
231
|
+
return any(
|
|
232
|
+
haystack[start : start + len(needle)] == needle
|
|
233
|
+
for start in range(len(haystack) - len(needle) + 1)
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _nearest_declared_input(name: str, declared_names: Iterable[str]) -> str | None:
|
|
238
|
+
"""Return the declared input ``name`` most plausibly meant, if any.
|
|
239
|
+
|
|
240
|
+
Three deterministic passes over sorted candidates, strongest first:
|
|
241
|
+
|
|
242
|
+
1. separator-insensitive equality (``bq_table`` vs ``bq-table``);
|
|
243
|
+
2. ``difflib`` near-match, which catches ordinary typos;
|
|
244
|
+
3. token containment, which catches qualification renames such as
|
|
245
|
+
``snapshot_date`` -> ``merchant_match_reference_snapshot_date``.
|
|
246
|
+
|
|
247
|
+
Semantic renames with no lexical overlap (``wait`` -> ``timeout``) return
|
|
248
|
+
None on purpose: a wrong hint is worse than none.
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
candidates = sorted(declared_names)
|
|
252
|
+
tokens = _name_tokens(name)
|
|
253
|
+
if not tokens:
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
for candidate in candidates:
|
|
257
|
+
if _name_tokens(candidate) == tokens:
|
|
258
|
+
return candidate
|
|
259
|
+
|
|
260
|
+
close = difflib.get_close_matches(name, candidates, n=1, cutoff=0.8)
|
|
261
|
+
if close:
|
|
262
|
+
return close[0]
|
|
263
|
+
|
|
264
|
+
containing = [
|
|
265
|
+
candidate
|
|
266
|
+
for candidate in candidates
|
|
267
|
+
if _contains_tokens(_name_tokens(candidate), tokens)
|
|
268
|
+
or _contains_tokens(tokens, _name_tokens(candidate))
|
|
269
|
+
]
|
|
270
|
+
if containing:
|
|
271
|
+
return min(containing, key=lambda candidate: (len(_name_tokens(candidate)), candidate))
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _suggest_declared_input(name: str, declared_names: Iterable[str]) -> str:
|
|
276
|
+
"""Return a ``Did you mean ...`` clause, or an empty string when unsure.
|
|
277
|
+
|
|
278
|
+
Real-world undeclared arguments are overwhelmingly typos or renames, so a
|
|
279
|
+
nearest-match hint is far more actionable than the declared-input list
|
|
280
|
+
alone.
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
nearest = _nearest_declared_input(name, declared_names)
|
|
284
|
+
return f" Did you mean '{nearest}'?" if nearest else ""
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _validate_undeclared_arguments(
|
|
288
|
+
full_task_name: str,
|
|
289
|
+
component_spec: Mapping[str, Any],
|
|
290
|
+
component_inputs: Any,
|
|
291
|
+
task_arguments: Mapping[str, Any],
|
|
292
|
+
declared_names: set[str],
|
|
293
|
+
) -> list[str]:
|
|
294
|
+
"""Return errors for task arguments the component does not declare.
|
|
295
|
+
|
|
296
|
+
Deliberately fails OPEN in the cases where the answer is unknowable rather
|
|
297
|
+
than wrong:
|
|
298
|
+
|
|
299
|
+
* the caller only invokes this when ``_get_component_spec`` resolved a spec,
|
|
300
|
+
so unhydrated / digest-pinned / URL-only component refs are skipped;
|
|
301
|
+
* a malformed (non-list) ``inputs`` field is skipped, because the declared
|
|
302
|
+
set cannot be trusted.
|
|
303
|
+
|
|
304
|
+
An empty-but-well-formed ``inputs`` list is NOT skipped: a component that
|
|
305
|
+
declares no inputs genuinely accepts no arguments.
|
|
306
|
+
|
|
307
|
+
``TaskSpec`` keeps ``annotations``, ``executionOptions`` and ``isEnabled``
|
|
308
|
+
as siblings of ``arguments`` (see the vendored pipeline schema), so there
|
|
309
|
+
are no reserved/metadata keys inside ``arguments`` to allowlist.
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
if _undeclared_arguments_allowed():
|
|
313
|
+
return []
|
|
314
|
+
if component_inputs is not None and not isinstance(component_inputs, list):
|
|
315
|
+
return []
|
|
316
|
+
|
|
317
|
+
undeclared = sorted(str(name) for name in task_arguments if str(name) not in declared_names)
|
|
318
|
+
if not undeclared:
|
|
319
|
+
return []
|
|
320
|
+
|
|
321
|
+
component_name = component_spec.get("name") or "<unnamed component>"
|
|
322
|
+
declared_display = sorted(declared_names)
|
|
323
|
+
return [
|
|
324
|
+
f"Task '{full_task_name}': argument '{name}' is not a declared input of "
|
|
325
|
+
f"component '{component_name}'.{_suggest_declared_input(name, declared_names)} "
|
|
326
|
+
f"Declared inputs: {declared_display}"
|
|
327
|
+
for name in undeclared
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
|
|
189
331
|
def _is_input_required(input_spec: Mapping[str, Any]) -> bool:
|
|
190
332
|
"""Return True when a component input is non-optional and lacks a default."""
|
|
191
333
|
|
|
@@ -283,7 +425,8 @@ def _validate_task_inputs(
|
|
|
283
425
|
) -> list[str]:
|
|
284
426
|
"""Return component-input wiring errors for one task.
|
|
285
427
|
|
|
286
|
-
Required component inputs must be present in task arguments
|
|
428
|
+
Required component inputs must be present in task arguments, and supplied
|
|
429
|
+
arguments must correspond to a declared component input. When declared
|
|
287
430
|
inputs are explicitly supplied, graph/task output references are checked
|
|
288
431
|
regardless of whether the input is required. Nested graph component specs
|
|
289
432
|
are validated recursively.
|
|
@@ -309,13 +452,27 @@ def _validate_task_inputs(
|
|
|
309
452
|
if not component_spec:
|
|
310
453
|
return errors
|
|
311
454
|
|
|
312
|
-
|
|
313
|
-
if
|
|
314
|
-
component_inputs = []
|
|
455
|
+
raw_component_inputs = component_spec.get("inputs", [])
|
|
456
|
+
component_inputs = raw_component_inputs if isinstance(raw_component_inputs, list) else []
|
|
315
457
|
task_arguments = task_spec.get("arguments", {}) or {}
|
|
316
458
|
if not isinstance(task_arguments, Mapping):
|
|
317
459
|
task_arguments = {}
|
|
318
460
|
|
|
461
|
+
declared_names = {
|
|
462
|
+
str(spec["name"])
|
|
463
|
+
for spec in component_inputs
|
|
464
|
+
if isinstance(spec, Mapping) and spec.get("name")
|
|
465
|
+
}
|
|
466
|
+
errors.extend(
|
|
467
|
+
_validate_undeclared_arguments(
|
|
468
|
+
full_task_name,
|
|
469
|
+
component_spec,
|
|
470
|
+
raw_component_inputs,
|
|
471
|
+
task_arguments,
|
|
472
|
+
declared_names,
|
|
473
|
+
)
|
|
474
|
+
)
|
|
475
|
+
|
|
319
476
|
for input_spec in component_inputs:
|
|
320
477
|
if not isinstance(input_spec, Mapping):
|
|
321
478
|
continue
|
|
@@ -344,12 +501,7 @@ def _validate_task_inputs(
|
|
|
344
501
|
implementation = component_spec.get("implementation", {})
|
|
345
502
|
nested_graph = implementation.get("graph") if isinstance(implementation, Mapping) else None
|
|
346
503
|
if isinstance(nested_graph, Mapping):
|
|
347
|
-
|
|
348
|
-
str(inp.get("name"))
|
|
349
|
-
for inp in component_inputs
|
|
350
|
-
if isinstance(inp, Mapping) and inp.get("name")
|
|
351
|
-
}
|
|
352
|
-
errors.extend(_validate_graph_inputs(nested_graph, subgraph_inputs, f"{full_task_name} > "))
|
|
504
|
+
errors.extend(_validate_graph_inputs(nested_graph, declared_names, f"{full_task_name} > "))
|
|
353
505
|
|
|
354
506
|
return errors
|
|
355
507
|
|
|
@@ -389,7 +541,10 @@ def _validate_graph_inputs(
|
|
|
389
541
|
|
|
390
542
|
|
|
391
543
|
def validate_component_inputs(pipeline_spec: Mapping[str, Any]) -> list[str]:
|
|
392
|
-
"""Return
|
|
544
|
+
"""Return input-wiring errors for a pipeline.
|
|
545
|
+
|
|
546
|
+
Covers missing required inputs, undeclared task arguments, and dangling
|
|
547
|
+
graph-input / task-output references.
|
|
393
548
|
|
|
394
549
|
Validation uses embedded component specs when present. If the pipeline has
|
|
395
550
|
no object-shaped implementation graph, this component-input pass returns no
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/args_container.py
RENAMED
|
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.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_from_func.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_generator.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_inspector.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/component_publisher.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/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.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/hydration_trust.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/module_bundler.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/openapi/parser.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_compiler.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/pipeline_spec_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/cfg.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/emit.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/errors.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/graph.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/ids.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/raw.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/ref.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/task.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/trace.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/python_pipeline/types.py
RENAMED
|
File without changes
|
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/packages/tangle-cli/src/tangle_cli/schema_validation.py
RENAMED
|
File without changes
|
{tangle_cli-0.1.12 → tangle_cli-0.1.13}/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.12 → tangle_cli-0.1.13}/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.12 → tangle_cli-0.1.13}/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
|