Skip to content
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

Accessing a tkinter object's string representation converts the object to a string on Windows #101830

Closed
daniilS opened this issue Feb 11, 2023 · 2 comments
Assignees
Labels
OS-windows topic-tkinter type-bug An unexpected behavior, bug, or error

Comments

@daniilS
Copy link

daniilS commented Feb 11, 2023

Introduced in #16545
Affects Python 3.7+ on Windows only


The FromObj function in _tkinter.c attempt to convert a Tcl_Obj to an equivalent Python object if possible, and otherwise returns a _tkinter.Tcl_Obj with the typename attribute set to the original object's type.

However, on Windows, accessing the resulting object's string representation calls Tcl_GetUnicodeFromObj, which converts the Tcl_Obj to a String. This side effect isn't mentioned in the Tcl documentation, but is in the Tcl source code. As a result, retrieving the same tk property afterwards will return a Python string instead.

Minimal example:

import tkinter as tk

root = tk.Tk()
print(type(root.cget("padx")))
_ = str(root.cget("padx"))  # should really not cause any side effects
print(type(root.cget("padx")))

# Windows:
# <class '_tkinter.Tcl_Obj'>
# <class 'str'>
# Other platforms:
# <class '_tkinter.Tcl_Obj'>
# <class '_tkinter.Tcl_Obj'>

Possible solutions: unicodeFromTclObj should copy the object before passing calling Tcl_GetUnicodeFromObj, or handle Unicode without it like on other platforms.

Linked PRs

@daniilS daniilS added the type-bug An unexpected behavior, bug, or error label Feb 11, 2023
@arhadthedev arhadthedev added OS-windows interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-tkinter labels Feb 11, 2023
@chrstphrchvz
Copy link
Contributor

To offer some background: Tcl usually calls this side effect “shimmering”. The Tcl syntax documentation does not seem to explain it, but the C API documentation gives some hints: https://www.tcl-lang.org/man/tcl8.6/TclLib/Object.htm explains that a Tcl value has a “string representation” (modified UTF-8 bytes) and up to one “internal representation” depending on its type; and in https://www.tcl-lang.org/man/tcl8.6/TclLib/StringObj.htm there is a distinction between a “Unicode representation” (a sequence of 16-bit or 32-bit codepoints) which is the internal representation of a value with the “string” type, versus the “string representation” for values of any type. So Tcl_GetUnicodeFromObj() can cause a value to generate a string representation (if it does not already have one) from its current internal representation, and then become the “string” type by discarding the existing internal representation and replacing it with a Unicode representation generated from the string representation.

@serhiy-storchaka serhiy-storchaka self-assigned this Aug 6, 2023
@AlexWaygood AlexWaygood removed the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Feb 10, 2024
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Jun 22, 2024
Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
@serhiy-storchaka
Copy link
Member

Thank you, I overlook this effect.

The reason of using Tcl_GetUnicodeFromObj/Tcl_NewUnicodeObj on Windows and Tcl_GetStringFromObj/Tcl_NewStringObj on other platforms is that by default Tcl does not support Unicode outside of the BMP, but the underlying graphic system may support if the data is present in native multibyte encoding (UTF16 on Windows, UTF8 on other platforms). Tcl cannot correctly convert between UTF16 and UTF8 representations of non-BMP characters, so we need to create Tcl objects in the appropriate representation.

Using Tcl_GetUnicodeFromObj only for Tcl objects with the “Unicode representation” should fix most issues. It will create a new issue: if the Tcl object is compound and contains strings with non-BMP characters, Tcl_GetStringFromObj will produce result containing broken UTF8. This is uncommon case, because Tcl "list" objects are represented as tuples in Python, but Tcl "dict" objects are represented as Tcl_Objs. I do not know whether Tcl "dict" objects are used in Tk. Copying the object before passing calling Tcl_GetUnicodeFromObj could solve this issue, but this is very complex solution.

I think that we should fix regression in common cases and leave possible complicated solution of more subtle problem until we encounter it in real world.

serhiy-storchaka added a commit that referenced this issue Jun 23, 2024
Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Jun 23, 2024
Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
(cherry picked from commit f4ddaa3)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit that referenced this issue Jun 23, 2024
…0905)

Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
(cherry picked from commit f4ddaa3)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Jun 23, 2024
…0884)

Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
(cherry picked from commit f4ddaa3)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit that referenced this issue Jun 23, 2024
…0913)

Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
(cherry picked from commit f4ddaa3)
mrahtz pushed a commit to mrahtz/cpython that referenced this issue Jun 30, 2024
Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
noahbkim pushed a commit to hudson-trading/cpython that referenced this issue Jul 11, 2024
Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
Accessing the Tkinter object's string representation no longer converts
the underlying Tcl object to a string on Windows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OS-windows topic-tkinter type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

5 participants