coiled 1.126.1.dev19__tar.gz → 1.126.1.dev20__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.

Potentially problematic release.


This version of coiled might be problematic. Click here for more details.

Files changed (102) hide show
  1. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/PKG-INFO +1 -1
  2. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/batch/run.py +2 -20
  3. coiled-1.126.1.dev20/coiled/cli/batch/util.py +28 -0
  4. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/run.py +24 -1
  5. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/cluster.py +7 -0
  6. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/core.py +2 -0
  7. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/.gitignore +0 -0
  8. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/LICENSE +0 -0
  9. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/README.md +0 -0
  10. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/__init__.py +0 -0
  11. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/__main__.py +0 -0
  12. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/analytics.py +0 -0
  13. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/auth.py +0 -0
  14. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/batch.py +0 -0
  15. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/capture_environment.py +0 -0
  16. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/__init__.py +0 -0
  17. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/batch/__init__.py +0 -0
  18. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/batch/list.py +0 -0
  19. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/batch/logs.py +0 -0
  20. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/batch/status.py +0 -0
  21. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/batch/wait.py +0 -0
  22. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/__init__.py +0 -0
  23. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/azure_logs.py +0 -0
  24. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/better_logs.py +0 -0
  25. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/crud.py +0 -0
  26. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/get_address.py +0 -0
  27. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/list.py +0 -0
  28. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/logs.py +0 -0
  29. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/metrics.py +0 -0
  30. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/ssh.py +0 -0
  31. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/cluster/utils.py +0 -0
  32. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/config.py +0 -0
  33. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/core.py +0 -0
  34. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/curl.py +0 -0
  35. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/diagnostics.py +0 -0
  36. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/env.py +0 -0
  37. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/file.py +0 -0
  38. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/__init__.py +0 -0
  39. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/examples/__init__.py +0 -0
  40. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/examples/exit.py +0 -0
  41. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/examples/hello_world.py +0 -0
  42. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/examples/nyc_parquet.py +0 -0
  43. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/examples/pytorch.py +0 -0
  44. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/examples/xarray_nwm.py +0 -0
  45. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/hello.py +0 -0
  46. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/scripts/fill_ipython.py +0 -0
  47. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/scripts/nyc_parquet.py +0 -0
  48. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/scripts/pytorch.py +0 -0
  49. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/scripts/xarray_nwm.py +0 -0
  50. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/hello/utils.py +0 -0
  51. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/login.py +0 -0
  52. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/notebook/__init__.py +0 -0
  53. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/notebook/notebook.py +0 -0
  54. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/package_sync.py +0 -0
  55. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/prefect.py +0 -0
  56. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/prefect_serve.py +0 -0
  57. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/__init__.py +0 -0
  58. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/amp.py +0 -0
  59. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/aws.py +0 -0
  60. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/azure.py +0 -0
  61. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/entry.py +0 -0
  62. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/gcp.py +0 -0
  63. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/prometheus.py +0 -0
  64. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/setup/util.py +0 -0
  65. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/sync.py +0 -0
  66. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cli/utils.py +0 -0
  67. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/cluster.py +0 -0
  68. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/coiled.yaml +0 -0
  69. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/compatibility.py +0 -0
  70. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/config.py +0 -0
  71. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/context.py +0 -0
  72. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/core.py +0 -0
  73. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/credentials/__init__.py +0 -0
  74. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/credentials/aws.py +0 -0
  75. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/credentials/google.py +0 -0
  76. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/errors.py +0 -0
  77. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/exceptions.py +0 -0
  78. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/extensions/__init__.py +0 -0
  79. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/extensions/prefect/__init__.py +0 -0
  80. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/extensions/prefect/runners.py +0 -0
  81. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/extensions/prefect/workers.py +0 -0
  82. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/filestore.py +0 -0
  83. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/function.py +0 -0
  84. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/plugins.py +0 -0
  85. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/prefect.py +0 -0
  86. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/pypi_conda_map.py +0 -0
  87. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/scan.py +0 -0
  88. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/software.py +0 -0
  89. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/software_utils.py +0 -0
  90. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/spans.py +0 -0
  91. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/spark.py +0 -0
  92. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/types.py +0 -0
  93. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/utils.py +0 -0
  94. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/__init__.py +0 -0
  95. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/cwi_log_link.py +0 -0
  96. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/states.py +0 -0
  97. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/widgets/__init__.py +0 -0
  98. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/widgets/interface.py +0 -0
  99. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/widgets/rich.py +0 -0
  100. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/v2/widgets/util.py +0 -0
  101. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/coiled/websockets.py +0 -0
  102. {coiled-1.126.1.dev19 → coiled-1.126.1.dev20}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coiled
