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 sliently discards all backgrond Tcl errors #37486

Closed
idiscovery mannequin opened this issue Nov 16, 2002 · 18 comments
Closed

Tkinter sliently discards all backgrond Tcl errors #37486

idiscovery mannequin opened this issue Nov 16, 2002 · 18 comments

Comments

@idiscovery
Copy link
Mannequin

idiscovery mannequin commented Nov 16, 2002

BPO 639266
Nosy @loewis

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 = None
closed_at = None
created_at = <Date 2002-11-16.07:35:48.000>
labels = ['expert-tkinter']
title = 'Tkinter sliently discards all backgrond Tcl errors'
updated_at = <Date 2014-02-03.17:14:10.789>
user = 'https://bugs.python.org/idiscovery'

bugs.python.org fields:

activity = <Date 2014-02-03.17:14:10.789>
actor = 'BreamoreBoy'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Tkinter']
creation = <Date 2002-11-16.07:35:48.000>
creator = 'idiscovery'
dependencies = []
files = []
hgrepos = []
issue_num = 639266
keywords = []
message_count = 17.0
messages = ['60278', '60279', '60280', '60281', '60282', '60283', '60284', '60285', '60286', '60287', '60288', '60289', '60290', '60291', '60292', '75162', '114188']
nosy_count = 4.0
nosy_names = ['loewis', 'jepler', 'idiscovery', 'gpolo']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue639266'
versions = []

@idiscovery
Copy link
Mannequin Author

idiscovery mannequin commented Nov 16, 2002

Tkinter silently discards all Tcl errors. Athough this may make Tkinter programs
appear robust, it violates the fundamental principle that erros should be raised
and dealt with.

In Tkinter.py is the line

        self.tk.createcommand('tkerror', _tkerror)

where _tkerror is defined as

def _tkerror(err):
    """Internal function."""
    pass

This disables all uses of the tcl procedure bgerror from signalling
background errors to the user, including I assume any errors
generated in after_idle.

@loewis
Copy link
Mannequin

loewis mannequin commented Nov 16, 2002

Logged In: YES
user_id=21627

The qualification "silently discards all Tcl errors" is definitely
incorrect:

>>> Tkinter.Label(foo="bar")
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in ?
    Tkinter.Label(foo="bar")
  File "E:\Python22\lib\lib-tk\Tkinter.py", line 2261, in __init__
    Widget.__init__(self, master, 'label', cnf, kw)
  File "E:\Python22\lib\lib-tk\Tkinter.py", line 1756, in __init__
    self.tk.call(
TclError: unknown option "-foo"

Instead, it would be more correct to say that all background
errors are discarded.

Can you provide a script that demonstrates this problem?
(i.e. one which behaves differently if the createcommand is
removed from Tkinter.py)

Can you propose a solution for this problem? Please take
into account that Tkinter behaved that way since the
beginning, so any change must take backwards compatibility
into account.

@jepler
Copy link
Mannequin

jepler mannequin commented Nov 17, 2002

Logged In: YES
user_id=2772

You could create a subclass of Tk that creates a different
'tkerror' command.

Anyway, CallWrapper (used when a function is passed to
functions like .after_idle()) calls
widget._report_exception, which calls
Tk.report_callback_exception. So you can override this
function too.

Neither of these things require changing Tkinter.py.

I don't seem to be permitted to attach a file, so I'm forced
to paste the code.

import Tkinter as _Tkinter

class Tk(_Tkinter.Tk):
    def __init__(self, *args, **kw):
        _Tkinter.Tk.__init__(self, *args, **kw)
        self.tk.createcommand('tkerror', self.tkerror)

    def report_callback_exception(self, exc, val, tb):
        print "callback exception", exc

    def tkerror(self, *args):
        print "tkerror", args

if __name__ == '__main__':
    w = Tk()
    w.after_idle(lambda: 1/0)
    _Tkinter.Button(w, command="expr 1/0").pack()
    w.mainloop()

@idiscovery
Copy link
Mannequin Author

idiscovery mannequin commented Nov 17, 2002

Logged In: YES
user_id=33229

But why is Tkinter silencing all Tk (Tcl or Python) errors in the first place?

I know I can subclass Tk, but _tkerror is clearly billed as an internal function,
and the only purpose of it is to disable Tcl's bgerror reporting. This lets
serious bugs go undetected.

@loewis
Copy link
Mannequin

loewis mannequin commented Nov 17, 2002

Logged In: YES
user_id=21627

It is not the case that Tkinter silently discards all Python
errors. In fact, I believe it never discards any Python
error silently. Can you provide an example that demonstrates
otherwise?

@idiscovery
Copy link
Mannequin Author

idiscovery mannequin commented Nov 19, 2002

Logged In: YES
user_id=33229

That's right: Tkinter silently discards all background Tcl
errors.

All errors from Tcl are silenced by def _tkerror(err): pass
So Tkinter users will never see any errors that come from
any bugs in Tcl, Tk or its extensions, including of course
errors that may only show up under Python.

The proposed solution for this problem is simply to
remove the createcomand / def _tkerror. I see no possible
reason for it to be in there, and it violates the
fundamental principle that errors should be raised and dealt
with.

Although Tkinter behaved that way since the beginning, the
change takes backwards compatibility into account because
it serves no good purpose that I know of to begin with. At
worst buried bugs will become visible and can be dealt with.

@loewis
Copy link
Mannequin

loewis mannequin commented Nov 19, 2002

Logged In: YES
user_id=21627

idiscovery, I still would like to see an example that
demonstrates that problem.

@idiscovery
Copy link
Mannequin Author

idiscovery mannequin commented Dec 11, 2002

Logged In: YES
user_id=33229

What possible reason can you give to ever drop errors silently?

One example is in the Python distribution that I asked you about
over a year ago: Demo/tix/tixwidgets.py

@loewis
Copy link
Mannequin

loewis mannequin commented Dec 11, 2002

Logged In: YES
user_id=21627

It's a basic engineering principle: Don't apply changes that
you haven't fully understood. I still don't believe this
problem could ever happen, and therefore, I still assume
that Tkinter does *not*, actually, drop any errors, even
though the code looks like it does.

However, my believes should be irrelevant if you can
demonstrate the problem.

@jepler
Copy link
Mannequin

jepler mannequin commented Dec 11, 2002

Logged In: YES
user_id=2772

Here's an example of the type of error which is discarded by
Tkinter._tkerror:

from Tkinter import Button
b = Button(command="expr 1/0")
b.pack()
b.mainloop()

When "b" is pressed, "expr" will produce an "Error: divide
by zero", and the equivalent wish app will show the bgerror
dialog. But replaces the normal bgerror handler with one
that discards the error, doing nothing.

Of course, I've pointed out in an earlier comment how
idiscovery can subclass Tk to handle this kind of error.

@loewis
Copy link
Mannequin

loewis mannequin commented Dec 11, 2002

Logged In: YES
user_id=21627

Thanks for the example. Is this the case that this can only
trigger by bugs in Tcl scripts which aren't produced by Tkinter?

@jepler
Copy link
Mannequin

jepler mannequin commented Dec 11, 2002

Logged In: YES
user_id=2772

As far as I can tell, the only way _tkerror can discard an
error is if it happens in an event-driven way (fired as a
-command, from a binding, or from "after") and the code in
question is pure tcl code.

So, for instance, in
b = Button(command = lambda: 1/0)
the error is reported by
Tkinter.Tk.report_callback_exception. So is

@jepler
Copy link
Mannequin

jepler mannequin commented Dec 11, 2002

Logged In: YES
user_id=2772

As far as I can tell, the only way _tkerror can discard an
error is if it happens in an event-driven way (fired as a
-command, from a binding, or from "after") and the code in
question is pure tcl code.

So, for instance, in
b = Button(command = lambda: 1/0)
the error is reported by
Tkinter.Tk.report_callback_exception. So is
b = Button(); b.configure(command=lambda:
b.tk.call("expr", "1/0"))

@idiscovery
Copy link
Mannequin Author

idiscovery mannequin commented Dec 15, 2002

Logged In: YES
user_id=33229

It's a basic computer engineering principle not to ignore errors
silently, and no one has given any reason, good or otherwise,
as to why this code should be in there.

To not believe this problem could ever happen is to assume that
there are never side effects in Tcl from Tkinter.

For an example of where a bug has been obscured by this,
comment out the line self.tk.createcommand('tkerror', _tkerror)
in Tkinter.py and run Demo/tix/tixwidgets.py Click on the
ComboBox in the ExFileSelectBox demo. The popdown scrolled
list widget is being created, then destroyed.

Martin I don't know how you could still assume
that Tkinter does *not*, actually, drop any errors
when you checked in the description of the bug
over a year ago: Demo/tix/tixwidgets/BUGS.txt
$Id: BUGS.txt,v 1.1 2001/03/21 07:42:07 loewis Exp $

@loewis
Copy link
Mannequin

loewis mannequin commented Dec 15, 2002

Logged In: YES
user_id=21627

The comment in BUGS.txt is too mysterious to make any sense
to me. It basically says "it appears there is some problem,
let me know if you understand it". This was fine as it
stands, but it didn't say "this is because there is a Tcl
error that is dropped by Python", and so far, you haven't
indicated that this is indeed the problem.

Uncommenting the line, I get tons of "bad window path name"
and "invalid command name" messages when running
tixwidgets.py. This tells me that
a) this might happen quite frequently in real life, and
b) the user of the Python application can do nothing about
it, they can't even disable the first message (it then asks
whether further messages should be skipped)

