dayhoff-tools 1.4.8__py3-none-any.whl → 1.4.12__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.
@@ -1606,6 +1606,9 @@ def attach_studio(
1606
1606
  engines = response.json().get("engines", [])
1607
1607
  engine = resolve_engine(engine_name_or_id, engines)
1608
1608
 
1609
+ # Flag to track if we started the engine in this command (affects retry length)
1610
+ engine_started_now: bool = False
1611
+
1609
1612
  if engine["state"].lower() != "running":
1610
1613
  console.print(f"[yellow]⚠️ Engine is {engine['state']}[/yellow]")
1611
1614
  if engine["state"].lower() == "stopped" and Confirm.ask(
@@ -1618,6 +1621,8 @@ def attach_studio(
1618
1621
  console.print("[red]❌ Failed to start engine[/red]")
1619
1622
  raise typer.Exit(1)
1620
1623
  console.print("[green]✓ Engine started[/green]")
1624
+ # Mark that we booted the engine so attach loop gets extended retries
1625
+ engine_started_now = True
1621
1626
  # No further waiting here – attachment attempts below handle retry logic while the
1622
1627
  # engine finishes booting.
1623
1628
  else:
@@ -1632,32 +1637,55 @@ def attach_studio(
1632
1637
 
1633
1638
  console.print(f"Attaching studio to engine [cyan]{engine['name']}[/cyan]...")
1634
1639
 
1635
- with Progress(
1636
- SpinnerColumn(),
1637
- TimeElapsedColumn(),
1638
- TextColumn("[progress.description]{task.description}"),
1639
- transient=True,
1640
- ) as prog:
1641
- task = prog.add_task("Attaching studio (engine is still booting)…", total=None)
1642
- ATTEMPT_LIMIT = 40 # ~6-7 min max (40 × 10 s)
1643
- RETRY_DELAY = 10
1644
- for attempt in range(ATTEMPT_LIMIT):
1640
+ # Determine retry strategy
1641
+ max_attempts = 40 if engine_started_now else 3
1642
+ retry_delay = 10 if engine_started_now else 3
1643
+
1644
+ if engine_started_now:
1645
+ # Long spinner-based loop while the freshly started engine finishes booting
1646
+ with Progress(
1647
+ SpinnerColumn(),
1648
+ TimeElapsedColumn(),
1649
+ TextColumn("[progress.description]{task.description}"),
1650
+ transient=True,
1651
+ ) as prog:
1652
+ task = prog.add_task("Attaching studio (engine is still booting)…", total=None)
1653
+
1654
+ for attempt in range(max_attempts):
1655
+ success, error_msg = _attempt_studio_attach(studio, engine, target_user, public_key)
1656
+
1657
+ if success:
1658
+ break # success!
1659
+
1660
+ # Update spinner every 3rd try to avoid log spam
1661
+ if attempt % 3 == 0:
1662
+ prog.update(task, description=f"Attaching studio (engine is still booting)… {attempt+1}/{max_attempts}")
1663
+
1664
+ if error_msg:
1665
+ console.print(f"[red]❌ Failed to attach studio: {error_msg}[/red]")
1666
+ return
1667
+
1668
+ time.sleep(retry_delay)
1669
+
1670
+ else:
1671
+ console.print("[yellow]Engine is still starting up – please retry in a minute.[/yellow]")
1672
+ return
1673
+ else:
1674
+ # Quick path: engine is already running – try a couple of times then fail fast
1675
+ for attempt in range(max_attempts):
1645
1676
  success, error_msg = _attempt_studio_attach(studio, engine, target_user, public_key)
1646
1677
 
1647
1678
  if success:
1648
- break # success!
1649
-
1650
- # Update spinner description with attempt number
1651
- prog.update(task, description=f"Attaching studio (engine is still booting)… {attempt+1}/{ATTEMPT_LIMIT}")
1679
+ break # good to go
1652
1680
 
1653
1681
  if error_msg:
1654
1682
  console.print(f"[red]❌ Failed to attach studio: {error_msg}[/red]")
1655
1683
  return
1656
1684
 
1657
- time.sleep(RETRY_DELAY)
1685
+ time.sleep(retry_delay)
1658
1686
 
1659
1687
  else:
1660
- console.print("[yellow]Engine is still starting up – please retry in a minute.[/yellow]")
1688
+ console.print("[yellow]Could not attach studio – please retry in a moment.[/yellow]")
1661
1689
  return
1662
1690
 
1663
1691
  # Successful attach path
@@ -1697,8 +1725,16 @@ def _attempt_studio_attach(studio, engine, target_user, public_key):
1697
1725
  "failed to mount",
1698
1726
  "device busy",
1699
1727
  "not available",
1728
+ "pending", # VM state pending
1729
+ ]
1730
+ FATAL_PATTERNS = [
1731
+ "in-use",
1732
+ "already attached",
1733
+ "permission",
1700
1734
  ]
1701
- if any(p in err_msg for p in RECOVERABLE_PATTERNS):
1735
+ if any(p in err_msg for p in FATAL_PATTERNS):
1736
+ recoverable = False
1737
+ elif any(p in err_msg for p in RECOVERABLE_PATTERNS):
1702
1738
  recoverable = True
1703
1739
 
1704
1740
  if not recoverable:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dayhoff-tools
3
- Version: 1.4.8
3
+ Version: 1.4.12
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
@@ -3,7 +3,7 @@ dayhoff_tools/chemistry/standardizer.py,sha256=uMn7VwHnx02nc404eO6fRuS4rsl4dvSPf
3
3
  dayhoff_tools/chemistry/utils.py,sha256=jt-7JgF-GeeVC421acX-bobKbLU_X94KNOW24p_P-_M,2257
4
4
  dayhoff_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  dayhoff_tools/cli/cloud_commands.py,sha256=33qcWLmq-FwEXMdL3F0OHm-5Stlh2r65CldyEZgQ1no,40904
6
- dayhoff_tools/cli/engine_commands.py,sha256=rjS1Fmz3Z91R2hcZN3WOMf1_1g-ovHHSevy1_EDvxSc,83623
6
+ dayhoff_tools/cli/engine_commands.py,sha256=enbpFSLCsmPACL1EOarxCcF8L-TkpiNqq4DB4vhv6X0,85005
7
7
  dayhoff_tools/cli/main.py,sha256=rgeEHD9lJ8SBCR34BTLb7gVInHUUdmEBNXAJnq5yEU4,4795
8
8
  dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
9
9
  dayhoff_tools/cli/utility_commands.py,sha256=qs8vH9TBFHsOPC3X8cU3qZigM3dDn-2Ytq4o_F2WubU,27874
@@ -27,7 +27,7 @@ dayhoff_tools/intake/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJq
27
27
  dayhoff_tools/logs.py,sha256=DKdeP0k0kliRcilwvX0mUB2eipO5BdWUeHwh-VnsICs,838
28
28
  dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
29
29
  dayhoff_tools/warehouse.py,sha256=8YbnQ--usrEgDQGfvpV4MrMji55A0rq2hZaOgFGh6ag,15896
30
- dayhoff_tools-1.4.8.dist-info/METADATA,sha256=1cbd0rQXE6kBHSeTr9WReY7AFzbLj7QBtLmurAttw1E,2824
31
- dayhoff_tools-1.4.8.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
- dayhoff_tools-1.4.8.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
- dayhoff_tools-1.4.8.dist-info/RECORD,,
30
+ dayhoff_tools-1.4.12.dist-info/METADATA,sha256=GjDgKBeFXN1cwgetohVhR8Ix8SD_bTxHAQqd7HrqX_4,2825
31
+ dayhoff_tools-1.4.12.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
+ dayhoff_tools-1.4.12.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
+ dayhoff_tools-1.4.12.dist-info/RECORD,,