Skip to content

Release Pillow 11.2.0 on April 1, 2025 #8722

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

Closed
8 of 14 tasks
radarhere opened this issue Jan 30, 2025 · 31 comments
Closed
8 of 14 tasks

Release Pillow 11.2.0 on April 1, 2025 #8722

radarhere opened this issue Jan 30, 2025 · 31 comments
Assignees
Labels
Milestone

Comments

@radarhere
Copy link
Member

radarhere commented Jan 30, 2025

Main Release

Released quarterly on January 2nd, April 1st, July 1st and October 15th.

Publicize Release

Documentation

Docker Images

  • Update Pillow in the Docker Images repository
    git clone https://github.com/python-pillow/docker-images
    cd docker-images
    ./update-pillow-tag.sh [[release tag]]
@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

Wheel build done.

But we've finally hit the PyPI project limit of 10 GB during upload:

WARNING  Error during upload. Retry with the --verbose option for more details. 
ERROR    HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/        
         Project size too large. Limit for project 'pillow' total size is 10 GB.
         See                                                                    
         https://docs.pypi.org/project-management/storage-limits#requesting-a-project-size-limit-increase                                              

https://github.com/python-pillow/Pillow/actions/runs/14194276478/job/39774057701

I'll request an increase.

73/80 wheels files made it up, sdist not there yet.

@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

The last release had 70 wheels and an sdist and is about 296 MB, an average 4.2 MB per file.

https://pypi.org/project/pillow/11.1.0/#files

This one is 80 wheels and an sdist and is 1.15 GB, an average of 14.2 MB per file.

https://github.com/python-pillow/Pillow/actions/runs/14194276478

@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

It's caused by the new AVIF binaries (#5201).

A couple of comparisons.

Pillow 11.1.0 11.2.0 Times bigger
cp313-cp313-macosx_11_0_arm64.whl 3.0 MB 8.5 MB 2.83x
cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.2 MB 18 MB 4.29x

The avif .so file is a lot bigger than the next biggest .so file. In the manylinux wheel:

11.2.0 Size
_avif.cpython-313-x86_64-linux-gnu.so 48 MB
_imaging.cpython-313-x86_64-linux-gnu.so 3.3 MB

In the macOS wheel:

11.2.0 Size
_avif.cpython-313-darwin.so 15 MB
_imaging.cpython-313-darwin.so 0.56 MB

Wheel files are zip files which means the .so files are compressed, but it makes our release more than 3x as big.

@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

