Skip to content

tkinter.Event is not subscriptable at runtime but generic in stub file #123341

Closed

Description

@yowoda

Bug report

Bug description:

import tkinter
tkinter.Event[tkinter.Canvas] # TypeError: 'type' object is not subscriptable

This has been briefly discussed at python/typeshed#12591

It would be great if this problem (a little more detailed version here) could be fixed in the entire standard library. As of right now, the inconsistency of class subscription support is just way too confusing for developers.

CPython versions tested on:

3.8, 3.9, 3.10, 3.11, 3.12, 3.13, CPython main branch

Operating systems tested on:

Linux, Windows

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Aug 26, 2024
  2. serhiy-storchaka commented on Aug 26, 2024

    @serhiy-storchaka
    Member

    What is the meaning of tkinter.Event[tkinter.Canvas]? Why the Event class is considered generic?

  3. yowoda commented on Aug 26, 2024

    @yowoda
    ContributorAuthor

    python/typeshed#12591 (comment)

    In this case, it implies the event was caused by an interaction with the canvas

  4. serhiy-storchaka commented on Aug 27, 2024

    @serhiy-storchaka
    Member

    How do canvas events differ from others?

  5. TeamSpen210 commented on Aug 27, 2024

    @TeamSpen210

    It means that some_event.widget is specifically a tkinter.Canvas object. Even if you don't directly use that attribute, being able to annotate your event handler functions with the specific widget would allow checkers to catch passing the wrong event handler to bind().

  6. Akuli commented on Aug 27, 2024

    @Akuli
    Contributor

    You can also do e.g. event.widget.create_rectangle(...) with an event that came from a Canvas.

    To me, this is a very stable part of tkinter stubs. The genericness of Event will not change any time soon, and Event has been generic since 2020.

    (I am the typeshed maintainer who basically takes care of everything tkinter related.)

  7. Akuli commented on Aug 27, 2024

    @Akuli
    Contributor

    Older discussion about this: python/typeshed#4431

  8. serhiy-storchaka commented on Aug 27, 2024

    @serhiy-storchaka
    Member

    So this is for the widget attribute? This is not correct. widget is not always the same as the widget for which bind() was called.

    Example:

    import tkinter
    root = tkinter.Tk()
    f = tkinter.Frame(root, name='frame', width=150, height=100)
    f.pack()
    root.wait_visibility()
    root.update_idletasks()
    
    def handler(e: 'tkinter.Event[tkinter.Tk]'):
        # assert isinstance(e.widget, tkinter.Tk)
        print(e.widget)
    
    event = '<Enter>'
    assert isinstance(root, tkinter.Tk)
    root.bind(event, lambda e: print(e.widget))
    f.event_generate(event)

    The output is .frame, not .. And the commented out assert in the handler would fail.

  9. yowoda commented on Aug 27, 2024

    @yowoda
    ContributorAuthor

    Well but the event does come from tkinter.Frame so imo the correct way to type hint this is tkinter.Event[tkinter.Frame] since hovering over the frame is what causes the function to be called

  10. Akuli commented on Aug 27, 2024

    @Akuli
    Contributor

    You are using Tk.bind(), which is already typed with tkinter.Event[tkinter.Misc] (that is, an event where the widget may be of any type). The same goes for Toplevel.bind. For other widgets, event.widget is always* the same widget whose .bind() was called, and the stubs define it in that way.

    * Technically not correct. You could use a Frame as a toplevel with the wm manage command and then receive events from arbitrary widgets, as with Tk and Toplevel, but most tkinter users don't do that and tkinter wasn't written to support it very well (Frame doesn't inherit from Wm).

  11. serhiy-storchaka commented on Aug 28, 2024

    @serhiy-storchaka
    Member

    Well, you're probably right. I was not able to find example with non-toplevel widgets.

  12. added a commit that references this issue on Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions