Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tkinter woes when porting 2.x code to 3.x, 'tkinter' module attribute doesn't exist

UPDATED: SEE BELOW

I've been porting the code for this assignment: http://www.stanford.edu/class/cs221/progAssignments/PA1/search.html (the entire source code is available as zip from there) from Python 2.x to 3.x. Note, porting is not the assignment, that's just me trying to keep the code up to date and avoiding installing another version of Python...

After the usual 2.x -> 3.x syntax fixes (printing, exception raising, etc), and realizing that the module Tkinter is now known as tkinter in 3.x (lower-case), I've run into stranger problems, with this snippet and several others like it:

def keys_pressed(d_o_e=tkinter.tkinter.dooneevent,d_w=tkinter.tkinter.DONT_WAIT)

The errors are of the type:

AttributeError: 'module' object has no attribute 'tkinter'

Code completion in my IDE and the variable trace indeed seems to indicate that the tkinter module has no attribute or sub-class tkinter under which one might refer to dooneevent or DONT_WAIT. However, there are a few other references on the Internet of people using constructs like

_tkinter.dooneevent(_tkinter.DONT_WAIT)

to move the main loop ahead, but even referencing it like that still yields the same error.

Any ideas greatly appreciated.


UPDATE: Referring to the _root_window via lambda notation seems to work, as in it no longer complains pre-execution time in the majority of cases. To my untrained eye however, this is basically "magic", and as such I have little idea what this subsequent error is saying or how to work around it. The method now looks like this, with my changes in the first line:

def move_to(object, x, y=None, d_o_e=lambda arg: _root_window(arg), d_w=tkinter._tkinter.DONT_WAIT):
    if y is None:
        try: x, y = x
        except: raise  'incomprehensible coordinates'

    horiz = True
    newCoords = []
    current_x, current_y = _canvas.coords(object)[0:2] # first point
    for coord in  _canvas.coords(object):
      if horiz:
        inc = x - current_x
      else:
        inc = y - current_y
      horiz = not horiz

      newCoords.append(coord + inc)

    _canvas.coords(object, *newCoords)
    d_o_e(d_w)

and the error I get is:

TypeError: 'Tk' object is not callable              

referencing the line where the method is defined (first line above).

like image 481
Mikael Avatar asked Oct 10 '11 14:10

Mikael


1 Answers

It appears Tkinter.tkinter was changed to tkinter._tkinter in Python 3. Compare these docs from Python 2 with these from Python 3. Also, dooneevent is no longer in tkinter._tkinter, but is still a member of the Tk (aka root) object.

So change your code to

def keys_pressed(d_o_e=lambda arg: _root_window.dooneevent(arg),
        d_w=tkinter._tkinter.DONT_WAIT):

This takes advantage of the fact that in your linked code _root_window is global, so while _root_window is not available when the class is defined, it will be available when the lambda is run.

like image 176
Steven Rumbalski Avatar answered Sep 27 '22 23:09

Steven Rumbalski