@@ -1296,8 +1296,9 @@ def __init__(
12961296 self ,
12971297 min_width : int = 10 ,
12981298 max_width : int = 50 ,
1299- bar_format : str = "{l} |{b}| [b]({c})/{t} [dim](([i]({p}%)))" ,
1300- limited_bar_format : str = "|{b}|" ,
1299+ bar_format : list [str ] | tuple [str , ...] = ["{l}" , "|{b}|" , "[b]({c})/{t}" , "[dim](([i]({p}%)))" ],
1300+ limited_bar_format : list [str ] | tuple [str , ...] = ["|{b}|" ],
1301+ sep : str = " " ,
13011302 chars : tuple [str , ...] = ("█" , "▉" , "▊" , "▋" , "▌" , "▍" , "▎" , "▏" , " " ),
13021303 ):
13031304 self .active : bool = False
@@ -1306,15 +1307,17 @@ def __init__(
13061307 """The min width of the progress bar in chars."""
13071308 self .max_width : int
13081309 """The max width of the progress bar in chars."""
1309- self .bar_format : str
1310- """The format string used to render the progress bar."""
1311- self .limited_bar_format : str
1312- """The simplified format string used when the console width is too small."""
1310+ self .bar_format : list [str ] | tuple [str , ...]
1311+ """The format strings used to render the progress bar (joined by `sep`)."""
1312+ self .limited_bar_format : list [str ] | tuple [str , ...]
1313+ """The simplified format strings used when the console width is too small."""
1314+ self .sep : str
1315+ """The separator string used to join multiple format strings."""
13131316 self .chars : tuple [str , ...]
13141317 """A tuple of characters ordered from full to empty progress."""
13151318
13161319 self .set_width (min_width , max_width )
1317- self .set_bar_format (bar_format , limited_bar_format )
1320+ self .set_bar_format (bar_format , limited_bar_format , sep )
13181321 self .set_chars (chars )
13191322
13201323 self ._buffer : list [str ] = []
@@ -1345,7 +1348,12 @@ def set_width(self, min_width: Optional[int] = None, max_width: Optional[int] =
13451348
13461349 self .max_width = max (self .min_width , max_width )
13471350
1348- def set_bar_format (self , bar_format : Optional [str ] = None , limited_bar_format : Optional [str ] = None ) -> None :
1351+ def set_bar_format (
1352+ self ,
1353+ bar_format : Optional [list [str ] | tuple [str , ...]] = None ,
1354+ limited_bar_format : Optional [list [str ] | tuple [str , ...]] = None ,
1355+ sep : Optional [str ] = None ,
1356+ ) -> None :
13491357 """Set the format string used to render the progress bar.\n
13501358 --------------------------------------------------------------------------------------------------
13511359 - `bar_format` -⠀the format string used to render the progress bar, containing placeholders:
@@ -1355,23 +1363,38 @@ def set_bar_format(self, bar_format: Optional[str] = None, limited_bar_format: O
13551363 * `{total}` `{t}`
13561364 * `{percentage}` `{percent}` `{p}`
13571365 - `limited_bar_format` -⠀a simplified format string used when the console width is too small
1366+ - `sep` -⠀the separator string used to join multiple format strings
13581367 --------------------------------------------------------------------------------------------------
13591368 The bar format (also limited) can additionally be formatted with special formatting codes. For
13601369 more detailed information about formatting codes, see the `format_codes` module documentation."""
1361- if not isinstance (bar_format , (str , type (None ))):
1362- raise TypeError (f"The 'bar_format' parameter must be a string or None, got { type (bar_format )} " )
1363- if not isinstance (limited_bar_format , (str , type (None ))):
1364- raise TypeError (f"The 'limited_bar_format' parameter must be a string or None, got { type (limited_bar_format )} " )
1365-
13661370 if bar_format is not None :
1367- if not _COMPILED ["bar" ].search (bar_format ):
1371+ if not isinstance (bar_format , (list , tuple )):
1372+ raise TypeError (f"The 'bar_format' parameter must be a list or tuple of strings, got { type (bar_format )} " )
1373+ elif not all (isinstance (s , str ) for s in bar_format ):
1374+ raise ValueError ("All elements of the 'bar_format' parameter must be strings." )
1375+ elif not any (_COMPILED ["bar" ].search (s ) for s in bar_format ):
13681376 raise ValueError ("The 'bar_format' parameter value must contain the '{bar}' or '{b}' placeholder." )
1377+
13691378 self .bar_format = bar_format
1379+
13701380 if limited_bar_format is not None :
1371- if not _COMPILED ["bar" ].search (limited_bar_format ):
1381+ if not isinstance (limited_bar_format , (list , tuple )):
1382+ raise TypeError (
1383+ f"The 'limited_bar_format' parameter must be a list or tuple of strings, got { type (limited_bar_format )} "
1384+ )
1385+ elif not all (isinstance (s , str ) for s in limited_bar_format ):
1386+ raise ValueError ("All elements of the 'limited_bar_format' parameter must be strings." )
1387+ elif not any (_COMPILED ["bar" ].search (s ) for s in limited_bar_format ):
13721388 raise ValueError ("The 'limited_bar_format' parameter value must contain the '{bar}' or '{b}' placeholder." )
1389+
13731390 self .limited_bar_format = limited_bar_format
13741391
1392+ if sep is not None :
1393+ if not isinstance (sep , str ):
1394+ raise TypeError (f"The 'sep' parameter must be a string or None, got { type (sep )} " )
1395+
1396+ self .sep = sep
1397+
13751398 def set_chars (self , chars : tuple [str , ...]) -> None :
13761399 """Set the characters used to render the progress bar.\n
13771400 --------------------------------------------------------------------------
@@ -1529,20 +1552,29 @@ def _draw_progress_bar(self, current: int, total: int, label: Optional[str] = No
15291552
15301553 def _get_formatted_info_and_bar_width (
15311554 self ,
1532- bar_format : str ,
1555+ bar_format : list [ str ] | tuple [ str , ...] ,
15331556 current : int ,
15341557 total : int ,
15351558 percentage : float ,
15361559 label : Optional [str ] = None ,
15371560 ) -> tuple [str , int ]:
1538- formatted = _COMPILED ["label" ].sub (label or "" , bar_format )
1539- formatted = _COMPILED ["current" ].sub (str (current ), formatted )
1540- formatted = _COMPILED ["total" ].sub (str (total ), formatted )
1541- formatted = _COMPILED ["percentage" ].sub (f"{ percentage :.1f} " , formatted )
1542- formatted = FormatCodes .to_ansi (formatted )
1543- bar_space = Console .w - len (FormatCodes .remove_ansi (_COMPILED ["bar" ].sub ("" , formatted )))
1561+ fmt_parts = []
1562+
1563+ for s in bar_format :
1564+ fmt_part = _COMPILED ["label" ].sub (label or "" , s )
1565+ fmt_part = _COMPILED ["current" ].sub (str (current ), fmt_part )
1566+ fmt_part = _COMPILED ["total" ].sub (str (total ), fmt_part )
1567+ fmt_part = _COMPILED ["percentage" ].sub (f"{ percentage :.1f} " , fmt_part )
1568+ if fmt_part :
1569+ fmt_parts .append (fmt_part )
1570+
1571+ fmt_str = self .sep .join (fmt_parts )
1572+ fmt_str = FormatCodes .to_ansi (fmt_str )
1573+
1574+ bar_space = Console .w - len (FormatCodes .remove_ansi (_COMPILED ["bar" ].sub ("" , fmt_str )))
15441575 bar_width = min (bar_space , self .max_width ) if bar_space > 0 else 0
1545- return formatted , bar_width
1576+
1577+ return fmt_str , bar_width
15461578
15471579 def _create_bar (self , current : int , total : int , bar_width : int ) -> str :
15481580 progress = current / total if total > 0 else 0
0 commit comments