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