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

Fix tkinter ImageSpec #11721 #13049

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Fix tkinter ImageSpec #11721 #13049

wants to merge 2 commits into from

Conversation

kbaikov
Copy link
Contributor

@kbaikov kbaikov commented Nov 20, 2024

Fixes #11721

This comment has been minimized.

@kbaikov
Copy link
Contributor Author

kbaikov commented Nov 20, 2024

@srittau Do i need to comment Any here too? If so what would be the appropriate comment.

Copy link
Contributor

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@Akuli
Copy link
Collaborator

Akuli commented Nov 20, 2024

Thanks for working on this! Tkinter is more tricky than you'd expect :)

After thinking about this again, I'm pretty sure that using Any is not a good idea. The problem is that it doesn't detect the following mistake, which is easy to make and gives a misleading error message at runtime:

import tkinter
import PIL.Image

root = tkinter.Tk()
img = PIL.Image.open("foo.png")
label = tkinter.Label(image=img)

The problem is that you forgot to wrap the PIL image in a PIL.ImageTk image. This is the correct code:

import tkinter
import PIL.Image
import PIL.ImageTk

root = tkinter.Tk()
img = PIL.Image.open("foo.png")
img_tk = PIL.ImageTk.PhotoImage(img)
label = tkinter.Label(root, image=img_tk)

To make type checkers complain about the wrong code, let's use the following protocol:

class _ImageLike(Protocol):
    def width(self) -> int: ...
    def height(self) -> int: ...

This matches tkinter's image classes (PhotoImage and BitmapImage) and PIL's tkinter-compatible class (PIL.ImageTk.PhotoImage), but not a plain PIL image that isn't tkinter compatible. The reason is that PIL has width and height attributes, not methods:

>>> img.width
788
>>> img_tk.width
<bound method PhotoImage.width of <PIL.ImageTk.PhotoImage object at 0x7fb2712e6510>>

Do you want to change this PR, or do you want me to make a new PR with the protocol?

@Akuli
Copy link
Collaborator

Akuli commented Nov 20, 2024

Apparently this has been a protocol before, but it was changed in #9733. There I said:

I'll probably merge this in a few days, unless someone comes up with a better idea or some reasoning to prefer the width(),height() protocol over fake classes.

And now that PIL ships its own type stubs, that is a good reason to prefer a protocol over fake classes that don't really work anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tkinter _Image hack
2 participants