tangle-cli 0.1.0__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/PKG-INFO +2 -2
  2. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/__init__.py +1 -1
  3. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/openapi/codegen.py +10 -2
  4. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_run_manager.py +36 -6
  5. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_runner.py +2 -0
  6. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_runs_cli.py +17 -1
  7. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/pyproject.toml +2 -2
  8. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/README.md +0 -0
  9. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/api_cli.py +0 -0
  10. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/api_schema.py +0 -0
  11. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/api_transport.py +0 -0
  12. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/args_container.py +0 -0
  13. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/artifacts.py +0 -0
  14. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/artifacts_cli.py +0 -0
  15. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/cli.py +0 -0
  16. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/cli_helpers.py +0 -0
  17. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/cli_options.py +0 -0
  18. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/client.py +0 -0
  19. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/component_from_func.py +0 -0
  20. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/component_generator.py +0 -0
  21. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/component_inspector.py +0 -0
  22. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/component_publisher.py +0 -0
  23. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/components_cli.py +0 -0
  24. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/dynamic_discovery_client.py +0 -0
  25. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/generated_model_extensions.py +0 -0
  26. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/handler.py +0 -0
  27. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/hydration_trust.py +0 -0
  28. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/logger.py +0 -0
  29. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/models.py +0 -0
  30. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/module_bundler.py +0 -0
  31. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/openapi/__init__.py +0 -0
  32. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/openapi/parser.py +0 -0
  33. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_dehydrator.py +0 -0
  34. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_hydrator.py +0 -0
  35. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_run_annotations.py +0 -0
  36. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_run_details.py +0 -0
  37. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipeline_run_search.py +0 -0
  38. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipelines.py +0 -0
  39. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/pipelines_cli.py +0 -0
  40. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/published_components_cli.py +0 -0
  41. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/py.typed +0 -0
  42. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/quickstart.py +0 -0
  43. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/secrets.py +0 -0
  44. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/secrets_cli.py +0 -0
  45. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/utils.py +0 -0
  46. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/packages/tangle-cli/src/tangle_cli/version_manager.py +0 -0
  47. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/OSS-CONVENTIONS.md +0 -0
  48. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/PORT-README.md +0 -0
  49. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/SKILL.md +0 -0
  50. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/auth-wizard.md +0 -0
  51. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/builder.md +0 -0
  52. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/debugger.md +0 -0
  53. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/reporter.md +0 -0
  54. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/researcher.md +0 -0
  55. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/reviewer.md +0 -0
  56. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/agents/scenario-builder.md +0 -0
  57. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/data-sources.md +0 -0
  58. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/event-log.md +0 -0
  59. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/example-scenarios/01-mslr-ranking.md +0 -0
  60. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/example-scenarios/02-text-classification.md +0 -0
  61. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/example-scenarios/INDEX.md +0 -0
  62. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/iterating-on-runs.md +0 -0
  63. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/knowledge-corpus.md +0 -0
  64. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/secrets.md +0 -0
  65. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/setup.md +0 -0
  66. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-0-initialize.md +0 -0
  67. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-1-analyze.md +0 -0
  68. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-2-hypothesize.md +0 -0
  69. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-3-submit.md +0 -0
  70. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-4-monitor.md +0 -0
  71. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-5-evaluate.md +0 -0
  72. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-6-synthesize.md +0 -0
  73. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/step-7-decide.md +0 -0
  74. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/skills/tangent/references/tangle-tools.md +0 -0
  75. {tangle_cli-0.1.0 → tangle_cli-0.1.2}/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.0
3
+ Version: 0.1.2
4
4
  Summary: CLI for Tangle, the open-source ML pipeline orchestration platform
5
5
  Author: Alexey Volkov, Tangle authors
6
6
  Author-email: Alexey Volkov <alexey.volkov@ark-kun.com>
@@ -13,7 +13,7 @@ Requires-Dist: platformdirs>=4.10.0
13
13
  Requires-Dist: pydantic>=2.0
14
14
  Requires-Dist: pyyaml>=6.0
15
15
  Requires-Dist: requests>=2.32.0
16
- Requires-Dist: tangle-api==0.1.0
16
+ Requires-Dist: tangle-api==0.1.1
17
17
  Requires-Dist: tomli>=2.0 ; python_full_version < '3.11'
18
18
  Requires-Python: >=3.10
19
19
  Project-URL: Homepage, https://tangleml.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.0"
17
+ __version__ = "0.1.1"
18
18
 
19
19
  __all__ = ["TangleDynamicDiscoveryClient", "__version__"]
