mirror of
https://github.com/python/cpython.git
synced 2025-11-02 03:01:58 +00:00
bpo-42630: Improve error reporting in Tkinter for absent default root (GH-23781)
* Tkinter functions and constructors which need a default root window raise now RuntimeError with descriptive message instead of obscure AttributeError or NameError if it is not created yet or cannot be created automatically. * Add tests for all functions which use default root window. * Fix import in the pynche script.
This commit is contained in:
parent
1e27b57dbc
commit
3d569fd6dc
19 changed files with 315 additions and 87 deletions
|
|
@ -270,7 +270,7 @@ class Event:
|
|||
)
|
||||
|
||||
|
||||
_support_default_root = 1
|
||||
_support_default_root = True
|
||||
_default_root = None
|
||||
|
||||
|
||||
|
|
@ -280,13 +280,26 @@ def NoDefaultRoot():
|
|||
Call this function to inhibit that the first instance of
|
||||
Tk is used for windows without an explicit parent window.
|
||||
"""
|
||||
global _support_default_root
|
||||
_support_default_root = 0
|
||||
global _default_root
|
||||
global _support_default_root, _default_root
|
||||
_support_default_root = False
|
||||
# Delete, so any use of _default_root will immediately raise an exception.
|
||||
# Rebind before deletion, so repeated calls will not fail.
|
||||
_default_root = None
|
||||
del _default_root
|
||||
|
||||
|
||||
def _get_default_root(what=None):
|
||||
if not _support_default_root:
|
||||
raise RuntimeError("No master specified and tkinter is "
|
||||
"configured to not support default root")
|
||||
if not _default_root:
|
||||
if what:
|
||||
raise RuntimeError(f"Too early to {what}: no default root window")
|
||||
root = Tk()
|
||||
assert _default_root is root
|
||||
return _default_root
|
||||
|
||||
|
||||
def _tkerror(err):
|
||||
"""Internal function."""
|
||||
pass
|
||||
|
|
@ -330,7 +343,7 @@ class Variable:
|
|||
raise TypeError("name must be a string")
|
||||
global _varnum
|
||||
if not master:
|
||||
master = _default_root
|
||||
master = _get_default_root('create variable')
|
||||
self._root = master._root()
|
||||
self._tk = master.tk
|
||||
if name:
|
||||
|
|
@ -591,7 +604,7 @@ class BooleanVar(Variable):
|
|||
|
||||
def mainloop(n=0):
|
||||
"""Run the main loop of Tcl."""
|
||||
_default_root.tk.mainloop(n)
|
||||
_get_default_root('run the main loop').tk.mainloop(n)
|
||||
|
||||
|
||||
getint = int
|
||||
|
|
@ -600,9 +613,9 @@ getdouble = float
|
|||
|
||||
|
||||
def getboolean(s):
|
||||
"""Convert true and false to integer values 1 and 0."""
|
||||
"""Convert Tcl object to True or False."""
|
||||
try:
|
||||
return _default_root.tk.getboolean(s)
|
||||
return _get_default_root('use getboolean()').tk.getboolean(s)
|
||||
except TclError:
|
||||
raise ValueError("invalid literal for getboolean()")
|
||||
|
||||
|
|
@ -2248,7 +2261,7 @@ class Tk(Misc, Wm):
|
|||
is the name of the widget class."""
|
||||
self.master = None
|
||||
self.children = {}
|
||||
self._tkloaded = 0
|
||||
self._tkloaded = False
|
||||
# to avoid recursions in the getattr code in case of failure, we
|
||||
# ensure that self.tk is always _something_.
|
||||
self.tk = None
|
||||
|
|
@ -2272,7 +2285,7 @@ class Tk(Misc, Wm):
|
|||
self._loadtk()
|
||||
|
||||
def _loadtk(self):
|
||||
self._tkloaded = 1
|
||||
self._tkloaded = True
|
||||
global _default_root
|
||||
# Version sanity checks
|
||||
tk_version = self.tk.getvar('tk_version')
|
||||
|
|
@ -2521,12 +2534,8 @@ class BaseWidget(Misc):
|
|||
|
||||
def _setup(self, master, cnf):
|
||||
"""Internal function. Sets up information about children."""
|
||||
if _support_default_root:
|
||||
global _default_root
|
||||
if not master:
|
||||
if not _default_root:
|
||||
_default_root = Tk()
|
||||
master = _default_root
|
||||
if not master:
|
||||
master = _get_default_root()
|
||||
self.master = master
|
||||
self.tk = master.tk
|
||||
name = None
|
||||
|
|
@ -3990,9 +3999,7 @@ class Image:
|
|||
def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
|
||||
self.name = None
|
||||
if not master:
|
||||
master = _default_root
|
||||
if not master:
|
||||
raise RuntimeError('Too early to create image')
|
||||
master = _get_default_root('create image')
|
||||
self.tk = getattr(master, 'tk', master)
|
||||
if not name:
|
||||
Image._last_id += 1
|
||||
|
|
@ -4146,11 +4153,13 @@ class BitmapImage(Image):
|
|||
|
||||
|
||||
def image_names():
|
||||
return _default_root.tk.splitlist(_default_root.tk.call('image', 'names'))
|
||||
tk = _get_default_root('use image_names()').tk
|
||||
return tk.splitlist(tk.call('image', 'names'))
|
||||
|
||||
|
||||
def image_types():
|
||||
return _default_root.tk.splitlist(_default_root.tk.call('image', 'types'))
|
||||
tk = _get_default_root('use image_types()').tk
|
||||
return tk.splitlist(tk.call('image', 'types'))
|
||||
|
||||
|
||||
class Spinbox(Widget, XView):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue