dayhoff-tools 1.13.2__py3-none-any.whl → 1.13.4__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.
@@ -330,7 +330,7 @@ Engines for AWS Account dev
330
330
  │ bob-training │ running │ bob │ a10g │ i-0fedcba987654321 │
331
331
  │ batch-worker │ stopped │ charlie │ cpumax │ i-0abc123def456789 │
332
332
  ╰──────────────┴─────────────┴─────────────┴─────────────┴─────────────────────╯
333
- Total: 3 engine(s)
333
+ Total: 3
334
334
 
335
335
  ```
336
336
 
@@ -764,7 +764,7 @@ Studios for AWS Account dev
764
764
  │ bob │ available │ - │ 200GB │ vol-0fedcba987654321 │
765
765
  │ carol │ attaching │ carol-gpu │ 150GB │ vol-0abc123def456789 │
766
766
  ╰────────┴──────────────┴──────────────┴───────────┴───────────────────────────╯
767
- Total: 3 studio(s)
767
+ Total: 3
768
768
 
769
769
  ```
770
770
 
@@ -123,7 +123,9 @@ def engine_cli():
123
123
  @click.option(
124
124
  "--skip-ssh-config", is_flag=True, help="Don't automatically update SSH config"
125
125
  )
126
- @click.option("--yes", "-y", is_flag=True, help="Skip confirmation for non-dev environments")
126
+ @click.option(
127
+ "--yes", "-y", is_flag=True, help="Skip confirmation for non-dev environments"
128
+ )
127
129
  @click.option(
128
130
  "--env",
129
131
  default=None,
@@ -210,6 +212,48 @@ def launch_engine(
210
212
  click.echo(f" dh engine status {name}")
211
213
 
212
214
  except Exception as e:
215
+ error_msg = str(e)
216
+
217
+ # Check for quota/limit errors
218
+ if "VcpuLimitExceeded" in error_msg or "vCPU limit" in error_msg:
219
+ click.echo(f"✗ Failed to launch engine: vCPU quota exceeded", err=True)
220
+ click.echo("", err=True)
221
+ click.echo(f"The {env} AWS account has insufficient vCPU quota for {engine_type} instances.", err=True)
222
+ click.echo("", err=True)
223
+ click.echo("Solutions:", err=True)
224
+ click.echo(" 1. Use a different instance type (e.g., --type cpu)", err=True)
225
+ click.echo(" 2. Request a quota increase:", err=True)
226
+ click.echo(" • AWS Console → Service Quotas → Amazon EC2", err=True)
227
+ click.echo(" • Find quota for the instance family", err=True)
228
+ click.echo(" • Request increase (typically approved within 24h)", err=True)
229
+ click.echo("", err=True)
230
+ click.echo("For testing infrastructure, use CPU instances instead of GPU.", err=True)
231
+ raise click.Abort()
232
+
233
+ # Check for insufficient capacity errors
234
+ if "InsufficientInstanceCapacity" in error_msg:
235
+ click.echo(f"✗ Failed to launch engine: insufficient EC2 capacity", err=True)
236
+ click.echo("", err=True)
237
+ click.echo(f"AWS does not have available {engine_type} capacity in your region/AZ.", err=True)
238
+ click.echo("", err=True)
239
+ click.echo("Solutions:", err=True)
240
+ click.echo(" 1. Try again in a few minutes (capacity fluctuates)", err=True)
241
+ click.echo(" 2. Use a different instance type", err=True)
242
+ click.echo(" 3. Contact AWS support for capacity reservations", err=True)
243
+ raise click.Abort()
244
+
245
+ # Check for instance limit errors
246
+ if "InstanceLimitExceeded" in error_msg or "instance limit" in error_msg.lower():
247
+ click.echo(f"✗ Failed to launch engine: instance limit exceeded", err=True)
248
+ click.echo("", err=True)
249
+ click.echo(f"You have reached the maximum number of running instances in {env}.", err=True)
250
+ click.echo("", err=True)
251
+ click.echo("Solutions:", err=True)
252
+ click.echo(" 1. Terminate unused engines: dh engine2 list --env {env}", err=True)
253
+ click.echo(" 2. Request a limit increase via AWS Service Quotas", err=True)
254
+ raise click.Abort()
255
+
256
+ # Generic error
213
257
  click.echo(f"✗ Failed to launch engine: {e}", err=True)
214
258
  raise click.Abort()
215
259
 
@@ -222,7 +266,9 @@ def launch_engine(
222
266
  @click.option(
223
267
  "--skip-ssh-config", is_flag=True, help="Don't automatically update SSH config"
224
268
  )
225
- @click.option("--yes", "-y", is_flag=True, help="Skip confirmation for non-dev environments")
269
+ @click.option(
270
+ "--yes", "-y", is_flag=True, help="Skip confirmation for non-dev environments"
271
+ )
226
272
  @click.option(
227
273
  "--env",
228
274
  default=None,
@@ -345,7 +391,9 @@ def start_engine(
345
391
 
346
392
  @engine_cli.command("stop")
347
393
  @click.argument("name_or_id")
348
- @click.option("--yes", "-y", is_flag=True, help="Skip confirmation for non-dev environments")
394
+ @click.option(
395
+ "--yes", "-y", is_flag=True, help="Skip confirmation for non-dev environments"
396
+ )
349
397
  @click.option(
350
398
  "--env",
351
399
  default=None,
@@ -588,7 +636,9 @@ def list_engines(env: Optional[str]):
588
636
  return
589
637
 
590
638
  # Calculate dynamic width for Name column (longest name + 2 for padding)
591
- max_name_len = max((len(engine.get("name", "unknown")) for engine in engines), default=4)
639
+ max_name_len = max(
640
+ (len(engine.get("name", "unknown")) for engine in engines), default=4
641
+ )
592
642
  name_width = max(max_name_len + 2, len("Name") + 2)
593
643
 
594
644
  # Fixed widths for other columns
@@ -597,11 +647,20 @@ def list_engines(env: Optional[str]):
597
647
  type_width = 12
598
648
  id_width = 20
599
649
 
600
- # Calculate total width for separator line
601
- total_width = name_width + state_width + user_width + type_width + id_width + 9 # +9 for separators and spaces
602
-
603
650
  # Table top border
604
- click.echo("╭" + "─" * (name_width + 1) + "┬" + "─" * (state_width + 1) + "┬" + "─" * (user_width + 1) + "┬" + "─" * (type_width + 1) + "┬" + "─" * (id_width + 1) + "╮")
651
+ click.echo(
652
+ "╭"
653
+ + "─" * (name_width + 1)
654
+ + "┬"
655
+ + "─" * (state_width + 1)
656
+ + "┬"
657
+ + "─" * (user_width + 1)
658
+ + "┬"
659
+ + "─" * (type_width + 1)
660
+ + "┬"
661
+ + "─" * (id_width + 1)
662
+ + "╮"
663
+ )
605
664
 
606
665
  # Table header
607
666
  click.echo(
@@ -609,7 +668,19 @@ def list_engines(env: Optional[str]):
609
668
  )
610
669
 
611
670
  # Header separator
612
- click.echo("├" + "─" * (name_width + 1) + "┼" + "─" * (state_width + 1) + "┼" + "─" * (user_width + 1) + "┼" + "─" * (type_width + 1) + "┼" + "─" * (id_width + 1) + "┤")
671
+ click.echo(
672
+ "├"
673
+ + "─" * (name_width + 1)
674
+ + "┼"
675
+ + "─" * (state_width + 1)
676
+ + "┼"
677
+ + "─" * (user_width + 1)
678
+ + "┼"
679
+ + "─" * (type_width + 1)
680
+ + "┼"
681
+ + "─" * (id_width + 1)
682
+ + "┤"
683
+ )
613
684
 
614
685
  # Table rows
615
686
  for engine in engines:
@@ -621,11 +692,11 @@ def list_engines(env: Optional[str]):
621
692
 
622
693
  # Truncate if needed
623
694
  if len(name) > name_width - 1:
624
- name = name[:name_width - 1]
695
+ name = name[: name_width - 1]
625
696
  if len(user) > user_width - 1:
626
- user = user[:user_width - 1]
697
+ user = user[: user_width - 1]
627
698
  if len(engine_type) > type_width - 1:
628
- engine_type = engine_type[:type_width - 1]
699
+ engine_type = engine_type[: type_width - 1]
629
700
 
630
701
  # Color the name (blue)
631
702
  name_display = f"\033[34m{name:<{name_width}}\033[0m"
@@ -648,9 +719,21 @@ def list_engines(env: Optional[str]):
648
719
  )
649
720
 
650
721
  # Table bottom border
651
- click.echo("╰" + "─" * (name_width + 1) + "┴" + "─" * (state_width + 1) + "┴" + "─" * (user_width + 1) + "┴" + "─" * (type_width + 1) + "┴" + "─" * (id_width + 1) + "╯")
722
+ click.echo(
723
+ "╰"
724
+ + "─" * (name_width + 1)
725
+ + "┴"
726
+ + "─" * (state_width + 1)
727
+ + "┴"
728
+ + "─" * (user_width + 1)
729
+ + "┴"
730
+ + "─" * (type_width + 1)
731
+ + "┴"
732
+ + "─" * (id_width + 1)
733
+ + "╯"
734
+ )
652
735
 
653
- click.echo(f"Total: {len(engines)} engine(s)\n")
736
+ click.echo(f"Total: {len(engines)}\n")
654
737
 
655
738
  except Exception as e:
656
739
  click.echo(f"✗ Error: {e}", err=True)
@@ -128,7 +128,7 @@ def format_list_output(engines: list[dict[str, Any]], env: str = "dev") -> None:
128
128
  + "╯"
129
129
  )
130
130
 
131
- print(f"Total: {len(engines)} engine(s)\n")
131
+ print(f"Total: {len(engines)}\n")
132
132
 
133
133
 
134
134
  def generate_scenarios() -> dict[str, dict[str, Any]]:
@@ -104,7 +104,7 @@ def format_list_output(studios: list[dict[str, Any]], engines_map: dict[str, str
104
104
  # Table bottom border
105
105
  print("╰" + "─" * (user_width + 1) + "┴" + "─" * (status_width + 1) + "┴" + "─" * (attached_width + 1) + "┴" + "─" * (size_width + 1) + "┴" + "─" * (id_width + 1) + "╯")
106
106
 
107
- print(f"Total: {len(studios)} studio(s)\n")
107
+ print(f"Total: {len(studios)}\n")
108
108
 
109
109
 
110
110
  def generate_scenarios() -> dict[str, dict[str, Any]]:
@@ -349,7 +349,7 @@ def list_studios(env: Optional[str]):
349
349
  # Table bottom border
350
350
  click.echo("╰" + "─" * (user_width + 1) + "┴" + "─" * (status_width + 1) + "┴" + "─" * (attached_width + 1) + "┴" + "─" * (size_width + 1) + "┴" + "─" * (id_width + 1) + "╯")
351
351
 
352
- click.echo(f"Total: {len(studios)} studio(s)\n")
352
+ click.echo(f"Total: {len(studios)}\n")
353
353
 
354
354
  except Exception as e:
355
355
  click.echo(f"✗ Error: {e}", err=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dayhoff-tools
3
- Version: 1.13.2
3
+ Version: 1.13.4
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
@@ -13,18 +13,18 @@ dayhoff_tools/cli/engine1/studio_commands.py,sha256=VwTQujz32-uMcYusDRE73SdzRpgv
13
13
  dayhoff_tools/cli/engines_studios/__init__.py,sha256=E6aG0C6qjJnJuClemSKRFlYvLUL49MQZOvfqNQ7SDKs,159
14
14
  dayhoff_tools/cli/engines_studios/api_client.py,sha256=9I55_Ns8VHxndGjvSt_c5ZohSqMOeywQlLjyuoDEqCQ,13039
15
15
  dayhoff_tools/cli/engines_studios/auth.py,sha256=rwetV5hp4jSvK8FyvKgXCnezLOZx1aW8oiSDc6U83iE,5189
16
- dayhoff_tools/cli/engines_studios/engine-studio-cli.md,sha256=vtFuQDi41DP_MAzxiQiyXWC396pwHnab4uil8kCrehk,29944
17
- dayhoff_tools/cli/engines_studios/engine_commands.py,sha256=qFoDJODwwQilflQZXNy-D-tcHvLi36AgLCNqqSQaj1w,34563
16
+ dayhoff_tools/cli/engines_studios/engine-studio-cli.md,sha256=or4k7ZZKPMTkvu67PdcUTE2_cxjnj0HQxxTuJZR1uiA,29924
17
+ dayhoff_tools/cli/engines_studios/engine_commands.py,sha256=ZvUt9Gfl1-mhTu-jWAP3w6C_JVcrwOqfJV_jG0-_YGA,37330
18
18
  dayhoff_tools/cli/engines_studios/progress.py,sha256=SMahdG2YmO5bEPSONrfAXVTdS6m_69Ep02t3hc2DdKQ,9264
19
19
  dayhoff_tools/cli/engines_studios/simulators/cli-simulators.md,sha256=FZJl6nehdr2Duht2cx3yijcak0yKyOaHTrTzvFTAfZs,4976
20
20
  dayhoff_tools/cli/engines_studios/simulators/demo.sh,sha256=8tYABSCxLNXqGs-4r071V9mpKNZ5DTQ34WZ-v3d5s94,5364
21
- dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py,sha256=NJOO0CZFRJuIBS1xpYYIU9FW2-hQs8oq2BxwMifUqtY,9535
21
+ dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py,sha256=vUrB6gV9UX74L5uCRMTVcPmk_1ZOuP1jYJf6cMP7dOE,9525
22
22
  dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py,sha256=KUm3gA2MiRgGrQV7KURhb5zabM18-30z_ugRjiq5iso,13024
23
23
  dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py,sha256=F_MfEXdPKNVDCKgJV72QyU2oMG8hLt-Bwic4yFadRXE,17570
24
24
  dayhoff_tools/cli/engines_studios/simulators/simulator_utils.py,sha256=HA08pIMJWV3OFrWj3Ca8GldvgJZfFoTOloyLK0UWMgA,6729
25
- dayhoff_tools/cli/engines_studios/simulators/studio_list_simulator.py,sha256=MVQf_CshYqPuldW_VXE8LijSm26yYPWMg6QJLuRTobg,11207
25
+ dayhoff_tools/cli/engines_studios/simulators/studio_list_simulator.py,sha256=CHqxeTApdYneOngfGCAZiNxi9al_yAP1hNhVsQJ57V4,11197
26
26
  dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py,sha256=6WvpnRawJVaQf_H81zuR1_66igRRVxPxjAt8e69xjp4,5394
27
- dayhoff_tools/cli/engines_studios/studio_commands.py,sha256=RbXayvlrydEt5ao7OjYNAkyaVgAkukre3Iq1VrolKk8,24401
27
+ dayhoff_tools/cli/engines_studios/studio_commands.py,sha256=0x0x2DZ7LWXQZOq0rKWdguVp2QQCrkSUjK43O6jnLOM,24391
28
28
  dayhoff_tools/cli/main.py,sha256=Nz_jtbppmvWKHZydQ0nkt_eejccJE90ces8xCGrerdY,7086
29
29
  dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
30
30
  dayhoff_tools/cli/utility_commands.py,sha256=e2P4dCCtoqMUGNyb0lFBZ6GZpl5Zslm1qqE5qIvsy38,50765
@@ -48,7 +48,7 @@ dayhoff_tools/intake/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJq
48
48
  dayhoff_tools/logs.py,sha256=DKdeP0k0kliRcilwvX0mUB2eipO5BdWUeHwh-VnsICs,838
49
49
  dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
50
50
  dayhoff_tools/warehouse.py,sha256=UETBtZD3r7WgvURqfGbyHlT7cxoiVq8isjzMuerKw8I,24475
51
- dayhoff_tools-1.13.2.dist-info/METADATA,sha256=3yH2B0VHCo_8AfohB70VdnxLjHuK_zWklWcW9zN62qk,2980
52
- dayhoff_tools-1.13.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
53
- dayhoff_tools-1.13.2.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
54
- dayhoff_tools-1.13.2.dist-info/RECORD,,
51
+ dayhoff_tools-1.13.4.dist-info/METADATA,sha256=sqkHAmS0J1THxON0ivHLsbJTVrfi5i8rkScs1WtD9qc,2980
52
+ dayhoff_tools-1.13.4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
53
+ dayhoff_tools-1.13.4.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
54
+ dayhoff_tools-1.13.4.dist-info/RECORD,,