@@ -87,6 +87,7 @@ def _process_offers_into_backend_gpus(
8787 spot = offer .instance .resources .spot ,
8888 count = gpu_count_in_offer ,
8989 price = offer .price ,
90+ region = offer .region ,
9091 )
9192
9293 backend_gpus_list = []
@@ -204,24 +205,23 @@ def _get_gpus_grouped_by_backend_and_region(backend_gpus: List[BackendGpus]) ->
204205 """Aggregates GPU specs, grouping them by both backend and region."""
205206 gpu_rows : Dict [Tuple , GpuGroup ] = {}
206207 for backend in backend_gpus :
207- for region in backend .regions :
208- for gpu in backend .gpus :
209- key = (gpu .name , gpu .memory_mib , gpu .vendor , backend .backend_type , region )
210- if key not in gpu_rows :
211- per_gpu_price = gpu .price / gpu .count
212- gpu_rows [key ] = GpuGroup (
213- name = gpu .name ,
214- memory_mib = gpu .memory_mib ,
215- vendor = gpu .vendor ,
216- availability = [gpu .availability ],
217- spot = ["spot" if gpu .spot else "on-demand" ],
218- count = Range [int ](min = gpu .count , max = gpu .count ),
219- price = Range [float ](min = per_gpu_price , max = per_gpu_price ),
220- backend = backend .backend_type ,
221- region = region ,
222- )
223- else :
224- _update_gpu_group (gpu_rows [key ], gpu , backend .backend_type )
208+ for gpu in backend .gpus :
209+ key = (gpu .name , gpu .memory_mib , gpu .vendor , backend .backend_type , gpu .region )
210+ if key not in gpu_rows :
211+ per_gpu_price = gpu .price / gpu .count
212+ gpu_rows [key ] = GpuGroup (
213+ name = gpu .name ,
214+ memory_mib = gpu .memory_mib ,
215+ vendor = gpu .vendor ,
216+ availability = [gpu .availability ],
217+ spot = ["spot" if gpu .spot else "on-demand" ],
218+ count = Range [int ](min = gpu .count , max = gpu .count ),
219+ price = Range [float ](min = per_gpu_price , max = per_gpu_price ),
220+ backend = backend .backend_type ,
221+ region = gpu .region ,
222+ )
223+ else :
224+ _update_gpu_group (gpu_rows [key ], gpu , backend .backend_type )
225225
226226 return sorted (
227227 list (gpu_rows .values ()),
@@ -313,31 +313,30 @@ def _get_gpus_grouped_by_backend_region_and_count(
313313 """Aggregates GPU specs, grouping them by backend, region, and GPU count."""
314314 gpu_rows : Dict [Tuple , GpuGroup ] = {}
315315 for backend in backend_gpus :
316- for region in backend .regions :
317- for gpu in backend .gpus :
318- key = (
319- gpu .name ,
320- gpu .memory_mib ,
321- gpu .vendor ,
322- backend .backend_type ,
323- region ,
324- gpu .count ,
316+ for gpu in backend .gpus :
317+ key = (
318+ gpu .name ,
319+ gpu .memory_mib ,
320+ gpu .vendor ,
321+ backend .backend_type ,
322+ gpu .region ,
323+ gpu .count ,
324+ )
325+ if key not in gpu_rows :
326+ per_gpu_price = gpu .price / gpu .count
327+ gpu_rows [key ] = GpuGroup (
328+ name = gpu .name ,
329+ memory_mib = gpu .memory_mib ,
330+ vendor = gpu .vendor ,
331+ availability = [gpu .availability ],
332+ spot = ["spot" if gpu .spot else "on-demand" ],
333+ count = Range [int ](min = gpu .count , max = gpu .count ),
334+ price = Range [float ](min = per_gpu_price , max = per_gpu_price ),
335+ backend = backend .backend_type ,
336+ region = gpu .region ,
325337 )
326- if key not in gpu_rows :
327- per_gpu_price = gpu .price / gpu .count
328- gpu_rows [key ] = GpuGroup (
329- name = gpu .name ,
330- memory_mib = gpu .memory_mib ,
331- vendor = gpu .vendor ,
332- availability = [gpu .availability ],
333- spot = ["spot" if gpu .spot else "on-demand" ],
334- count = Range [int ](min = gpu .count , max = gpu .count ),
335- price = Range [float ](min = per_gpu_price , max = per_gpu_price ),
336- backend = backend .backend_type ,
337- region = region ,
338- )
339- else :
340- _update_gpu_group (gpu_rows [key ], gpu , backend .backend_type )
338+ else :
339+ _update_gpu_group (gpu_rows [key ], gpu , backend .backend_type )
341340
342341 return sorted (
343342 list (gpu_rows .values ()),
@@ -366,6 +365,11 @@ async def list_gpus_grouped(
366365
367366 group_by_set = set (group_by ) if group_by else set ()
368367
368+ if "region" in group_by_set and "backend" not in group_by_set :
369+ from dstack ._internal .core .errors import ServerClientError
370+
371+ raise ServerClientError ("Cannot group by 'region' without also grouping by 'backend'" )
372+
369373 # Determine grouping strategy based on combination
370374 has_backend = "backend" in group_by_set
371375 has_region = "region" in group_by_set
0 commit comments