@@ -281,6 +281,40 @@ def __init__(
281281 )
282282 self .sites : Dict [int , PlateHolder ] = sites or {} # fix type
283283
284+ def summary (self ) -> str :
285+ """Return a summary of the carrier's sites and their contents."""
286+
287+ def create_pretty_table (header , * columns ) -> str :
288+ col_widths = [
289+ max (len (str (item )) for item in [header [i ]] + list (columns [i ])) for i in range (len (header ))
290+ ]
291+
292+ def format_row (row , border = "|" ) -> str :
293+ return (
294+ f"{ border } "
295+ + " | " .join (f"{ str (row [i ]).ljust (col_widths [i ])} " for i in range (len (row )))
296+ + f" { border } "
297+ )
298+
299+ def separator_line (cross : str = "+" , line : str = "-" ) -> str :
300+ return cross + cross .join (line * (width + 2 ) for width in col_widths ) + cross
301+
302+ table = []
303+ table .append (separator_line ()) # Top border
304+ table .append (format_row (header ))
305+ table .append (separator_line ()) # Header separator
306+ for row in zip (* columns ):
307+ table .append (format_row (row ))
308+ table .append (separator_line ()) # Bottom border
309+ return "\n " .join (table )
310+
311+ indices = sorted (self .sites .keys ())
312+ header = ["Site" , "Content" ]
313+ site_numbers = list (reversed ([str (i ) for i in indices ]))
314+ site_resources = list (reversed ([self .sites [i ].resource for i in indices ]))
315+ site_contents = [r .name if r is not None else "<empty>" for r in site_resources ]
316+ return create_pretty_table (header , site_numbers , site_contents )
317+
284318
285319class MFXCarrier (Carrier [ResourceHolder ]):
286320 def __init__ (
0 commit comments