classification
Title: Tkinter Variables require a proper master
Type: behavior Stage: resolved
Components: Tkinter Versions: Python 3.4, Python 3.5, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: gpolo, martin.panter, serhiy.storchaka, terry.reedy
Priority: normal Keywords:

Created on 2013-06-04 01:12 by terry.reedy, last changed 2020-12-21 09:13 by serhiy.storchaka. This issue is now closed.

Messages (5)
msg190574 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-06-04 01:12
The signature for tkinter class Variable and its subclasses StringVar, IntVar, DoubleVar, BooleanVar is
  def __init__(self, master=None, value=None, name=None):
However, the None default is invalid because of
        self._tk = master.tk
The preceding lines
        if not master:
            master = _default_root
might suggest that None is acceptible. But _default_root is set to None at the top of the file, so that just replaces None with None.

If Variables must have a gui widget parent, then they cannot be used in gui-free tests, even though they have no graphic representation.

Moveover, not everything is a proper master. configSectionNameDialog.py . GetCfgSectionNameDialog(Toplevel) . Create.Widgets(self) has these lines:
        self.name = StringVar(self)
        self.fontSize = StringVar(self)
However, these are not (always) garbage collectable.

After fixing the dialog test at the bottom of the file, and running it with 3.3 python_d -m idlelib.configSectionNameDialog (#18130), and adding the gc flag, I repeatedly got
[sys:1: ResourceWarning: gc: 2 uncollectable objects at shutdown [<tkinter.StringVar object at 0x02C597E0>, <tkinter.StringVar ...]]
(This only showed when running from the console, not when running within Idle started within the interactive debug interpreter.)

Running the test multiple times within a session, by repeatedly creating new dialogs with the [dialog] button in the test window, multiplied the uncollected objects.

Replacing 'self' with 'self.parent' solved the problem, at least in the test situation.
msg228416 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2014-10-04 00:24
Just a gentle reminder.
msg228523 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-10-05 01:36
My first message discussed two different issues.  The first, generalized, is that unconditionally using tkinter._default_root, which can be either None or absent, as a backup for master=None in __init__ functions, seems a bit sloppy.  Image.__init__ does this check
        if not master:
            master = _default_root
            if not master:
                raise RuntimeError('Too early to create image')
but that will fail if _default_root has been deleted.  Also, the message is wrong in that it is not 'too early' if an explicit master is passed.  I am thinking that all uses of _default_root should raise something like WhateverError("An explicit master is required when _default_root is None or deleted.")  Serhiy, what do you think?

The second issue noted that while widgets often have a container widget as master, the non-graphics classes like Variable and Font should have a Tk and not a widget as master.  I have corrected idlelib.configHandler and there is a tkinter patch on another issue (applied yet?) to automatically replace master=widget by master-widget.tk.  So Variable calls are no longer part of this issue.
msg228557 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-10-05 10:43
> I am thinking that all uses of _default_root should raise something like
> WhateverError("An explicit master is required when _default_root is None or
> deleted.")  Serhiy, what do you think?

Technically all works (raises some exception), but I agree that error message 
can be more friendly. But _default_root is implementation detail. This name 
doesn't mean anything for non-experienced user (and experienced user already 
knows about these mystical RuntimeError and NameError). The message should say 
something like "No default root window" if _default_root is None and "The 
master argument is mandatory after calling NoDefautRoot()" if _default_root 
isn't set.

And now we came to the way how to create default root window. Issue4343 looks 
related (I haven't looked at it close however).

Second issue was fixed in issue22068.
msg383495 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-12-21 09:13
And the first issue was fixed in issue42630.
History
Date User Action Args
2020-12-21 09:13:31serhiy.storchakasetstatus: open -> closed
resolution: fixed
messages: + msg383495

stage: needs patch -> resolved
2019-04-26 17:51:51BreamoreBoysetnosy: - BreamoreBoy
2014-10-05 10:43:51serhiy.storchakasetmessages: + msg228557
2014-10-05 01:36:49terry.reedysetnosy: + serhiy.storchaka
messages: + msg228523
2014-10-04 23:27:26martin.pantersetnosy: + martin.panter
2014-10-04 00:24:43BreamoreBoysetnosy: + BreamoreBoy

messages: + msg228416
versions: + Python 3.5, - Python 3.3
2013-06-04 01:12:59terry.reedycreate