Skip to content

Tkinter ttk widgets cget() returning _tkinter.Tcl_Obj instead of str #126008

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

Open
maj113 opened this issue Oct 26, 2024 · 16 comments
Open

Tkinter ttk widgets cget() returning _tkinter.Tcl_Obj instead of str #126008

maj113 opened this issue Oct 26, 2024 · 16 comments
Labels
docs Documentation in the Doc dir topic-tkinter

Comments

@maj113
Copy link

maj113 commented Oct 26, 2024

The docstring: """Return the resource value for a KEY given as string.""" claims it returns as a string however it returns a _tkinter.Tcl_Obj
which seems to lack __eq__/the ability to compare it to a string so something like this:

is_normal = radio_button.cget("state") == tk.NORMAL

Will always return false no matter what unless its wrapped in a str()

I propose either clarifying the docstr or returning as a str() wrapped obj but i presume that's a breaking change

Linked PRs

@maj113 maj113 added the docs Documentation in the Doc dir label Oct 26, 2024
@Xiaokang2022
Copy link
Contributor

Xiaokang2022 commented Oct 27, 2024

Hello, @maj113

The result of my test is no problem, my environment is as follows:

  • OS: Windows11 23H2
  • Python: 3.13.0

The code I tested is as follows:

import tkinter

root = tkinter.Tk()

radio_button = tkinter.Radiobutton(root)
state = radio_button.cget("state")
is_normal = state == tkinter.NORMAL

print(f"{is_normal=}, {type(state)=}")

The output is as follows:

is_normal=True, type(state)=<class 'str'>

Obviously, it's not a _tkinter.Tcl_Obj. Therefore you should specifically point out the environment, as this may be a problem that only arises in certain environments. If there's a problem with the way I'm testing, feel free to point it out.

@maj113
Copy link
Author

maj113 commented Oct 27, 2024

Obviously, it's not a _tkinter.Tcl_Obj. Therefore you should specifically point out the environment, as this may be a problem that only arises in certain environments. If there's a problem with the way I'm testing, feel free to point it out.

I'm testing this on Windows 11 24H2 with the same behavior on (C)python 3.12.5 and 3.13.0

@maj113
Copy link
Author

maj113 commented Oct 27, 2024

okay the issue occurs ONLY with ttk widgets, not regular tk ones
image

@Xiaokang2022
Copy link
Contributor

Ok, I'll try to create a PR later to fix this.

I don't think this should be solved just by modifying the docstring, _tkinter.Tcl_Obj should be converted to a string type.

@maj113 maj113 changed the title Tkinter widget cget() misleading documentation about returning as a string Tkinter ttk widgets cget() returning _tkinter.Tcl_Obj instead of str Oct 29, 2024
@brianzhouzc
Copy link

I've encountered the same issue yesterday by accessing the state using the key directly. Took me way to long to figure out that the state isn't string type.

self.entry_box = ttk.Entry(self.root, width=40)

# This doesn't work!
if (self.entry_box['state'] == 'normal'):
    print('State is normal')

The weird thing is, if you access the state before hand by printing it as a string, then it becomes a string type.

import tkinter as tk
from tkinter import ttk, messagebox

class App:
    def __init__(self, root):
        self.root = root

        self.entry_box = ttk.Entry(self.root, width=40)
        self.entry_box.pack(padx=10, pady=10)

        messagebox.showinfo(message=f"Type: {type(self.entry_box['state'])}\nState: {self.entry_box['state']}\nType after access: {type(self.entry_box['state'])}")

if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()

Result:

Type: <class '_tkinter.Tcl_Obj'>
State: normal
Type after access: <class 'str'>

@Xiaokang2022
Copy link
Contributor

Hello, @brianzhouzc

I tested your code and it turned out to be different from yours:

Result:

Type: <class '_tkinter.Tcl_Obj'>
State: normal
Type after access: <class '_tkinter.Tcl_Obj'>

Perhaps you should point out your environment.

@terryjreedy
Copy link
Member

@serhiy-storchaka We need a decision on what to do before too much effort is put into PRs.

@serhiy-storchaka
Copy link
Member

The docstring is outdated. Perhaps it was written when all low-level Tkinter API returned only strings. "as string" should be removed.

@brianzhouzc
Copy link

brianzhouzc commented Oct 29, 2024

Hello, @brianzhouzc

I tested your code and it turned out to be different from yours:

Result:

Type: <class '_tkinter.Tcl_Obj'>
State: normal
Type after access: <class '_tkinter.Tcl_Obj'>

Perhaps you should point out your environment.

Apologies, my environment is Windows 10 Business 22H2 19045.5011, Python 3.11.9.

Tried on Python 3.12.6 as well and the behaviours is indeed different, like what you have in your reply.

@maj113
Copy link
Author

maj113 commented Oct 29, 2024

The docstring is outdated. Perhaps it was written when all low-level Tkinter API returned only strings. "as string" should be removed.

I don't think just removing that would be enough to clarify the return value, it still might confuse people that the same key behaves differently comparing tk vs ttk, I haven't checked how tkinter.Tcl_Obj is implemented but maybe it can be extended with a eq so that at least string comparisons work as expected without the need to wrap it in a str

@serhiy-storchaka
Copy link
Member

This is a Tk implementation detail. Depending on the key, the Tk version, the way of creating and modifying the widget, you can get a number, a boolean, a string, a tuple, a Tcl_Obj. If you get a Tcl_Obj and need a string, just call str().

Making Tcl_Obj comparable with str is an interesting idea, but this is a new feature which can only be added in a new Python version. It may require significant internal changes in Tkinter.

@Xiaokang2022
Copy link
Contributor

The docstring is outdated. Perhaps it was written when all low-level Tkinter API returned only strings. "as string" should be removed.

Is it possible that the "as string" in the comment refers to the KEY, not the return value? This can really be misleading.

But beyond that, it's also a problem that widgets of tk don't behave consistently with widgets of ttk.

@picnixz
Copy link
Member

picnixz commented Oct 30, 2024

What I understood wrongly: the key is a string, the return value is a string as well because everything is stored as a string. But this was wrong! (I think?)

The key is a string, the return value is anything. Am I correct now?

@Xiaokang2022
Copy link
Contributor

The key is a string, the return value is anything. Am I correct now?

I think so.

@Xiaokang2022
Copy link
Contributor

I added tests to the PR, can anyone help review that?

Is it possible that the "as string" in the comment refers to the KEY, not the return value? This can really be misleading.
But beyond that, it's also a problem that widgets of tk don't behave consistently with widgets of ttk.

Also, as mentioned above, this should be more than just a docs issue.

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue May 2, 2025
…thods

* Explain the behavior of Widget.configure() depending on arguments.
* Unify descriptions.
* Replace "resource" with "option".
@serhiy-storchaka
Copy link
Member

To me, it looks like saying that KEY is a string. This is redundant and may be confusing, so it is is better to remove it. There are also other issues with docstrings of cget() and configure()` methods. #133303 tryes to improve them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation in the Doc dir topic-tkinter
Projects
Status: Todo
Development

No branches or pull requests

6 participants