Pillow icon indicating copy to clipboard operation
Pillow copied to clipboard

10.2.0 to 10.3.0 breaks typing

Open LewisCowlesMotive opened this issue 1 year ago • 6 comments

What did you do?

I ran poetry lock --no-update followed by poetry install --sync

What did you expect to happen?

Nothing; my tests and CI still work

What actually happened?

file.py:77: error: Image? has no attribute "convert"  [attr-defined]
file.py:84: error: Module "PIL.Image" is not valid as a type  [valid-type]
file.py:84: note: Perhaps you meant to use a protocol matching the module structure?
file.py:86: error: Image? has no attribute "getexif"  [attr-defined]
file.py:89: error: Module has no attribute "FLIP_LEFT_RIGHT"  [attr-defined]
file.py:90: error: Module has no attribute "ROTATE_180"  [attr-defined]
file.py:91: error: Module has no attribute "FLIP_TOP_BOTTOM"  [attr-defined]
file.py:92: error: Module has no attribute "TRANSPOSE"  [attr-defined]
file.py:93: error: Module has no attribute "ROTATE_270"  [attr-defined]
file.py:94: error: Module has no attribute "TRANSVERSE"  [attr-defined]
file.py:95: error: Module has no attribute "ROTATE_90"  [attr-defined]
file.py:97: error: Image? has no attribute "transpose"  [attr-defined]
file.py:101: error: Module "PIL.Image" is not valid as a type  [valid-type]
file.py:101: note: Perhaps you meant to use a protocol matching the module structure?
file.py:104: error: Image? has no attribute "thumbnail"  [attr-defined]
file.py:108: error: Module "PIL.Image" is not valid as a type  [valid-type]
file.py:108: note: Perhaps you meant to use a protocol matching the module structure?
file.py:120: error: Module "PIL.Image" is not valid as a type  [valid-type]
file.py:120: note: Perhaps you meant to use a protocol matching the module structure?
file.py:138: error: Module "PIL.Image" is not valid as a type  [valid-type]
file.py:138: note: Perhaps you meant to use a protocol matching the module structure?
file.py:144: error: Image? has no attribute "save"  [attr-defined]
Found 29 errors in 1 file (checked 138 source files)

My lockfile updated, and updated to a version where Image is now the module, and all my imports have to be updated.

What are your OS, Python and Pillow versions?

  • OS: OSX
  • Python: 3.11.6
  • Pillow: 10.3.0
python3 -m PIL.report
--------------------------------------------------------------------
Pillow 10.3.0
Python 3.11.6 (main, Dec  5 2023, 10:10:39) [Clang 15.0.0 (clang-1500.0.40.1)]
--------------------------------------------------------------------
Python executable is /Users/lewiscowles/Library/Caches/pypoetry/virtualenvs/{project}-py3.11/bin/python3
Environment Python files loaded from /Users/lewiscowles/Library/Caches/pypoetry/virtualenvs/{project}-py3.11
System Python files loaded from /Users/lewiscowles/.pyenv/versions/3.11.6
--------------------------------------------------------------------
Python Pillow modules loaded from /Users/lewiscowles/Library/Caches/pypoetry/virtualenvs/{project}-py3.11/lib/python3.11/site-packages/PIL
Binary Pillow modules loaded from /Users/lewiscowles/Library/Caches/pypoetry/virtualenvs/{project}-py3.11/lib/python3.11/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 10.3.0
*** TKINTER support not installed
--- FREETYPE2 support ok, loaded 2.13.2
--- LITTLECMS2 support ok, loaded 2.16
--- WEBP support ok, loaded 1.3.2
--- WEBP Transparency support ok
--- WEBPMUX support ok
--- WEBP Animation support ok
--- JPEG support ok, compiled for libjpeg-turbo 3.0.2
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.2
--- ZLIB (PNG/ZIP) support ok, loaded 1.3.1
--- LIBTIFF support ok, loaded 4.6.0
--- RAQM (Bidirectional Text) support ok, loaded 0.10.1, fribidi 1.0.13, harfbuzz 8.4.0
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

I'm unable to provide the code itself. Essentially

from PIL import Image, UnidentifiedImageError

Is the line where I bring in PIL

LewisCowlesMotive avatar Jun 25 '24 12:06 LewisCowlesMotive

Interestingly; I did attempt to change the import

from PIL import UnidentifiedImageError
from PIL.Image import Image

This resulted in the same issue; but lets say we shouldn't break from 10.2.0 to 10.3.0

LewisCowlesMotive avatar Jun 25 '24 12:06 LewisCowlesMotive

Hi. Pillow 10.3.0 was the first release to signal that we provide type hints ourselves, so that would be the reason for the change.

Even though you're unable to provide your original code, would you be able to create a simple example showing these problems? It may be hard to help you otherwise, as your first error is about convert(), but that should have been typed in Pillow 10.3.0.

radarhere avatar Jun 25 '24 12:06 radarhere

Hi Sorry, I have produced enough to find the underlying issue.

All of the Any type warnings, are actually because PIL.Image is now a module, rather than a class; or was not understood to be that way prior. 10.2.0 has also been confirmed working for some months with the original import.

Most of the mypy errors are because of moving namespaces.

So it's not that convert doesn't have a type; but that it is an instance method, not a module method; so is coming back as any typed.

LewisCowlesMotive avatar Jun 25 '24 12:06 LewisCowlesMotive

from PIL import Image has always been a module, and from PIL import Image; Image.Image has always been a class. It sounds like the presence of Pillow type hints just made that clear.

So is there anything for us to do here? It sounds like you've figured out what is going on.

radarhere avatar Jun 25 '24 21:06 radarhere

If there is no change I'm unsure why it started breaking. Is it just good types?

LewisCowlesMotive avatar Jun 27 '24 16:06 LewisCowlesMotive

It sounds like your code was along the lines of

from PIL import Image
im: Image = Image.new("RGB", (1, 1))
im.convert("L")

If so, then that type hint were incorrect, and the new version of Pillow has revealed that. The correct type hint would be

from PIL import Image
im: Image.Image = Image.new("RGB", (1, 1))
im.convert("L")

radarhere avatar Jun 27 '24 22:06 radarhere

Has that answered your question?

radarhere avatar Jul 03 '24 21:07 radarhere

Sorry I've not had a chance to look at it. It failed when I trivially renamed before (it was my first port of call before raising this); but I've not been able to reproduce outside of the repo I'm in; so I'll close.

LewisCowlesMotive avatar Jul 04 '24 08:07 LewisCowlesMotive