tqdm/tqdm · error · AttributeError
`tk_parent` required when using `tkinter.NoDefaultRoot()`
Error message
`tk_parent` required when using `tkinter.NoDefaultRoot()`
What it means
tqdm.utils.CallbackIoContext (the object returned by file-like wrappers such as tqdm.wrapattr used on unknown methods) only knows how to wrap read or write; asking it to wrap another method name raises KeyError('Can only wrap read/write methods').
Source
Thrown at tqdm/tk.py:65
"""
kwargs = kwargs.copy()
kwargs['gui'] = True
# convert disable = None to False
kwargs['disable'] = bool(kwargs.get('disable', False))
self._warn_leave = 'leave' in kwargs
grab = kwargs.pop('grab', False)
tk_parent = kwargs.pop('tk_parent', None)
self._cancel_callback = kwargs.pop('cancel_callback', None)
super().__init__(*args, **kwargs)
if self.disable:
return
if tk_parent is None: # Discover parent widget
try:
tk_parent = tkinter._default_root
except AttributeError:
raise AttributeError(
"`tk_parent` required when using `tkinter.NoDefaultRoot()`")
if tk_parent is None: # use new default root window as display
self._tk_window = tkinter.Tk()
else: # some other windows already exist
self._tk_window = tkinter.Toplevel()
else:
self._tk_window = tkinter.Toplevel(tk_parent)
warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2)
self._tk_dispatching = self._tk_dispatching_helper()
self._tk_window.protocol("WM_DELETE_WINDOW", self.cancel)
self._tk_window.wm_title(self.desc)
self._tk_window.wm_attributes("-topmost", 1)
self._tk_window.after(0, lambda: self._tk_window.wm_attributes("-topmost", 0))
self._tk_n_var = tkinter.DoubleVar(self._tk_window, value=0)
self._tk_text_var = tkinter.StringVar(self._tk_window)
pbar_frame = ttk.Frame(self._tk_window, padding=5)View on GitHub (pinned to 96f2e60e45)
Solutions
- Wrap 'read' or 'write' only
- For other methods, count manually via update() inside your own loop
- Wrap the underlying buffered stream's read/write instead of the exotic method
Example fix
# before t = tqdm.wrapattr(sock, 'send', total=n) # after t = tqdm(total=n) # ... in send loop: t.update(len(chunk))
Defensive patterns
Strategy: validation
Validate before calling
method = 'readline'
assert method in ('read', 'write'), f'cannot wrap {method!r}' Type guard
def is_wrappable(method: str) -> bool:
return method in ('read', 'write') Try / catch
try:
with tqdm.wrapattr(f, 'read', total=n) as _:
data = _.read()
except KeyError:
data = manual_read_with_progress(f) Prevention
- Only wrap read/write with wrapattr
- Count bytes via bar.update(len(chunk)) for other methods
When it happens
Trigger: tqdm.wrapattr(f, 'readline', ...) or Tqdm.wrapattr(stream, 'send', ...) — any method name other than 'read' or 'write'.
Common situations: Trying to wrap socket.send, file.readline, or ws.send to count bytes progressed.
Related errors
- {val} : {typ}
- str(e)
- Can only have one of --bytes --update --update_to
- cannot release un-acquired lock
- Please `pip install slack-sdk`
AI-assisted analysis of tqdm/tqdm@96f2e60e45 (2026-08-28).
Data as JSON: /api/errors/25045b766ed2766c.
Report an issue: GitHub.