3
- Version: 1.126.1.dev19
3
+ Version: 1.126.1.dev20
4
4
  Summary: Python client for coiled.io dask clusters
5
5
  Project-URL: Homepage, https://coiled.io
6
6
  Maintainer-email: Coiled <info@coiled.io>
@@ -10,12 +10,12 @@ import shlex
10
10
 
11
11
  import click
12
12
  import dask.config
13
- import yaml
14
13
  from dask.utils import format_bytes, format_time, parse_timedelta
15
14
  from rich.console import Console
16
15
  from rich.panel import Panel
17
16
 
18
17
  import coiled
18
+ from coiled.cli.batch.util import load_sidecar_spec
19
19
  from coiled.cli.batch.wait import batch_job_wait
20
20
  from coiled.cli.curl import sync_request
21
21
  from coiled.cli.run import dict_from_key_val_list
@@ -755,25 +755,7 @@ def _batch_run(default_kwargs, logger=None, from_cli=False, **kwargs) -> dict:
755
755
 
756
756
  batch_job_container = f"{kwargs['container']}!" if kwargs["ignore_container_entrypoint"] else kwargs["container"]
757
757
 
758
- scheduler_sidecars = []
759
- if kwargs.get("scheduler_sidecar_spec"):
760
- with open(kwargs["scheduler_sidecar_spec"]) as f:
761
- if kwargs["scheduler_sidecar_spec"].endswith((".yaml", ".yml")):
762
- sidecar_spec = yaml.safe_load(f)
763
- elif kwargs["scheduler_sidecar_spec"].endswith(".json"):
764
- sidecar_spec = json.load(f)
765
- else:
766
- raise ValueError(f"Unknown format for {kwargs['scheduler_sidecar_spec']}, json or yaml expected.")
767
-
768
- # support either list-like or dict-like
769
- if isinstance(sidecar_spec, list):
770
- scheduler_sidecars = sidecar_spec
771
- if isinstance(sidecar_spec, dict):
772
- scheduler_sidecars = [{"name": key, **val} for key, val in sidecar_spec.items()]
773
-
774
- for sidecar in scheduler_sidecars:
775
- # allow `image` as the key, to match docker compose spec
776
- sidecar["container"] = sidecar.get("container") or sidecar.get("image")
758
+ scheduler_sidecars = load_sidecar_spec(kwargs.get("scheduler_sidecar_spec"))
777
759
 
