coiled 1.128.1.dev2__py3-none-any.whl → 1.128.2__py3-none-any.whl

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.

coiled/cli/mpi.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os.path
2
+ import pathlib
2
3
  import shlex
3
4
 
4
5
  import click
@@ -9,7 +10,7 @@ import coiled
9
10
  from .. import AWSOptions
10
11
  from ..v2.cluster_comms import get_cluster_connection_info, get_comm_from_connection_info
11
12
  from .cluster.utils import find_cluster
12
- from .run import KeepaliveSession, get_ssh_connection, write_via_ssh
13
+ from .run import KeepaliveSession, get_ssh_connection, upload_file
13
14
  from .utils import CONTEXT_SETTINGS
14
15
 
15
16
 
@@ -99,34 +100,13 @@ def setup(
99
100
  default=True,
100
101
  type=bool,
101
102
  )
103
+ @click.option("--upload", type=str, multiple=True)
102
104
  @click.argument("command", nargs=-1, required=True)
103
- def run(cluster, workspace, legate, include_head, command):
105
+ def run(cluster, workspace, legate, include_head, upload, command):
104
106
  nodes = "$(cat workers | wc -w)"
105
107
 
106
108
  command = list(command)
107
109
 
108
- files = {}
109
- for i, c in enumerate(command):
110
- if os.path.exists(c):
111
- remote_path = f"/scratch/batch/{os.path.basename(c)}"
112
- command[i] = remote_path
113
- with open(c) as f:
114
- content = f.read()
115
- files[remote_path] = content
116
-
117
- if legate:
118
- # TODO make "--gpus 1 --sysmem 2000 --fbmem 20000" configurable
119
- wrapped_command = f"""
120
- legate \
121
- --gpus 1 --sysmem 2000 --fbmem 20000 \
122
- --nodes {nodes} \
123
- --launcher mpirun \
124
- --launcher-extra ' --hostfile workers -x PATH ' \
125
- {shlex.join(command)}
126
- """
127
- else:
128
- wrapped_command = f"mpirun --hostfile workers -x PATH {shlex.join(command)}"
129
-
130
110
  with coiled.Cloud(workspace=workspace) as cloud:
131
111
  cluster_info = find_cluster(cloud, cluster)
132
112
  cluster_id = cluster_info["id"]
@@ -136,9 +116,11 @@ legate \
136
116
 
137
117
  setup_mpi_ssh(connection, include_scheduler=include_head)
138
118
 
139
- if files:
140
- worker_connections = []
119
+ has_implicit_file = any(os.path.exists(c) for c in command)
141
120
 
121
+ if has_implicit_file or upload:
122
+ # get SSH connections to each of the workers (using scheduler as jump server)
123
+ worker_connections = []
142
124
  for worker in cluster_info["workers"]:
143
125
  if (
144
126
  not worker.get("instance")
@@ -154,10 +136,66 @@ legate \
154
136
  )
155
137
  )
156
138
 
157
- for path, content in files.items():
158
- write_via_ssh(connection, content=content, path=path)
139
+ for idx, implicit_file in enumerate(command):
140
+ if os.path.exists(implicit_file) and os.path.isfile(implicit_file):
141
+ # this will preserve path structure relative to cwd
142
+ # so `coiled run python ./subdir/foo.py` will go to `/scratch/subdir/foo.py`
143
+ remote_path = upload_file(connection, implicit_file, remote_root="/scratch/batch")
144
+ print(f"Uploaded {implicit_file} to {remote_path}")
145
+
146
+ for conn in worker_connections:
147
+ upload_file(conn, implicit_file, remote_root="/scratch/batch")
148
+
149
+ # adjust command to reference path on VM
150
+ command[idx] = remote_path
151
+
152
+ files_to_upload = []
153
+ for f in upload:
154
+ path = pathlib.Path(f)
155
+ if not path.exists():
156
+ raise FileNotFoundError(f"Cannot find specified file {f}")
157
+
158
+ if path.is_file():
159
+ files_to_upload.append({"f": path})
160
+ elif path.is_dir():
161
+ # for paths outside cwd, parent_dir is used as the root so that path structure from there is preserved
162
+ parent_dir = pathlib.Path(path).parent
163
+ for subfile in path.rglob("*"):
164
+ if subfile.is_file():
165
+ files_to_upload.append({"f": subfile, "specified_root": parent_dir})
166
+
167
+ if files_to_upload:
168
+ print(
169
+ f"Uploading {len(files_to_upload)} file{'s' if len(files_to_upload) > 1 else ''} "
170
+ "from local machine to cloud VM..."
171
+ )
172
+ for i, file_to_upload in enumerate(files_to_upload):
173
+ try:
174
+ mb_size = file_to_upload["f"].stat().st_size / 1_000_000
175
+ if mb_size > 1:
176
+ print(f" {file_to_upload['f']} is {mb_size:.2f} MB, this may be slow to upload")
177
+ except Exception:
178
+ pass
179
+ remote_path = upload_file(connection, remote_root="/scratch/batch", **file_to_upload)
180
+ print(" ", remote_path)
159
181
  for conn in worker_connections:
160
- write_via_ssh(conn, content=content, path=path) # , mode=0o555
182
+ upload_file(conn, remote_root="/scratch/batch", **file_to_upload)
183
+ if i and (i % 20 == 0 or i + 1 == len(files_to_upload)):
184
+ print(f" {i + 1}/{len(files_to_upload)} files uploaded")
185
+
186
+ if legate:
187
+ # TODO make "--gpus 1 --sysmem 2000 --fbmem 20000" configurable
188
+ # wrapped_command = f"""
189
+ wrapped_command = f"""
190
+ legate \
191
+ --gpus 1 --sysmem 2000 --fbmem 20000 \
192
+ --nodes {nodes} \
193
+ --launcher mpirun \
194
+ --launcher-extra ' --hostfile workers -x PATH ' \
195
+ {shlex.join(command)}
196
+ """
197
+ else:
198
+ wrapped_command = f"mpirun --hostfile workers -x PATH {shlex.join(command)}"
161
199
 
162
200
  print(f"Running command:\n{wrapped_command}")
163
201
 
coiled/cli/run.py CHANGED
@@ -125,7 +125,7 @@ def write_files_into_container(connection, container_name: str, files: Dict[str,
125
125
  )
126
126
 
127
127
 
128
- def upload_file(connection, f, specified_root=None) -> str:
128
+ def upload_file(connection: fabric.Connection, f: str, specified_root=None, remote_root="/scratch") -> str:
129
129
  cwd = os.path.abspath(os.path.curdir)
130
130
  base = os.path.basename(f)
131
131
  is_under_cwd = os.path.commonpath((os.path.abspath(f), cwd)) == cwd
@@ -151,16 +151,16 @@ def upload_file(connection, f, specified_root=None) -> str:
151
151
  # For example, if user specified `--file /absolute/subdir/`, then preserve path structure relative
152
152
  # to `/absolute/subdir/`, so `/absolute/subdir/foo/bar.txt` would go to `/scratch/subdir/foo/bar.txt`.
153
153
  specified_path_dir = os.path.dirname(os.path.relpath(f, relative_to))
154
- remote_dir = f"/scratch/{specified_path_dir}/"
154
+ remote_dir = f"{remote_root}/{specified_path_dir}/"
155
155
  make_remote_dir(connection, remote_dir)
156
156
  else:
157
- remote_dir = "/scratch/"
157
+ remote_dir = f"{remote_root}/"
158
158
 
159
159
  connection.put(f, remote_dir)
160
160
 
161
161
  # we want path on Linux VM, which might not match os.path.join run client-side, so join path manually
162
162
  # remote_dir should already end in "/"
163
- return f"{remote_dir}{base}"
163
+ return f"{remote_dir}{base}".replace("//", "/")
164
164
 
165
165
 
166
166
  def run_via_ssh(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coiled
3
- Version: 1.128.1.dev2
3
+ Version: 1.128.2
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>
@@ -33,11 +33,11 @@ coiled/cli/diagnostics.py,sha256=1jIeue7xLOaf7LQFsNc6NmO5yU1jqmPFpKZSKjGN4rs,394
33
33
  coiled/cli/env.py,sha256=NHh7ZSq9yfongkpFqzon1eLhnH1FwToVvkKFIhqXRBE,6932
34
34
  coiled/cli/file.py,sha256=fJmOG3YhxpxXokGYu90wpjdwkJpp1XVqPJ_iveb5ShA,3623
35
35
  coiled/cli/login.py,sha256=cByVXmMsfGEuY2TkYU_Y8zq1zVTUHAxOe_wpw2uHsBs,2242
36
- coiled/cli/mpi.py,sha256=_i5GPTu4kE1kc-DQ1JLixIEpVVNJ0suwyLUgjp-iUww,6793
36
+ coiled/cli/mpi.py,sha256=mg0GakT_vwX3-PJKZYDaAIFSe8sly9GE5HFB8sy57jQ,8874
37
37
  coiled/cli/package_sync.py,sha256=lABDY20yjfLYGfPlQu8ugI-Q8doY4JtN8_0nb9PkcT4,4101
38
38
  coiled/cli/prefect.py,sha256=T-SSFey4jlA_jpEI0DqAhVIPwlt2GvBFogEqYCwwevI,302
39
39
  coiled/cli/prefect_serve.py,sha256=gemq6YOVbnBoq4k3tSaU2gFJR3aMSxXLNxH6jB8V3n8,4378
40
- coiled/cli/run.py,sha256=CtUmIarGMBC4n2xpbplStTrGGgGZiP5mTTKXOoEN_yo,31600
40
+ coiled/cli/run.py,sha256=Lwv9n6NSU9vKRYguBbZriwoWpN-uzqvyr1kE3dctUv8,31678
41
41
  coiled/cli/sync.py,sha256=S5PzB9GSPJn3HvviOMLKVbo4ET46FlPwLYK_7sRyonQ,9726
42
42
  coiled/cli/utils.py,sha256=cp7ToFGRpUKi6iNL6BbLjzgrgeTYSX_C55lYhaKWHHA,3479
43
43
  coiled/cli/batch/__init__.py,sha256=539CnfnqqcW7ndSufTS-Ie5FGZiElMYxE0Ptu70wo8M,660
@@ -97,8 +97,8 @@ coiled/v2/widgets/__init__.py,sha256=Bt3GHTTyri-kFUaqGRVydDM-sCg5NdNujDg2RyvgV8U
97
97
  coiled/v2/widgets/interface.py,sha256=YeMQ5qdRbbpM04x9qIg2LE1xwxyRxFbdDYnkrwHazPk,301
98
98
  coiled/v2/widgets/rich.py,sha256=3rU5-yso92NdeEh3uSvEE-GwPNyp6i0Nb5PE5czXCik,28974
99
99
  coiled/v2/widgets/util.py,sha256=Y8qpGqwNzqfCzgyRFRy7vcscBoXqop-Upi4HLPpXLgg,3120
100
- coiled-1.128.1.dev2.dist-info/METADATA,sha256=DmtJPbPcwjTIrtL3KrjYJhhT1Zb-_Ut-M5yoQymaUQ0,2181
101
- coiled-1.128.1.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
102
- coiled-1.128.1.dev2.dist-info/entry_points.txt,sha256=C8dz1ST_bTlTO-kNvuHBJQma9PyJPotg0S4xpPt5aHY,47
103
- coiled-1.128.1.dev2.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
104
- coiled-1.128.1.dev2.dist-info/RECORD,,
100
+ coiled-1.128.2.dist-info/METADATA,sha256=SAYit9d_AoaIVDFg3AgaA52Q__dRGUDvOvPim1WR7k0,2176
101
+ coiled-1.128.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
102
+ coiled-1.128.2.dist-info/entry_points.txt,sha256=C8dz1ST_bTlTO-kNvuHBJQma9PyJPotg0S4xpPt5aHY,47
103
+ coiled-1.128.2.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
104
+ coiled-1.128.2.dist-info/RECORD,,