@@ -510,7 +510,7 @@ def _param_signature(
510
510
  body_names.append(name)
511
511
  if parameter.required:
512
512
  required_body_names.add(name)
513
- include_body = has_request_body and not body_names
513
+ include_body = has_request_body
514
514
  if include_body:
515
515
  body_annotation = "dict[str, Any] | None" if raw_body_override else "Any"
516
516
  signature_parts.append(f"body: {body_annotation} = None")
@@ -537,6 +537,12 @@ def _body_dict_literal(names: list[str], required_names: set[str]) -> str:
537
537
  return "{" + f"**{required_literal}, **{{{optional_expr}}}" + "}"
538
538
 
539
539
 
540
+ def _merged_body_dict_literal(names: list[str], required_names: set[str]) -> str:
541
+ """Return request JSON with generic body fields overridden by named fields."""
542
+
543
+ return f"{{**(body or {{}}), **{_body_dict_literal(names, required_names)}}}"
544
+
545
+
540
546
  def _validate_operation_path(path: str) -> None:
541
547
  """Reject OpenAPI operation paths that could override the configured origin."""
542
548
 
@@ -625,7 +631,9 @@ def generate_operations(
625
631
  f" path_params={_dict_literal(path_names)},",
626
632
  f" params={_dict_literal(query_names)},",
627
633
  ])
628
- if body_names:
634
+ if body_names and include_body:
635
+ lines.append(f" json_data={_merged_body_dict_literal(body_names, required_body_names)},")
636
+ elif body_names:
629
637
  lines.append(f" json_data={_body_dict_literal(body_names, required_body_names)},")
630
638
  elif include_body:
631
639
  lines.append(" json_data=body,")
@@ -37,8 +37,8 @@ _FAILURE_EARLY_EXIT_STATUSES = ("FAILED", "SYSTEM_ERROR")
37
37
  _EXECUTION_STATE_TIMINGS_METADATA_KEY = "execution_state_timings"
38
38
  _EXECUTION_STATE_TIMING_MONOTONIC_METADATA_KEY = "_execution_state_timing_monotonic"
39
39
  _SUBMISSION_ID_ANNOTATION_KEY = "tangle-cli/submission-id"
40
- _SUBMIT_RECOVERY_LOOKUP_ATTEMPTS = 2
41
- _SUBMIT_RECOVERY_LOOKUP_DELAY_SECONDS = 0.1
40
+ _SUBMIT_RECOVERY_BACKOFF_SECONDS = (0.5, 1.0, 2.0, 4.0, 8.0, 16.0)
41
+ _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS = 2
42
42
 
43
43
 
44
44
  class PipelineRunError(RuntimeError):
@@ -1529,6 +1529,11 @@ class PipelineRunManager(TangleCliHandler):
1529
1529
  submission_id = annotations.get(_SUBMISSION_ID_ANNOTATION_KEY)
1530
1530
  return str(submission_id) if submission_id else None
1531
1531
 
1532
+ @staticmethod
1533
+ def _submit_recovery_backoff_seconds(submit_recovery_attempts: int) -> tuple[float, ...]:
1534
+ attempt_count = max(0, min(int(submit_recovery_attempts), len(_SUBMIT_RECOVERY_BACKOFF_SECONDS)))
1535
+ return _SUBMIT_RECOVERY_BACKOFF_SECONDS[:attempt_count]
1536
+
1532
1537
  def _submitted_runs_for_submission_id(self, submission_id: str) -> list[dict[str, Any]]:
1533
1538
  query = {
1534
1539
  "and": [
@@ -1554,14 +1559,32 @@ class PipelineRunManager(TangleCliHandler):
1554
1559
  self,
1555
1560
  *,
1556
1561
  submission_id: str | None,
1562
+ submit_recovery_attempts: int = _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
1557
1563
  ) -> dict[str, Any] | None:
1558
1564
  if not submission_id:
1559
1565
  return None
1560
- for lookup_attempt in range(1, _SUBMIT_RECOVERY_LOOKUP_ATTEMPTS + 1):
1566
+ backoff_seconds = self._submit_recovery_backoff_seconds(submit_recovery_attempts)
1567
+ total_lookup_attempts = len(backoff_seconds)
1568
+ if total_lookup_attempts == 0:
1569
+ self.logger.warn(
1570
+ "Submit recovery lookup disabled "
1571
+ f"({_SUBMISSION_ID_ANNOTATION_KEY}={submission_id}, "
1572
+ f"submit_recovery_attempts={submit_recovery_attempts}); "
1573
+ "resubmitting the same frozen body with preserved inputs."
1574
+ )
1575
+ return None
1576
+ for lookup_attempt, delay_seconds in enumerate(backoff_seconds, start=1):
1577
+ self.logger.info(
1578
+ "Waiting "
1579
+ f"{delay_seconds:g}s before checking whether failed submit already created a pipeline run "
1580
+ f"({_SUBMISSION_ID_ANNOTATION_KEY}={submission_id}, "
1581
+ f"lookup_attempt={lookup_attempt}/{total_lookup_attempts})"
1582
+ )
1583
+ time.sleep(delay_seconds)
1561
1584
  self.logger.info(
1562
1585
  "Checking whether failed submit already created a pipeline run "
1563
1586
  f"({_SUBMISSION_ID_ANNOTATION_KEY}={submission_id}, "
1564
- f"lookup_attempt={lookup_attempt}/{_SUBMIT_RECOVERY_LOOKUP_ATTEMPTS})"
1587
+ f"lookup_attempt={lookup_attempt}/{total_lookup_attempts})"
1565
1588
  )
1566
1589
  try:
1567
1590
  matches = self._submitted_runs_for_submission_id(submission_id)
@@ -1598,8 +1621,6 @@ class PipelineRunManager(TangleCliHandler):
1598
1621
  f"{_SUBMISSION_ID_ANNOTATION_KEY}={submission_id}: {', '.join(run_ids) or matches!r}. "
1599
1622
  "Refusing to submit a duplicate."
1600
1623
  )
1601
- if lookup_attempt < _SUBMIT_RECOVERY_LOOKUP_ATTEMPTS:
1602
- time.sleep(_SUBMIT_RECOVERY_LOOKUP_DELAY_SECONDS)
1603
1624
  self.logger.warn(
1604
1625
  "No existing pipeline run found after submit failure "
1605
1626
  f"({_SUBMISSION_ID_ANNOTATION_KEY}={submission_id}); "
@@ -1647,6 +1668,7 @@ class PipelineRunManager(TangleCliHandler):
1647
1668
  timeout_clock: str = "monotonic",
1648
1669
  exit_on_first_failure: bool = False,
1649
1670
  metadata: dict[str, Any] | None = None,
1671
+ submit_recovery_attempts: int = _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
1650
1672
  metadata_factory: Callable[
1651
1673
  [int, PipelineRunContext | None, Exception | None], dict[str, Any]
1652
1674
  ] | None = None,
@@ -1723,6 +1745,7 @@ class PipelineRunManager(TangleCliHandler):
1723
1745
  if reused_after_submit_failure:
1724
1746
  recovered_response = self._recover_submitted_run_after_submit_error(
1725
1747
  submission_id=self._submission_id_from_body(body),
1748
+ submit_recovery_attempts=submit_recovery_attempts,
1726
1749
  )
1727
1750
  if recovered_response is not None:
1728
1751
  response = self._adopt_submitted_run(
@@ -1754,6 +1777,7 @@ class PipelineRunManager(TangleCliHandler):
1754
1777
  )
1755
1778
  recovered_response = self._recover_submitted_run_after_submit_error(
1756
1779
  submission_id=submission_id_for_recovery,
1780
+ submit_recovery_attempts=submit_recovery_attempts,
1757
1781
  )
1758
1782
  if recovered_response is None:
1759
1783
  self.hooks.on_submit_error(submit_exc, context=context)
@@ -1834,6 +1858,7 @@ class PipelineRunManager(TangleCliHandler):
1834
1858
  timeout_clock: str = "monotonic",
1835
1859
  exit_on_first_failure: bool = False,
1836
1860
  metadata: dict[str, Any] | None = None,
1861
+ submit_recovery_attempts: int = _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
1837
1862
  ) -> dict[str, Any]:
1838
1863
  """Submit/wait/retry an already prepared submit body.
1839
1864
 
@@ -1862,6 +1887,7 @@ class PipelineRunManager(TangleCliHandler):
1862
1887
  timeout_clock=timeout_clock,
1863
1888
  exit_on_first_failure=exit_on_first_failure,
1864
1889
  metadata=metadata,
1890
+ submit_recovery_attempts=submit_recovery_attempts,
1865
1891
  )
1866
1892
 
1867
1893
  def run_pipeline_spec(
@@ -1882,6 +1908,7 @@ class PipelineRunManager(TangleCliHandler):
1882
1908
  timeout_clock: str = "monotonic",
1883
1909
  exit_on_first_failure: bool = False,
1884
1910
  metadata: dict[str, Any] | None = None,
1911
+ submit_recovery_attempts: int = _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
1885
1912
  ) -> dict[str, Any]:
1886
1913
  """Submit/wait/retry an already hydrated/validated in-memory spec."""
1887
1914
 
@@ -1911,6 +1938,7 @@ class PipelineRunManager(TangleCliHandler):
1911
1938
  timeout_clock=timeout_clock,
1912
1939
  exit_on_first_failure=exit_on_first_failure,
1913
1940
  metadata=metadata,
1941
+ submit_recovery_attempts=submit_recovery_attempts,
1914
1942
  )
1915
1943
 
1916
1944
  def run_pipeline(
@@ -1931,6 +1959,7 @@ class PipelineRunManager(TangleCliHandler):
1931
1959
  timeout_clock: str = "monotonic",
1932
1960
  exit_on_first_failure: bool = False,
1933
1961
  metadata: dict[str, Any] | None = None,
1962
+ submit_recovery_attempts: int = _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
1934
1963
  ) -> dict[str, Any]:
1935
1964
  """Submit (and optionally wait for) a pipeline with lifecycle hooks.
