Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tkinter: Canvas().keys returns empty strings. #70365

Closed
terryjreedy opened this issue Jan 22, 2016 · 6 comments
Closed

tkinter: Canvas().keys returns empty strings. #70365

terryjreedy opened this issue Jan 22, 2016 · 6 comments
Assignees
Labels
stdlib Python modules in the Lib dir topic-tkinter type-bug An unexpected behavior, bug, or error

Comments

@terryjreedy
Copy link
Member

BPO 26177
Nosy @terryjreedy, @serhiy-storchaka
Files
  • tkinter_keys.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/serhiy-storchaka'
    closed_at = <Date 2016-03-09.08:55:11.946>
    created_at = <Date 2016-01-22.06:51:29.409>
    labels = ['expert-tkinter', 'type-bug', 'library']
    title = 'tkinter: Canvas().keys returns empty strings.'
    updated_at = <Date 2016-03-09.08:55:11.946>
    user = 'https://github.com/terryjreedy'

    bugs.python.org fields:

    activity = <Date 2016-03-09.08:55:11.946>
    actor = 'serhiy.storchaka'
    assignee = 'serhiy.storchaka'
    closed = True
    closed_date = <Date 2016-03-09.08:55:11.946>
    closer = 'serhiy.storchaka'
    components = ['Library (Lib)', 'Tkinter']
    creation = <Date 2016-01-22.06:51:29.409>
    creator = 'terry.reedy'
    dependencies = []
    files = ['41686']
    hgrepos = []
    issue_num = 26177
    keywords = ['patch']
    message_count = 6.0
    messages = ['258789', '258790', '258791', '258843', '258856', '261407']
    nosy_count = 3.0
    nosy_names = ['terry.reedy', 'python-dev', 'serhiy.storchaka']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue26177'
    versions = ['Python 2.7', 'Python 3.5', 'Python 3.6']

    @terryjreedy
    Copy link
    Member Author

    tkinter wraps tk widgets as option-value mappings with subscripting and .keys(). The latter does not work for Canvas (subscripting does). First tested with 3.5.1, Win 10. First Text versus Canvas contrast below was confirmed with 2.7.11.

    >>> import tkinter as tk
    >>> tk.Text().keys()
    ['autoseparators', 'background', 'bd', 'bg', 'blockcursor', 'tabstyle', 
    ...
    'takefocus', 'undo', 'width', 'wrap', 'xscrollcommand', 'yscrollcommand']
    >>> tk.Canvas().keys()
    ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

    Explanation: Widget classes inherit keys from Misc via BaseWidget and Widget. Misc.keys calls into tk.

        def keys(self):
            """Return a list of all resource names of this widget."""
            return [x[0][1:] for x in
                    self.tk.splitlist(self.tk.call(self._w, 'configure'))]

    The call returns different types for Text and Canvas.

    >>> self = tk.Text()
    >>> self.tk.call(self._w, 'configure')  # tuple of tuples
    (('-autoseparators', 'autoSeparators', 'AutoSeparators', 1, 1),
     ('-background', 'background', 'Background', <border object: 'SystemWindow'>, 'SystemWindow'), <etc>)
    >>> self = tk.Canvas()
    >>> self.tk.call(self._w, 'configure')  # tcl list as single string
    '{-background background Background SystemButtonFace SystemButtonFace} {-bd borderWidth} {-bg background} {-borderwidth borderWidth BorderWidth 0 0} ...'

    This difference between widgets seems odd. A bug in tcl/tk/_tkinter?

    tk.splitlist appears to return the Text tuple of tuples as is. It splits the Canvas string into a tuple of strings

    ('-background background Background SystemButtonFace SystemButtonFace', '-bd borderWidth', ... )

    but does not split the inner strings. As a consequence, x[0] is the first character of each string ('{' as it turns out, though not relevant) and the slice [1:] of a single char string is always ''.

    Possible remedy: tk.split also leaves tuple of tuples alone *and* splits the inner strings to a tuple.

    >>> self.tk.split(self.tk.call(self._w, 'configure'))
    (('-background', 'background', 'Background', 'SystemButtonFace', 'red'), ('-bd', 'borderWidth'), ...)

    So a fix (if the different returns are not changed) is to change 'splitlines' to 'split'. With this change, keys (extracted as a function) gives the expected list.

    >>> keys(tk.Canvas())
    ['background', 'bd', ..., 'yscrollincrement']

    A test for Canvas().keys should be added somewhere.

    @terryjreedy terryjreedy added the type-bug An unexpected behavior, bug, or error label Jan 22, 2016
    @terryjreedy
    Copy link
    Member Author

    Bug came from https://stackoverflow.com/questions/34911069/tk-canvas-options-keys-list-empy. Bryan Oakley answered that tk.Canvas().configure().keys() does work, making sorted(x.configure.keys()) a replacement for x.keys that should work for all widgets.

    @serhiy-storchaka serhiy-storchaka self-assigned this Jan 22, 2016
    @serhiy-storchaka
    Copy link
    Member

    split() has many warts, it shouldn't be used. It is enough just call splitlist() for elements of a list.

    Proposed patch fixes Misc.keys(). It also adds tests for missed options (some of them are not explicitly documented).

    @serhiy-storchaka serhiy-storchaka added stdlib Python modules in the Lib dir topic-tkinter labels Jan 22, 2016
    @terryjreedy
    Copy link
    Member Author

    With patch applied to 3.5, tk.Canvas().keys() works and test_tk and other three files pass with -ugui.

    Is avoiding splitlist calls when not needed worthwhile? Tests also pass with

        def keys(self):
            """Return a list of all resource names of this widget."""
            config = self.tk.call(self._w, 'configure')
            if type(config) == tuple:
                return [x[0][1:] for x in config]
            else:  # str
                splitlist = self.tk.splitlist
                return [splitlist(x)[0][1:] for x in
                    splitlist(config)]

    I am a bit curious why Canvas gives a different return. Is the special casing in _tkinter or tk itself? Otherwise, looks good to me.

    @serhiy-storchaka
    Copy link
    Member

    Is avoiding splitlist calls when not needed worthwhile?

    We can't guarantee that future release of Tk wouldn't return a list of strings. Calling splitlist() for a tuple is cheap (but looks cumbersome).

    I am a bit curious why Canvas gives a different return. Is the special casing in _tkinter or tk itself?

    Tk is full of such inconsistencies. A result for one widget can be a list of numbers, but for other it is a list of strings or a list of special Tcl objects. One method can return empty list, other returns empty string. One widgets truncate floating point parameters, others round them up or down.

    I'll commit the patch after testing with Tk 8.5 and 8.4.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Mar 9, 2016

    New changeset d86891dee68a by Serhiy Storchaka in branch '3.5':
    Issue bpo-26177: Fixed the keys() method for Canvas and Scrollbar widgets.
    https://hg.python.org/cpython/rev/d86891dee68a

    New changeset f0c895fb0374 by Serhiy Storchaka in branch '2.7':
    Issue bpo-26177: Fixed the keys() method for Canvas and Scrollbar widgets.
    https://hg.python.org/cpython/rev/f0c895fb0374

    New changeset 3a0bc2efed26 by Serhiy Storchaka in branch 'default':
    Issue bpo-26177: Fixed the keys() method for Canvas and Scrollbar widgets.
    https://hg.python.org/cpython/rev/3a0bc2efed26

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir topic-tkinter type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants