Skip to content

Commit 565f8a7

Browse files
Shorter resource syntax for dstack apply, dstack offer, and dstack ps #2571" (second attempt)
1 parent 3aaa2f9 commit 565f8a7

6 files changed

Lines changed: 41 additions & 41 deletions

File tree

src/dstack/_internal/cli/services/configurators/fleet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ def th(s: str) -> str:
312312
offer.instance.name,
313313
resources.pretty_format(),
314314
"yes" if resources.spot else "no",
315-
f"${offer.price:g}",
315+
f"${offer.price:3f}".rstrip("0").rstrip("."),
316316
availability,
317317
style=None if index == 1 else "secondary",
318318
)

src/dstack/_internal/cli/utils/fleet.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ def get_fleets_table(
7979
"BACKEND": backend,
8080
"REGION": region,
8181
"RESOURCES": resources,
82-
"PRICE": f"${instance.price:.4}" if instance.price is not None else "",
82+
"PRICE": f"${instance.price:.4f}".rstrip("0").rstrip(".")
83+
if instance.price is not None
84+
else "",
8385
"STATUS": status,
8486
"CREATED": format_date(instance.created),
8587
"ERROR": error,

src/dstack/_internal/cli/utils/run.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
from typing import Any, Dict, List, Optional, Union
23

34
from rich.markup import escape
@@ -35,7 +36,7 @@ def print_run_plan(
3536

3637
req = job_plan.job_spec.requirements
3738
pretty_req = req.pretty_format(resources_only=True)
38-
max_price = f"${req.max_price:g}" if req.max_price else "-"
39+
max_price = f"${req.max_price:3f}".rstrip("0").rstrip(".") if req.max_price else "-"
3940
max_duration = (
4041
format_pretty_duration(job_plan.job_spec.max_duration)
4142
if job_plan.job_spec.max_duration
@@ -93,14 +94,12 @@ def th(s: str) -> str:
9394
props.add_row(th("Inactivity duration"), inactivity_duration)
9495
props.add_row(th("Reservation"), run_plan.run_spec.configuration.reservation or "-")
9596

96-
offers = Table(box=None)
97+
offers = Table(box=None, expand=os.get_terminal_size()[0] <= 110)
9798
offers.add_column("#")
98-
offers.add_column("BACKEND")
99-
offers.add_column("REGION")
100-
offers.add_column("INSTANCE TYPE")
101-
offers.add_column("RESOURCES")
102-
offers.add_column("SPOT")
103-
offers.add_column("PRICE")
99+
offers.add_column("BACKEND", style="grey58", ratio=2)
100+
offers.add_column("RESOURCES", ratio=4)
101+
offers.add_column("INSTANCE TYPE", style="grey58", ratio=2)
102+
offers.add_column("PRICE", style="grey58", ratio=1)
104103
offers.add_column()
105104

106105
job_plan.offers = job_plan.offers[:max_offers] if max_offers else job_plan.offers
@@ -121,14 +120,12 @@ def th(s: str) -> str:
121120
instance += f" ({offer.blocks}/{offer.total_blocks})"
122121
offers.add_row(
123122
f"{i}",
124-
offer.backend.replace("remote", "ssh"),
125-
offer.region,
123+
offer.backend.replace("remote", "ssh") + " (" + offer.region + ")",
124+
r.pretty_format(include_spot=True),
126125
instance,
127-
r.pretty_format(),
128-
"yes" if r.spot else "no",
129-
f"${offer.price:g}",
126+
f"${offer.price:.4f}".rstrip("0").rstrip("."),
130127
availability,
131-
style=None if i == 1 else "secondary",
128+
style=None if i == 1 or not include_run_properties else "secondary",
132129
)
133130
if job_plan.total_offers > len(job_plan.offers):
134131
offers.add_row("", "...", style="secondary")
@@ -140,7 +137,8 @@ def th(s: str) -> str:
140137
if job_plan.total_offers > len(job_plan.offers):
141138
console.print(
142139
f"[secondary] Shown {len(job_plan.offers)} of {job_plan.total_offers} offers, "
143-
f"${job_plan.max_price:g} max[/]"
140+
f"${job_plan.max_price:3f}".rstrip("0").rstrip(".")
141+
+ "max[/]"
144142
)
145143
console.print()
146144
else:
@@ -150,19 +148,18 @@ def th(s: str) -> str:
150148
def get_runs_table(
151149
runs: List[Run], verbose: bool = False, format_date: DateFormatter = pretty_date
152150
) -> Table:
153-
table = Table(box=None)
154-
table.add_column("NAME", style="bold", no_wrap=True)
155-
table.add_column("BACKEND", style="grey58")
151+
table = Table(box=None, expand=os.get_terminal_size()[0] <= 110)
152+
table.add_column("NAME", style="bold", no_wrap=True, ratio=2)
153+
table.add_column("BACKEND", style="grey58", ratio=2)
154+
table.add_column("RESOURCES", ratio=3 if not verbose else 2)
156155
if verbose:
157-
table.add_column("INSTANCE", no_wrap=True)
158-
table.add_column("RESOURCES")
156+
table.add_column("INSTANCE", no_wrap=True, ratio=1)
157+
table.add_column("RESERVATION", no_wrap=True, ratio=1)
158+
table.add_column("PRICE", style="grey58", ratio=1)
159+
table.add_column("STATUS", no_wrap=True, ratio=1)
160+
table.add_column("SUBMITTED", style="grey58", no_wrap=True, ratio=1)
159161
if verbose:
160-
table.add_column("RESERVATION", no_wrap=True)
161-
table.add_column("PRICE", no_wrap=True)
162-
table.add_column("STATUS", no_wrap=True)
163-
table.add_column("SUBMITTED", style="grey58", no_wrap=True)
164-
if verbose:
165-
table.add_column("ERROR", no_wrap=True)
162+
table.add_column("ERROR", no_wrap=True, ratio=2)
166163

167164
for run in runs:
168165
run_error = _get_run_error(run)
@@ -201,10 +198,10 @@ def get_runs_table(
201198
job_row.update(
202199
{
203200
"BACKEND": f"{jpd.backend.value.replace('remote', 'ssh')} ({jpd.region})",
204-
"INSTANCE": instance,
205201
"RESOURCES": resources.pretty_format(include_spot=True),
202+
"INSTANCE": instance,
206203
"RESERVATION": jpd.reservation,
207-
"PRICE": f"${jpd.price:.4}",
204+
"PRICE": f"${jpd.price:.4f}".rstrip("0").rstrip("."),
208205
}
209206
)
210207
if len(run.jobs) == 1:

src/dstack/_internal/core/models/instances.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def pretty_format(self, include_spot: bool = False) -> str:
5757
if self.memory_mib > 0:
5858
resources["memory"] = f"{self.memory_mib / 1024:.0f}GB"
5959
if self.disk.size_mib > 0:
60-
resources["disk_size"] = f"{self.disk.size_mib / 1024:.1f}GB"
60+
resources["disk_size"] = f"{self.disk.size_mib / 1024:.0f}GB"
6161
if self.gpus:
6262
gpu = self.gpus[0]
6363
resources["gpu_name"] = gpu.name
@@ -66,7 +66,7 @@ def pretty_format(self, include_spot: bool = False) -> str:
6666
resources["gpu_memory"] = f"{gpu.memory_mib / 1024:.0f}GB"
6767
output = pretty_resources(**resources)
6868
if include_spot and self.spot:
69-
output += ", SPOT"
69+
output += " (spot)"
7070
return output
7171

7272

src/dstack/_internal/core/models/runs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def pretty_format(self, resources_only: bool = False):
162162
if self.spot is not None:
163163
res += f", {'spot' if self.spot else 'on-demand'}"
164164
if self.max_price is not None:
165-
res += f" under ${self.max_price:g} per hour"
165+
res += f" under ${self.max_price:3f}".rstrip("0").rstrip(".") + " per hour"
166166
return res
167167

168168

src/dstack/_internal/utils/common.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,25 +110,26 @@ def pretty_resources(
110110
"""
111111
parts = []
112112
if cpus is not None:
113-
parts.append(f"{cpus}xCPU")
113+
parts.append(f"cpu={cpus}")
114114
if memory is not None:
115-
parts.append(f"{memory}")
115+
parts.append(f"mem={memory}")
116116
if gpu_count:
117117
gpu_parts = []
118+
gpu_parts.append(f"{gpu_name or 'gpu'}")
118119
if gpu_memory is not None:
119120
gpu_parts.append(f"{gpu_memory}")
121+
if gpu_count is not None:
122+
gpu_parts.append(f"{gpu_count}")
120123
if total_gpu_memory is not None:
121-
gpu_parts.append(f"total {total_gpu_memory}")
124+
gpu_parts.append(f"{total_gpu_memory}")
122125
if compute_capability is not None:
123126
gpu_parts.append(f"{compute_capability}")
124127

125-
gpu = f"{gpu_count}x{gpu_name or 'GPU'}"
126-
if gpu_parts:
127-
gpu += f" ({', '.join(gpu_parts)})"
128+
gpu = ":".join(gpu_parts)
128129
parts.append(gpu)
129130
if disk_size:
130-
parts.append(f"{disk_size} (disk)")
131-
return ", ".join(parts)
131+
parts.append(f"disk={disk_size}")
132+
return " ".join(parts)
132133

133134

134135
def since(timestamp: str) -> datetime:

0 commit comments

Comments
 (0)