printbuddies.printbuddies
1from os import get_terminal_size 2from time import sleep 3from typing import Any 4 5from noiftimer import Timer 6 7 8def clear(): 9 """Erase the current line from the terminal.""" 10 try: 11 print(" " * (get_terminal_size().columns - 1), flush=True, end="\r") 12 except OSError: 13 ... 14 except Exception as e: 15 raise e 16 17 18def print_in_place(string: str, animate: bool = False, animate_refresh: float = 0.01): 19 """Calls to `print_in_place` will overwrite the previous line of text in the terminal with `string`. 20 21 #### :params: 22 23 `animate`: Will cause `string` to be printed to the terminal one character at a time. 24 25 `animate_refresh`: Number of seconds between the addition of characters when `animate` is `True`.""" 26 clear() 27 string = str(string) 28 try: 29 width = get_terminal_size().columns 30 string = string[: width - 2] 31 if animate: 32 for i in range(len(string)): 33 print(f"{string[:i+1]}", flush=True, end=" \r") 34 sleep(animate_refresh) 35 else: 36 print(string, flush=True, end="\r") 37 except OSError: 38 ... 39 except Exception as e: 40 raise e 41 42 43def ticker(info: list[str]): 44 """Prints `info` to terminal with top and bottom padding so that previous text is not visible. 45 46 Similar visually to `print_in_place`, but for multiple lines.""" 47 try: 48 width = get_terminal_size().columns 49 info = [str(line)[: width - 1] for line in info] 50 height = get_terminal_size().lines - len(info) 51 print("\n" * (height * 2), end="") 52 print(*info, sep="\n", end="") 53 print("\n" * (int((height) / 2)), end="") 54 except OSError: 55 ... 56 except Exception as e: 57 raise e 58 59 60class ProgBar: 61 """Self incrementing, dynamically sized progress bar. 62 63 Includes an internal timer that starts when this object is created. 64 65 Easily add runtime to progress display: 66 67 >>> bar = ProgBar(total=100) 68 >>> time.sleep(30) 69 >>> bar.display(prefix=f"Doin stuff ~ {bar.runtime}") 70 >>> "Doin stuff ~ runtime: 30s [_///////////////////]-1.00%" """ 71 72 def __init__( 73 self, 74 total: float, 75 update_frequency: int = 1, 76 fill_ch: str = "_", 77 unfill_ch: str = "/", 78 width_ratio: float = 0.5, 79 new_line_after_completion: bool = True, 80 clear_after_completion: bool = False, 81 ): 82 """ 83 #### :params: 84 85 `total`: The number of calls to reach 100% completion. 86 87 `update_frequency`: The progress bar will only update once every this number of calls to `display()`. 88 The larger the value, the less performance impact `ProgBar` has on the loop in which it is called. 89 e.g. 90 >>> bar = ProgBar(100, update_frequency=10) 91 >>> for _ in range(100): 92 >>> bar.display() 93 94 ^The progress bar in the terminal will only update once every ten calls, going from 0%->100% in 10% increments. 95 Note: If `total` is not a multiple of `update_frequency`, the display will not show 100% completion when the loop finishes. 96 97 `fill_ch`: The character used to represent the completed part of the bar. 98 99 `unfill_ch`: The character used to represent the incomplete part of the bar. 100 101 `width_ratio`: The width of the progress bar relative to the width of the terminal window. 102 103 `new_line_after_completion`: Make a call to `print()` once `self.counter >= self.total`. 104 105 `clear_after_completion`: Make a call to `printbuddies.clear()` once `self.counter >= self.total`. 106 107 Note: if `new_line_after_completion` and `clear_after_completion` are both `True`, the line will be cleared 108 then a call to `print()` will be made.""" 109 self.total = total 110 self.update_frequency = update_frequency 111 self.fill_ch = fill_ch[0] 112 self.unfill_ch = unfill_ch[0] 113 self.width_ratio = width_ratio 114 self.new_line_after_completion = new_line_after_completion 115 self.clear_after_completion = clear_after_completion 116 self.reset() 117 self.with_context = False 118 119 def __enter__(self): 120 self.with_context = True 121 return self 122 123 def __exit__(self, *args, **kwargs): 124 if self.clear_after_completion: 125 clear() 126 else: 127 print() 128 129 def reset(self): 130 self.counter = 1 131 self.percent = "" 132 self.prefix = "" 133 self.suffix = "" 134 self.filled = "" 135 self.unfilled = "" 136 self.timer = Timer(subsecond_resolution=False).start() 137 138 @property 139 def runtime(self) -> str: 140 return f"runtime:{self.timer.elapsed_str}" 141 142 @property 143 def bar(self) -> str: 144 return f"{self.prefix}{' '*bool(self.prefix)}[{self.filled}{self.unfilled}]-{self.percent}% {self.suffix}" 145 146 def get_percent(self) -> str: 147 """Returns the percentage completed to two decimal places as a string without the `%`.""" 148 percent = str(round(100.0 * self.counter / self.total, 2)) 149 if len(percent.split(".")[1]) == 1: 150 percent = percent + "0" 151 if len(percent.split(".")[0]) == 1: 152 percent = "0" + percent 153 return percent 154 155 def _prepare_bar(self): 156 self.terminal_width = get_terminal_size().columns - 1 157 bar_length = int(self.terminal_width * self.width_ratio) 158 progress = int(bar_length * min(self.counter / self.total, 1.0)) 159 self.filled = self.fill_ch * progress 160 self.unfilled = self.unfill_ch * (bar_length - progress) 161 self.percent = self.get_percent() 162 163 def _trim_bar(self): 164 original_width = self.width_ratio 165 while len(self.bar) > self.terminal_width and self.width_ratio > 0: 166 self.width_ratio -= 0.01 167 self._prepare_bar() 168 self.width_ratio = original_width 169 170 def get_bar(self): 171 return f"{self.prefix}{' '*bool(self.prefix)}[{self.filled}{self.unfilled}]-{self.percent}% {self.suffix}" 172 173 def display( 174 self, 175 prefix: str = "", 176 suffix: str = "", 177 counter_override: float | None = None, 178 total_override: float | None = None, 179 return_object: Any | None = None, 180 ) -> Any: 181 """Writes the progress bar to the terminal. 182 183 #### :params: 184 185 `prefix`: String affixed to the front of the progress bar. 186 187 `suffix`: String appended to the end of the progress bar. 188 189 `counter_override`: When an externally incremented completion counter is needed. 190 191 `total_override`: When an externally controlled bar total is needed. 192 193 `return_object`: An object to be returned by display(). 194 Allows `display()` to be called within a comprehension: 195 196 e.g. 197 198 >>> bar = ProgBar(10) 199 >>> def square(x: int | float)->int|float: 200 >>> return x * x 201 >>> myList = [bar.display(return_object=square(i)) for i in range(10)] 202 >>> <progress bar gets displayed> 203 >>> myList 204 >>> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]""" 205 if not self.timer.started: 206 self.timer.start() 207 if counter_override is not None: 208 self.counter = counter_override 209 if total_override: 210 self.total = total_override 211 # Don't wanna divide by 0 there, pal 212 while self.total <= 0: 213 self.total += 1 214 try: 215 if self.counter % self.update_frequency == 0: 216 self.prefix = prefix 217 self.suffix = suffix 218 self._prepare_bar() 219 self._trim_bar() 220 pad = " " * (self.terminal_width - len(self.bar)) 221 width = get_terminal_size().columns 222 print(f"{self.bar}{pad}"[: width - 2], flush=True, end="\r") 223 if self.counter >= self.total: 224 self.timer.stop() 225 if not self.with_context: 226 if self.clear_after_completion: 227 clear() 228 if self.new_line_after_completion: 229 print() 230 self.counter += 1 231 except OSError: 232 ... 233 except Exception as e: 234 raise e 235 return return_object 236 237 238class Spinner: 239 """Prints one of a sequence of characters in order everytime `display()` is called. 240 241 The `display` function writes the new character to the same line, overwriting the previous character. 242 243 The sequence will be cycled through indefinitely. 244 245 If used as a context manager, the last printed character will be cleared upon exiting. 246 """ 247 248 def __init__( 249 self, sequence: list[str] = ["/", "-", "\\"], width_ratio: float = 0.25 250 ): 251 """ 252 #### params: 253 254 `sequence`: Override the built in spin sequence. 255 256 `width_ratio`: The fractional amount of the terminal for characters to move across.""" 257 self._base_sequence = sequence 258 self.width_ratio = width_ratio 259 self.sequence = self._base_sequence 260 261 def __enter__(self): 262 return self 263 264 def __exit__(self, *args, **kwargs): 265 clear() 266 267 @property 268 def width_ratio(self) -> float: 269 return self._width_ratio 270 271 @width_ratio.setter 272 def width_ratio(self, ratio: float): 273 self._width_ratio = ratio 274 self._update_width() 275 276 def _update_width(self): 277 self._current_terminal_width = get_terminal_size().columns 278 self._width = int((self._current_terminal_width - 1) * self.width_ratio) 279 280 @property 281 def sequence(self) -> list[Any]: 282 return self._sequence 283 284 @sequence.setter 285 def sequence(self, character_list: list[Any]): 286 self._sequence = [ 287 ch.rjust(i + j) 288 for i in range(1, self._width, len(character_list)) 289 for j, ch in enumerate(character_list) 290 ] 291 self._sequence += self._sequence[::-1] 292 293 def _get_next(self) -> str: 294 """Pop the first element of `self._sequence`, append it to the end, and return the element.""" 295 ch = self.sequence.pop(0) 296 self.sequence.append(ch) 297 return ch 298 299 def display(self): 300 """Print the next character in the sequence.""" 301 try: 302 if get_terminal_size().columns != self._current_terminal_width: 303 self._update_width() 304 self.sequence = self._base_sequence 305 print_in_place(self._get_next()) 306 except OSError: 307 ... 308 except Exception as e: 309 raise e
9def clear(): 10 """Erase the current line from the terminal.""" 11 try: 12 print(" " * (get_terminal_size().columns - 1), flush=True, end="\r") 13 except OSError: 14 ... 15 except Exception as e: 16 raise e
Erase the current line from the terminal.
19def print_in_place(string: str, animate: bool = False, animate_refresh: float = 0.01): 20 """Calls to `print_in_place` will overwrite the previous line of text in the terminal with `string`. 21 22 #### :params: 23 24 `animate`: Will cause `string` to be printed to the terminal one character at a time. 25 26 `animate_refresh`: Number of seconds between the addition of characters when `animate` is `True`.""" 27 clear() 28 string = str(string) 29 try: 30 width = get_terminal_size().columns 31 string = string[: width - 2] 32 if animate: 33 for i in range(len(string)): 34 print(f"{string[:i+1]}", flush=True, end=" \r") 35 sleep(animate_refresh) 36 else: 37 print(string, flush=True, end="\r") 38 except OSError: 39 ... 40 except Exception as e: 41 raise e
Calls to print_in_place will overwrite the previous line of text in the terminal with string.
:params:
animate: Will cause string to be printed to the terminal one character at a time.
animate_refresh: Number of seconds between the addition of characters when animate is True.
44def ticker(info: list[str]): 45 """Prints `info` to terminal with top and bottom padding so that previous text is not visible. 46 47 Similar visually to `print_in_place`, but for multiple lines.""" 48 try: 49 width = get_terminal_size().columns 50 info = [str(line)[: width - 1] for line in info] 51 height = get_terminal_size().lines - len(info) 52 print("\n" * (height * 2), end="") 53 print(*info, sep="\n", end="") 54 print("\n" * (int((height) / 2)), end="") 55 except OSError: 56 ... 57 except Exception as e: 58 raise e
Prints info to terminal with top and bottom padding so that previous text is not visible.
Similar visually to print_in_place, but for multiple lines.
61class ProgBar: 62 """Self incrementing, dynamically sized progress bar. 63 64 Includes an internal timer that starts when this object is created. 65 66 Easily add runtime to progress display: 67 68 >>> bar = ProgBar(total=100) 69 >>> time.sleep(30) 70 >>> bar.display(prefix=f"Doin stuff ~ {bar.runtime}") 71 >>> "Doin stuff ~ runtime: 30s [_///////////////////]-1.00%" """ 72 73 def __init__( 74 self, 75 total: float, 76 update_frequency: int = 1, 77 fill_ch: str = "_", 78 unfill_ch: str = "/", 79 width_ratio: float = 0.5, 80 new_line_after_completion: bool = True, 81 clear_after_completion: bool = False, 82 ): 83 """ 84 #### :params: 85 86 `total`: The number of calls to reach 100% completion. 87 88 `update_frequency`: The progress bar will only update once every this number of calls to `display()`. 89 The larger the value, the less performance impact `ProgBar` has on the loop in which it is called. 90 e.g. 91 >>> bar = ProgBar(100, update_frequency=10) 92 >>> for _ in range(100): 93 >>> bar.display() 94 95 ^The progress bar in the terminal will only update once every ten calls, going from 0%->100% in 10% increments. 96 Note: If `total` is not a multiple of `update_frequency`, the display will not show 100% completion when the loop finishes. 97 98 `fill_ch`: The character used to represent the completed part of the bar. 99 100 `unfill_ch`: The character used to represent the incomplete part of the bar. 101 102 `width_ratio`: The width of the progress bar relative to the width of the terminal window. 103 104 `new_line_after_completion`: Make a call to `print()` once `self.counter >= self.total`. 105 106 `clear_after_completion`: Make a call to `printbuddies.clear()` once `self.counter >= self.total`. 107 108 Note: if `new_line_after_completion` and `clear_after_completion` are both `True`, the line will be cleared 109 then a call to `print()` will be made.""" 110 self.total = total 111 self.update_frequency = update_frequency 112 self.fill_ch = fill_ch[0] 113 self.unfill_ch = unfill_ch[0] 114 self.width_ratio = width_ratio 115 self.new_line_after_completion = new_line_after_completion 116 self.clear_after_completion = clear_after_completion 117 self.reset() 118 self.with_context = False 119 120 def __enter__(self): 121 self.with_context = True 122 return self 123 124 def __exit__(self, *args, **kwargs): 125 if self.clear_after_completion: 126 clear() 127 else: 128 print() 129 130 def reset(self): 131 self.counter = 1 132 self.percent = "" 133 self.prefix = "" 134 self.suffix = "" 135 self.filled = "" 136 self.unfilled = "" 137 self.timer = Timer(subsecond_resolution=False).start() 138 139 @property 140 def runtime(self) -> str: 141 return f"runtime:{self.timer.elapsed_str}" 142 143 @property 144 def bar(self) -> str: 145 return f"{self.prefix}{' '*bool(self.prefix)}[{self.filled}{self.unfilled}]-{self.percent}% {self.suffix}" 146 147 def get_percent(self) -> str: 148 """Returns the percentage completed to two decimal places as a string without the `%`.""" 149 percent = str(round(100.0 * self.counter / self.total, 2)) 150 if len(percent.split(".")[1]) == 1: 151 percent = percent + "0" 152 if len(percent.split(".")[0]) == 1: 153 percent = "0" + percent 154 return percent 155 156 def _prepare_bar(self): 157 self.terminal_width = get_terminal_size().columns - 1 158 bar_length = int(self.terminal_width * self.width_ratio) 159 progress = int(bar_length * min(self.counter / self.total, 1.0)) 160 self.filled = self.fill_ch * progress 161 self.unfilled = self.unfill_ch * (bar_length - progress) 162 self.percent = self.get_percent() 163 164 def _trim_bar(self): 165 original_width = self.width_ratio 166 while len(self.bar) > self.terminal_width and self.width_ratio > 0: 167 self.width_ratio -= 0.01 168 self._prepare_bar() 169 self.width_ratio = original_width 170 171 def get_bar(self): 172 return f"{self.prefix}{' '*bool(self.prefix)}[{self.filled}{self.unfilled}]-{self.percent}% {self.suffix}" 173 174 def display( 175 self, 176 prefix: str = "", 177 suffix: str = "", 178 counter_override: float | None = None, 179 total_override: float | None = None, 180 return_object: Any | None = None, 181 ) -> Any: 182 """Writes the progress bar to the terminal. 183 184 #### :params: 185 186 `prefix`: String affixed to the front of the progress bar. 187 188 `suffix`: String appended to the end of the progress bar. 189 190 `counter_override`: When an externally incremented completion counter is needed. 191 192 `total_override`: When an externally controlled bar total is needed. 193 194 `return_object`: An object to be returned by display(). 195 Allows `display()` to be called within a comprehension: 196 197 e.g. 198 199 >>> bar = ProgBar(10) 200 >>> def square(x: int | float)->int|float: 201 >>> return x * x 202 >>> myList = [bar.display(return_object=square(i)) for i in range(10)] 203 >>> <progress bar gets displayed> 204 >>> myList 205 >>> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]""" 206 if not self.timer.started: 207 self.timer.start() 208 if counter_override is not None: 209 self.counter = counter_override 210 if total_override: 211 self.total = total_override 212 # Don't wanna divide by 0 there, pal 213 while self.total <= 0: 214 self.total += 1 215 try: 216 if self.counter % self.update_frequency == 0: 217 self.prefix = prefix 218 self.suffix = suffix 219 self._prepare_bar() 220 self._trim_bar() 221 pad = " " * (self.terminal_width - len(self.bar)) 222 width = get_terminal_size().columns 223 print(f"{self.bar}{pad}"[: width - 2], flush=True, end="\r") 224 if self.counter >= self.total: 225 self.timer.stop() 226 if not self.with_context: 227 if self.clear_after_completion: 228 clear() 229 if self.new_line_after_completion: 230 print() 231 self.counter += 1 232 except OSError: 233 ... 234 except Exception as e: 235 raise e 236 return return_object
Self incrementing, dynamically sized progress bar.
Includes an internal timer that starts when this object is created.
Easily add runtime to progress display:
>>> bar = ProgBar(total=100)
>>> time.sleep(30)
>>> bar.display(prefix=f"Doin stuff ~ {bar.runtime}")
>>> "Doin stuff ~ runtime: 30s [_///////////////////]-1.00%"
73 def __init__( 74 self, 75 total: float, 76 update_frequency: int = 1, 77 fill_ch: str = "_", 78 unfill_ch: str = "/", 79 width_ratio: float = 0.5, 80 new_line_after_completion: bool = True, 81 clear_after_completion: bool = False, 82 ): 83 """ 84 #### :params: 85 86 `total`: The number of calls to reach 100% completion. 87 88 `update_frequency`: The progress bar will only update once every this number of calls to `display()`. 89 The larger the value, the less performance impact `ProgBar` has on the loop in which it is called. 90 e.g. 91 >>> bar = ProgBar(100, update_frequency=10) 92 >>> for _ in range(100): 93 >>> bar.display() 94 95 ^The progress bar in the terminal will only update once every ten calls, going from 0%->100% in 10% increments. 96 Note: If `total` is not a multiple of `update_frequency`, the display will not show 100% completion when the loop finishes. 97 98 `fill_ch`: The character used to represent the completed part of the bar. 99 100 `unfill_ch`: The character used to represent the incomplete part of the bar. 101 102 `width_ratio`: The width of the progress bar relative to the width of the terminal window. 103 104 `new_line_after_completion`: Make a call to `print()` once `self.counter >= self.total`. 105 106 `clear_after_completion`: Make a call to `printbuddies.clear()` once `self.counter >= self.total`. 107 108 Note: if `new_line_after_completion` and `clear_after_completion` are both `True`, the line will be cleared 109 then a call to `print()` will be made.""" 110 self.total = total 111 self.update_frequency = update_frequency 112 self.fill_ch = fill_ch[0] 113 self.unfill_ch = unfill_ch[0] 114 self.width_ratio = width_ratio 115 self.new_line_after_completion = new_line_after_completion 116 self.clear_after_completion = clear_after_completion 117 self.reset() 118 self.with_context = False
:params:
total: The number of calls to reach 100% completion.
update_frequency: The progress bar will only update once every this number of calls to display().
The larger the value, the less performance impact ProgBar has on the loop in which it is called.
e.g.
>>> bar = ProgBar(100, update_frequency=10)
>>> for _ in range(100):
>>> bar.display()
^The progress bar in the terminal will only update once every ten calls, going from 0%->100% in 10% increments.
Note: If total is not a multiple of update_frequency, the display will not show 100% completion when the loop finishes.
fill_ch: The character used to represent the completed part of the bar.
unfill_ch: The character used to represent the incomplete part of the bar.
width_ratio: The width of the progress bar relative to the width of the terminal window.
new_line_after_completion: Make a call to print() once self.counter >= self.total.
clear_after_completion: Make a call to printbuddies.clear() once self.counter >= self.total.
Note: if new_line_after_completion and clear_after_completion are both True, the line will be cleared
then a call to print() will be made.
147 def get_percent(self) -> str: 148 """Returns the percentage completed to two decimal places as a string without the `%`.""" 149 percent = str(round(100.0 * self.counter / self.total, 2)) 150 if len(percent.split(".")[1]) == 1: 151 percent = percent + "0" 152 if len(percent.split(".")[0]) == 1: 153 percent = "0" + percent 154 return percent
Returns the percentage completed to two decimal places as a string without the %.
174 def display( 175 self, 176 prefix: str = "", 177 suffix: str = "", 178 counter_override: float | None = None, 179 total_override: float | None = None, 180 return_object: Any | None = None, 181 ) -> Any: 182 """Writes the progress bar to the terminal. 183 184 #### :params: 185 186 `prefix`: String affixed to the front of the progress bar. 187 188 `suffix`: String appended to the end of the progress bar. 189 190 `counter_override`: When an externally incremented completion counter is needed. 191 192 `total_override`: When an externally controlled bar total is needed. 193 194 `return_object`: An object to be returned by display(). 195 Allows `display()` to be called within a comprehension: 196 197 e.g. 198 199 >>> bar = ProgBar(10) 200 >>> def square(x: int | float)->int|float: 201 >>> return x * x 202 >>> myList = [bar.display(return_object=square(i)) for i in range(10)] 203 >>> <progress bar gets displayed> 204 >>> myList 205 >>> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]""" 206 if not self.timer.started: 207 self.timer.start() 208 if counter_override is not None: 209 self.counter = counter_override 210 if total_override: 211 self.total = total_override 212 # Don't wanna divide by 0 there, pal 213 while self.total <= 0: 214 self.total += 1 215 try: 216 if self.counter % self.update_frequency == 0: 217 self.prefix = prefix 218 self.suffix = suffix 219 self._prepare_bar() 220 self._trim_bar() 221 pad = " " * (self.terminal_width - len(self.bar)) 222 width = get_terminal_size().columns 223 print(f"{self.bar}{pad}"[: width - 2], flush=True, end="\r") 224 if self.counter >= self.total: 225 self.timer.stop() 226 if not self.with_context: 227 if self.clear_after_completion: 228 clear() 229 if self.new_line_after_completion: 230 print() 231 self.counter += 1 232 except OSError: 233 ... 234 except Exception as e: 235 raise e 236 return return_object
Writes the progress bar to the terminal.
:params:
prefix: String affixed to the front of the progress bar.
suffix: String appended to the end of the progress bar.
counter_override: When an externally incremented completion counter is needed.
total_override: When an externally controlled bar total is needed.
return_object: An object to be returned by display().
Allows display() to be called within a comprehension:
e.g.
>>> bar = ProgBar(10)
>>> def square(x: int | float)->int|float:
>>> return x * x
>>> myList = [bar.display(return_object=square(i)) for i in range(10)]
>>> <progress bar gets displayed>
>>> myList
>>> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
239class Spinner: 240 """Prints one of a sequence of characters in order everytime `display()` is called. 241 242 The `display` function writes the new character to the same line, overwriting the previous character. 243 244 The sequence will be cycled through indefinitely. 245 246 If used as a context manager, the last printed character will be cleared upon exiting. 247 """ 248 249 def __init__( 250 self, sequence: list[str] = ["/", "-", "\\"], width_ratio: float = 0.25 251 ): 252 """ 253 #### params: 254 255 `sequence`: Override the built in spin sequence. 256 257 `width_ratio`: The fractional amount of the terminal for characters to move across.""" 258 self._base_sequence = sequence 259 self.width_ratio = width_ratio 260 self.sequence = self._base_sequence 261 262 def __enter__(self): 263 return self 264 265 def __exit__(self, *args, **kwargs): 266 clear() 267 268 @property 269 def width_ratio(self) -> float: 270 return self._width_ratio 271 272 @width_ratio.setter 273 def width_ratio(self, ratio: float): 274 self._width_ratio = ratio 275 self._update_width() 276 277 def _update_width(self): 278 self._current_terminal_width = get_terminal_size().columns 279 self._width = int((self._current_terminal_width - 1) * self.width_ratio) 280 281 @property 282 def sequence(self) -> list[Any]: 283 return self._sequence 284 285 @sequence.setter 286 def sequence(self, character_list: list[Any]): 287 self._sequence = [ 288 ch.rjust(i + j) 289 for i in range(1, self._width, len(character_list)) 290 for j, ch in enumerate(character_list) 291 ] 292 self._sequence += self._sequence[::-1] 293 294 def _get_next(self) -> str: 295 """Pop the first element of `self._sequence`, append it to the end, and return the element.""" 296 ch = self.sequence.pop(0) 297 self.sequence.append(ch) 298 return ch 299 300 def display(self): 301 """Print the next character in the sequence.""" 302 try: 303 if get_terminal_size().columns != self._current_terminal_width: 304 self._update_width() 305 self.sequence = self._base_sequence 306 print_in_place(self._get_next()) 307 except OSError: 308 ... 309 except Exception as e: 310 raise e
Prints one of a sequence of characters in order everytime display() is called.
The display function writes the new character to the same line, overwriting the previous character.
The sequence will be cycled through indefinitely.
If used as a context manager, the last printed character will be cleared upon exiting.
249 def __init__( 250 self, sequence: list[str] = ["/", "-", "\\"], width_ratio: float = 0.25 251 ): 252 """ 253 #### params: 254 255 `sequence`: Override the built in spin sequence. 256 257 `width_ratio`: The fractional amount of the terminal for characters to move across.""" 258 self._base_sequence = sequence 259 self.width_ratio = width_ratio 260 self.sequence = self._base_sequence
params:
sequence: Override the built in spin sequence.
width_ratio: The fractional amount of the terminal for characters to move across.
300 def display(self): 301 """Print the next character in the sequence.""" 302 try: 303 if get_terminal_size().columns != self._current_terminal_width: 304 self._update_width() 305 self.sequence = self._base_sequence 306 print_in_place(self._get_next()) 307 except OSError: 308 ... 309 except Exception as e: 310 raise e
Print the next character in the sequence.