classification
Title: Tkinter widget events become tuples
Type: behavior Stage: resolved
Components: Tkinter Versions: Python 3.7
process
Status: closed Resolution: third party
Dependencies: Superseder:
Assigned To: Nosy List: Hênio Tierra Sampaio, serhiy.storchaka, terry.reedy
Priority: normal Keywords:

Created on 2020-03-19 01:45 by Hênio Tierra Sampaio, last changed 2020-03-21 14:27 by Hênio Tierra Sampaio. This issue is now closed.

Files
File name Uploaded Description Edit
tboplayer.py Hênio Tierra Sampaio, 2020-03-19 01:45
Repositories containing patches
https://github.com/KenT2/tboplayer
Messages (4)
msg364592 - (view) Author: Hênio Tierra Sampaio (Hênio Tierra Sampaio) Date: 2020-03-19 04:04
I'm maintainer for a project for the RaspberryPi, a GUI for OMXPlayer called TBOPlayer. This GUI was originally made for Python 2, but with Python 2 deprecation, I decided to convert it to Python 3. After (supposedly) converting all of it I had a surprise to see that the events that worked in the original code with Python 2 didn't work anymore in Python 3 with errors like

    File "/home/henio/Projetos/tboplayer/lib/tboplayer.py", line 1566, in select_track
    sel = event.widget.curselection()
    AttributeError: 'tuple' object has no attribute 'widget'


And upon investigation, I noticed all the widget events (originally of type tkinter.Event) were now of type Tuple. WTF. Ok, I tried to circumvent this by using the tuple "attributes", like, in the event

    (('17685', '1', '??', '??', '??', '256', '59467466', '??', '212', '11', '??', '0', '??', '??', '.!listbox', '5', '1030', '344', '??'),)

I can access the x position of the cursor in relation to the widget by doing:

    event[0][8]

Which I did. However, I obviously cannot use any of the Event methods, and this way I cannot get the current selection from a Listbox, for example, and trying to gives me the exact error mentioned above. This renders TBOPlayer useless as the user cannot even select a track for playing.

And unfortunately, I was unable to reproduce this issue with a minimum code, so I have no idea what's going on.

This issue comment describes how to reproduce the bug inside of TBOPlyaer: https://github.com/KenT2/tboplayer/issues/175#issuecomment-600861514
msg364720 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2020-03-20 23:05
IDLE uses tkinter extensively and runs fine on 3.0 to the upcoming 3.9.  Events remain Events and event.type, event.widget, event.x, and so on continue to work as appropriate for the event type.  As far as I know, the only directly tkinter-related changes were the import names for tkinter and its subpackages.

The same has been true for countless other tkinter users. So until you or someone can produce a short example that only imports tkinter and definitely not anything outside of the stdlib, I (and I think 'we') will assume that the problem is with your code or one of the modules you import or possibly a system-specific bad compilation of tcl/tk/_tkinter.c or mangled tkinter.py.

Some notes to maybe help:
1. When reporting an exception, one should nearly always paste the complete traceback.

2. The first post-import statement in tboplayer.py monkey-patches tkinter with
  tk.CallWrapper = ExceptionCatcher
where ExceptionCatcher must be a class from one of the 3rd party * imports.

To see if one of the 3rd party modules is replacing tk.Event when imported, put 'print(Event)' after 'from tkinter import *'.  You should see "<class 'tkinter.Event'>".  If not, move the import and debug print up.  If so, put debug prints down in your code.

3. Passing non-Events (like False) as the event argument, especially when this unusually possibility is not documented.  A common idiom would be
    def select_track(event=None):
        ...
        if event is not None: ...
A reader should be able to assume that any non-None event is really an event.

Python-list, which I read, would be one good place for any further discussion.
msg364736 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-03-21 10:26
The problem is in ExceptionCatcher. It uses builtin function apply() which was outdated even in Python 2.7 and was removed in Python 3 (instead of apply(func, args) you can use func(*args)). So that code always failed, but all exceptions were logged and suppressed. You may see it in your logs at the start of the application.
msg364751 - (view) Author: Hênio Tierra Sampaio (Hênio Tierra Sampaio) Date: 2020-03-21 14:27
Yes, you guys were right. I solved the problem by writing a new, simpler debugging class. I'm sorry for taking your time! Thank you!
History
Date User Action Args
2020-03-21 14:27:32Hênio Tierra Sampaiosetmessages: + msg364751
2020-03-21 10:26:18serhiy.storchakasetmessages: + msg364736
2020-03-20 23:05:05terry.reedysetstatus: open -> closed
title: Tkinter widget events are of type Tuple -> Tkinter widget events become tuples
nosy: + terry.reedy, - gpolo
messages: + msg364720

resolution: third party
stage: resolved
2020-03-20 08:27:45ned.deilysetnosy: + gpolo, serhiy.storchaka
type: crash -> behavior
2020-03-20 08:27:02ned.deilysetmessages: - msg364593
2020-03-20 08:26:52ned.deilysetmessages: - msg364586
2020-03-19 04:09:41Hênio Tierra Sampaiosetmessages: + msg364593
2020-03-19 04:04:24Hênio Tierra Sampaiosetmessages: + msg364592
2020-03-19 01:52:32Hênio Tierra Sampaiosettitle: Widget events are of type Tuple -> Tkinter widget events are of type Tuple
2020-03-19 01:45:57Hênio Tierra Sampaiocreate