dayhoff-tools 1.6.5__tar.gz → 1.6.7__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 dayhoff-tools might be problematic. Click here for more details.

Files changed (32) hide show
  1. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/PKG-INFO +1 -1
  2. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/cli/engine_commands.py +54 -18
  3. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/pyproject.toml +1 -1
  4. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/README.md +0 -0
  5. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/__init__.py +0 -0
  6. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/chemistry/standardizer.py +0 -0
  7. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/chemistry/utils.py +0 -0
  8. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/cli/__init__.py +0 -0
  9. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/cli/cloud_commands.py +0 -0
  10. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/cli/main.py +0 -0
  11. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/cli/swarm_commands.py +0 -0
  12. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/cli/utility_commands.py +0 -0
  13. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/base.py +0 -0
  14. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/deploy_aws.py +0 -0
  15. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/deploy_gcp.py +0 -0
  16. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/deploy_utils.py +0 -0
  17. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/job_runner.py +0 -0
  18. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/processors.py +0 -0
  19. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/deployment/swarm.py +0 -0
  20. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/embedders.py +0 -0
  21. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/fasta.py +0 -0
  22. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/file_ops.py +0 -0
  23. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/h5.py +0 -0
  24. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/intake/gcp.py +0 -0
  25. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/intake/gtdb.py +0 -0
  26. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/intake/kegg.py +0 -0
  27. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/intake/mmseqs.py +0 -0
  28. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/intake/structure.py +0 -0
  29. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/intake/uniprot.py +0 -0
  30. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/logs.py +0 -0
  31. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/sqlite.py +0 -0
  32. {dayhoff_tools-1.6.5 → dayhoff_tools-1.6.7}/dayhoff_tools/warehouse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dayhoff-tools
3
- Version: 1.6.5
3
+ Version: 1.6.7
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
@@ -1710,6 +1710,23 @@ def attach_studio(
1710
1710
 
1711
1711
  console.print(f"Attaching studio to engine [cyan]{engine['name']}[/cyan]...")
1712
1712
 
1713
+ # Helper --------------------------------------------------------------
1714
+ def _is_studio_attached(target_studio_id: str, target_vm_id: str) -> bool:
1715
+ """Return True when the given studio already shows as attached to the VM.
1716
+
1717
+ Using this extra check lets us stop the outer retry loop as soon as the
1718
+ asynchronous attach operation actually finishes, even in the unlikely
1719
+ event that the operation-tracking DynamoDB record is not yet updated.
1720
+ """
1721
+ resp = make_api_request("GET", f"/studios/{target_studio_id}")
1722
+ if resp.status_code != 200:
1723
+ return False
1724
+ data = resp.json()
1725
+ return (
1726
+ data.get("status") == "in-use"
1727
+ and data.get("attached_vm_id") == target_vm_id
1728
+ )
1729
+
1713
1730
  # Determine retry strategy based on whether we just started the engine
1714
1731
  if engine_started_now:
1715
1732
  max_attempts = 40 # About 7 minutes total with exponential backoff
@@ -1734,6 +1751,12 @@ def attach_studio(
1734
1751
  last_error = None
1735
1752
 
1736
1753
  for attempt in range(max_attempts):
1754
+ # If the attach already completed in the previous iteration (but we
1755
+ # didn't notice because the operation table wasn’t updated yet),
1756
+ # bail out early.
1757
+ if _is_studio_attached(studio["studio_id"], engine["instance_id"]):
1758
+ success = True
1759
+ break
1737
1760
  success, error_msg = _attempt_studio_attach(
1738
1761
  studio, engine, target_user, public_key
1739
1762
  )
@@ -1860,27 +1883,40 @@ def _attempt_studio_attach(studio, engine, target_user, public_key):
1860
1883
 
1861
1884
 
1862
1885
  def _poll_operation(operation_id: str, timeout: int = 600) -> Tuple[bool, str]:
1863
- """Poll /operations/<id> until COMPLETED or FAILED.
1886
+ """Poll `/operations/<id>` until it reports COMPLETED or FAILED.
1864
1887
 
1865
- Returns (True, "") on success or (False, error_message) on failure / timeout.
1866
- Uses a simple status spinner to avoid nested Live displays.
1888
+ Returns (True, "") on success or (False, error_message) on failure or
1889
+ timeout.
1890
+
1891
+ IMPORTANT: This helper deliberately *avoids* creating its own Rich Live/
1892
+ spinner so that it can be called from inside another Progress/Live context
1893
+ (the outer "Attaching studio…" progress bar). Nested Live renderables lead
1894
+ to constant hide/show repaint cycles, which is what caused the flickering
1895
+ the user observed.
1867
1896
  """
1868
1897
  start_ts = time.time()
1869
- with console.status("[cyan]Waiting for studio attach to complete…", spinner="dots") as status:
1870
- while True:
1871
- if time.time() - start_ts > timeout:
1872
- return False, "Timed out waiting for attach operation to complete"
1873
- op_resp = make_api_request("GET", f"/operations/{operation_id}")
1874
- if op_resp.status_code != 200:
1875
- return False, f"Failed to fetch operation status (HTTP {op_resp.status_code})"
1876
- data = op_resp.json()
1877
- op_status = data.get("status")
1878
- if op_status == "COMPLETED":
1879
- return True, ""
1880
- if op_status == "FAILED":
1881
- return False, data.get("error", "Operation failed")
1882
- # keep spinner steady – no constant message updates
1883
- time.sleep(3)
1898
+ while True:
1899
+ # ---- timeout guard -------------------------------------------------
1900
+ if time.time() - start_ts > timeout:
1901
+ return False, "Timed out waiting for attach operation to complete"
1902
+
1903
+ # ---- fetch status ---------------------------------------------------
1904
+ op_resp = make_api_request("GET", f"/operations/{operation_id}")
1905
+ if op_resp.status_code != 200:
1906
+ return False, (
1907
+ f"Failed to fetch operation status (HTTP {op_resp.status_code})"
1908
+ )
1909
+ data = op_resp.json()
1910
+ op_status = data.get("status")
1911
+
1912
+ # ---- interpret state -----------------------------------------------
1913
+ if op_status == "COMPLETED":
1914
+ return True, ""
1915
+ if op_status == "FAILED":
1916
+ return False, data.get("error", "Operation failed")
1917
+
1918
+ # Not finished yet – wait a little and poll again (no live spinner)
1919
+ time.sleep(3)
1884
1920
 
1885
1921
 
1886
1922
  @studio_app.command("detach")
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
5
5
 
6
6
  [project]
7
7
  name = "dayhoff-tools"
8
- version = "1.6.5"
8
+ version = "1.6.7"
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"}
File without changes