778
760
  dask_container = (
779
761
  kwargs.get("dask_container") or dask.config.get("coiled.batch.dask-container", None) or "ghcr.io/dask/dask"
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ import yaml
6
+
7
+
8
+ def load_sidecar_spec(spec_path: str | None):
9
+ scheduler_sidecars = []
10
+ if spec_path:
11
+ with open(spec_path) as f:
12
+ if spec_path.endswith((".yaml", ".yml")):
13
+ sidecar_spec = yaml.safe_load(f)
14
+ elif spec_path.endswith(".json"):
15
+ sidecar_spec = json.load(f)
16
+ else:
17
+ raise ValueError(f"Unknown format for {spec_path}, json or yaml expected.")
18
+
19
+ # support either list-like or dict-like
20
+ if isinstance(sidecar_spec, list):
21
+ scheduler_sidecars = sidecar_spec
22
+ if isinstance(sidecar_spec, dict):
23
+ scheduler_sidecars = [{"name": key, **val} for key, val in sidecar_spec.items()]
24
+
25
+ for sidecar in scheduler_sidecars:
26
+ # allow `image` as the key, to match docker compose spec
27
+ sidecar["container"] = sidecar.get("container") or sidecar.get("image")
28
+ return scheduler_sidecars
@@ -31,6 +31,7 @@ from coiled.utils import (
31
31
  from coiled.v2.cluster import ClusterKwargs
32
32
  from coiled.v2.widgets.rich import LightRichClusterWidget
33
33
 
34
+ from ..filestore import FilestoreManager
34
35
  from .sync import SYNC_TARGET, start_sync, stop_sync
35
36
  from .utils import CONTEXT_SETTINGS
36
37
 
@@ -238,7 +239,7 @@ def run_via_ssh(
238
239
 
239
240
  if container and "/uv:" in container and command_string.startswith("uv"):
240
241
  command_string = (
241
- "(apt update && apt upgrade && apt install -y --no-install-recommends ca-certificates) "
242
+ "(apt update -y && apt upgrade -y && apt install -y --no-install-recommends ca-certificates) "
242
243
  "2>&1 > /dev/null\n"
243
244
  f"{command_string}"
244
245
  )
@@ -550,6 +551,13 @@ def get_entrypoint(connection, container_name) -> str:
550
551
  default=None,
551
552
  help="Non-default value for shm_size (for example, '3 GiB').",
552
553
  )
554
+ @click.option(
555
+ "--filestore",
556
+ "filestore_names",
557
+ default=None,
558
+ multiple=True,
559
+ help="Name of filestore to attach; can be specified multiple times for multiple filestores.",
560
+ )
553
561
  @click.argument("command", nargs=-1)
554
562
  def run(
555
563
  name: str | None,
@@ -580,6 +588,7 @@ def run(
580
588
  package_sync_strict,
581
589
  package_sync_conda_extras,
582
590
  docker_shm_size,
591
+ filestore_names,
583
592
  command,
584
593
  ):
585
594
  """
@@ -615,6 +624,7 @@ def run(
615
624
  package_sync_strict=package_sync_strict,
616
625
  package_sync_conda_extras=package_sync_conda_extras,
617
626
  docker_shm_size=docker_shm_size,
627
+ filestore_names=filestore_names,
618
628
  )
619
629
  sys.exit(info["exit_code"])
620
630
 
@@ -652,6 +662,7 @@ def start_run(
652
662
  package_sync_strict: bool = False,
653
663
  package_sync_conda_extras: List[str] | None = None,
654
664
  docker_shm_size: str | None = None,
665
+ filestore_names: list[str] | None = None,
655
666
  ):
656
667
  runtime_env_dict = dict_from_key_val_list(env)
657
668
  tags = dict_from_key_val_list(tag)
@@ -694,9 +705,20 @@ def start_run(
694
705
  # fail early if user specified `--file` that doesn't exist
695
706
  check_explicit_files(file)
696
707
 
708
+ filestores_to_attach = []
709
+
697
710
  try:
698
711
  with coiled.Cloud(workspace=workspace or account) as cloud:
699
712
  workspace = workspace or cloud.default_workspace
713
+
714
+ if filestore_names:
715
+ filestores = FilestoreManager.get_or_create_filestores(
716
+ names=filestore_names,
717
+ workspace=workspace,
718
+ region=region,
719
+ )
720
+ filestores_to_attach.extend([{"id": fs["id"], "input": True, "output": True} for fs in filestores])
721
+
700
722
  with LightRichClusterWidget(
701
723
  workspace=workspace,
702
724
  title=f"Running [bold]{coiled.utils.join_command_parts(command)}[/bold]",
@@ -737,6 +759,7 @@ def start_run(
737
759
  "package_sync_conda_extras": package_sync_conda_extras,
738
760
  "backend_options": {"docker_shm_size": docker_shm_size} if docker_shm_size else None,
739
761
  "unset_single_threading_variables": True,
762
+ "filestores_to_attach": filestores_to_attach,
740
763
  }
741
764
  cluster_kwargs["name"] = name or f"run-{short_random_string()}"
742
765
  cluster_kwargs["cloud"] = cloud
@@ -210,6 +210,7 @@ class ClusterKwargs(TypedDict, total=False):
210
210
  scheduler_sidecars: list[dict] | None
211
211
  worker_sidecars: list[dict] | None
212
212
  pause_on_exit: bool | None
213
+ filestores_to_attach: list[dict] | None
213
214
 
214
215
 
215
216
  class Cluster(DistributedCluster, Generic[IsAsynchronous]):
@@ -478,6 +479,8 @@ class Cluster(DistributedCluster, Generic[IsAsynchronous]):
478
479
  Like ``scheduler_sidecars``, but run on worker VMs instead of scheduler.
479
480
  pause_on_exit
480
481
  Pause the cluster instead of shutting it down when exiting.
482
+ filestores_to_attach
483
+ List of filestores to attach (specified as ``{"id": id, "input": True, "output": True}``, not name).
481
484
  """
482
485
 
483
486
  _instances = weakref.WeakSet()
@@ -563,6 +566,7 @@ class Cluster(DistributedCluster, Generic[IsAsynchronous]):
563
566
  scheduler_sidecars: list[dict] | None = None,
564
567
  worker_sidecars: list[dict] | None = None,
565
568
  pause_on_exit: bool | None = None,
569
+ filestores_to_attach: list[dict] | None = None,
566
570
  ):
567
571
  self.pause_on_exit = pause_on_exit
568
572
  self.init_time = datetime.datetime.now(tz=datetime.timezone.utc)
@@ -1007,6 +1011,8 @@ class Cluster(DistributedCluster, Generic[IsAsynchronous]):
1007
1011
  no_client_timeout if no_client_timeout != NO_CLIENT_DEFAULT else (idle_timeout or "2 minutes")
1008
1012
  )
1009
1013
 
1014
+ self.filestores_to_attach = filestores_to_attach
1015
+
1010
1016
  if not self.asynchronous:
1011
1017
  # If we don't close the cluster, the user's ipython session gets spammed with
1012
1018
  # messages from distributed.
@@ -1617,6 +1623,7 @@ class Cluster(DistributedCluster, Generic[IsAsynchronous]):
1617
1623
  worker_sidecars=self.worker_sidecars,
1618
1624
  host_setup_script_content=self.host_setup_script_content,
1619
1625
  pause_on_exit=self.pause_on_exit,
1626
+ filestores_to_attach=self.filestores_to_attach,
1620
1627
  cluster_timeout_seconds=self.cluster_timeout_seconds,
1621
1628
  )
1622
1629
  cluster_created = not cluster_existed
@@ -643,6 +643,7 @@ class CloudV2(OldCloud, Generic[IsAsynchronous]):
643
643
  host_setup_script_content: str | None = None,
644
644
  pause_on_exit: bool | None = None,
645
645
  cluster_timeout_seconds: int | None = None,
646
+ filestores_to_attach: list[dict] | None = None,
646
647
  ) -> Tuple[int, bool]:
647
648
  # TODO (Declarative): support these args, or decide not to
648
649
  # https://gitlab.com/coiled/cloud/-/issues/4305
@@ -684,6 +685,7 @@ class CloudV2(OldCloud, Generic[IsAsynchronous]):
684
685
  "pause_on_exit": pause_on_exit,
685
686
  "cluster_timeout_seconds": cluster_timeout_seconds,
686
687
  "coiled_cloud_env_image": dask.config.get("coiled.cloud-env-image", None),
688
+ "filestores_to_attach": filestores_to_attach,
687
689
  }
688
690
 
689
691
  try:
File without changes
File without changes