I am using Wing to write and debug a Tkinter GUI. I am finding that the Stack Data View doesn't seem to match the actual attributes of my widgets. Take this code for example:
import Tkinter
import ttk
root = Tkinter.Tk()
checkbutton = ttk.Checkbutton(root, text="Test Check Button")
print checkbutton.text
This gives me an attribute error at the last line. However, when I look at the stack, there is clearly an attribute called 'text' with the value that I'm looking for:
Anyone know what's going on?
I'm using:
Wing version: Wing IDE Pro 5.1.3-1 (rev 33002)
Tkinter version: '$Revision: 81008 $'
Python version: 2.7.10
I posted this to the Wing email list, and I got the following response from the developers:
It looks like a ttk.Checkbutton defines keys() and __getitem__()
methods to exposes tk attributes via checkbutton[<name>]. Because
of the keys() and __getitem__(), Wing is displaying the instance
as if it were a dictionary, with the keys and values interspersed with
the attributes. Wing does this because often you want to view an
object that defines keys() and __getitem__() as if it were a
dictionary, but I agree that it's confusing in this instance.
We'll try to improve this in a future release.
What you are calling attributes are not object attributes. Widgets use an internal system for managing the widget options. .text is not an attribute, which is why you get the error. To reference the configuration use .cget(...) to get the value and .configure(...) to change the value.
Related
I'm wanting to go through a list of objects so that my PyCharm IDE knows what type each list item is:
For example, say I know that each item in a list is an class instance of type 'myClass' - how do I use this to cast my objects so that my ide can help with code completion?
for i in range(len(myList)):
myClass(myList[i]).myClassProperty .....
I know how to do it in Delphi (something like the above) but not in python.
Thanks
In PyCharm, you can use Type Hinting:
class Bar:
def __init__(self,bar):
self.bar = bar
def do_bar(self):
return self.bar
def foo(x):
for el in x: # type: Bar
el.do_bar()
bars = [Bar('hello'), Bar('World')]
foo(bars)
You can't get code completion similar to Java or C++ in dynamically typed, interpreted language.There is no casting, because you don't need it in python. A function works for a given object if it has needed methods implemented, type is irrelevant to the language at this point. It is good practice though to leave some runtime checks using isinstance, if you expect your argument to be e.g. a dict. Otherwise you will end up with many difficult bugs.
As for code completion in python there are two solutions I find useful. The best IDEs around here are probably PyCharm https://www.jetbrains.com/pycharm/ and PyDev the Eclipse Plugin http://www.pydev.org/manual_101_install.html. They provide some code completion.
The other is interactive console Jupyter http://jupyter.org/. As you write your code, you could execute it in chunks (cells) and easily see object methods or fields, using not the type information, but the object itself existing in memory. This is very good for data analysis or playing with framework you don't know well.
I am trying to debug a python application using pudb, everything is fine and good except that it's not displaying the instance variables (which we access with self.xxx). It just displays 1 variable called self. And it's of the original class type.
Even if I tell it to show after calling str(self), it still only displays the object information.
If you see the code has created many variables like self.parser, self.groups and I am not able to view/inspect any of them.
Is there a way to view all the instance variables of the current class while debugging using pudb?
This is the expected behaviour, and has nothing to do with your debugger: you only have one name, self.
To see its contents you can use dir(self).
See inspect complex variable in python debugger, like pudb
The short way: Highlight the variable and press backslash \ to toggle between the "Expanded" view of a variable in the variable inspection panel.
In this case we would just highlight self, and press \, which is just the Python variable representing the instance of the class.
Alternatively, press ENTER to open the "Variable Inspection Options" menu where at the bottom you can see the "Expanded" option.
I was implementing a ttk progress bar yesterday and saw some code that I didn't quite understand.
A maximum value can be set for a progress bar by using something like the following:
progress_bar["maximum"] = max
I was expecting the ttk Progressbar object would use an instance variable to track the maximum value for a created object, but that syntax would look more like:
progres_bar.maximum = max
So my question is, what exactly is happening with the bracketed syntax here, what's the terminology, and where can I read more on this? When I looked at the Progressbar class, all I saw was
class Progressbar(Widget):
"""Ttk Progressbar widget shows the status of a long-running
operation. They can operate in two modes: determinate mode shows the
amount completed relative to the total amount of work to be done, and
indeterminate mode provides an animated display to let the user know
that something is happening."""
def __init__(self, master=None, **kw):
"""Construct a Ttk Progressbar with parent master.
STANDARD OPTIONS
class, cursor, style, takefocus
WIDGET-SPECIFIC OPTIONS
orient, length, mode, maximum, value, variable, phase
"""
Widget.__init__(self, master, "ttk::progressbar", kw)
I see there's a "widget-specifc option", but I don't understand how progress_bar["maximum"] = max sets that value, or how it's stored.
What is happening is that the ttk module is a thin wrapper around a tcl interpreter with the tk package installed. Tcl/tk has no concept of python classes.
In tcl/tk, the way to set an attribute is with a function call. For example, to set the maximum attribute, you would do something like this:
.progress_bar configure -maximum 100
The ttk wrapper is very similar:
progress_bar.configure(maximum=100)
For a reason only known to the original tkinter developers, they decided to implement a dictionary interface that allows you to use bracket notation. Maybe they thought it was more pythonic? For example:
progress_bar["maximum"] = 100
Almost certainly, the reason they didn't make these attributes of the object (eg: progress_bar.maximum = 100) is because some tcl/tk widget attributes would clash with python reserved words or standard attributes (for example, id). By using a dictionary they avoid such clashes.
Widget extends Tkinter.Widget extends BaseWidget extends Misc which contains:
__getitem__ = cget
def __setitem__(self, key, value):
self.configure({key: value})
You can find this in your Python's library folder; search for Tkinter.py
This is the code which implement the dict interface. There is no implementation for attribute access which would use __getattr__() and __setattr__().
As to why the Tk guys went this way? It's hard to say. Tk integration in Python is pretty old. Or the people felt that __getattr__() with its quirks would cause more trouble.
I have an instance of a ttkcalendar object, "cal". When I bind a button click to cal, the function called only executes if I click in the corners of the ttcalendar frame; when I click on the actual calendar area, while the ttkcalendar functions execute, my bind does not.
This code runs when I click Frame corners
# Calendar Frame
self.cal=Calendar(LeftFrame)
self.cal.pack(side=TOP)
self.cal.bind("<Button-1>",self.clicked)
I thought that if I try to bind to the canvas object of the calendar it would work. However this code returns AttributeError: Calendar instance has no attribute canvas.
# Calendar Frame
self.cal=Calendar(LeftFrame)
self.cal.pack(side=TOP)
self.cal.canvas.bind("<Button-1>",self.clicked)
As I said, internal ttkcalendar binds work fine for switching date shown. Any insights? Thanks
The error message should be pretty clear. If python is telling you "AttributeError: Calendar instance has no attribute canvas", you must assume that to be true.
Looking at the source code of the Calendar class, I don't see any canvas attribute. Just like the error is telling you, you're trying to access an attribute that doesn't exist.
The Calendar class does have an attribute named _canvas, maybe you can try using that instead. Though, that leading underscore denotes that it is intended as a private attribute and may go away in future revisions of the code.
I'm trying to avoid the well-known PyQt Runtime Error when the underlying C/C++ object is deleted:
http://www.riverbankcomputing.com/pipermail/pyqt/2009-April/022809.html
PyQt4 - "RuntimeError: underlying C/C object has been deleted"
PyQt4 nested classes - "RuntimeError: underlying C/C++ object has been deleted"
PyQt: RuntimeError: wrapped C/C++ object has been deleted
Every one of my subclasses calls the super() method and therefore the base classes are properly constructed.
Still, I get this error and am wondering if it is due to the fact that I'm adding a QComboBox widget to a QTreeWidgetItem (using the setItemWidget() method of a QTreeWidget) but I cannot set the parent as the QTreeWidgetItem that contains it. When I try, I get the following error:
TypeError: QComboBox(QWidget parent=None): argument 1 has unexpected type 'QTreeWidgetItem'
Of course, I can either omit the parent in the constructor or pass the QTreeWidget as the parent, but I think I need to reference the correct parent.
I have subclassed the QComboBox and in my subclass it runs some basic operations on the QTreeWidget, but as soon as I enter the methods of my subclassed QComboBox, the underlying C object for the parent QTreeWidgetItem containing the QComboBox is deleted (which is why I'm thinking its something to do with setting the parent of the QComboBox).
I understand 9 times out of 10 the runtime error is due to not constructing the base class. But with that ruled out, how else can the error occur? Could it be due to not referencing the correct parent?
EDIT
I'm using the QComboBox to signal when a new combobox selection was made. Upon a new selection, it adds that selected value to a PyXB XML node. Interestingly, this issue only occurs if I append the value to the PyXB class binding storing the information permanently in an XML file. In otherwords, if that part of the code doesn't run I dont get the error - its only when the code runs the PyXB operation for appending a value to an XML node binding...
I usually avoid that kind of errors keeping a reference on my class to all the objects susceptible of being deleted like your QComboBox so try something like self.comboBoxHolder = QComboBox(...) when you create it.