Filename 11.1.0 11.2.0 Times bigger
1 cp39-cp39-macosx_10_10_x86_64.whl 3.2 MB 11.4 MB 3.56x
2 cp39-cp39-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
3 cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 4.3 MB 17.1 MB 3.98x
4 cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.4 MB 18.9 MB 4.30x
5 cp39-cp39-manylinux_2_28_aarch64.whl 4.4 MB 17.6 MB 4.00x
6 cp39-cp39-manylinux_2_28_x86_64.whl 4.5 MB 19.6 MB 4.36x
7 cp39-cp39-musllinux_1_2_aarch64.whl 4.3 MB 18.0 MB 4.19x
8 cp39-cp39-musllinux_1_2_x86_64.whl 4.4 MB 19.8 MB 4.50x
9 cp39-cp39-win32.whl 2.3 MB 2.3 MB 1.00x
10 cp39-cp39-win_amd64.whl 2.6 MB 13.8 MB 5.31x
11 cp39-cp39-win_arm64.whl 2.4 MB 2.4 MB 1.00x
12 cp310-cp310-macosx_10_10_x86_64.whl 3.2 MB 11.4 MB 3.56x
13 cp310-cp310-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
14 cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 4.3 MB 17.1 MB 3.98x
15 cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.4 MB 18.9 MB 4.30x
16 cp310-cp310-manylinux_2_28_aarch64.whl 4.4 MB 17.6 MB 4.00x
17 cp310-cp310-manylinux_2_28_x86_64.whl 4.5 MB 19.6 MB 4.36x
18 cp310-cp310-musllinux_1_2_aarch64.whl 4.3 MB 18.0 MB 4.19x
19 cp310-cp310-musllinux_1_2_x86_64.whl 4.4 MB 19.8 MB 4.50x
20 cp310-cp310-win32.whl 2.3 MB 2.3 MB 1.00x
21 cp310-cp310-win_amd64.whl 2.6 MB 13.8 MB 5.31x
22 cp310-cp310-win_arm64.whl 2.4 MB 2.4 MB 1.00x
23 cp311-cp311-macosx_10_10_x86_64.whl 3.2 MB 11.4 MB 3.56x
24 cp311-cp311-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
25 cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 4.3 MB 17.1 MB 3.98x
26 cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.4 MB 18.9 MB 4.30x
27 cp311-cp311-manylinux_2_28_aarch64.whl 4.4 MB 17.6 MB 4.00x
28 cp311-cp311-manylinux_2_28_x86_64.whl 4.5 MB 19.6 MB 4.36x
29 cp311-cp311-musllinux_1_2_aarch64.whl 4.3 MB 18.0 MB 4.19x
30 cp311-cp311-musllinux_1_2_x86_64.whl 4.4 MB 19.8 MB 4.50x
31 cp311-cp311-win32.whl 2.3 MB 2.3 MB 1.00x
32 cp311-cp311-win_amd64.whl 2.6 MB 13.8 MB 5.31x
33 cp311-cp311-win_arm64.whl 2.4 MB 2.4 MB 1.00x
34 cp312-cp312-macosx_10_13_x86_64.whl 3.2 MB 11.4 MB 3.56x
35 cp312-cp312-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
36 cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 4.3 MB 17.1 MB 3.98x
37 cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.4 MB 18.9 MB 4.30x
38 cp312-cp312-manylinux_2_28_aarch64.whl 4.4 MB 17.6 MB 4.00x
39 cp312-cp312-manylinux_2_28_x86_64.whl 4.5 MB 19.6 MB 4.36x
40 cp312-cp312-musllinux_1_2_aarch64.whl 4.3 MB 18.0 MB 4.19x
41 cp312-cp312-musllinux_1_2_x86_64.whl 4.4 MB 19.8 MB 4.50x
42 cp312-cp312-win32.whl 2.3 MB 2.3 MB 1.00x
43 cp312-cp312-win_amd64.whl 2.6 MB 13.8 MB 5.31x
44 cp312-cp312-win_arm64.whl 2.4 MB 2.4 MB 1.00x
45 cp313-cp313-macosx_10_13_x86_64.whl 3.2 MB 11.4 MB 3.56x
46 cp313-cp313-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
47 cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 4.3 MB 17.1 MB 3.98x
48 cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.4 MB 18.9 MB 4.30x
49 cp313-cp313-manylinux_2_28_aarch64.whl 4.4 MB 17.6 MB 4.00x
50 cp313-cp313-manylinux_2_28_x86_64.whl 4.5 MB 19.6 MB 4.36x
51 cp313-cp313-musllinux_1_2_aarch64.whl 4.3 MB 18.0 MB 4.19x
52 cp313-cp313-musllinux_1_2_x86_64.whl 4.4 MB 19.8 MB 4.50x
53 cp313-cp313-win32.whl 2.3 MB 2.3 MB 1.00x
54 cp313-cp313-win_amd64.whl 2.6 MB 13.8 MB 5.31x
55 cp313-cp313-win_arm64.whl 2.4 MB 2.4 MB 1.00x
56 cp313-cp313t-macosx_10_13_x86_64.whl 3.2 MB 11.4 MB 3.56x
57 cp313-cp313t-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
58 cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 4.4 MB 17.1 MB 3.89x
59 cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 4.4 MB 18.9 MB 4.30x
60 cp313-cp313t-manylinux_2_28_aarch64.whl 4.5 MB 17.6 MB 3.91x
61 cp313-cp313t-manylinux_2_28_x86_64.whl 4.5 MB 19.6 MB 4.36x
62 cp313-cp313t-musllinux_1_2_x86_64.whl 4.5 MB 19.8 MB 4.40x
63 cp313-cp313t-win32.whl 2.3 MB 2.3 MB 1.00x
64 cp313-cp313t-win_amd64.whl 2.6 MB 13.8 MB 5.31x
65 cp313-cp313t-win_arm64.whl 2.4 MB 2.4 MB 1.00x
66 pp310-pypy310_pp73-macosx_10_15_x86_64.whl 3.2 MB 11.4 MB 3.56x
67 pp310-pypy310_pp73-macosx_11_0_arm64.whl 3.1 MB 8.9 MB 2.87x
68 pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 3.4 MB 16.1 MB 4.74x
69 pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 3.4 MB 17.8 MB 5.24x
70 pp310-pypy310_pp73-manylinux_2_28_aarch64.whl 3.4 MB 16.6 MB 4.88x
71 pp310-pypy310_pp73-manylinux_2_28_x86_64.whl 3.5 MB 18.5 MB 5.29x
72 pp310-pypy310_pp73-win_amd64.whl 2.6 MB 13.2 MB 5.08x
73 pp311-pypy311_pp73-macosx_10_15_x86_64.whl 11.4 MB
74 pp311-pypy311_pp73-macosx_11_0_arm64.whl 8.9 MB
75 pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl 16.1 MB
76 pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 17.8 MB
77 pp311-pypy311_pp73-manylinux_2_28_aarch64.whl 16.6 MB
78 pp311-pypy311_pp73-manylinux_2_28_x86_64.whl 18.5 MB
79 pp311-pypy311_pp73-win_amd64.whl 13.2 MB
Total 258 MB 1.06 GB 4.2x

@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

Requested a limit increase from 10 GB to 20 GB: pypi/support#6014.

Opened #8856 to see if we can reduce the wheel size.

@hugovk
Copy link
Member

hugovk commented Apr 1, 2025

While the release is in a half-released state, plus there's some uncertainty about the wheel sizes, I suggest we "yank" 11.2.0 on PyPI.

Yanking is a reversible action, the files remain on PyPI but are only installed if you specifically request 11.2.0. You won't get it with a normal install or upgrade.

If we choose not to do anything about the wheel size for this release, and when we get a limit increase, we can un-yank the release and upload the remaining files.

@hugovk
Copy link
Member

hugovk commented Apr 2, 2025

@aclark4life / @wiredfool Please could you give @radarhere and me owner permission on PyPI so we can yank this release?

@wiredfool
Copy link
Member

@hugovk Done

@hugovk
Copy link
Member

hugovk commented Apr 2, 2025

Thanks, 11.2.0 has been yanked for now.

https://pypi.org/project/pillow/11.2.0/

@aclark4life
Copy link
Member

@wiredfool @hugovk @radarhere thanks for all the extra hard work getting this one out

@aclark4life
Copy link
Member

aclark4life commented Apr 4, 2025

Are we planning to wait for PyPI or shrink the wheels or both? I assume they'll grant the request… at some point… but I'm not sure if we can get an accurate ETA?

@hugovk
Copy link
Member

hugovk commented Apr 4, 2025

We don't have an accurate ETA, maybe about a month or so looking at other requests?

My thinking:

  • Let's shrink the wheels.
  • Then delete the partial 11.2.0 release -- this will free up space for a new, smaller release.
  • Then make a new 11.2.1 release. (We can't re-upload files with names that once existed, to prevent surreptitious maliciousness. And a new version number will prevent any confusion with any files people have downloaded.)

This way we're not immediately blocked by the PyPI increase. We will still need an increase, we would have hit in an couple of releases or so anyway.

@wiredfool
Copy link
Member

Sounds good to me.

@aclark4life
Copy link
Member

Cool in that case do we have an ETA on shrink-wheel release? I don't think here is any particular urgency, just curious. Thanks all

@hugovk
Copy link
Member

hugovk commented Apr 4, 2025

Perhaps this weekend, or early next week?

As soon as we decide on one of:

@aclark4life
Copy link
Member

Anyone want to merge #8876 and release Pillow 11.2? 😄

@radarhere
Copy link
Member Author

If you're giving the green light, I'm happy to do so.

@aclark4life
Copy link
Member

Great! Let's confirm with @hugovk and then go for it, thanks.

@hugovk
Copy link
Member

hugovk commented Apr 12, 2025

I'm AFK right now and can check it over later today, and do the release.

Good news, we got the PyPI increase:

pypi/support#6014 (comment)

And they also asked if we can use the Limited API, which would drastically reduce the amount of wheels we need. I'm not sure how feasible that is for something of Pillow's vintage and size, but something to look into at some point.

https://docs.python.org/3/c-api/stable.html#limited-c-api

For the release, let's stick to the plan of deleting 11.2.0 and doing 11.2.1.

Let's put something in the release notes to say why this is 11.2.1 and 11.2.0 is pining for the fjörds.

Are there any other PRs that are important to include in this release, beyond the dependency and docs updates?

@radarhere
Copy link
Member Author

Are there any other PRs that are important to include in this release, beyond the dependency and docs updates?

No, I don't think anything else stands out.

And they also asked if we can use the Limited API

I attempted this briefly, and ran into a problem with PyTypeObject - https://docs.python.org/3/c-api/typeobj.html#static-types

since PyTypeObject is only part of the Limited API as an opaque struct, any extension modules using static types must be compiled for a specific Python minor version.

@hugovk
Copy link
Member

hugovk commented Apr 12, 2025

  • Do not include libavif in wheels #8876 is merged
  • Add 11.2.1 release notes #8885 updates release notes for 11.2.1
  • I'll un-yank 11.2.0 from PyPI so I can delete it (there's no option to delete a yanked release)
  • I'll delete the 11.2.0 tag from the repo
  • I'll create a new release issue for 11.2.1 with a fresh release checklist and close this
  • and then release 11.2.1

