typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

Tkinter `_Image` hack

Open srittau opened this issue 1 year ago • 2 comments

Currently, tkinter uses a hack to mark classes compatible with the image parameter:

https://github.com/python/typeshed/blob/130a04905c0cab48604ac7be1f3d18ce96567c68/stdlib/tkinter/init.pyi#L3276-L3280

Classes implementing this interface are expected to derive from this stub-only class (or one of its sub-classes). Our Pillow stubs did so. Unfortunately, now that Pillow has its own type annotations, I think it's unreasonable for them to do so at runtime. I think our best bet is to change change _Image to Any here, as this interface can't be represented in our type system.

Cc @Akuli

srittau avatar Apr 05 '24 11:04 srittau

This seems reasonable. Basically, this type alias would be changed to Any:

https://github.com/python/typeshed/blob/130a04905c0cab48604ac7be1f3d18ce96567c68/stdlib/tkinter/init.pyi#L181

The most common use cases for tkinter images are setting a window icon with wm_iconphoto() and displaying images in the UI with various image=... keyword arguments. These would become basically Any-typed. IMO that's not a huge problem, because if you do these things wrong, you typically get an error when the program starts, so at least it fails loudly and early.

Another option, if it works, is to just import Pillow's type in tkinter stubs with a # type: ignore. Mypy will treat it as Any when pillow is not installed, but I'm not sure what other type checkers would do.

Akuli avatar Apr 05 '24 14:04 Akuli

One more option would be to make a protocol that matches the width, height and paste methods of PIL.ImageTk.PhotoImage. Something like this:

class _PillowPhotoImage:
    def width(self) -> int: ...
    def height(self) -> int: ...
    def paste(self, im: Any, /) -> None: ...

It's unlikely that anything matches this accidentally, and autocompletions will show a somewhat useful _PillowPhotoImage.

Akuli avatar Apr 06 '24 17:04 Akuli