@@ -736,7 +736,7 @@ def main():
736736
737737 env = Environment (loader = FileSystemLoader (Path (__file__ ).parent / "templates" ))
738738
739- # Load optional display deadlines from deadlines.yml and/or auto-compute evenly
739+ # Load optional display deadline labels from deadlines.yml.
740740 deadlines_display_threads : dict [str , str ] | None = None
741741 deadlines_display_processes : dict [str , str ] | None = None
742742 try :
@@ -749,80 +749,32 @@ def main():
749749 except Exception :
750750 pass
751751
752- # Helper: compute evenly spaced dates for current semester (MSK)
753- import calendar
754- from datetime import date , timedelta
755-
756- def _abbr (day : date ) -> str :
757- return f"{ day .day } { calendar .month_abbr [day .month ]} "
758-
759- def _spring_bounds (today : date ) -> tuple [date , date ]:
760- """Return [1 Feb .. 15 May] window for the appropriate year.
761- If today is past 15 May, use next year's spring; otherwise this year's.
762- """
763- y = today .year
764- start = date (y , 2 , 1 )
765- end = date (y , 5 , 15 )
766- if today > end :
767- y += 1
768- start = date (y , 2 , 1 )
769- end = date (y , 5 , 15 )
770- return start , end
771-
772- def _autumn_bounds (today : date ) -> tuple [date , date ]:
773- """Return [15 Oct .. 14 Dec] window for the appropriate year.
774- If today is past 14 Dec, use next year's autumn; otherwise this year's.
775- """
776- y = today .year
777- start = date (y , 10 , 15 )
778- end = date (y , 12 , 14 )
779- if today > end :
780- y += 1
781- start = date (y , 10 , 15 )
782- end = date (y , 12 , 14 )
783- return start , end
784-
785- def _evenly_spaced_dates (n : int , start : date , end : date ) -> list [date ]:
786- """
787- Return n deadlines evenly spaced across the window (start..end],
788- i.e., strictly after the start date, with the last at end.
789- Positions are at fractions (i+1)/n of the total span.
790- """
791- if n <= 1 :
792- return [end ]
793- total = (end - start ).days
794- if total < 0 :
795- start , end = end , start
796- total = - total
797- res = []
798- for i in range (n ):
799- off = int (round ((i + 1 ) * total / n ))
800- if off <= 0 :
801- off = 1
802- if off > total :
803- off = total
804- res .append (start + timedelta (days = off ))
805- return res
806-
807- def _compute_display_deadlines_threads (order : list [str ]) -> dict [str , date ]:
808- # Threads = Spring semester (prefer MSK; fallback to local time)
809- try :
810- today = _now_msk ().date ()
811- except Exception :
812- today = datetime .now ().date ()
813- s , e = _spring_bounds (today )
814- ds = _evenly_spaced_dates (len (order ), s , e )
815- return {t : d for t , d in zip (order , ds )}
816-
817- def _compute_display_deadlines_processes (n_items : int ) -> list [date ]:
818- # Processes = Autumn semester (prefer MSK; fallback to local time)
819- try :
820- today = _now_msk ().date ()
821- except Exception :
822- today = datetime .now ().date ()
823- s , e = _autumn_bounds (today )
824- ds = _evenly_spaced_dates (n_items , s , e )
825- return ds
752+ def _deadline_label (value ) -> str :
753+ if value is None or isinstance (value , (bool , int , float )):
754+ return ""
755+ return str (value )
756+
757+ def _thread_deadline_labels (order : list [str ]) -> dict [str , str ]:
758+ if not deadlines_display_threads :
759+ return {}
760+ labels = {}
761+ for task_type in order :
762+ label = _deadline_label (deadlines_display_threads .get (task_type ))
763+ if label :
764+ labels [task_type ] = label
765+ return labels
766+
767+ def _process_deadline_labels (task_numbers : list [int ]) -> list [str ]:
768+ if not deadlines_display_processes :
769+ return []
770+ labels = []
771+ for task_number in task_numbers :
772+ label = _deadline_label (
773+ deadlines_display_processes .get (f"task_{ task_number } " )
774+ or deadlines_display_processes .get (f"mpi_task_{ task_number } " )
775+ )
776+ labels .append (label )
777+ return labels if any (labels ) else []
826778
827779 # Locate perf CSVs from CI or local runs (threads and processes)
828780 candidates_threads = [
@@ -1239,30 +1191,9 @@ def _build_process_rows(processes_dirs: list[str]):
12391191 generated_msk = _now_msk ().strftime ("%Y-%m-%d %H:%M:%S" )
12401192 table_template = env .get_template ("index.html.j2" )
12411193 threads_vmax = int ((cfg .get ("threads" , {}) or {}).get ("variants_max" , 1 ))
1242- # Build display deadlines (use file values if present, fill missing with auto)
1194+ # Build display deadlines from explicit file values.
12431195 threads_order = task_types_threads
1244- auto_threads_dl = _compute_display_deadlines_threads (threads_order )
1245- dl_threads_out = {}
1246- for t in threads_order :
1247- base_date = auto_threads_dl .get (t )
1248- # Default = 0 shift
1249- shift_days = 0
1250- label = None
1251- if deadlines_display_threads and t in deadlines_display_threads :
1252- val = deadlines_display_threads .get (t )
1253- if isinstance (val , int ):
1254- shift_days = val
1255- else :
1256- # try int-like string, else treat as explicit label
1257- try :
1258- shift_days = int (str (val ).strip ())
1259- except Exception :
1260- label = str (val )
1261- if label is None and isinstance (base_date , date ):
1262- vdate = base_date + timedelta (days = shift_days )
1263- dl_threads_out [t ] = _abbr (vdate )
1264- else :
1265- dl_threads_out [t ] = label or ""
1196+ dl_threads_out = _thread_deadline_labels (threads_order )
12661197
12671198 threads_html = table_template .render (
12681199 task_types = task_types_threads ,
@@ -1275,31 +1206,8 @@ def _build_process_rows(processes_dirs: list[str]):
12751206 # Use dedicated template for processes table layout
12761207 processes_template = env .get_template ("processes.html.j2" )
12771208 proc_vmaxes = [_find_process_variants_max (cfg , n ) for n in expected_numbers ]
1278- # Build display deadlines for processes in task order (1..3)
1279- auto_proc_dl = _compute_display_deadlines_processes (len (expected_numbers ))
1280- proc_deadlines_list : list [str ] = []
1281- for i , n in enumerate (expected_numbers ):
1282- base_date = auto_proc_dl [i ]
1283- shift_days = 0
1284- label = None
1285- if deadlines_display_processes :
1286- key = f"task_{ n } "
1287- val = deadlines_display_processes .get (
1288- key
1289- ) or deadlines_display_processes .get (f"mpi_task_{ n } " )
1290- if val is not None :
1291- if isinstance (val , int ):
1292- shift_days = val
1293- else :
1294- try :
1295- shift_days = int (str (val ).strip ())
1296- except Exception :
1297- label = str (val )
1298- if label is None and isinstance (base_date , date ):
1299- vdate = base_date + timedelta (days = shift_days )
1300- proc_deadlines_list .append (_abbr (vdate ))
1301- else :
1302- proc_deadlines_list .append (label or "" )
1209+ # Build display deadlines for processes in task order (1..3).
1210+ proc_deadlines_list = _process_deadline_labels (expected_numbers )
13031211
13041212 processes_html = processes_template .render (
13051213 top_task_names = proc_top_headers ,
@@ -1357,27 +1265,8 @@ def _slugify(text: str) -> str:
13571265 eff_num_proc ,
13581266 deadlines_cfg ,
13591267 )
1360- # Rebuild deadline labels for this page
1361- auto_threads_dl_g = _compute_display_deadlines_threads (threads_order )
1362- dl_threads_out_g = {}
1363- for t in threads_order :
1364- base_date = auto_threads_dl_g .get (t )
1365- shift_days = 0
1366- label = None
1367- if deadlines_display_threads and t in deadlines_display_threads :
1368- val = deadlines_display_threads .get (t )
1369- if isinstance (val , int ):
1370- shift_days = val
1371- else :
1372- try :
1373- shift_days = int (str (val ).strip ())
1374- except Exception :
1375- label = str (val )
1376- if label is None and isinstance (base_date , date ):
1377- vdate = base_date + timedelta (days = shift_days )
1378- dl_threads_out_g [t ] = _abbr (vdate )
1379- else :
1380- dl_threads_out_g [t ] = label or ""
1268+ # Rebuild deadline labels for this page.
1269+ dl_threads_out_g = _thread_deadline_labels (threads_order )
13811270
13821271 html_g = table_template .render (
13831272 task_types = task_types_threads ,
@@ -1427,31 +1316,8 @@ def _id_key(stud: dict) -> str:
14271316 rows_g = _build_process_rows (filtered_dirs )
14281317
14291318 proc_vmaxes_g = [_find_process_variants_max (cfg , n ) for n in [1 , 2 , 3 ]]
1430- # Build display deadlines for processes group page
1431- auto_proc_dl_g = _compute_display_deadlines_processes (3 )
1432- proc_deadlines_list_g : list [str ] = []
1433- for i , n in enumerate ([1 , 2 , 3 ]):
1434- base_date = auto_proc_dl_g [i ]
1435- shift_days = 0
1436- label = None
1437- if deadlines_display_processes :
1438- key = f"task_{ n } "
1439- val = deadlines_display_processes .get (
1440- key
1441- ) or deadlines_display_processes .get (f"mpi_task_{ n } " )
1442- if val is not None :
1443- if isinstance (val , int ):
1444- shift_days = val
1445- else :
1446- try :
1447- shift_days = int (str (val ).strip ())
1448- except Exception :
1449- label = str (val )
1450- if label is None and isinstance (base_date , date ):
1451- vdate = base_date + timedelta (days = shift_days )
1452- proc_deadlines_list_g .append (_abbr (vdate ))
1453- else :
1454- proc_deadlines_list_g .append (label or "" )
1319+ # Build display deadlines for processes group page.
1320+ proc_deadlines_list_g = _process_deadline_labels ([1 , 2 , 3 ])
14551321
14561322 html_g = processes_template .render (
14571323 top_task_names = proc_top_headers_g ,
0 commit comments