dayhoff-tools 1.3.3__py3-none-any.whl → 1.3.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.
- dayhoff_tools/cli/engine_commands.py +56 -11
- {dayhoff_tools-1.3.3.dist-info → dayhoff_tools-1.3.4.dist-info}/METADATA +1 -1
- {dayhoff_tools-1.3.3.dist-info → dayhoff_tools-1.3.4.dist-info}/RECORD +5 -5
- {dayhoff_tools-1.3.3.dist-info → dayhoff_tools-1.3.4.dist-info}/WHEEL +0 -0
- {dayhoff_tools-1.3.3.dist-info → dayhoff_tools-1.3.4.dist-info}/entry_points.txt +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
import json
|
4
4
|
import subprocess
|
5
5
|
import sys
|
6
|
-
from datetime import datetime, timedelta
|
6
|
+
from datetime import datetime, timedelta, timezone
|
7
7
|
from pathlib import Path
|
8
8
|
from typing import Dict, List, Optional, Tuple
|
9
9
|
|
@@ -134,11 +134,15 @@ def parse_launch_time(launch_time_str: str) -> datetime:
|
|
134
134
|
]
|
135
135
|
for fmt in formats:
|
136
136
|
try:
|
137
|
-
|
137
|
+
parsed = datetime.strptime(launch_time_str, fmt)
|
138
|
+
# If the format includes 'Z', it's UTC
|
139
|
+
if fmt.endswith('Z'):
|
140
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
141
|
+
return parsed
|
138
142
|
except ValueError:
|
139
143
|
continue
|
140
144
|
# Fallback: assume it's recent
|
141
|
-
return datetime.
|
145
|
+
return datetime.now(timezone.utc)
|
142
146
|
|
143
147
|
|
144
148
|
def format_status(state: str, ready: Optional[bool]) -> str:
|
@@ -363,7 +367,7 @@ def list_engines(
|
|
363
367
|
total_cost = 0.0
|
364
368
|
for engine in engines:
|
365
369
|
launch_time = parse_launch_time(engine["launch_time"])
|
366
|
-
uptime = datetime.
|
370
|
+
uptime = datetime.now(timezone.utc) - launch_time
|
367
371
|
hourly_cost = HOURLY_COSTS.get(engine["engine_type"], 0)
|
368
372
|
|
369
373
|
if engine["state"].lower() == "running":
|
@@ -418,7 +422,7 @@ def engine_status(
|
|
418
422
|
|
419
423
|
# Calculate costs
|
420
424
|
launch_time = parse_launch_time(engine["launch_time"])
|
421
|
-
uptime = datetime.
|
425
|
+
uptime = datetime.now(timezone.utc) - launch_time
|
422
426
|
hourly_cost = HOURLY_COSTS.get(engine["engine_type"], 0)
|
423
427
|
total_cost = hourly_cost * (uptime.total_seconds() / 3600)
|
424
428
|
|
@@ -550,7 +554,7 @@ def terminate_engine(
|
|
550
554
|
|
551
555
|
# Calculate cost
|
552
556
|
launch_time = parse_launch_time(engine["launch_time"])
|
553
|
-
uptime = datetime.
|
557
|
+
uptime = datetime.now(timezone.utc) - launch_time
|
554
558
|
hourly_cost = HOURLY_COSTS.get(engine["engine_type"], 0)
|
555
559
|
total_cost = hourly_cost * (uptime.total_seconds() / 3600)
|
556
560
|
|
@@ -1001,10 +1005,19 @@ def studio_status():
|
|
1001
1005
|
return
|
1002
1006
|
|
1003
1007
|
# Create status panel
|
1008
|
+
# Format status with colors
|
1009
|
+
status = studio['status']
|
1010
|
+
if status == "in-use":
|
1011
|
+
status_display = "[magenta]attached[/magenta]"
|
1012
|
+
elif status in ["attaching", "detaching"]:
|
1013
|
+
status_display = f"[yellow]{status}[/yellow]"
|
1014
|
+
else:
|
1015
|
+
status_display = f"[green]{status}[/green]"
|
1016
|
+
|
1004
1017
|
status_lines = [
|
1005
1018
|
f"[bold]Studio ID:[/bold] {studio['studio_id']}",
|
1006
1019
|
f"[bold]User:[/bold] {studio['user']}",
|
1007
|
-
f"[bold]Status:[/bold] {
|
1020
|
+
f"[bold]Status:[/bold] {status_display}",
|
1008
1021
|
f"[bold]Size:[/bold] {studio['size_gb']}GB",
|
1009
1022
|
f"[bold]Created:[/bold] {studio['creation_date']}",
|
1010
1023
|
]
|
@@ -1214,6 +1227,13 @@ def list_studios(
|
|
1214
1227
|
console.print("No studios found.")
|
1215
1228
|
return
|
1216
1229
|
|
1230
|
+
# Get all engines to map instance IDs to names
|
1231
|
+
engines_response = make_api_request("GET", "/engines")
|
1232
|
+
engines = {}
|
1233
|
+
if engines_response.status_code == 200:
|
1234
|
+
for engine in engines_response.json().get("engines", []):
|
1235
|
+
engines[engine["instance_id"]] = engine["name"]
|
1236
|
+
|
1217
1237
|
# Create table
|
1218
1238
|
table = Table(title="Studios", box=box.ROUNDED)
|
1219
1239
|
table.add_column("Studio ID", style="cyan")
|
@@ -1224,14 +1244,39 @@ def list_studios(
|
|
1224
1244
|
table.add_column("Created")
|
1225
1245
|
|
1226
1246
|
for studio in studios:
|
1227
|
-
|
1247
|
+
# Change status display
|
1248
|
+
if studio["status"] == "in-use":
|
1249
|
+
status_display = "[magenta]attached[/magenta]"
|
1250
|
+
elif studio["status"] in ["attaching", "detaching"]:
|
1251
|
+
status_display = "[yellow]" + studio["status"] + "[/yellow]"
|
1252
|
+
else:
|
1253
|
+
status_display = "[green]available[/green]"
|
1254
|
+
|
1255
|
+
# Format attached engine info
|
1256
|
+
attached_to = "-"
|
1257
|
+
if studio.get("attached_vm_id"):
|
1258
|
+
vm_id = studio["attached_vm_id"]
|
1259
|
+
engine_name = engines.get(vm_id, "unknown")
|
1260
|
+
attached_to = f"{engine_name} ({vm_id})"
|
1261
|
+
|
1262
|
+
# Format creation date (remove microseconds and timezone info)
|
1263
|
+
created = studio["creation_date"]
|
1264
|
+
try:
|
1265
|
+
# Parse and reformat to just show date and time
|
1266
|
+
if 'T' in created:
|
1267
|
+
created_dt = datetime.fromisoformat(created.replace('Z', '+00:00'))
|
1268
|
+
created = created_dt.strftime("%Y-%m-%d %H:%M")
|
1269
|
+
except:
|
1270
|
+
# If parsing fails, just truncate
|
1271
|
+
created = created.split('T')[0] if 'T' in created else created[:16]
|
1272
|
+
|
1228
1273
|
table.add_row(
|
1229
1274
|
studio["studio_id"],
|
1230
1275
|
studio["user"],
|
1231
|
-
|
1276
|
+
status_display,
|
1232
1277
|
f"{studio['size_gb']}GB",
|
1233
|
-
|
1234
|
-
|
1278
|
+
attached_to,
|
1279
|
+
created,
|
1235
1280
|
)
|
1236
1281
|
|
1237
1282
|
console.print(table)
|
@@ -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=
|
6
|
+
dayhoff_tools/cli/engine_commands.py,sha256=w0wzs4aQUdzeyAyhHH9lHxpJEG8acrbguQ4Rd0u5bA4,48179
|
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.3.
|
31
|
-
dayhoff_tools-1.3.
|
32
|
-
dayhoff_tools-1.3.
|
33
|
-
dayhoff_tools-1.3.
|
30
|
+
dayhoff_tools-1.3.4.dist-info/METADATA,sha256=YZw82MtQpm4aWNzOfEl62Iov6ZRXtw6LfZ43eI9psKE,2842
|
31
|
+
dayhoff_tools-1.3.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
32
|
+
dayhoff_tools-1.3.4.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
|
33
|
+
dayhoff_tools-1.3.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|