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
Ability to trace Tcl commands executed by Tkinter #71592
Comments
For debugging purpose it would be helpful to have an ability to show all Tcl commands executed by Tkinter. In particular it would be helpful for testing wherever some issue is Tkinter issue or Tcl/Tk issue. I'm working on a patch, but there is a design question about an interface. In simplest case you set the debug property of Tk instance to True and all Tcl commands are printed to stdout or stderr in the form ready for executing with Tcl/Tk interpreter. You also can set the module global tkinter.debug to True, and this will affect all new Tk instances (as with tkinter.wantobjects). But maybe there is a need in larger customization? For example specifying the command that accepts every Tcl command as a string or a tuple? |
+1 for at least a simple interface: tkinter/root.debug = True. Let's do at least that much. I don't understand what you propose in the last sentence, do you mean 'add a new function that accepts any tcl command, as string or tuple'? Or add better access to the existing call function? Or does the existing call function have limitations I do not not know about? |
I meant adding API similar to sys.settrace() for specifying a function that will be called before executing every Tcl command. |
Here is preliminary patch. It contains leaks, don't worry. |
In "debug = False+1', I presume the '+1' is just temporary. The debug property and the clinic file refer to _tkinter.tkapp.get/settrace, which do not exist. Did you just forget to include that part? Or does 'preliminary' mean 'do not test yet'? >>> import tkinter
>>> tkinter.debug
1
>>> import idlelib.idle
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "F:\Python\dev\36\lib\idlelib\idle.py", line 11, in <module>
idlelib.pyshell.main()
File "F:\Python\dev\36\lib\idlelib\pyshell.py", line 1553, in main
root = Tk(className="Idle")
File "F:\Python\dev\36\lib\tkinter\__init__.py", line 2018, in __init__
self.debug = debug
File "F:\Python\dev\36\lib\tkinter\__init__.py", line 2110, in debug
self.tk.settrace(trace)
AttributeError: '_tkinter.tkapp' object has no attribute 'settrace' At least the error shows that the code works as far as written ;-). I now understand 'larger customization ...' to mean supplying a trace function other than the default, to do something with 'cmd' other than just print it. For instance, one could record tcl commands in a file and later count the tcl function calls, much like python's trace does. To do that, I believe you could just replace 'def trace ... with if iscallable(value):
trace = value
else:
def trace ... +1 on adding this. The default trace would be useful for simple interaction, but less so for what I tried to do above, which is to trace a complete IDLE session. |
You need to recompile the _tkinter module. |
I just noticed that the patch includes a patch to _tkinter.c, which however, does not show up on the Rietveld dashboad, where I first reviewed it. Sorry for the mistaken comment. |
After re-compiling, import tkinter crashed 3.6. Reversion did not help. After trying to update VS2015 (not successfully), and doing a binary search, it was your patch for bpo-26765. |
Here is more mature patch. Now you can set tracing function with the tkinter.Tk.settrace() method. Tracing function takes the single argument -- a tuple containing the command and arguments. If set global tkinter.debug to True, the tracing function of newly created Tk object will be set to tkinter.print_command that prints the command to stdout. |
The patch changes 4 non-tkinter clinic files. Accident? All 4 are rejected. Will compile and test tkinter changes. |
Much better. I can more or less follow IDLE startup.
>>> import tkinter
>>> tkinter.debug
False
>>> tkinter.debug = True
>>> import idlelib.idle
proc tkerror {} {<function _tkerror at 0x038479F8>}
proc exit {} {<function _exit at 0x03847A58>}
proc 27305592destroy {} {<bound method CallWrapper.__call__ of <tkinter.CallWrapper object at 0x04033658>>}
wm protocol . WM_DELETE_WINDOW 27305592destroy
wm withdraw .
wm iconbitmap . -default F:\\Python\\dev\\36\\lib\\idlelib\\Icons\\idle.ico
tcl_wordBreakAfter {a b} 0
set tcl_wordchars [a-zA-Z0-9_]
set tcl_nonwordchars [^a-zA-Z0-9_]
tk windowingsystem
menu .`menu
toplevel .`listedtoplevel -menu .`menu
wm iconname . None
wm iconname .`listedtoplevel {}
wm title . None
wm title .`listedtoplevel idle
...
proc 67104888handler {} {<bound method CallWrapper.__call__ of <tkinter.CallWrapper object at 0x05727690>>}
bind .`listedtoplevel.`frame.text <Control-KeyPress> if\ \{"[67104888handler\ %#\ %b\ %f\ %h\ %k\ %s\ %t\ %w\ %x\ %y\ %A\ %E\ %K\ %N\ %W\ %T\ %X\ %Y\ %D]"\ ==\ "break"\}\ break\
... # lots of above, binding for Shell window. Default print is noisy.
# I presume a custom handler that recognizes 'proc' could be better. menu . Will ...settrace(None)? Aside from that, I would like to see this in 3.6. (ie, applied now, upgraded later, if definitely safe). (Note: 4AM here, so this is best I can review now ;-). |
I ran idle and tcl/tk/ttk tests. all pass with and without patch. text_tcl before and with patch ends with warning: Windows fatal exception: access violation. I have seen this for perhaps a couple of weeks (check windows buildbot), but not forever. You should probably try to fix. |
If not in 3.6, I can still apply patch from shelf, recompile, use for awhile, re-shelve, recompile. So not tragedy if miss deadline. |
This feature is useful first at all for us, core developers. I think we could add it with provisional status in the beta stage or wait to 3.7. In any case the documentation and tests are not ready yet. |
Let's target it for 3.7 and when it is ready we can discuss whether to backport it to 3.6 as well. |
Seems like this didn't make 3.7. Would it be good to make a PR targeting 3.8? |
It is an experimental feature, for internal use. Setting tkinter._debug = True before creating the root window enables printing every executed Tcl command (or a Tcl command equivalent to the used Tcl C API). It will help to convert a Tkinter example into Tcl script to check whether the issue is caused by Tkinter or exists in the underlying Tcl/Tk library.
It stuck for a long time because I was hesitant about the user interface. But every time I investigate a problem, I regret that this feature was not added. So I decided to add it as a private feature for our internal use. When we have some experience, we can add a public interface. For the same reason, it is better to backport it. |
…18291) This is an experimental feature, for internal use. Setting tkinter._debug = True before creating the root window enables printing every executed Tcl command (or a Tcl command equivalent to the used Tcl C API). This will help to convert a Tkinter example into Tcl script to check whether the issue is caused by Tkinter or exists in the underlying Tcl/Tk library.
…Tkinter (pythonGH-118291) This is an experimental feature, for internal use. Setting tkinter._debug = True before creating the root window enables printing every executed Tcl command (or a Tcl command equivalent to the used Tcl C API). This will help to convert a Tkinter example into Tcl script to check whether the issue is caused by Tkinter or exists in the underlying Tcl/Tk library. (cherry picked from commit 1ff626e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
GH-118291) (GH-118662) This is an experimental feature, for internal use. Setting tkinter._debug = True before creating the root window enables printing every executed Tcl command (or a Tcl command equivalent to the used Tcl C API). This will help to convert a Tkinter example into Tcl script to check whether the issue is caused by Tkinter or exists in the underlying Tcl/Tk library. (cherry picked from commit 1ff626e) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
The merged interface: set tkinter._debug = True before creating the root window sets tracing (l.2454) with tkinter._print_command (l.5=2543), which prints every executed Tcl command . Creating a branch and setting _debug at the top of pyshell.py and running
I successfully stopped the loop with ctrl-C. To use this with IDLE, to see for instance the calls resulting from a particular post-startup action, a custom Sorry I did not review earlier. |
I made sure that all Tkinter and IDLE tests are passed when run with |
…pythonGH-118291) This is an experimental feature, for internal use. Setting tkinter._debug = True before creating the root window enables printing every executed Tcl command (or a Tcl command equivalent to the used Tcl C API). This will help to convert a Tkinter example into Tcl script to check whether the issue is caused by Tkinter or exists in the underlying Tcl/Tk library.
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:
bugs.python.org fields:
Linked PRs
The text was updated successfully, but these errors were encountered: