@@ -1618,12 +1618,15 @@ class Spinner:
16181618 def __init__ (
16191619 self ,
16201620 label : Optional [str ] = None ,
1621- spinner_format : str = "{l} [b]({a}) " ,
1621+ spinner_format : list [str ] | tuple [str , ...] = ["{l}" , "[b]({a}) " ],
1622+ sep : str = " " ,
16221623 frames : tuple [str , ...] = ("· " , "·· " , "···" , " ··" , " ·" , " ·" , " ··" , "···" , "·· " , "· " ),
16231624 interval : float = 0.2 ,
16241625 ):
1625- self .animation_format : str
1626- """The format string used to render the spinner."""
1626+ self .spinner_format : list [str ] | tuple [str , ...]
1627+ """The format strings used to render the spinner (joined by `sep`)."""
1628+ self .sep : str
1629+ """The separator string used to join multiple format strings."""
16271630 self .frames : tuple [str , ...]
16281631 """A tuple of strings representing the animation frames."""
16291632 self .interval : float
@@ -1634,7 +1637,7 @@ def __init__(
16341637 """Whether the spinner is currently active (intercepting stdout) or not."""
16351638
16361639 self .update_label (label )
1637- self .set_format (spinner_format )
1640+ self .set_format (spinner_format , sep )
16381641 self .set_frames (frames )
16391642 self .set_interval (interval )
16401643
@@ -1646,18 +1649,26 @@ def __init__(
16461649 self ._stop_event : Optional [_threading .Event ] = None
16471650 self ._animation_thread : Optional [_threading .Thread ] = None
16481651
1649- def set_format (self , animation_format : str ) -> None :
1652+ def set_format (self , spinner_format : list [ str ] | tuple [ str , ...], sep : Optional [ str ] = None ) -> None :
16501653 """Set the format string used to render the spinner.\n
1651- ----------------------------------------------------------------------------------------------
1652- - `animation_format` -⠀the format string used to render the spinner, containing placeholders:
1653- * `{label}` `{l}`
1654- * `{animation}` `{a}`"""
1655- if not isinstance (animation_format , str ):
1656- raise TypeError (f"The 'animation_format' parameter must be a string, got { type (animation_format )} " )
1657- elif not _COMPILED ["animation" ].search (animation_format ):
1658- raise ValueError ("The 'animation_format' parameter value must contain the '{animation}' or '{a}' placeholder." )
1654+ ---------------------------------------------------------------------------------------------
1655+ - `spinner_format` -⠀the format strings used to render the spinner, containing placeholders:
1656+ * `{label}` `{l}`
1657+ * `{animation}` `{a}`
1658+ - `sep` -⠀the separator string used to join multiple format strings"""
1659+ if not isinstance (spinner_format , (list , tuple )):
1660+ raise TypeError (f"The 'spinner_format' parameter must be a list or tuple, got { type (spinner_format )} " )
1661+ elif not all (isinstance (fmt , str ) for fmt in spinner_format ):
1662+ raise TypeError ("All elements of the 'spinner_format' parameter must be strings." )
1663+ elif not any (_COMPILED ["animation" ].search (fmt ) for fmt in spinner_format ):
1664+ raise ValueError (
1665+ "At least one format string in 'spinner_format' must contain the '{animation}' or '{a}' placeholder."
1666+ )
1667+ if sep is not None and not isinstance (sep , str ):
1668+ raise TypeError (f"The 'sep' parameter must be a string or None, got { type (sep )} " )
16591669
1660- self .animation_format = animation_format
1670+ self .spinner_format = spinner_format
1671+ self .sep = sep or self .sep
16611672
16621673 def set_frames (self , frames : tuple [str , ...]) -> None :
16631674 """Set the frames used for the spinner animation.\n
@@ -1760,11 +1771,15 @@ def _animation_loop(self) -> None:
17601771 self ._flush_buffer ()
17611772
17621773 frame = FormatCodes .to_ansi (f"{ self .frames [self ._frame_index % len (self .frames )]} [*]" )
1763- formatted_template = FormatCodes .to_ansi (_COMPILED ["label" ].sub (self .label or "" , self .animation_format ))
1764- final_str = _COMPILED ["animation" ].sub (frame , formatted_template )
1765-
1766- self ._current_animation_str = final_str
1767- self ._last_line_len = len (final_str )
1774+ formatted = FormatCodes .to_ansi (self .sep .join (
1775+ s for s in ( \
1776+ _COMPILED ["animation" ].sub (frame , _COMPILED ["label" ].sub (self .label or "" , s ))
1777+ for s in self .spinner_format
1778+ ) if s
1779+ ))
1780+
1781+ self ._current_animation_str = formatted
1782+ self ._last_line_len = len (formatted )
17681783 self ._redraw_display ()
17691784 self ._frame_index += 1
17701785
0 commit comments