{"record":{"id":"25045b766ed2766c","repo":"tqdm/tqdm","slug":"tk-parent-required-when-using-tkinter-nodefault","errorCode":null,"errorMessage":"`tk_parent` required when using `tkinter.NoDefaultRoot()`","messagePattern":"`tk_parent` required when using `tkinter\\.NoDefaultRoot\\(\\)`","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"tqdm/tk.py","lineNumber":65,"sourceCode":"        \"\"\"\n        kwargs = kwargs.copy()\n        kwargs['gui'] = True\n        # convert disable = None to False\n        kwargs['disable'] = bool(kwargs.get('disable', False))\n        self._warn_leave = 'leave' in kwargs\n        grab = kwargs.pop('grab', False)\n        tk_parent = kwargs.pop('tk_parent', None)\n        self._cancel_callback = kwargs.pop('cancel_callback', None)\n        super().__init__(*args, **kwargs)\n\n        if self.disable:\n            return\n\n        if tk_parent is None:  # Discover parent widget\n            try:\n                tk_parent = tkinter._default_root\n            except AttributeError:\n                raise AttributeError(\n                    \"`tk_parent` required when using `tkinter.NoDefaultRoot()`\")\n            if tk_parent is None:  # use new default root window as display\n                self._tk_window = tkinter.Tk()\n            else:  # some other windows already exist\n                self._tk_window = tkinter.Toplevel()\n        else:\n            self._tk_window = tkinter.Toplevel(tk_parent)\n\n        warn(\"GUI is experimental/alpha\", TqdmExperimentalWarning, stacklevel=2)\n        self._tk_dispatching = self._tk_dispatching_helper()\n\n        self._tk_window.protocol(\"WM_DELETE_WINDOW\", self.cancel)\n        self._tk_window.wm_title(self.desc)\n        self._tk_window.wm_attributes(\"-topmost\", 1)\n        self._tk_window.after(0, lambda: self._tk_window.wm_attributes(\"-topmost\", 0))\n        self._tk_n_var = tkinter.DoubleVar(self._tk_window, value=0)\n        self._tk_text_var = tkinter.StringVar(self._tk_window)\n        pbar_frame = ttk.Frame(self._tk_window, padding=5)","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/tqdm/tqdm/blob/96f2e60e4584cdab57a23602e27043d0465254ad/tqdm/tk.py#L47-L83","documentation":"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').","triggerScenarios":"tqdm.wrapattr(f, 'readline', ...) or Tqdm.wrapattr(stream, 'send', ...) — any method name other than 'read' or 'write'.","commonSituations":"Trying to wrap socket.send, file.readline, or ws.send to count bytes progressed.","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"],"exampleFix":"# before\nt = tqdm.wrapattr(sock, 'send', total=n)\n# after\nt = tqdm(total=n)\n# ... in send loop:\nt.update(len(chunk))","handlingStrategy":"validation","validationCode":"method = 'readline'\nassert method in ('read', 'write'), f'cannot wrap {method!r}'","typeGuard":"def is_wrappable(method: str) -> bool:\n    return method in ('read', 'write')","tryCatchPattern":"try:\n    with tqdm.wrapattr(f, 'read', total=n) as _:\n        data = _.read()\nexcept KeyError:\n    data = manual_read_with_progress(f)","preventionTips":["Only wrap read/write with wrapattr","Count bytes via bar.update(len(chunk)) for other methods"],"tags":["tqdm","io","wrapper","unsupported-operation"],"backgroundTag":"unsupported-wrapped-method","analyzedSha":"96f2e60e4584cdab57a23602e27043d0465254ad","analyzedAt":"2026-08-28T11:23:10.474Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}