1936
1965
 
@@ -1965,6 +1994,7 @@ class PipelineRunManager(TangleCliHandler):
1965
1994
  timeout_clock=timeout_clock,
1966
1995
  exit_on_first_failure=exit_on_first_failure,
1967
1996
  metadata=metadata,
1997
+ submit_recovery_attempts=submit_recovery_attempts,
1968
1998
  )
1969
1999
 
1970
2000
 
@@ -507,6 +507,7 @@ class PipelineRunner(PipelineRunnerHooks, PipelineRunManager):
507
507
  open_browser: bool = False,
508
508
  include_next_steps: bool = False,
509
509
  metadata: dict[str, Any] | None = None,
510
+ submit_recovery_attempts: int = 2,
510
511
  ) -> dict[str, Any]:
511
512
  """Run a pipeline path through generic preparation + lifecycle hooks.
512
513
 
@@ -603,6 +604,7 @@ class PipelineRunner(PipelineRunnerHooks, PipelineRunManager):
603
604
  timeout_clock=timeout_clock,
604
605
  exit_on_first_failure=exit_on_first_failure,
605
606
  metadata_factory=metadata_factory,
607
+ submit_recovery_attempts=submit_recovery_attempts,
606
608
  )
607
609
  context = result.get("context")
608
610
  attempt = context.attempt if isinstance(context, PipelineRunContext) else max(preparations)
@@ -28,6 +28,7 @@ from .cli_options import (
28
28
  from .logger import Logger, logger_for_log_type
29
29
  from .pipeline_run_annotations import AnnotationManager
30
30
  from .pipeline_run_manager import (
31
+ _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
31
32
  PipelineRunError,
32
33
  PipelineRunHooks,
33
34
  PipelineRunManager,
@@ -166,6 +167,15 @@ def pipeline_runs_submit(
166
167
  auth_header: AuthHeaderOption = None,
167
168
  header: HeaderOption = None,
168
169
  config: ConfigOption = None,
170
+ submit_recovery_attempts: Annotated[
171
+ int,
172
+ Parameter(
173
+ help=(
174
+ "Number of post-failed-submit recovery lookups before resubmitting; "
175
+ "higher values wait longer for delayed run registration."
176
+ )
177
+ ),
178
+ ] = _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS,
169
179
  log_type: LogTypeOption = "console",
170
180
  ) -> None:
171
181
  """Hydrate and submit a local pipeline YAML file as a run."""
@@ -181,6 +191,7 @@ def pipeline_runs_submit(
181
191
  "run_as": (run_as, None),
182
192
  "trusted_source": (trusted_source, None),
183
193
  "trusted_hydration_cli": ("trusted_hydration_cli", trusted_hydration, None, False),
194
+ "submit_recovery_attempts": (submit_recovery_attempts, _DEFAULT_SUBMIT_RECOVERY_ATTEMPTS),
184
195
  "log_type": (log_type, "console"),
185
196
  **api_arg_specs(base_url=base_url, token=token, auth_header=auth_header, header=header),
186
197
  }
@@ -194,7 +205,12 @@ def pipeline_runs_submit(
194
205
  }
195
206
  if args.dry_run:
196
207
  return manager.build_submit_body(args.pipeline_path, **kwargs)
197
- return manager.submit_pipeline(args.pipeline_path, **kwargs)
208
+ result = manager.run_pipeline(
209
+ args.pipeline_path,
210
+ **kwargs,
211
+ submit_recovery_attempts=args.submit_recovery_attempts,
212
+ )
213
+ return result["response"]
198
214
 
199
215
  _run_manager_action(config, base_url, specs, action)
200
216
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tangle-cli"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "CLI for Tangle, the open-source ML pipeline orchestration platform"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -18,7 +18,7 @@ dependencies = [
18
18
  "pydantic>=2.0",
19
19
  "pyyaml>=6.0",
20
20
  "requests>=2.32.0",
21
- "tangle-api==0.1.0",
21
+ "tangle-api==0.1.1",
22
22
  "tomli>=2.0; python_version < '3.11'",
23
23
  ]
24
24
 
File without changes