@hugovk
Copy link
Member

hugovk commented Apr 12, 2025

11.2.0 un-yanked and deleted:

Image

@hugovk
Copy link
Member

hugovk commented Apr 12, 2025

11.2.0 tag deleted.

For the record, it was commit 09adcfb.

git show 11.2.0
Found existing alias for "git show". You should use: "gsh"
commit 09adcfb4e4bd1ad57896ea176a021d396a7965f4 (tag: 11.2.0)
Author: Hugo van Kemenade <[email protected]>
Date:   Tue Apr 1 12:49:21 2025 +0300

    11.2.0 version bump


Δ src/PIL/_version.py
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

─────┐
• 1: │
─────┘
  1 ⋮  1 │# Master version for Pillow
  2 ⋮  2 │from __future__ import annotations
  3 ⋮  3 │
  4 ⋮    │__version__ = "11.2.0.dev0"
    ⋮  4 │__version__ = "11.2.0"

@hugovk
Copy link
Member

hugovk commented Apr 12, 2025

Let's continue 11.2.1 in #8886.

@hugovk hugovk closed this as not planned Won't fix, can't repro, duplicate, stale Apr 12, 2025
@aclark4life aclark4life unpinned this issue Apr 12, 2025
@aclark4life
Copy link
Member

@hugovk Is there any scenario in which we'd leave the yanked release in place? Or to put it another way, isn't yanking sufficient and preferable over deleting in order to prevent downloads and leave a trail of what happened? That's my current understanding but I could be wrong 😄

@hugovk
Copy link
Member

hugovk commented Apr 12, 2025

It's already deleted, but in theory, if it was left as yanked, then pip install pillow==11.2.0 would still install it -- but only for those platforms that had wheels uploaded. And there was no source zip, to even try building on the other platforms; or for people who don't want wheels, and want to build their own release from source.

We don't want that 11.2.0 install to happen in this case, because we removed a feature from there without our normal one-year deprecation period.

So because the release was never completed, I think this is okay -- we've decided 11.2.0 never existed.

If we'd left 11.2.0 as yanked, I would have still wanted to respect out deprecation period.


A case where you may want to yank without deleting: a release was made successfully. But then you discover some ugly bug and fix it. You can then yank the old one, so it doesn't install "normally", but also doesn't break people who have pinned it in their lockfiles. They can upgrade with care as normal for the new release.

@OJFord
Copy link

OJFord commented Apr 14, 2025

imo:

A case where you may want to yank without deleting: a release was made successfully. But then you discover some ugly bug and fix it. You can then yank the old one, so it doesn't install "normally", but also doesn't break people who have pinned it in their lockfiles. They can upgrade with care as normal for the new release.

is exactly what happened here with:

because we removed a feature from [11.2.0] without our normal one-year deprecation period.

(I'm here during a failing production deployment after we ran 11.2.0 through test environments no problem.)

An inadvertent breaking change is a bug, a bugfix is a patch release, doing that in 11.2.1 with the known bug in 11.2.0 is absolutely fine and normal as far as I'm concerned, and would've not caused us a problem (whereas this procedure did).

@hugovk
Copy link
Member

hugovk commented Apr 14, 2025

Thanks for letting us know!

We were in the situation where 11.2.0 hadn't been fully released and we were unable to complete the release at the time. The source and many wheels were missing from PyPI, and we hadn't pushed the tags here.

And then we decided to remove features from planned-11.2.0, so it wasn't a bugfix, but feature removal without deprecation. I don't think that would be appropriate in a normal patch release.

I'm curious, do you know how you managed to pick up 11.2.0 in the first place?

(It was partially released and un-yanked for about 18 hours.)

@OJFord
Copy link

OJFord commented Apr 15, 2025

From a Dependabot PR created 1 April 23:18 GMT. (I'd link but private repo.)

@hugovk
Copy link
Member

hugovk commented Apr 15, 2025

Got it, so the Dependabot update passed with 11.2.0 during the window, was merged, the yank also didn't cause problems because it was still pinned, but then the delete broke things.

I do hope we won't have to delete, or yank, anything in the future, but won't do so without careful consideration.

Thanks again!

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

No branches or pull requests

5 participants