1+ # Copyright 2025 IBM, Red Hat
2+ #
3+ # Licensed under the Apache License, Version 2.0 (the "License");
4+ # you may not use this file except in compliance with the License.
5+ # You may obtain a copy of the License at
6+ #
7+ # http://www.apache.org/licenses/LICENSE-2.0
8+ #
9+ # Unless required by applicable law or agreed to in writing, software
10+ # distributed under the License is distributed on an "AS IS" BASIS,
11+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ # See the License for the specific language governing permissions and
13+ # limitations under the License.
14+
15+ """
16+ This sub-module exists primarily to be used internally by the RayJob object
17+ (in the rayjob sub-module) for pretty-printing job status and details.
18+ """
19+
20+ from rich .console import Console
21+ from rich .table import Table
22+ from rich .panel import Panel
23+ from typing import Tuple , Optional
24+
25+ from .status import RayJobDeploymentStatus , RayJobInfo
26+
27+
28+ def print_job_status (job_info : RayJobInfo ):
29+ """
30+ Pretty print the job status in a format similar to cluster status.
31+ """
32+ status_display , header_color = _get_status_display (job_info .status )
33+
34+ # Create main info table
35+ table = _create_info_table (header_color , job_info .name , status_display )
36+ table .add_row (f"[bold]Job ID:[/bold] { job_info .job_id } " )
37+ table .add_row (f"[bold]Status:[/bold] { job_info .status .value } " )
38+ table .add_row (f"[bold]RayCluster:[/bold] { job_info .cluster_name } " )
39+ table .add_row (f"[bold]Namespace:[/bold] { job_info .namespace } " )
40+
41+ # Add timing information if available
42+ if job_info .start_time :
43+ table .add_row (f"[bold]Started:[/bold] { job_info .start_time } " )
44+
45+ # Add attempt counts if there are failures
46+ if job_info .failed_attempts > 0 :
47+ table .add_row (f"[bold]Failed Attempts:[/bold] { job_info .failed_attempts } " )
48+
49+ _print_table_in_panel (table )
50+
51+
52+ def print_no_job_found (job_name : str , namespace : str ):
53+ """
54+ Print a message when no job is found.
55+ """
56+ # Create table with error message
57+ table = _create_info_table ("[white on red][bold]Name" , job_name , "[bold red]No RayJob found" )
58+ table .add_row ()
59+ table .add_row ("Have you run rayjob.submit() yet?" )
60+ table .add_row ()
61+ table .add_row (f"[bold]Namespace:[/bold] { namespace } " )
62+
63+ _print_table_in_panel (table )
64+
65+
66+ def _get_status_display (status : RayJobDeploymentStatus ) -> Tuple [str , str ]:
67+ """
68+ Get the display string and header color for a given status.
69+
70+ Returns:
71+ Tuple of (status_display, header_color)
72+ """
73+ status_mapping = {
74+ RayJobDeploymentStatus .COMPLETE : ("Complete :white_heavy_check_mark:" , "[white on green][bold]Name" ),
75+ RayJobDeploymentStatus .RUNNING : ("Running :gear:" , "[white on blue][bold]Name" ),
76+ RayJobDeploymentStatus .FAILED : ("Failed :x:" , "[white on red][bold]Name" ),
77+ RayJobDeploymentStatus .SUSPENDED : ("Suspended :pause_button:" , "[white on yellow][bold]Name" ),
78+ }
79+
80+ return status_mapping .get (status , ("Unknown :question:" , "[white on red][bold]Name" ))
81+
82+
83+ def _create_info_table (header_color : str , name : str , status_display : str ) -> Table :
84+ """
85+ Create a standardized info table with header and status.
86+
87+ Returns:
88+ Table with header row, name/status row, and empty separator row
89+ """
90+ table = Table (box = None , show_header = False )
91+ table .add_row (header_color )
92+ table .add_row ("[bold underline]" + name , status_display )
93+ table .add_row () # Empty separator row
94+ return table
95+
96+
97+ def _print_table_in_panel (table : Table ):
98+ """
99+ Print a table wrapped in a consistent panel format.
100+ """
101+ console = Console ()
102+ main_table = Table (box = None , title = "[bold] :package: CodeFlare RayJob Status :package:" )
103+ main_table .add_row (Panel .fit (table ))
104+ console .print (main_table )
0 commit comments