classification
Title: Ability to trace Tcl commands executed by Tkinter
Type: enhancement Stage: test needed
Components: Tkinter Versions: Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: ned.deily, serhiy.storchaka, terry.reedy
Priority: normal Keywords: patch

Created on 2016-06-28 08:06 by serhiy.storchaka, last changed 2016-09-12 09:07 by ned.deily.

Files
File name Uploaded Description Edit
tkinter_trace_tcl.patch serhiy.storchaka, 2016-06-30 21:53 review
tkinter_trace_tcl2.patch serhiy.storchaka, 2016-09-11 17:41 review
Messages (15)
msg269425 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-06-28 08:05
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?
msg269447 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-06-28 17:49
+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?
msg269626 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-06-30 20:18
I meant adding API similar to sys.settrace() for specifying a function that will be called before executing every Tcl command.
msg269631 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-06-30 21:53
Here is preliminary patch. It contains leaks, don't worry.
msg269697 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-07-01 21:20
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.
msg269699 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-07-01 21:24
You need to recompile the _tkinter module.
msg269702 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-07-01 23:02
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.
msg269745 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-07-02 23:22
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 #26765.
msg275813 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-09-11 17:41
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.
msg275983 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-09-12 07:30
The patch changes 4 non-tkinter clinic files.  Accident?  All 4 are rejected.  Will compile and test tkinter changes.
msg275988 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-09-12 08:00
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 .`menu.file -tearoff 0
.`menu add cascade -label File -menu .`menu.file -underline 0
... # menu for Shell
.`menu.file add command -label {New File} -underline 0 -command 62029624command -accelerator Ctrl+N
... # more menu - new names **really** help!!!

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 ;-).
msg275991 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-09-12 08:08
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.
msg275992 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-09-12 08:10
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.
msg276000 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-09-12 08:37
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.
msg276007 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2016-09-12 09:07
Let's target it for 3.7 and when it is ready we can discuss whether to backport it to 3.6 as well.
History
Date User Action Args
2016-09-12 09:07:07ned.deilysetmessages: + msg276007
versions: + Python 3.7, - Python 3.6
2016-09-12 08:37:41serhiy.storchakasetnosy: + ned.deily
messages: + msg276000
2016-09-12 08:10:54terry.reedysetmessages: + msg275992
2016-09-12 08:08:34terry.reedysetmessages: + msg275991
2016-09-12 08:00:25terry.reedysetmessages: + msg275988
2016-09-12 07:30:24terry.reedysetmessages: + msg275983
2016-09-11 17:41:20serhiy.storchakasetfiles: + tkinter_trace_tcl2.patch

messages: + msg275813
2016-07-02 23:22:28terry.reedysetmessages: + msg269745
2016-07-01 23:02:18terry.reedysetmessages: + msg269702
2016-07-01 21:24:54serhiy.storchakasetmessages: + msg269699
2016-07-01 21:20:01terry.reedysetassignee: serhiy.storchaka
messages: + msg269697
stage: test needed
2016-06-30 21:53:19serhiy.storchakasetfiles: + tkinter_trace_tcl.patch
keywords: + patch
messages: + msg269631
2016-06-30 20:18:19serhiy.storchakasetmessages: + msg269626
2016-06-28 17:49:51terry.reedysetmessages: + msg269447
2016-06-28 08:06:00serhiy.storchakacreate