dayhoff-tools 1.14.11__tar.gz → 1.14.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.
Files changed (76) hide show
  1. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/PKG-INFO +1 -1
  2. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/cancel.py +66 -2
  3. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/status.py +98 -3
  4. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/pyproject.toml +1 -1
  5. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/README.md +0 -0
  6. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/__init__.py +0 -0
  7. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/batch/__init__.py +0 -0
  8. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/batch/workers/__init__.py +0 -0
  9. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/batch/workers/base.py +0 -0
  10. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/batch/workers/boltz.py +0 -0
  11. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/batch/workers/embed_t5.py +0 -0
  12. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/chemistry/standardizer.py +0 -0
  13. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/chemistry/utils.py +0 -0
  14. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/__init__.py +0 -0
  15. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/__init__.py +0 -0
  16. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/aws_batch.py +0 -0
  17. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/__init__.py +0 -0
  18. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/boltz.py +0 -0
  19. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/clean.py +0 -0
  20. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/embed_t5.py +0 -0
  21. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/finalize.py +0 -0
  22. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/list_jobs.py +0 -0
  23. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/local.py +0 -0
  24. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/logs.py +0 -0
  25. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/retry.py +0 -0
  26. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/commands/submit.py +0 -0
  27. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/job_id.py +0 -0
  28. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/batch/manifest.py +0 -0
  29. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/cloud_commands.py +0 -0
  30. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/__init__.py +0 -0
  31. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/engine_core.py +0 -0
  32. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/engine_lifecycle.py +0 -0
  33. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/engine_maintenance.py +0 -0
  34. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/engine_management.py +0 -0
  35. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/shared.py +0 -0
  36. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engine1/studio_commands.py +0 -0
  37. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/__init__.py +0 -0
  38. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/api_client.py +0 -0
  39. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/auth.py +0 -0
  40. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/engine-studio-cli.md +0 -0
  41. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/engine_commands.py +0 -0
  42. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/progress.py +0 -0
  43. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/cli-simulators.md +0 -0
  44. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/demo.sh +0 -0
  45. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py +0 -0
  46. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py +0 -0
  47. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py +0 -0
  48. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/simulator_utils.py +0 -0
  49. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/studio_list_simulator.py +0 -0
  50. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py +0 -0
  51. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/ssh_config.py +0 -0
  52. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/engines_studios/studio_commands.py +0 -0
  53. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/github_commands.py +0 -0
  54. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/main.py +0 -0
  55. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/swarm_commands.py +0 -0
  56. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/cli/utility_commands.py +0 -0
  57. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/base.py +0 -0
  58. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/deploy_aws.py +0 -0
  59. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/deploy_gcp.py +0 -0
  60. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/deploy_utils.py +0 -0
  61. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/job_runner.py +0 -0
  62. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/processors.py +0 -0
  63. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/deployment/swarm.py +0 -0
  64. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/embedders.py +0 -0
  65. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/fasta.py +0 -0
  66. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/file_ops.py +0 -0
  67. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/h5.py +0 -0
  68. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/intake/gcp.py +0 -0
  69. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/intake/gtdb.py +0 -0
  70. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/intake/kegg.py +0 -0
  71. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/intake/mmseqs.py +0 -0
  72. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/intake/structure.py +0 -0
  73. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/intake/uniprot.py +0 -0
  74. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/logs.py +0 -0
  75. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/sqlite.py +0 -0
  76. {dayhoff_tools-1.14.11 → dayhoff_tools-1.14.13}/dayhoff_tools/warehouse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dayhoff-tools
3
- Version: 1.14.11
3
+ Version: 1.14.13
4
4
  Summary: Common tools for all the repos at Dayhoff Labs
5
5
  Author: Daniel Martin-Alarcon
6
6
  Author-email: dma@dayhofflabs.com
@@ -1,5 +1,7 @@
1
1
  """Cancel command for stopping running jobs."""
2
2
 
3
+ import re
4
+
3
5
  import click
4
6
 
5
7
  from ..aws_batch import BatchClient, BatchError
@@ -11,6 +13,14 @@ from ..manifest import (
11
13
  )
12
14
 
13
15
 
16
+ def _parse_retry_job_id(job_id: str) -> tuple[str, str | None]:
17
+ """Parse a job ID to extract parent job ID and retry suffix."""
18
+ match = re.match(r"^(.+)(-r\d+)$", job_id)
19
+ if match:
20
+ return match.group(1), job_id
21
+ return job_id, None
22
+
23
+
14
24
  @click.command()
15
25
  @click.argument("job_id")
16
26
  @click.option("--force", is_flag=True, help="Force termination of running containers")
@@ -19,19 +29,29 @@ def cancel(job_id, force, base_path):
19
29
  """Cancel a running batch job.
20
30
 
21
31
  Cancels the job in AWS Batch and updates the manifest status.
32
+ Also supports cancelling retry jobs by their ID (e.g., job-id-r1).
22
33
 
23
34
  \b
24
35
  Examples:
25
36
  dh batch cancel dma-embed-20260109-a3f2
37
+ dh batch cancel dma-embed-20260109-a3f2-r1 # Cancel specific retry
26
38
  dh batch cancel dma-embed-20260109-a3f2 --force
27
39
  """
40
+ # Check if this is a retry job ID
41
+ parent_job_id, retry_id = _parse_retry_job_id(job_id)
42
+
28
43
  # Load manifest
29
44
  try:
30
- manifest = load_manifest(job_id, base_path)
45
+ manifest = load_manifest(parent_job_id, base_path)
31
46
  except FileNotFoundError:
32
- click.echo(f"Job not found: {job_id}", err=True)
47
+ click.echo(f"Job not found: {parent_job_id}", err=True)
33
48
  raise SystemExit(1)
34
49
 
50
+ # If cancelling a specific retry job
51
+ if retry_id:
52
+ _cancel_retry_job(manifest, retry_id, force, base_path)
53
+ return
54
+
35
55
  # Check if job can be cancelled
36
56
  if manifest.status in (
37
57
  JobStatus.SUCCEEDED,
@@ -94,3 +114,47 @@ def cancel(job_id, force, base_path):
94
114
  except BatchError as e:
95
115
  click.echo(click.style(f"✗ Failed to cancel job: {e}", fg="red"), err=True)
96
116
  raise SystemExit(1)
117
+
118
+
119
+ def _cancel_retry_job(manifest, retry_id: str, force: bool, base_path: str):
120
+ """Cancel a specific retry job."""
121
+ # Find the retry info
122
+ retry_info = None
123
+ for retry in manifest.retries:
124
+ if retry.retry_id == retry_id:
125
+ retry_info = retry
126
+ break
127
+
128
+ if not retry_info:
129
+ click.echo(f"Retry job not found: {retry_id}", err=True)
130
+ click.echo(f"Known retries: {[r.retry_id for r in manifest.retries]}", err=True)
131
+ raise SystemExit(1)
132
+
133
+ if not retry_info.batch_job_id:
134
+ click.echo(f"Retry job {retry_id} has no AWS Batch job ID.", err=True)
135
+ raise SystemExit(1)
136
+
137
+ # Cancel in AWS Batch
138
+ try:
139
+ client = BatchClient()
140
+
141
+ if force:
142
+ click.echo(f"Terminating retry job {retry_info.batch_job_id}...")
143
+ client.terminate_job(
144
+ retry_info.batch_job_id,
145
+ reason="Terminated by user via dh batch cancel --force",
146
+ )
147
+ else:
148
+ click.echo(f"Cancelling retry job {retry_info.batch_job_id}...")
149
+ client.cancel_job(
150
+ retry_info.batch_job_id,
151
+ reason="Cancelled by user via dh batch cancel",
152
+ )
153
+
154
+ click.echo()
155
+ click.echo(click.style(f"✓ Retry job {retry_id} cancelled successfully", fg="green"))
156
+ click.echo(f"Parent job: {manifest.job_id}")
157
+
158
+ except BatchError as e:
159
+ click.echo(click.style(f"✗ Failed to cancel retry job: {e}", fg="red"), err=True)
160
+ raise SystemExit(1)
@@ -174,15 +174,41 @@ def _show_job_list(user, status_filter, pipeline, base_path):
174
174
  click.echo("Use 'dh batch status <job-id>' for details.")
175
175
 
176
176
 
177
+ def _parse_retry_job_id(job_id: str) -> tuple[str, str | None]:
178
+ """Parse a job ID to extract parent job ID and retry suffix.
179
+
180
+ Args:
181
+ job_id: Job ID like 'dma-embed-20260120-63ec' or 'dma-embed-20260120-63ec-r1'
182
+
183
+ Returns:
184
+ Tuple of (parent_job_id, retry_id or None)
185
+ """
186
+ import re
187
+
188
+ # Check for retry suffix like -r1, -r2, etc.
189
+ match = re.match(r"^(.+)(-r\d+)$", job_id)
190
+ if match:
191
+ return match.group(1), job_id
192
+ return job_id, None
193
+
194
+
177
195
  def _show_job_details(job_id: str, base_path: str):
178
196
  """Show detailed status for a specific job."""
197
+ # Check if this is a retry job ID
198
+ parent_job_id, retry_id = _parse_retry_job_id(job_id)
199
+
179
200
  try:
180
- manifest = load_manifest(job_id, base_path)
201
+ manifest = load_manifest(parent_job_id, base_path)
181
202
  except FileNotFoundError:
182
203
  click.echo(f"Job not found: {job_id}", err=True)
183
- click.echo(f"Looking in: {base_path}/{job_id}/manifest.json", err=True)
204
+ click.echo(f"Looking in: {base_path}/{parent_job_id}/manifest.json", err=True)
184
205
  raise SystemExit(1)
185
206
 
207
+ # If showing a retry job, show retry-specific details
208
+ if retry_id:
209
+ _show_retry_details(manifest, retry_id)
210
+ return
211
+
186
212
  click.echo()
187
213
  click.echo(f"Job ID: {manifest.job_id}")
188
214
  click.echo(f"Status: {format_status(manifest.status)}")
@@ -235,7 +261,31 @@ def _show_job_details(job_id: str, base_path: str):
235
261
  click.echo()
236
262
  click.echo("Retries:")
237
263
  for retry in manifest.retries:
238
- click.echo(f" - {retry.retry_id}: indices {retry.indices}")
264
+ reslice_info = ""
265
+ if retry.reslice_prefix:
266
+ reslice_info = f" (resliced to {retry.reslice_count} chunks)"
267
+ click.echo(f" - {retry.retry_id}: {len(retry.indices)} indices{reslice_info}")
268
+ click.echo(f" Indices: {retry.indices}")
269
+ if retry.batch_job_id:
270
+ # Show brief status for retry job
271
+ try:
272
+ client = BatchClient()
273
+ array_status = client.get_array_job_status(retry.batch_job_id)
274
+ if array_status.is_complete:
275
+ pct = array_status.success_rate * 100
276
+ color = "green" if pct == 100 else "yellow" if pct > 90 else "red"
277
+ click.echo(
278
+ f" Status: Complete - {click.style(f'{pct:.0f}%', fg=color)} "
279
+ f"({array_status.succeeded}/{array_status.total} succeeded)"
280
+ )
281
+ else:
282
+ click.echo(
283
+ f" Status: Running - {array_status.succeeded}/{array_status.total} done, "
284
+ f"{array_status.running} running"
285
+ )
286
+ except BatchError:
287
+ click.echo(f" Status: (could not fetch)")
288
+ click.echo(f" Details: dh batch status {retry.retry_id}")
239
289
 
240
290
  # Suggest next steps
241
291
  click.echo()
@@ -285,3 +335,48 @@ def _show_array_status(batch_job_id: str):
285
335
 
286
336
  except BatchError as e:
287
337
  click.echo(f" (Could not fetch live status: {e})")
338
+
339
+
340
+ def _show_retry_details(manifest, retry_id: str):
341
+ """Show detailed status for a retry job."""
342
+ # Find the retry info
343
+ retry_info = None
344
+ for retry in manifest.retries:
345
+ if retry.retry_id == retry_id:
346
+ retry_info = retry
347
+ break
348
+
349
+ if not retry_info:
350
+ click.echo(f"Retry job not found: {retry_id}", err=True)
351
+ click.echo(f"Known retries: {[r.retry_id for r in manifest.retries]}", err=True)
352
+ raise SystemExit(1)
353
+
354
+ click.echo()
355
+ click.echo(f"Retry Job: {retry_id}")
356
+ click.echo(f"Parent Job: {manifest.job_id}")
357
+ click.echo(f"Pipeline: {manifest.pipeline}")
358
+ click.echo(f"User: {manifest.user}")
359
+ click.echo(
360
+ f"Created: {retry_info.created.isoformat()} ({format_time_ago(retry_info.created)})"
361
+ )
362
+
363
+ click.echo()
364
+ click.echo("Retry Config:")
365
+ click.echo(f" Indices: {retry_info.indices}")
366
+ if retry_info.reslice_prefix:
367
+ click.echo(f" Reslice: {retry_info.reslice_prefix} ({retry_info.reslice_count} chunks)")
368
+ else:
369
+ click.echo(f" Reslice: No (retrying original chunks)")
370
+
371
+ if retry_info.batch_job_id:
372
+ click.echo()
373
+ click.echo("Batch:")
374
+ click.echo(f" AWS Job ID: {retry_info.batch_job_id}")
375
+
376
+ # Get live status from AWS Batch
377
+ _show_array_status(retry_info.batch_job_id)
378
+
379
+ click.echo()
380
+ click.echo("Next steps:")
381
+ click.echo(f" View logs: dh batch logs {manifest.job_id}")
382
+ click.echo(f" Parent status: dh batch status {manifest.job_id}")
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
5
5
 
6
6
  [project]
7
7
  name = "dayhoff-tools"
8
- version = "1.14.11"
8
+ version = "1.14.13"
9
9
  description = "Common tools for all the repos at Dayhoff Labs"
10
10
  authors = [
11
11
  {name = "Daniel Martin-Alarcon", email = "dma@dayhofflabs.com"}