I don't feel privileged to approve a change here; you should
bring this up on python-dev. My feeling is that the Tcl
error message is too annoying to just remove the tkerror
command; printing the message to stderr might be acceptable.

@gpolo
Copy link
Mannequin

gpolo mannequin commented Oct 24, 2008

Uhm, long time without discussion but I'm hoping someone interested may
read this.

You have to provide a "bgerror" command to Tcl, so it will get invoked
when a background error happens. Either _tkinter.c could create one for
an interpreter is created or Tkinter.py could create one when a Tk
instance is created. The command will be invoked with a single argument,
the background error message.

If you want to play with it:

import Tkinter

def bgerr_handler(msg):
    print msg, "<<"

root = Tkinter.Tk()
root.tk.createcommand("bgerror", bgerr_handler)
btn = Tkinter.Button(command="expr 1/0")
btn.pack()
root.mainloop()

To get some form of traceback you would need to play with inspect and
traceback modules. But in both cases (in the example above and using
inspect) an exception isn't raised at all, and if you try raising then
Tcl will think the bgerror handler failed and will tell you that. For
this reason I would prefer to leave to _tkinter.c to handle this.

@BreamoreBoy
Copy link
Mannequin

BreamoreBoy mannequin commented Aug 17, 2010

@guilherme I take it that you're still interested in this?

@BreamoreBoy BreamoreBoy mannequin changed the title Tkinter sliently discards all Tcl errors Tkinter sliently discards all backgrond Tcl errors May 25, 2013
@BreamoreBoy BreamoreBoy mannequin changed the title Tkinter sliently discards all Tcl errors Tkinter sliently discards all backgrond Tcl errors May 25, 2013
@ezio-melotti ezio-melotti transferred this issue from another repository Apr 9, 2022
@iritkatriel
Copy link
Member

This is now 20 years old and there was no agreement on the problem. If there is a problem to fix, it will be raised again.

@iritkatriel iritkatriel closed this as not planned Won't fix, can't repro, duplicate, stale Oct 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant