annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/tqdm/tk.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
rev   line source
jpayne@68 1 """
jpayne@68 2 Tkinter GUI progressbar decorator for iterators.
jpayne@68 3
jpayne@68 4 Usage:
jpayne@68 5 >>> from tqdm.tk import trange, tqdm
jpayne@68 6 >>> for i in trange(10):
jpayne@68 7 ... ...
jpayne@68 8 """
jpayne@68 9 import re
jpayne@68 10 import sys
jpayne@68 11 import tkinter
jpayne@68 12 import tkinter.ttk as ttk
jpayne@68 13 from warnings import warn
jpayne@68 14
jpayne@68 15 from .std import TqdmExperimentalWarning, TqdmWarning
jpayne@68 16 from .std import tqdm as std_tqdm
jpayne@68 17
jpayne@68 18 __author__ = {"github.com/": ["richardsheridan", "casperdcl"]}
jpayne@68 19 __all__ = ['tqdm_tk', 'ttkrange', 'tqdm', 'trange']
jpayne@68 20
jpayne@68 21
jpayne@68 22 class tqdm_tk(std_tqdm): # pragma: no cover
jpayne@68 23 """
jpayne@68 24 Experimental Tkinter GUI version of tqdm!
jpayne@68 25
jpayne@68 26 Note: Window interactivity suffers if `tqdm_tk` is not running within
jpayne@68 27 a Tkinter mainloop and values are generated infrequently. In this case,
jpayne@68 28 consider calling `tqdm_tk.refresh()` frequently in the Tk thread.
jpayne@68 29 """
jpayne@68 30
jpayne@68 31 # TODO: @classmethod: write()?
jpayne@68 32
jpayne@68 33 def __init__(self, *args, **kwargs):
jpayne@68 34 """
jpayne@68 35 This class accepts the following parameters *in addition* to
jpayne@68 36 the parameters accepted by `tqdm`.
jpayne@68 37
jpayne@68 38 Parameters
jpayne@68 39 ----------
jpayne@68 40 grab : bool, optional
jpayne@68 41 Grab the input across all windows of the process.
jpayne@68 42 tk_parent : `tkinter.Wm`, optional
jpayne@68 43 Parent Tk window.
jpayne@68 44 cancel_callback : Callable, optional
jpayne@68 45 Create a cancel button and set `cancel_callback` to be called
jpayne@68 46 when the cancel or window close button is clicked.
jpayne@68 47 """
jpayne@68 48 kwargs = kwargs.copy()
jpayne@68 49 kwargs['gui'] = True
jpayne@68 50 # convert disable = None to False
jpayne@68 51 kwargs['disable'] = bool(kwargs.get('disable', False))
jpayne@68 52 self._warn_leave = 'leave' in kwargs
jpayne@68 53 grab = kwargs.pop('grab', False)
jpayne@68 54 tk_parent = kwargs.pop('tk_parent', None)
jpayne@68 55 self._cancel_callback = kwargs.pop('cancel_callback', None)
jpayne@68 56 super().__init__(*args, **kwargs)
jpayne@68 57
jpayne@68 58 if self.disable:
jpayne@68 59 return
jpayne@68 60
jpayne@68 61 if tk_parent is None: # Discover parent widget
jpayne@68 62 try:
jpayne@68 63 tk_parent = tkinter._default_root
jpayne@68 64 except AttributeError:
jpayne@68 65 raise AttributeError(
jpayne@68 66 "`tk_parent` required when using `tkinter.NoDefaultRoot()`")
jpayne@68 67 if tk_parent is None: # use new default root window as display
jpayne@68 68 self._tk_window = tkinter.Tk()
jpayne@68 69 else: # some other windows already exist
jpayne@68 70 self._tk_window = tkinter.Toplevel()
jpayne@68 71 else:
jpayne@68 72 self._tk_window = tkinter.Toplevel(tk_parent)
jpayne@68 73
jpayne@68 74 warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2)
jpayne@68 75 self._tk_dispatching = self._tk_dispatching_helper()
jpayne@68 76
jpayne@68 77 self._tk_window.protocol("WM_DELETE_WINDOW", self.cancel)
jpayne@68 78 self._tk_window.wm_title(self.desc)
jpayne@68 79 self._tk_window.wm_attributes("-topmost", 1)
jpayne@68 80 self._tk_window.after(0, lambda: self._tk_window.wm_attributes("-topmost", 0))
jpayne@68 81 self._tk_n_var = tkinter.DoubleVar(self._tk_window, value=0)
jpayne@68 82 self._tk_text_var = tkinter.StringVar(self._tk_window)
jpayne@68 83 pbar_frame = ttk.Frame(self._tk_window, padding=5)
jpayne@68 84 pbar_frame.pack()
jpayne@68 85 _tk_label = ttk.Label(pbar_frame, textvariable=self._tk_text_var,
jpayne@68 86 wraplength=600, anchor="center", justify="center")
jpayne@68 87 _tk_label.pack()
jpayne@68 88 self._tk_pbar = ttk.Progressbar(
jpayne@68 89 pbar_frame, variable=self._tk_n_var, length=450)
jpayne@68 90 if self.total is not None:
jpayne@68 91 self._tk_pbar.configure(maximum=self.total)
jpayne@68 92 else:
jpayne@68 93 self._tk_pbar.configure(mode="indeterminate")
jpayne@68 94 self._tk_pbar.pack()
jpayne@68 95 if self._cancel_callback is not None:
jpayne@68 96 _tk_button = ttk.Button(pbar_frame, text="Cancel", command=self.cancel)
jpayne@68 97 _tk_button.pack()
jpayne@68 98 if grab:
jpayne@68 99 self._tk_window.grab_set()
jpayne@68 100
jpayne@68 101 def close(self):
jpayne@68 102 if self.disable:
jpayne@68 103 return
jpayne@68 104
jpayne@68 105 self.disable = True
jpayne@68 106
jpayne@68 107 with self.get_lock():
jpayne@68 108 self._instances.remove(self)
jpayne@68 109
jpayne@68 110 def _close():
jpayne@68 111 self._tk_window.after('idle', self._tk_window.destroy)
jpayne@68 112 if not self._tk_dispatching:
jpayne@68 113 self._tk_window.update()
jpayne@68 114
jpayne@68 115 self._tk_window.protocol("WM_DELETE_WINDOW", _close)
jpayne@68 116
jpayne@68 117 # if leave is set but we are self-dispatching, the left window is
jpayne@68 118 # totally unresponsive unless the user manually dispatches
jpayne@68 119 if not self.leave:
jpayne@68 120 _close()
jpayne@68 121 elif not self._tk_dispatching:
jpayne@68 122 if self._warn_leave:
jpayne@68 123 warn("leave flag ignored if not in tkinter mainloop",
jpayne@68 124 TqdmWarning, stacklevel=2)
jpayne@68 125 _close()
jpayne@68 126
jpayne@68 127 def clear(self, *_, **__):
jpayne@68 128 pass
jpayne@68 129
jpayne@68 130 def display(self, *_, **__):
jpayne@68 131 self._tk_n_var.set(self.n)
jpayne@68 132 d = self.format_dict
jpayne@68 133 # remove {bar}
jpayne@68 134 d['bar_format'] = (d['bar_format'] or "{l_bar}<bar/>{r_bar}").replace(
jpayne@68 135 "{bar}", "<bar/>")
jpayne@68 136 msg = self.format_meter(**d)
jpayne@68 137 if '<bar/>' in msg:
jpayne@68 138 msg = "".join(re.split(r'\|?<bar/>\|?', msg, maxsplit=1))
jpayne@68 139 self._tk_text_var.set(msg)
jpayne@68 140 if not self._tk_dispatching:
jpayne@68 141 self._tk_window.update()
jpayne@68 142
jpayne@68 143 def set_description(self, desc=None, refresh=True):
jpayne@68 144 self.set_description_str(desc, refresh)
jpayne@68 145
jpayne@68 146 def set_description_str(self, desc=None, refresh=True):
jpayne@68 147 self.desc = desc
jpayne@68 148 if not self.disable:
jpayne@68 149 self._tk_window.wm_title(desc)
jpayne@68 150 if refresh and not self._tk_dispatching:
jpayne@68 151 self._tk_window.update()
jpayne@68 152
jpayne@68 153 def cancel(self):
jpayne@68 154 """
jpayne@68 155 `cancel_callback()` followed by `close()`
jpayne@68 156 when close/cancel buttons clicked.
jpayne@68 157 """
jpayne@68 158 if self._cancel_callback is not None:
jpayne@68 159 self._cancel_callback()
jpayne@68 160 self.close()
jpayne@68 161
jpayne@68 162 def reset(self, total=None):
jpayne@68 163 """
jpayne@68 164 Resets to 0 iterations for repeated use.
jpayne@68 165
jpayne@68 166 Parameters
jpayne@68 167 ----------
jpayne@68 168 total : int or float, optional. Total to use for the new bar.
jpayne@68 169 """
jpayne@68 170 if hasattr(self, '_tk_pbar'):
jpayne@68 171 if total is None:
jpayne@68 172 self._tk_pbar.configure(maximum=100, mode="indeterminate")
jpayne@68 173 else:
jpayne@68 174 self._tk_pbar.configure(maximum=total, mode="determinate")
jpayne@68 175 super().reset(total=total)
jpayne@68 176
jpayne@68 177 @staticmethod
jpayne@68 178 def _tk_dispatching_helper():
jpayne@68 179 """determine if Tkinter mainloop is dispatching events"""
jpayne@68 180 codes = {tkinter.mainloop.__code__, tkinter.Misc.mainloop.__code__}
jpayne@68 181 for frame in sys._current_frames().values():
jpayne@68 182 while frame:
jpayne@68 183 if frame.f_code in codes:
jpayne@68 184 return True
jpayne@68 185 frame = frame.f_back
jpayne@68 186 return False
jpayne@68 187
jpayne@68 188
jpayne@68 189 def ttkrange(*args, **kwargs):
jpayne@68 190 """Shortcut for `tqdm.tk.tqdm(range(*args), **kwargs)`."""
jpayne@68 191 return tqdm_tk(range(*args), **kwargs)
jpayne@68 192
jpayne@68 193
jpayne@68 194 # Aliases
jpayne@68 195 tqdm = tqdm_tk
jpayne@68 196 trange = ttkrange