diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 2dc44ad36a7f73..8bfa17957913f9 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -70,10 +70,7 @@ Tkinter Modules Most of the time, :mod:`tkinter` is all you really need, but a number of additional modules are available as well. The Tk interface is located in a -binary module named :mod:`_tkinter`. This module contains the low-level -interface to Tk, and should never be used directly by application programmers. -It is usually a shared library (or DLL), but might in some cases be statically -linked with the Python interpreter. +binary module named :mod:`_tkinter`. In addition to the Tk interface module, :mod:`tkinter` includes a number of Python modules, :mod:`tkinter.constants` being one of the most important. @@ -82,10 +79,6 @@ so, usually, to use Tkinter all you need is a simple import statement:: import tkinter -Or, more often:: - - from tkinter import * - .. class:: Tk(screenName=None, baseName=None, className='Tk', useTk=1) @@ -95,6 +88,38 @@ Or, more often:: .. FIXME: The following keyword arguments are currently recognized: + Below are a few of the methods provided by the :class:`Tk` class. + + .. sectionauthor:: Richard Sheridan + + .. method:: mainloop(threshold) + + Enters the main loop of Tkinter. This repeatedly dispatches Tcl events + until either :meth:`Tk.quit` is called, the number of open windows drops + below ``threshold``, or an error occurs while executing events. Usually + the default threshold of 0 is appropriate. + + .. method:: quit() + + Signals the Tkinter main loop to stop dispatching. + The main loop will exit AFTER the current Tcl event handler is + finished calling. If quit is called outside the context of a Tcl + event, for example from a thread, the main loop will not exit + until after the NEXT event is dispatched. If no more events are + forthcoming, main loop will keep blocking even if quit has been + called. In that case, call ``after(0, quit)`` instead. + + .. method:: dispatching() + + Determines if the Tkinter main loop is running. Returns True if the main + loop is running, or returns False if the main loop is not running. It is + possible for some entity other than the main loop to be dispatching + events. Some examples are: calling the :meth:`Tk.update` command, + :meth:`_tkinter.tkapp.doonevent`, and the python command line EventHook. + :meth:`Tk.dispatching` does not provide any information about entities + dispatching other than :meth:`Tk.mainloop`. + + .. versionadded:: 3.10 .. function:: Tcl(screenName=None, baseName=None, className='Tk', useTk=0) @@ -106,7 +131,6 @@ Or, more often:: created by the :func:`Tcl` object can have a Toplevel window created (and the Tk subsystem initialized) by calling its :meth:`loadtk` method. - Other modules that provide Tk support include: :mod:`tkinter.colorchooser` diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index a3b53ba48e9b7c..696e1e38269cf9 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -117,6 +117,22 @@ Add :data:`sys.orig_argv` attribute: the list of the original command line arguments passed to the Python executable. (Contributed by Victor Stinner in :issue:`23427`.) +tkinter +------- + +XXX Added :meth:`tkinter.dispatching`, :meth:`tkinter.Misc.dispatching`, and +:meth:`_tkinter.tkapp.dispatching`. +You can reliably call these to determine if the tkinter mainloop is running. + +Some internal thread waiting behavior has been deprecated to preserve the +correctness of the new dispatching methods. + +Added another new method :meth:`_tkinter.tkapp.setmainloopwaitattempts` which +can be used to obtain future thread waiting behavior. + +(see also Deprecated section) +(Contributed by Richard Sheridan in :issue:`41176`.) + Optimizations ============= @@ -130,6 +146,13 @@ Optimizations Deprecated ========== +XXX The :mod:`tkinter` module has deprected the undocumented behavior where a +thread will implicitly wait up to one second for the main thread to enter +the main loop and then fail. +The undocumented :meth:`_tkinter.tkapp.willdispatch` method which sidesteps +this behavior has also been deprecated. +(See also tkinter in the Improved Modules section) +(Contributed by Richard Sheridan in :issue:`41176`.) Removed ======= diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index a3378d012fb41a..bb940cf7dd64f8 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -590,9 +590,20 @@ def get(self): raise ValueError("invalid literal for getboolean()") -def mainloop(n=0): - """Run the main loop of Tcl.""" - _default_root.tk.mainloop(n) +def mainloop(threshold=0): + """Call the main loop of Tkinter.""" + _default_root.tk.mainloop(threshold) + + +def dispatching(): + """Determine if the Tkinter main loop is running. + + Returns True if the main loop is running. + Returns False if the main loop is not running. + + NOTE: Using update will dispatch events without the main + loop. Dispatching will return False in these cases.""" + return _default_root.tk.dispatching() getint = int @@ -1303,13 +1314,13 @@ def winfo_y(self): self.tk.call('winfo', 'y', self._w)) def update(self): - """Enter event loop until all pending events have been processed by Tcl.""" + """Process all events, including idle tasks, in the Tcl queue.""" self.tk.call('update') def update_idletasks(self): - """Enter event loop until all idle callbacks have been called. This - will update the display of windows but not process events caused by - the user.""" + """Process all idle callbacks in the Tcl queue. + This will update the display of windows but not process events + caused by the user.""" self.tk.call('update', 'idletasks') def bindtags(self, tagList=None): @@ -1417,12 +1428,30 @@ def unbind_class(self, className, sequence): all functions.""" self.tk.call('bind', className , sequence, '') - def mainloop(self, n=0): - """Call the mainloop of Tk.""" - self.tk.mainloop(n) + def mainloop(self, threshold=0): + """Call the main loop of Tkinter.""" + self.tk.mainloop(threshold) + + def dispatching(self): + """Determine if the Tkinter main loop is running. + + Returns True if the main loop is running. + Returns False if the main loop is not running. + + NOTE: Using update will dispatch events without the main + loop. Dispatching will return False in these cases.""" + return self.tk.dispatching() def quit(self): - """Quit the Tcl interpreter. All widgets will be destroyed.""" + """Signal the Tkinter main loop to stop dispatching. + + The main loop will exit AFTER the current Tcl event handler is + finished calling. If quit is called outside the context of a Tcl + event, for example from a thread, the main loop will not exit + until after the NEXT event is dispatched. If no more events are + forthcoming, main loop will keep blocking even if quit has been + called. In that case, have the thread call after(0, quit) instead. + """ self.tk.quit() def _getints(self, string): diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py index 467a0b66c265c0..1220854205917b 100644 --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -22,7 +22,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - cls.root.update_idletasks() + cls.root.update() cls.root.destroy() del cls.root tkinter._default_root = None @@ -38,7 +38,7 @@ def tearDown(self): def destroy_default_root(): if getattr(tkinter, '_default_root', None): - tkinter._default_root.update_idletasks() + tkinter._default_root.update() tkinter._default_root.destroy() tkinter._default_root = None diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py index 1e089747a91ee5..5e71e8fa0c7c92 100644 --- a/Lib/tkinter/test/test_tkinter/test_misc.py +++ b/Lib/tkinter/test/test_tkinter/test_misc.py @@ -1,5 +1,7 @@ import unittest import tkinter +import threading +import time from test import support from tkinter.test.support import AbstractTkTest @@ -109,7 +111,7 @@ def callback(start=0, step=1): idle1 = root.after_idle(callback) self.assertIn(idle1, root.tk.call('after', 'info')) (script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1)) - root.update_idletasks() # Process all pending events. + root.update() # Process all pending events. self.assertEqual(count, 1) with self.assertRaises(tkinter.TclError): root.tk.call(script) @@ -117,7 +119,7 @@ def callback(start=0, step=1): # Set up with callback with args. count = 0 idle1 = root.after_idle(callback, 42, 11) - root.update_idletasks() # Process all pending events. + root.update() # Process all pending events. self.assertEqual(count, 53) # Cancel before called. @@ -192,6 +194,100 @@ def test_clipboard_astral(self): with self.assertRaises(tkinter.TclError): root.clipboard_get() + def test_mainloop_dispatching(self): + # reconstruct default root destroyed by AbstractTkTest + root = tkinter._default_root = self.root + for obj in (root.tk, root, tkinter): + self.assertFalse(obj.dispatching()) + root.after(0, lambda:self.assertTrue(obj.dispatching())) + + # guarantees mainloop end after first call to Tcl_DoOneEvent + root.after(0, root.quit) + + root.mainloop() + self.assertFalse(obj.dispatching()) + + def test_willdispatch(self): + root = self.root + self.assertFalse(root.dispatching()) + with self.assertWarns(DeprecationWarning): + root.tk.willdispatch() + self.assertTrue(root.dispatching()) + # reset dispatching flag + root.after(0,root.quit) + root.mainloop() + self.assertFalse(root.dispatching()) + + def test_thread_must_wait_for_mainloop(self): + # remove test on eventual WaitForMainloop removal + sentinel = object() + thread_properly_raises = sentinel + thread_dispatching_early = sentinel + thread_dispatching_eventually = sentinel + + def target(): + nonlocal thread_dispatching_early + nonlocal thread_properly_raises + nonlocal thread_dispatching_eventually + + try: + thread_dispatching_early = root.dispatching() + root.after(0) # Null op + except RuntimeError as e: + if str(e) == "main thread is not in main loop": + thread_properly_raises=True + else: + thread_properly_raises=False + raise + else: + thread_properly_raises=False + return + finally: + # must guarantee that any reason not to run mainloop + # is flagged in the above try/except/else and will + # keep the main thread from calling root.mainloop() + ready_for_mainloop.set() + + # self.assertTrue(root.dispatching()) but patient + for i in range(1000): + if root.dispatching(): + thread_dispatching_eventually = True + break + time.sleep(0.01) + else: # if not break + thread_dispatching_eventually = False + root.after(0, root.quit) + + root = self.root + + with self.assertWarns(DeprecationWarning): + root.tk.setmainloopwaitattempts(0) + + try: + ready_for_mainloop = threading.Event() + thread = threading.Thread(target=target) + self.assertFalse(root.dispatching()) + thread.start() + ready_for_mainloop.wait() + + # if these fail we don't want to risk starting mainloop + self.assertFalse(thread_dispatching_early is sentinel) + self.assertFalse(thread_dispatching_early) + self.assertFalse(thread_properly_raises is sentinel) + self.assertTrue(thread_properly_raises) + + root.mainloop() + self.assertFalse(root.dispatching()) + thread.join() + finally: + # this global *must* be reset + with self.assertWarns(DeprecationWarning): + root.tk.setmainloopwaitattempts(10) + + self.assertFalse(thread_dispatching_eventually is sentinel) + self.assertTrue(thread_dispatching_eventually) + + tests_gui = (MiscTest, ) diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py index a45f882bb00d48..ff0fb8cacae158 100644 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -10,7 +10,7 @@ class LabeledScaleTest(AbstractTkTest, unittest.TestCase): def tearDown(self): - self.root.update_idletasks() + self.root.update() super().tearDown() def test_widget_destroy(self): @@ -219,7 +219,7 @@ def test_widget_destroy(self): var = tkinter.StringVar(self.root) optmenu = ttk.OptionMenu(self.root, var) name = var._name - optmenu.update_idletasks() + optmenu.update() optmenu.destroy() self.assertEqual(optmenu.tk.globalgetvar(name), var.get()) del var diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 2598bc67652075..4dd09d905aa3c7 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -64,7 +64,7 @@ def setUp(self): def test_identify(self): - self.widget.update_idletasks() + self.widget.update() self.assertEqual(self.widget.identify( int(self.widget.winfo_width() / 2), int(self.widget.winfo_height() / 2) @@ -327,7 +327,7 @@ def test_bbox(self): def test_identify(self): self.entry.pack() self.entry.wait_visibility() - self.entry.update_idletasks() + self.entry.update() # bpo-27313: macOS Cocoa widget differs from X, allow either if sys.platform == 'darwin': @@ -439,7 +439,7 @@ def _show_drop_down_listbox(self): width = self.combo.winfo_width() self.combo.event_generate('', x=width - 5, y=5) self.combo.event_generate('', x=width - 5, y=5) - self.combo.update_idletasks() + self.combo.update() def test_virtual_event(self): @@ -1134,7 +1134,7 @@ def _click_increment_arrow(self): y = height//2 - 5 self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) - self.spin.update_idletasks() + self.spin.update() def _click_decrement_arrow(self): width = self.spin.winfo_width() @@ -1143,7 +1143,7 @@ def _click_decrement_arrow(self): y = height//2 + 4 self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) - self.spin.update_idletasks() + self.spin.update() def test_command(self): success = [] @@ -1159,7 +1159,7 @@ def test_command(self): # testing postcommand removal self.spin['command'] = '' - self.spin.update_idletasks() + self.spin.update() self._click_increment_arrow() self._click_decrement_arrow() self.spin.update() diff --git a/Misc/ACKS b/Misc/ACKS index 641ef0cace00e2..183e19313a44bb 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1563,6 +1563,7 @@ Vlad Shcherbina Justin Sheehy Akash Shende Charlie Shepherd +Richard Sheridan Bruce Sherwood Alexander Shigin Pete Shinners diff --git a/Misc/NEWS.d/next/Library/2020-07-05-15-38-26.bpo-41176.Q5Ua74.rst b/Misc/NEWS.d/next/Library/2020-07-05-15-38-26.bpo-41176.Q5Ua74.rst new file mode 100644 index 00000000000000..5a629bcfe55e36 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-05-15-38-26.bpo-41176.Q5Ua74.rst @@ -0,0 +1,6 @@ +Added :meth:`tkinter.dispatching`, :meth:`tkinter.Misc.dispatching`, and :meth:`_tkinter.tkapp.dispatching`. +These methods may be used to query if the :mod:`tkinter` mainloop is running +Added :meth:`_tkinter.tkapp.setmainloopwaitattempts`. +Deprecated :meth:`_tkinter.tkapp.willdispatch`. +Deprecated undocumented :mod:`tkinter` thread mainloop waiting behavior. +Patch by Richard Sheridan \ No newline at end of file diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 793c5e71548846..57c50fc6b1378a 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -360,21 +360,35 @@ Sleep(int milli) } #endif /* MS_WINDOWS */ -/* Wait up to 1s for the mainloop to come up. */ +/* Wait for the mainloop to come up. */ +static int mainloopwaitattempts = 10; // 1 second static int WaitForMainloop(TkappObject* self) { int i; - for (i = 0; i < 10; i++) { - if (self->dispatching) - return 1; + int max_attempts = mainloopwaitattempts; + if (self->dispatching) + { + return 1; + } + for (i = 0; i < max_attempts; i++) { Py_BEGIN_ALLOW_THREADS Sleep(100); Py_END_ALLOW_THREADS + if (self->dispatching) + { + return 1; + } } - if (self->dispatching) - return 1; + PyErr_WarnEx(PyExc_DeprecationWarning, + "It seems you are waiting for Tcl events " + "to be dispatched.\n" + "Future behavior will wait indefinitely. Adjust the wait time " + "limit with setmainloopwaitattempts().\n" + "If you want to avoid this wait consider polling " + "dispatching() before issuing commands from a thread.\n", 1 + ); PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop"); return 0; } @@ -1500,7 +1514,8 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) marshal the parameters to the interpreter thread. */ Tkapp_CallEvent *ev; Tcl_Condition cond = NULL; - PyObject *exc_type, *exc_value, *exc_tb; + PyObject *exc_type, *exc_value, *exc_tb; + /* Remove after WaitForMainloop deprecation */ if (!WaitForMainloop(self)) return NULL; ev = (Tkapp_CallEvent*)attemptckalloc(sizeof(Tkapp_CallEvent)); @@ -1777,6 +1792,8 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) /* The current thread is not the interpreter thread. Marshal the call to the interpreter thread, then wait for completion. */ + + /* Remove after WaitForMainloop deprecation*/ if (!WaitForMainloop(self)) return NULL; @@ -2477,6 +2494,7 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name, return NULL; } + /* Remove after WaitForMainloop deprecation */ if (self->threaded && self->thread_id != Tcl_GetCurrentThread() && !WaitForMainloop(self)) return NULL; @@ -3022,17 +3040,89 @@ Tkapp_WantObjects(PyObject *self, PyObject *args) /*[clinic input] _tkinter.tkapp.willdispatch +Skips main loop wait polling until next call of mainloop finishes + +DEPRECATED + +call(), var_invoke(), and createcommand() will wait indefinitely for main loop +Sets the internal dispatching flag regardless of mainloop dispatch state +May lead to unexpected hangs or inconsistencies in dispatching + [clinic start generated code]*/ static PyObject * _tkinter_tkapp_willdispatch_impl(TkappObject *self) -/*[clinic end generated code: output=0e3f46d244642155 input=d88f5970843d6dab]*/ +/*[clinic end generated code: output=0e3f46d244642155 input=7b46376275304a4a]*/ { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "willdispatch() is deprecated; in the future it will have no effect.", 1)) + { + return NULL; + } self->dispatching = 1; Py_RETURN_NONE; } +/*[clinic input] +_tkinter.tkapp.dispatching + +Returns the internal dispatching state + +Returns True if the main loop is running. +Returns False if the main loop is not running. + +NOTE: Using update or dooneevent will dispatch events without the main + loop. Dispatching will return False in these cases. + +[clinic start generated code]*/ + +static PyObject * +_tkinter_tkapp_dispatching_impl(TkappObject *self) +/*[clinic end generated code: output=1b0192766b008005 input=ff427bd1ca93bac4]*/ +{ + return PyBool_FromLong(self->dispatching); +} + +/*[clinic input] +_tkinter.tkapp.setmainloopwaitattempts + + new_val: int + / + +Set number of 100 millisecond mainloop wait attempts. + +These are used for threads that call(), var_invoke(), and createcommand(). + +Current default is 10 for a 1 second wait, but future behavior +will be equivalent to an unlimited number. + +Setting this will trigger a DeprecationWarning. + +[clinic start generated code]*/ + +static PyObject * +_tkinter_tkapp_setmainloopwaitattempts_impl(TkappObject *self, int new_val) +/*[clinic end generated code: output=a0867fb187c8946e input=2b60ed355c8d7fac]*/ +{ + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "In future behavior, threads will wait indefinitely " + "for the main thread to dispatch.\n" + "If you want to avoid delays, consider polling dispatching()" + "before issuing commands from a thread instead.", 1)) + { + return NULL; + } + if (new_val < 0) + { + PyErr_SetString(PyExc_ValueError, + "mainloopwaitattempts must be >= 0"); + return NULL; + } + mainloopwaitattempts = new_val; + Py_RETURN_NONE; +} + /**** Tkapp Type Methods ****/ @@ -3252,6 +3342,8 @@ static PyType_Spec Tktt_Type_spec = { static PyMethodDef Tkapp_methods[] = { _TKINTER_TKAPP_WILLDISPATCH_METHODDEF + _TKINTER_TKAPP_DISPATCHING_METHODDEF + _TKINTER_TKAPP_SETMAINLOOPWAITATTEMPTS_METHODDEF {"wantobjects", Tkapp_WantObjects, METH_VARARGS}, {"call", Tkapp_Call, METH_VARARGS}, _TKINTER_TKAPP_EVAL_METHODDEF diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h index 9718986838fbb3..3a49ae0ace0f2c 100644 --- a/Modules/clinic/_tkinter.c.h +++ b/Modules/clinic/_tkinter.c.h @@ -631,7 +631,14 @@ _tkinter_tkapp_loadtk(TkappObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_tkinter_tkapp_willdispatch__doc__, "willdispatch($self, /)\n" "--\n" -"\n"); +"\n" +"Skips main loop wait polling until next call of mainloop finishes\n" +"\n" +"DEPRECATED\n" +"\n" +"call(), var_invoke(), and createcommand() will wait indefinitely for main loop\n" +"Sets the internal dispatching flag regardless of mainloop dispatch state\n" +"May lead to unexpected hangs or inconsistencies in dispatching"); #define _TKINTER_TKAPP_WILLDISPATCH_METHODDEF \ {"willdispatch", (PyCFunction)_tkinter_tkapp_willdispatch, METH_NOARGS, _tkinter_tkapp_willdispatch__doc__}, @@ -645,6 +652,65 @@ _tkinter_tkapp_willdispatch(TkappObject *self, PyObject *Py_UNUSED(ignored)) return _tkinter_tkapp_willdispatch_impl(self); } +PyDoc_STRVAR(_tkinter_tkapp_dispatching__doc__, +"dispatching($self, /)\n" +"--\n" +"\n" +"Returns the internal dispatching state\n" +"\n" +"Returns True if the main loop is running.\n" +"Returns False if the main loop is not running.\n" +"\n" +"NOTE: Using update or dooneevent will dispatch events without the main\n" +" loop. Dispatching will return False in these cases."); + +#define _TKINTER_TKAPP_DISPATCHING_METHODDEF \ + {"dispatching", (PyCFunction)_tkinter_tkapp_dispatching, METH_NOARGS, _tkinter_tkapp_dispatching__doc__}, + +static PyObject * +_tkinter_tkapp_dispatching_impl(TkappObject *self); + +static PyObject * +_tkinter_tkapp_dispatching(TkappObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _tkinter_tkapp_dispatching_impl(self); +} + +PyDoc_STRVAR(_tkinter_tkapp_setmainloopwaitattempts__doc__, +"setmainloopwaitattempts($self, new_val, /)\n" +"--\n" +"\n" +"Set number of 100 millisecond mainloop wait attempts.\n" +"\n" +"These are used for threads that call(), var_invoke(), and createcommand().\n" +"\n" +"Current default is 10 for a 1 second wait, but future behavior\n" +"will be equivalent to an unlimited number.\n" +"\n" +"Setting this will trigger a DeprecationWarning."); + +#define _TKINTER_TKAPP_SETMAINLOOPWAITATTEMPTS_METHODDEF \ + {"setmainloopwaitattempts", (PyCFunction)_tkinter_tkapp_setmainloopwaitattempts, METH_O, _tkinter_tkapp_setmainloopwaitattempts__doc__}, + +static PyObject * +_tkinter_tkapp_setmainloopwaitattempts_impl(TkappObject *self, int new_val); + +static PyObject * +_tkinter_tkapp_setmainloopwaitattempts(TkappObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + int new_val; + + new_val = _PyLong_AsInt(arg); + if (new_val == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _tkinter_tkapp_setmainloopwaitattempts_impl(self, new_val); + +exit: + return return_value; +} + PyDoc_STRVAR(_tkinter__flatten__doc__, "_flatten($module, item, /)\n" "--\n" @@ -867,4 +933,4 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=ab311480dd044fe4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8a843a5f7728537c input=a9049054013a1b77]*/ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy