Skip to content

Commit 4070c59

Browse files
Reformat for pre-commit checks
1 parent 130328b commit 4070c59

File tree

5 files changed

+335
-129
lines changed

5 files changed

+335
-129
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-

src/codeflare_sdk/cluster/cluster.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -870,10 +870,12 @@ def _map_to_ray_cluster(rc) -> Optional[RayCluster]:
870870
worker_mem_requests=rc["spec"]["workerGroupSpecs"][0]["template"]["spec"][
871871
"containers"
872872
][0]["resources"]["requests"]["memory"],
873-
worker_cpu_requests=rc["spec"]["workerGroupSpecs"][0]["template"]["spec"]["containers"][0]["resources"]["requests"]["cpu"],
874-
worker_cpu_limits=rc["spec"]["workerGroupSpecs"][0]["template"]["spec"]["containers"][
875-
0
876-
]["resources"]["limits"]["cpu"],
873+
worker_cpu_requests=rc["spec"]["workerGroupSpecs"][0]["template"]["spec"][
874+
"containers"
875+
][0]["resources"]["requests"]["cpu"],
876+
worker_cpu_limits=rc["spec"]["workerGroupSpecs"][0]["template"]["spec"][
877+
"containers"
878+
][0]["resources"]["limits"]["cpu"],
877879
worker_extended_resources=worker_extended_resources,
878880
namespace=rc["metadata"]["namespace"],
879881
head_cpu_requests=rc["spec"]["headGroupSpec"]["template"]["spec"]["containers"][

src/codeflare_sdk/cluster/widgets.py

+183-55
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,13 @@ def view_clusters(namespace: str = None):
107107
view_clusters function will display existing clusters with their specs, and handle user interactions.
108108
"""
109109
if not is_notebook():
110-
warnings.warn("view_clusters can only be used in a Jupyter Notebook environment.")
111-
return # Exit function if not in Jupyter Notebook
110+
warnings.warn(
111+
"view_clusters can only be used in a Jupyter Notebook environment."
112+
)
113+
return # Exit function if not in Jupyter Notebook
112114

113115
from .cluster import get_current_namespace
116+
114117
if not namespace:
115118
namespace = get_current_namespace()
116119

@@ -124,42 +127,76 @@ def view_clusters(namespace: str = None):
124127
return
125128

126129
classification_widget = widgets.ToggleButtons(
127-
options=ray_clusters_df["Name"].tolist(), value=ray_clusters_df["Name"].tolist()[0],
128-
description='Select an existing cluster:',
130+
options=ray_clusters_df["Name"].tolist(),
131+
value=ray_clusters_df["Name"].tolist()[0],
132+
description="Select an existing cluster:",
129133
)
130134
# Setting the initial value to trigger the event handler to display the cluster details.
131135
initial_value = classification_widget.value
132-
_on_cluster_click({"new": initial_value}, raycluster_data_output, namespace, classification_widget)
133-
classification_widget.observe(lambda selection_change: _on_cluster_click(selection_change, raycluster_data_output, namespace, classification_widget), names="value")
136+
_on_cluster_click(
137+
{"new": initial_value}, raycluster_data_output, namespace, classification_widget
138+
)
139+
classification_widget.observe(
140+
lambda selection_change: _on_cluster_click(
141+
selection_change, raycluster_data_output, namespace, classification_widget
142+
),
143+
names="value",
144+
)
134145

135146
# UI table buttons
136147
delete_button = widgets.Button(
137-
description='Delete Cluster',
138-
icon='trash',
139-
tooltip="Delete the selected cluster"
140-
)
141-
delete_button.on_click(lambda b: _on_delete_button_click(b, classification_widget, ray_clusters_df, raycluster_data_output, user_output, delete_button, list_jobs_button, ray_dashboard_button))
148+
description="Delete Cluster",
149+
icon="trash",
150+
tooltip="Delete the selected cluster",
151+
)
152+
delete_button.on_click(
153+
lambda b: _on_delete_button_click(
154+
b,
155+
classification_widget,
156+
ray_clusters_df,
157+
raycluster_data_output,
158+
user_output,
159+
delete_button,
160+
list_jobs_button,
161+
ray_dashboard_button,
162+
)
163+
)
142164

143165
list_jobs_button = widgets.Button(
144-
description='View Jobs',
145-
icon='suitcase',
146-
tooltip="Open the Ray Job Dashboard"
147-
)
148-
list_jobs_button.on_click(lambda b: _on_list_jobs_button_click(b, classification_widget, ray_clusters_df, user_output, url_output))
166+
description="View Jobs", icon="suitcase", tooltip="Open the Ray Job Dashboard"
167+
)
168+
list_jobs_button.on_click(
169+
lambda b: _on_list_jobs_button_click(
170+
b, classification_widget, ray_clusters_df, user_output, url_output
171+
)
172+
)
149173

150174
ray_dashboard_button = widgets.Button(
151-
description='Open Ray Dashboard',
152-
icon='dashboard',
153-
tooltip="Open the Ray Dashboard in a new tab",
154-
layout=widgets.Layout(width='auto'),
155-
)
156-
ray_dashboard_button.on_click(lambda b: _on_ray_dashboard_button_click(b, classification_widget, ray_clusters_df, user_output, url_output))
175+
description="Open Ray Dashboard",
176+
icon="dashboard",
177+
tooltip="Open the Ray Dashboard in a new tab",
178+
layout=widgets.Layout(width="auto"),
179+
)
180+
ray_dashboard_button.on_click(
181+
lambda b: _on_ray_dashboard_button_click(
182+
b, classification_widget, ray_clusters_df, user_output, url_output
183+
)
184+
)
157185

158186
display(widgets.VBox([classification_widget, raycluster_data_output]))
159-
display(widgets.HBox([delete_button, list_jobs_button, ray_dashboard_button]), url_output, user_output)
187+
display(
188+
widgets.HBox([delete_button, list_jobs_button, ray_dashboard_button]),
189+
url_output,
190+
user_output,
191+
)
160192

161193

162-
def _on_cluster_click(selection_change, raycluster_data_output: widgets.Output, namespace: str, classification_widget: widgets.ToggleButtons):
194+
def _on_cluster_click(
195+
selection_change,
196+
raycluster_data_output: widgets.Output,
197+
namespace: str,
198+
classification_widget: widgets.ToggleButtons,
199+
):
163200
"""
164201
_on_cluster_click handles the event when a cluster is selected from the toggle buttons, updating the output with cluster details.
165202
"""
@@ -168,21 +205,51 @@ def _on_cluster_click(selection_change, raycluster_data_output: widgets.Output,
168205
ray_clusters_df = _fetch_cluster_data(namespace)
169206
classification_widget.options = ray_clusters_df["Name"].tolist()
170207
with raycluster_data_output:
171-
display(HTML(ray_clusters_df[ray_clusters_df["Name"]==new_value][["Name", "Namespace", "Num Workers", "Head GPUs", "Head CPU Req~Lim", "Head Memory Req~Lim", "Worker GPUs", "Worker CPU Req~Lim", "Worker Memory Req~Lim", "status"]].to_html(escape=False, index=False, border=2)))
172-
173-
174-
def _on_delete_button_click(b, classification_widget: widgets.ToggleButtons, ray_clusters_df: pd.DataFrame, raycluster_data_output: widgets.Output, user_output: widgets.Output, delete_button: widgets.Button, list_jobs_button: widgets.Button, ray_dashboard_button: widgets.Button):
208+
display(
209+
HTML(
210+
ray_clusters_df[ray_clusters_df["Name"] == new_value][
211+
[
212+
"Name",
213+
"Namespace",
214+
"Num Workers",
215+
"Head GPUs",
216+
"Head CPU Req~Lim",
217+
"Head Memory Req~Lim",
218+
"Worker GPUs",
219+
"Worker CPU Req~Lim",
220+
"Worker Memory Req~Lim",
221+
"status",
222+
]
223+
].to_html(escape=False, index=False, border=2)
224+
)
225+
)
226+
227+
228+
def _on_delete_button_click(
229+
b,
230+
classification_widget: widgets.ToggleButtons,
231+
ray_clusters_df: pd.DataFrame,
232+
raycluster_data_output: widgets.Output,
233+
user_output: widgets.Output,
234+
delete_button: widgets.Button,
235+
list_jobs_button: widgets.Button,
236+
ray_dashboard_button: widgets.Button,
237+
):
175238
"""
176239
_on_delete_button_click handles the event when the Delete Button is clicked, deleting the selected cluster.
177240
"""
178241
cluster_name = classification_widget.value
179-
namespace = ray_clusters_df[ray_clusters_df["Name"]==classification_widget.value]["Namespace"].values[0]
242+
namespace = ray_clusters_df[ray_clusters_df["Name"] == classification_widget.value][
243+
"Namespace"
244+
].values[0]
180245

181246
_delete_cluster(cluster_name, namespace)
182247

183248
with user_output:
184249
user_output.clear_output()
185-
print(f"Cluster {cluster_name} in the {namespace} namespace was deleted successfully.")
250+
print(
251+
f"Cluster {cluster_name} in the {namespace} namespace was deleted successfully."
252+
)
186253

187254
# Refresh the dataframe
188255
new_df = _fetch_cluster_data(namespace)
@@ -197,16 +264,28 @@ def _on_delete_button_click(b, classification_widget: widgets.ToggleButtons, ray
197264
else:
198265
classification_widget.options = new_df["Name"].tolist()
199266

200-
def _on_ray_dashboard_button_click(b, classification_widget: widgets.ToggleButtons, ray_clusters_df: pd.DataFrame, user_output: widgets.Output, url_output: widgets.Output):
267+
268+
def _on_ray_dashboard_button_click(
269+
b,
270+
classification_widget: widgets.ToggleButtons,
271+
ray_clusters_df: pd.DataFrame,
272+
user_output: widgets.Output,
273+
url_output: widgets.Output,
274+
):
201275
"""
202276
_on_ray_dashboard_button_click handles the event when the Open Ray Dashboard button is clicked, opening the Ray Dashboard in a new tab
203277
"""
204278
from codeflare_sdk.cluster import Cluster
279+
205280
cluster_name = classification_widget.value
206-
namespace = ray_clusters_df[ray_clusters_df["Name"]==classification_widget.value]["Namespace"].values[0]
281+
namespace = ray_clusters_df[ray_clusters_df["Name"] == classification_widget.value][
282+
"Namespace"
283+
].values[0]
207284

208285
# Suppress from Cluster Object initialisation widgets and outputs
209-
with widgets.Output(), contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
286+
with widgets.Output(), contextlib.redirect_stdout(
287+
io.StringIO()
288+
), contextlib.redirect_stderr(io.StringIO()):
210289
cluster = Cluster(ClusterConfiguration(cluster_name, namespace))
211290
dashboard_url = cluster.cluster_dashboard_uri()
212291

@@ -216,22 +295,36 @@ def _on_ray_dashboard_button_click(b, classification_widget: widgets.ToggleButto
216295
with url_output:
217296
display(Javascript(f'window.open("{dashboard_url}", "_blank");'))
218297

219-
def _on_list_jobs_button_click(b, classification_widget: widgets.ToggleButtons, ray_clusters_df: pd.DataFrame, user_output: widgets.Output, url_output: widgets.Output):
298+
299+
def _on_list_jobs_button_click(
300+
b,
301+
classification_widget: widgets.ToggleButtons,
302+
ray_clusters_df: pd.DataFrame,
303+
user_output: widgets.Output,
304+
url_output: widgets.Output,
305+
):
220306
"""
221307
_on_list_jobs_button_click handles the event when the View Jobs button is clicked, opening the Ray Jobs Dashboard in a new tab
222308
"""
223309
from codeflare_sdk.cluster import Cluster
310+
224311
cluster_name = classification_widget.value
225-
namespace = ray_clusters_df[ray_clusters_df["Name"]==classification_widget.value]["Namespace"].values[0]
312+
namespace = ray_clusters_df[ray_clusters_df["Name"] == classification_widget.value][
313+
"Namespace"
314+
].values[0]
226315

227316
# Suppress from Cluster Object initialisation widgets and outputs
228-
with widgets.Output(), contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
317+
with widgets.Output(), contextlib.redirect_stdout(
318+
io.StringIO()
319+
), contextlib.redirect_stderr(io.StringIO()):
229320
cluster = Cluster(ClusterConfiguration(cluster_name, namespace))
230321
dashboard_url = cluster.cluster_dashboard_uri()
231322

232323
with user_output:
233324
user_output.clear_output()
234-
print(f"Opening Ray Jobs Dashboard for {cluster_name} cluster:\n{dashboard_url}/#/jobs")
325+
print(
326+
f"Opening Ray Jobs Dashboard for {cluster_name} cluster:\n{dashboard_url}/#/jobs"
327+
)
235328
with url_output:
236329
display(Javascript(f'window.open("{dashboard_url}/#/jobs", "_blank");'))
237330

@@ -289,12 +382,14 @@ def _delete_cluster(
289382
time.sleep(interval)
290383
timeout -= interval
291384
if timeout <= 0:
292-
raise TimeoutError(f"Timeout waiting for {cluster_name} to be deleted.")
385+
raise TimeoutError(
386+
f"Timeout waiting for {cluster_name} to be deleted."
387+
)
293388
except ApiException as e:
294389
# Resource is deleted
295390
if e.status == 404:
296391
break
297-
except Exception as e:
392+
except Exception as e: # pragma: no cover
298393
return _kube_api_error_handling(e)
299394

300395

@@ -303,6 +398,7 @@ def _fetch_cluster_data(namespace):
303398
_fetch_cluster_data function fetches all clusters and their spec in a given namespace and returns a DataFrame.
304399
"""
305400
from .cluster import list_all_clusters
401+
306402
rayclusters = list_all_clusters(namespace, False)
307403
if not rayclusters:
308404
return pd.DataFrame()
@@ -311,26 +407,58 @@ def _fetch_cluster_data(namespace):
311407
num_workers = [item.num_workers for item in rayclusters]
312408
head_extended_resources = [
313409
f"{list(item.head_extended_resources.keys())[0]}: {list(item.head_extended_resources.values())[0]}"
314-
if item.head_extended_resources else "0"
410+
if item.head_extended_resources
411+
else "0"
315412
for item in rayclusters
316413
]
317414
worker_extended_resources = [
318415
f"{list(item.worker_extended_resources.keys())[0]}: {list(item.worker_extended_resources.values())[0]}"
319-
if item.worker_extended_resources else "0"
416+
if item.worker_extended_resources
417+
else "0"
418+
for item in rayclusters
419+
]
420+
head_cpu_requests = [
421+
item.head_cpu_requests if item.head_cpu_requests else 0 for item in rayclusters
422+
]
423+
head_cpu_limits = [
424+
item.head_cpu_limits if item.head_cpu_limits else 0 for item in rayclusters
425+
]
426+
head_cpu_rl = [
427+
f"{requests}~{limits}"
428+
for requests, limits in zip(head_cpu_requests, head_cpu_limits)
429+
]
430+
head_mem_requests = [
431+
item.head_mem_requests if item.head_mem_requests else 0 for item in rayclusters
432+
]
433+
head_mem_limits = [
434+
item.head_mem_limits if item.head_mem_limits else 0 for item in rayclusters
435+
]
436+
head_mem_rl = [
437+
f"{requests}~{limits}"
438+
for requests, limits in zip(head_mem_requests, head_mem_limits)
439+
]
440+
worker_cpu_requests = [
441+
item.worker_cpu_requests if item.worker_cpu_requests else 0
442+
for item in rayclusters
443+
]
444+
worker_cpu_limits = [
445+
item.worker_cpu_limits if item.worker_cpu_limits else 0 for item in rayclusters
446+
]
447+
worker_cpu_rl = [
448+
f"{requests}~{limits}"
449+
for requests, limits in zip(worker_cpu_requests, worker_cpu_limits)
450+
]
451+
worker_mem_requests = [
452+
item.worker_mem_requests if item.worker_mem_requests else 0
320453
for item in rayclusters
321454
]
322-
head_cpu_requests = [item.head_cpu_requests if item.head_cpu_requests else 0 for item in rayclusters]
323-
head_cpu_limits = [item.head_cpu_limits if item.head_cpu_limits else 0 for item in rayclusters]
324-
head_cpu_rl = [f"{requests}~{limits}" for requests, limits in zip(head_cpu_requests, head_cpu_limits)]
325-
head_mem_requests = [item.head_mem_requests if item.head_mem_requests else 0 for item in rayclusters]
326-
head_mem_limits = [item.head_mem_limits if item.head_mem_limits else 0 for item in rayclusters]
327-
head_mem_rl = [f"{requests}~{limits}" for requests, limits in zip(head_mem_requests, head_mem_limits)]
328-
worker_cpu_requests = [item.worker_cpu_requests if item.worker_cpu_requests else 0 for item in rayclusters]
329-
worker_cpu_limits = [item.worker_cpu_limits if item.worker_cpu_limits else 0 for item in rayclusters]
330-
worker_cpu_rl = [f"{requests}~{limits}" for requests, limits in zip(worker_cpu_requests, worker_cpu_limits)]
331-
worker_mem_requests = [item.worker_mem_requests if item.worker_mem_requests else 0 for item in rayclusters]
332-
worker_mem_limits = [item.worker_mem_limits if item.worker_mem_limits else 0 for item in rayclusters]
333-
worker_mem_rl = [f"{requests}~{limits}" for requests, limits in zip(worker_mem_requests, worker_mem_limits)]
455+
worker_mem_limits = [
456+
item.worker_mem_limits if item.worker_mem_limits else 0 for item in rayclusters
457+
]
458+
worker_mem_rl = [
459+
f"{requests}~{limits}"
460+
for requests, limits in zip(worker_mem_requests, worker_mem_limits)
461+
]
334462
status = [item.status.name for item in rayclusters]
335463

336464
status = [_format_status(item.status) for item in rayclusters]
@@ -345,7 +473,7 @@ def _fetch_cluster_data(namespace):
345473
"Head Memory Req~Lim": head_mem_rl,
346474
"Worker CPU Req~Lim": worker_cpu_rl,
347475
"Worker Memory Req~Lim": worker_mem_rl,
348-
"status": status
476+
"status": status,
349477
}
350478
return pd.DataFrame(data)
351479

@@ -359,6 +487,6 @@ def _format_status(status):
359487
RayClusterStatus.SUSPENDED: '<span style="color: #007BFF;">Suspended ❄️</span>',
360488
RayClusterStatus.FAILED: '<span style="color: red;">Failed ✗</span>',
361489
RayClusterStatus.UNHEALTHY: '<span style="color: purple;">Unhealthy</span>',
362-
RayClusterStatus.UNKNOWN: '<span style="color: purple;">Unknown</span>'
490+
RayClusterStatus.UNKNOWN: '<span style="color: purple;">Unknown</span>',
363491
}
364492
return status_map.get(status, status)

0 commit comments

Comments
 (0)