From 0607dd64639bf873414a638a6a60cf447f871769 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 16 Dec 2024 19:38:07 +1100 Subject: [PATCH] faster --- .appveyor.yml | 99 -------- .ci/install.sh | 27 +-- .ci/test.sh | 2 +- .github/workflows/cifuzz.yml | 62 ----- .github/workflows/docs.yml | 71 ------ .github/workflows/lint.yml | 56 ----- .github/workflows/macos-install.sh | 19 -- .github/workflows/release-drafter.yml | 28 --- .github/workflows/stale.yml | 33 --- .github/workflows/test-cygwin.yml | 154 ------------- .github/workflows/test-docker.yml | 117 ---------- .github/workflows/test-mingw.yml | 94 -------- .github/workflows/test-valgrind.yml | 58 ----- .github/workflows/test-windows.yml | 237 ------------------- .github/workflows/test.yml | 19 -- .github/workflows/wheels.yml | 312 -------------------------- Tests/test_file_avif.py | 16 +- 17 files changed, 13 insertions(+), 1391 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .github/workflows/cifuzz.yml delete mode 100644 .github/workflows/docs.yml delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/release-drafter.yml delete mode 100644 .github/workflows/stale.yml delete mode 100644 .github/workflows/test-cygwin.yml delete mode 100644 .github/workflows/test-docker.yml delete mode 100644 .github/workflows/test-mingw.yml delete mode 100644 .github/workflows/test-valgrind.yml delete mode 100644 .github/workflows/test-windows.yml delete mode 100644 .github/workflows/wheels.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 781ad4a4b1d..00000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,99 +0,0 @@ -skip_commits: - files: - - ".github/**/*" - - ".gitmodules" - - "docs/**/*" - - "wheels/**/*" - -version: '{build}' -clone_folder: c:\pillow -init: -- ECHO %PYTHON% -#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) -# Uncomment previous line to get RDP access during the build. - -environment: - COVERAGE_CORE: sysmon - EXECUTABLE: python.exe - TEST_OPTIONS: - DEPLOY: YES - matrix: - - PYTHON: C:/Python313 - ARCHITECTURE: x86 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 - - PYTHON: C:/Python39-x64 - ARCHITECTURE: AMD64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - - -install: -- '%PYTHON%\%EXECUTABLE% --version' -- '%PYTHON%\%EXECUTABLE% -m pip install --upgrade pip' -- curl -fsSL -o pillow-test-images.zip https://github.com/python-pillow/test-images/archive/main.zip -- 7z x pillow-test-images.zip -oc:\ -- xcopy /S /Y c:\test-images-main\* c:\pillow\tests\images -- curl -fsSL -o nasm-win64.zip https://raw.githubusercontent.com/python-pillow/pillow-depends/main/nasm-2.16.03-win64.zip -- 7z x nasm-win64.zip -oc:\ -- choco install ghostscript --version=10.4.0 -- path c:\nasm-2.16.03;C:\Program Files\gs\gs10.04.0\bin;%PATH% -- cd c:\pillow\winbuild\ -- ps: | - c:\python39\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ - c:\pillow\winbuild\build\build_dep_all.cmd - $host.SetShouldExit(0) -- path C:\pillow\winbuild\build\bin;%PATH% - -build_script: -- cd c:\pillow -- winbuild\build\build_env.cmd -- '%PYTHON%\%EXECUTABLE% -m pip install -v -C raqm=vendor -C fribidi=vendor .' -- '%PYTHON%\%EXECUTABLE% selftest.py --installed' - -test_script: -- cd c:\pillow -- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov pytest-timeout defusedxml ipython numpy olefile pyroma' -- c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE% -- path %PYTHON%;%PATH% -- .ci\test.cmd - -after_test: -- curl -Os https://uploader.codecov.io/latest/windows/codecov.exe -- .\codecov.exe --file coverage.xml --name %PYTHON% --flags AppVeyor - -matrix: - fast_finish: true - -cache: -- '%LOCALAPPDATA%\pip\Cache' - -artifacts: -- path: pillow\*.egg - name: egg -- path: pillow\*.whl - name: wheel - -before_deploy: - - cd c:\pillow - - '%PYTHON%\%EXECUTABLE% -m pip wheel -v -C raqm=vendor -C fribidi=vendor .' - - ps: Get-ChildItem .\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - -deploy: - provider: S3 - region: us-west-2 - access_key_id: AKIAIRAXC62ZNTVQJMOQ - secret_access_key: - secure: Hwb6klTqtBeMgxAjRoDltiiqpuH8xbwD4UooDzBSiCWXjuFj1lyl4kHgHwTCCGqi - bucket: pillow-nightly - folder: win/$(APPVEYOR_BUILD_NUMBER)/ - artifact: /.*egg|wheel/ - on: - APPVEYOR_REPO_NAME: python-pillow/Pillow - branch: main - deploy: YES - - -# Uncomment the following lines to get RDP access after the build/test and block for -# up to the timeout limit (~1hr) -# -#on_finish: -#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/.ci/install.sh b/.ci/install.sh index b247440496a..9fdeb222af5 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -20,26 +20,21 @@ fi set -e if [[ $(uname) != CYGWIN* ]]; then - sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ - ghostscript libjpeg-turbo-progs libopenjp2-7-dev\ - cmake meson imagemagick libharfbuzz-dev libfribidi-dev\ - sway wl-clipboard libopenblas-dev nasm + sudo apt-get -qq install python3-tk\ + libjpeg-turbo-progs libopenjp2-7-dev\ + cmake meson\ + sway wl-clipboard nasm fi python3 -m pip install --upgrade pip python3 -m pip install --upgrade wheel python3 -m pip install coverage -python3 -m pip install defusedxml -python3 -m pip install ipython -python3 -m pip install olefile python3 -m pip install -U pytest python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-timeout python3 -m pip install pyroma if [[ $(uname) != CYGWIN* ]]; then - python3 -m pip install numpy - # PyQt6 doesn't support PyPy3 if [[ $GHA_PYTHON_VERSION == 3.* ]]; then sudo apt-get -qq install libegl1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0 @@ -53,20 +48,6 @@ if [[ $(uname) != CYGWIN* ]]; then python3 -m pip install "setuptools>=67.8" fi - # webp - pushd depends && ./install_webp.sh && popd - - # libimagequant - pushd depends && ./install_imagequant.sh && popd - - # raqm - pushd depends && ./install_raqm.sh && popd - # libavif pushd depends && ./install_libavif.sh && popd - - # extra test images - pushd depends && ./install_extra_test_images.sh && popd -else - cd depends && ./install_extra_test_images.sh && cd .. fi diff --git a/.ci/test.sh b/.ci/test.sh index 3f0ddc350a9..bb1afd0b87a 100755 --- a/.ci/test.sh +++ b/.ci/test.sh @@ -4,4 +4,4 @@ set -e python3 -c "from PIL import Image" -python3 -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests $REVERSE +python3 -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests/test_file_avif.py $REVERSE diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml deleted file mode 100644 index 0456bbaba3c..00000000000 --- a/.github/workflows/cifuzz.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: CIFuzz - -on: - push: - branches: - - "**" - paths: - - ".github/workflows/cifuzz.yml" - - ".github/workflows/wheels-dependencies.sh" - - "**.c" - - "**.h" - pull_request: - paths: - - ".github/workflows/cifuzz.yml" - - ".github/workflows/wheels-dependencies.sh" - - "**.c" - - "**.h" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - Fuzzing: - runs-on: ubuntu-latest - steps: - - name: Build Fuzzers - id: build - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master - with: - oss-fuzz-project-name: 'pillow' - language: python - dry-run: false - - name: Run Fuzzers - id: run - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master - with: - oss-fuzz-project-name: 'pillow' - fuzz-seconds: 600 - language: python - dry-run: false - - name: Upload New Crash - uses: actions/upload-artifact@v4 - if: failure() && steps.build.outcome == 'success' - with: - name: artifacts - path: ./out/artifacts - - name: Upload Legacy Crash - uses: actions/upload-artifact@v4 - if: steps.run.outcome == 'success' - with: - name: crash - path: ./out/crash* - - name: Fail on legacy crash - if: success() - run: | - [ ! -e out/crash-* ] - echo No legacy crash detected diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 626824f3830..00000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Docs - -on: - push: - branches: - - "**" - paths: - - ".github/workflows/docs.yml" - - "docs/**" - - "src/PIL/**" - pull_request: - paths: - - ".github/workflows/docs.yml" - - "docs/**" - - "src/PIL/**" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - FORCE_COLOR: 1 - -jobs: - build: - - runs-on: ubuntu-latest - name: Docs - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.x" - cache: pip - cache-dependency-path: | - ".ci/*.sh" - "pyproject.toml" - - - name: Build system information - run: python3 .github/workflows/system-info.py - - - name: Cache libimagequant - uses: actions/cache@v4 - id: cache-libimagequant - with: - path: ~/cache-libimagequant - key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }} - - - name: Install Linux dependencies - run: | - .ci/install.sh - env: - GHA_PYTHON_VERSION: "3.x" - GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }} - - - name: Build - run: | - .ci/build.sh - - - name: Docs - run: | - make doccheck diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 8e789a73489..00000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Lint - -on: [push, pull_request, workflow_dispatch] - -env: - FORCE_COLOR: 1 - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - - runs-on: ubuntu-latest - - name: Lint - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: pre-commit cache - uses: actions/cache@v4 - with: - path: ~/.cache/pre-commit - key: lint-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }} - restore-keys: | - lint-pre-commit- - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.x" - cache: pip - cache-dependency-path: "setup.py" - - - name: Build system information - run: python3 .github/workflows/system-info.py - - - name: Install dependencies - run: | - python3 -m pip install -U pip - python3 -m pip install -U tox - - - name: Lint - run: tox -e lint - env: - PRE_COMMIT_COLOR: always - - - name: Mypy - run: tox -e mypy diff --git a/.github/workflows/macos-install.sh b/.github/workflows/macos-install.sh index 0c3e55eae3c..cb3343dfc60 100755 --- a/.github/workflows/macos-install.sh +++ b/.github/workflows/macos-install.sh @@ -6,37 +6,18 @@ if [[ "$ImageOS" == "macos13" ]]; then brew uninstall gradle maven fi brew install \ - freetype \ - ghostscript \ jpeg-turbo \ - libimagequant \ - libtiff \ - little-cms2 \ - openjpeg \ - webp \ dav1d \ aom \ rav1e \ ninja -if [[ "$ImageOS" == "macos13" ]]; then - brew install --ignore-dependencies libraqm -else - brew install libraqm -fi export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig" python3 -m pip install coverage -python3 -m pip install defusedxml -python3 -m pip install ipython -python3 -m pip install olefile python3 -m pip install -U pytest python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-timeout python3 -m pip install pyroma -python3 -m pip install numpy # libavif pushd depends && ./install_libavif.sh && popd - -# extra test images -pushd depends && ./install_extra_test_images.sh && popd diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml deleted file mode 100644 index a8ddef22c86..00000000000 --- a/.github/workflows/release-drafter.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Release drafter - -on: - push: - # branches to consider in the event; optional, defaults to all - branches: - - main - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - update_release_draft: - permissions: - contents: write # for release-drafter/release-drafter to create a github release - pull-requests: write # for release-drafter/release-drafter to add label to PR - if: github.repository == 'python-pillow/Pillow' - runs-on: ubuntu-latest - steps: - # Drafts your next release notes as pull requests are merged into "main" - - uses: release-drafter/release-drafter@v6 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index 61ccf58e2ea..00000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Close stale issues - -on: - schedule: - - cron: "10 0 * * *" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - stale: - if: github.repository_owner == 'python-pillow' - permissions: - issues: write - - runs-on: ubuntu-latest - - steps: - - name: "Check issues" - uses: actions/stale@v9 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - only-labels: "Awaiting OP Action" - close-issue-message: "Closing this issue as no feedback has been received." - days-before-stale: 7 - days-before-issue-close: 0 - days-before-pr-close: -1 - labels-to-remove-when-unstale: "Awaiting OP Action" diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml deleted file mode 100644 index 5b0a0394688..00000000000 --- a/.github/workflows/test-cygwin.yml +++ /dev/null @@ -1,154 +0,0 @@ -name: Test Cygwin - -on: - push: - branches: - - "**" - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - pull_request: - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - COVERAGE_CORE: sysmon - -jobs: - build: - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - python-minor-version: [9] - - timeout-minutes: 40 - - name: Python 3.${{ matrix.python-minor-version }} - - steps: - - name: Fix line endings - run: | - git config --global core.autocrlf input - - - name: Checkout Pillow - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Install Cygwin - uses: cygwin/cygwin-install-action@v4 - with: - packages: > - gcc-g++ - ghostscript - git - ImageMagick - jpeg - libfreetype-devel - libimagequant-devel - libjpeg-devel - liblapack-devel - liblcms2-devel - libopenjp2-devel - libraqm-devel - libtiff-devel - libwebp-devel - libxcb-devel - libxcb-xinerama0 - make - netpbm - perl - python3${{ matrix.python-minor-version }}-cython - python3${{ matrix.python-minor-version }}-devel - python3${{ matrix.python-minor-version }}-ipython - python3${{ matrix.python-minor-version }}-numpy - python3${{ matrix.python-minor-version }}-sip - python3${{ matrix.python-minor-version }}-tkinter - wget - xorg-server-extra - zlib-devel - - - name: Add Lapack to PATH - uses: egor-tensin/cleanup-path@v4 - with: - dirs: 'C:\cygwin\bin;C:\cygwin\lib\lapack' - - - name: Select Python version - run: | - ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3 - - - name: pip cache - uses: actions/cache@v4 - with: - path: 'C:\cygwin\home\runneradmin\.cache\pip' - key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-${{ hashFiles('.ci/install.sh') }} - restore-keys: | - ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}- - - - name: Build system information - run: | - dash.exe -c "python3 .github/workflows/system-info.py" - - - name: Install dependencies - run: | - bash.exe .ci/install.sh - - - name: Build - shell: bash.exe -eo pipefail -o igncr "{0}" - run: | - .ci/build.sh - - - name: Test - run: | - bash.exe xvfb-run -s '-screen 0 1024x768x24' .ci/test.sh - - - name: Prepare to upload errors - if: failure() - run: | - dash.exe -c "mkdir -p Tests/errors" - - - name: Upload errors - uses: actions/upload-artifact@v4 - if: failure() - with: - name: errors - path: Tests/errors - - - name: After success - run: | - bash.exe .ci/after_success.sh - rm C:\cygwin\bin\bash.EXE - - - name: Upload coverage - uses: codecov/codecov-action@v5 - with: - files: ./coverage.xml - flags: GHA_Cygwin - name: Cygwin Python 3.${{ matrix.python-minor-version }} - token: ${{ secrets.CODECOV_ORG_TOKEN }} - - success: - permissions: - contents: none - needs: build - runs-on: ubuntu-latest - name: Cygwin Test Successful - steps: - - name: Success - run: echo Cygwin Test Successful diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml deleted file mode 100644 index cc5f9d4a5a9..00000000000 --- a/.github/workflows/test-docker.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: Test Docker - -on: - push: - branches: - - "**" - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - pull_request: - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - docker: [ - # Run slower jobs first to give them a headstart and reduce waiting time - ubuntu-22.04-jammy-arm64v8, - ubuntu-24.04-noble-ppc64le, - ubuntu-24.04-noble-s390x, - # Then run the remainder - alpine, - amazon-2-amd64, - amazon-2023-amd64, - arch, - centos-stream-9-amd64, - debian-12-bookworm-x86, - debian-12-bookworm-amd64, - fedora-40-amd64, - fedora-41-amd64, - gentoo, - ubuntu-22.04-jammy-amd64, - ubuntu-24.04-noble-amd64, - ] - dockerTag: [main] - include: - - docker: "ubuntu-22.04-jammy-arm64v8" - qemu-arch: "aarch64" - - docker: "ubuntu-24.04-noble-ppc64le" - qemu-arch: "ppc64le" - - docker: "ubuntu-24.04-noble-s390x" - qemu-arch: "s390x" - - name: ${{ matrix.docker }} - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Build system information - run: python3 .github/workflows/system-info.py - - - name: Set up QEMU - if: "matrix.qemu-arch" - run: | - docker run --rm --privileged aptman/qus -s -- -p ${{ matrix.qemu-arch }} - - - name: Docker pull - run: | - docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} - - - name: Docker build - run: | - # The Pillow user in the docker container is UID 1001 - sudo chown -R 1001 $GITHUB_WORKSPACE - docker run --name pillow_container -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} - sudo chown -R runner $GITHUB_WORKSPACE - - - name: After success - run: | - PATH="$PATH:~/.local/bin" - docker start pillow_container - pil_path=`docker exec pillow_container /vpy3/bin/python -c 'import os, PIL;print(os.path.realpath(os.path.dirname(PIL.__file__)))'` - docker stop pillow_container - sudo mkdir -p $pil_path - sudo cp src/PIL/*.py $pil_path - .ci/after_success.sh - env: - MATRIX_DOCKER: ${{ matrix.docker }} - - - name: Upload coverage - uses: codecov/codecov-action@v5 - with: - flags: GHA_Docker - name: ${{ matrix.docker }} - token: ${{ secrets.CODECOV_ORG_TOKEN }} - - success: - permissions: - contents: none - needs: build - runs-on: ubuntu-latest - name: Docker Test Successful - steps: - - name: Success - run: echo Docker Test Successful diff --git a/.github/workflows/test-mingw.yml b/.github/workflows/test-mingw.yml deleted file mode 100644 index 5db9140675d..00000000000 --- a/.github/workflows/test-mingw.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Test MinGW - -on: - push: - branches: - - "**" - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - pull_request: - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - COVERAGE_CORE: sysmon - -jobs: - build: - runs-on: windows-latest - - defaults: - run: - shell: bash.exe --login -eo pipefail "{0}" - env: - MSYSTEM: MINGW64 - CHERE_INVOKING: 1 - - timeout-minutes: 30 - name: "MinGW" - - steps: - - name: Checkout Pillow - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Set up shell - run: echo "C:\msys64\usr\bin\" >> $env:GITHUB_PATH - shell: pwsh - - - name: Install dependencies - run: | - pacman -S --noconfirm \ - mingw-w64-x86_64-freetype \ - mingw-w64-x86_64-gcc \ - mingw-w64-x86_64-ghostscript \ - mingw-w64-x86_64-lcms2 \ - mingw-w64-x86_64-libimagequant \ - mingw-w64-x86_64-libjpeg-turbo \ - mingw-w64-x86_64-libraqm \ - mingw-w64-x86_64-libavif \ - mingw-w64-x86_64-libtiff \ - mingw-w64-x86_64-libwebp \ - mingw-w64-x86_64-openjpeg2 \ - mingw-w64-x86_64-python3-numpy \ - mingw-w64-x86_64-python3-olefile \ - mingw-w64-x86_64-python3-pip \ - mingw-w64-x86_64-python-pytest \ - mingw-w64-x86_64-python-pytest-cov \ - mingw-w64-x86_64-python-pytest-timeout \ - mingw-w64-x86_64-python-pyqt6 - - pushd depends && ./install_extra_test_images.sh && popd - - - name: Build Pillow - run: CFLAGS="-coverage" python3 -m pip install . - - - name: Test Pillow - run: | - python3 selftest.py --installed - .ci/test.sh - - - name: Upload coverage - uses: codecov/codecov-action@v5 - with: - files: ./coverage.xml - flags: GHA_Windows - name: "MSYS2 MinGW" - token: ${{ secrets.CODECOV_ORG_TOKEN }} diff --git a/.github/workflows/test-valgrind.yml b/.github/workflows/test-valgrind.yml deleted file mode 100644 index 8818b3b2357..00000000000 --- a/.github/workflows/test-valgrind.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Test Valgrind - -# like the Docker tests, but running valgrind only on *.c/*.h changes. - -on: - push: - branches: - - "**" - paths: - - ".github/workflows/test-valgrind.yml" - - "**.c" - - "**.h" - pull_request: - paths: - - ".github/workflows/test-valgrind.yml" - - "**.c" - - "**.h" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - docker: [ - ubuntu-22.04-jammy-amd64-valgrind, - ] - dockerTag: [main] - - name: ${{ matrix.docker }} - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Build system information - run: python3 .github/workflows/system-info.py - - - name: Docker pull - run: | - docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} - - - name: Build and Run Valgrind - run: | - # The Pillow user in the docker container is UID 1001 - sudo chown -R 1001 $GITHUB_WORKSPACE - docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} - sudo chown -R runner $GITHUB_WORKSPACE diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml deleted file mode 100644 index 39223089d36..00000000000 --- a/.github/workflows/test-windows.yml +++ /dev/null @@ -1,237 +0,0 @@ -name: Test Windows - -on: - push: - branches: - - "**" - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - pull_request: - paths-ignore: - - ".github/workflows/docs.yml" - - ".github/workflows/wheels*" - - ".gitmodules" - - "docs/**" - - "wheels/**" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - COVERAGE_CORE: sysmon - -jobs: - build: - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - python-version: ["pypy3.10", "3.9", "3.10", "3.11", "3.12", "3.13"] - - timeout-minutes: 45 - - name: Python ${{ matrix.python-version }} - - steps: - - name: Checkout Pillow - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Checkout cached dependencies - uses: actions/checkout@v4 - with: - persist-credentials: false - repository: python-pillow/pillow-depends - path: winbuild\depends - - - name: Checkout extra test images - uses: actions/checkout@v4 - with: - persist-credentials: false - repository: python-pillow/test-images - path: Tests\test-images - - # sets env: pythonLocation - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - allow-prereleases: true - cache: pip - cache-dependency-path: ".github/workflows/test-windows.yml" - - - name: Print build system information - run: python3 .github/workflows/system-info.py - - - name: Upgrade pip - run: | - python3 -m pip install --upgrade pip - - - name: Install CPython dependencies - if: "!contains(matrix.python-version, 'pypy')" - run: | - python3 -m pip install PyQt6 - - - name: Install dependencies - id: install - run: | - choco install nasm --no-progress - echo "C:\Program Files\NASM" >> $env:GITHUB_PATH - - choco install ghostscript --version=10.4.0 --no-progress - echo "C:\Program Files\gs\gs10.04.0\bin" >> $env:GITHUB_PATH - - # Install extra test images - xcopy /S /Y Tests\test-images\* Tests\images - - # make cache key depend on VS version - & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" ` - | find """catalog_buildVersion""" ` - | ForEach-Object { $a = $_.split(" ")[1]; echo "vs=$a" >> $env:GITHUB_OUTPUT } - shell: pwsh - - - name: Cache build - id: build-cache - uses: actions/cache@v4 - with: - path: winbuild\build - key: - ${{ hashFiles('winbuild\build_prepare.py') }}-${{ hashFiles('.github\workflows\test-windows.yml') }}-${{ env.pythonLocation }}-${{ steps.install.outputs.vs }} - - - name: Prepare build - if: steps.build-cache.outputs.cache-hit != 'true' - run: | - & python.exe winbuild\build_prepare.py -v - shell: pwsh - - - name: Build dependencies / libjpeg-turbo - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libjpeg.cmd" - - - name: Build dependencies / zlib - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_zlib.cmd" - - - name: Build dependencies / xz - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_xz.cmd" - - - name: Build dependencies / WebP - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libwebp.cmd" - - - name: Build dependencies / LibTiff - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libtiff.cmd" - - # for FreeType CBDT/SBIX font support - - name: Build dependencies / libpng - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libpng.cmd" - - - name: Build dependencies / libavif - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libavif.cmd" - - # for FreeType WOFF2 font support - - name: Build dependencies / brotli - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_brotli.cmd" - - - name: Build dependencies / FreeType - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_freetype.cmd" - - - name: Build dependencies / LCMS2 - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_lcms2.cmd" - - - name: Build dependencies / OpenJPEG - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_openjpeg.cmd" - - # GPL licensed - - name: Build dependencies / libimagequant - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libimagequant.cmd" - - # Raqm dependencies - - name: Build dependencies / HarfBuzz - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_harfbuzz.cmd" - - # Raqm dependencies - - name: Build dependencies / FriBidi - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_fribidi.cmd" - - # trim ~150MB for each job - - name: Optimize build cache - if: steps.build-cache.outputs.cache-hit != 'true' - run: rmdir /S /Q winbuild\build\src - shell: cmd - - - name: Build Pillow - run: | - $FLAGS="-C raqm=vendor -C fribidi=vendor" - cmd /c "winbuild\build\build_env.cmd && $env:pythonLocation\python.exe -m pip install -v $FLAGS .[tests]" - & $env:pythonLocation\python.exe selftest.py --installed - shell: pwsh - - # skip PyPy for speed - - name: Enable heap verification - if: "!contains(matrix.python-version, 'pypy')" - run: | - & reg.exe add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\python.exe" /v "GlobalFlag" /t REG_SZ /d "0x02000000" /f - - - name: Test Pillow - run: | - path %GITHUB_WORKSPACE%\winbuild\build\bin;%PATH% - .ci\test.cmd - shell: cmd - - - name: Prepare to upload errors - if: failure() - run: | - mkdir -p Tests/errors - shell: bash - - - name: Upload errors - uses: actions/upload-artifact@v4 - if: failure() - with: - name: errors - path: Tests/errors - - - name: After success - run: | - .ci/after_success.sh - shell: pwsh - - - name: Upload coverage - uses: codecov/codecov-action@v5 - with: - files: ./coverage.xml - flags: GHA_Windows - name: ${{ runner.os }} Python ${{ matrix.python-version }} - token: ${{ secrets.CODECOV_ORG_TOKEN }} - - success: - permissions: - contents: none - needs: build - runs-on: ubuntu-latest - name: Windows Test Successful - steps: - - name: Success - run: echo Windows Test Successful diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 83a696f5f8b..247f8a7e49b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,10 +22,6 @@ on: permissions: contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: COVERAGE_CORE: sysmon FORCE_COLOR: 1 @@ -41,23 +37,8 @@ jobs: "ubuntu-latest", ] python-version: [ - "pypy3.10", - "3.13t", "3.13", - "3.12", - "3.11", - "3.10", - "3.9", ] - include: - - { python-version: "3.11", PYTHONOPTIMIZE: 1, REVERSE: "--reverse" } - - { python-version: "3.10", PYTHONOPTIMIZE: 2 } - # Free-threaded - - { python-version: "3.13t", disable-gil: true } - # M1 only available for 3.10+ - - { os: "macos-13", python-version: "3.9" } - exclude: - - { os: "macos-latest", python-version: "3.9" } runs-on: ${{ matrix.os }} name: ${{ matrix.os }} Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml deleted file mode 100644 index c5e55aa621d..00000000000 --- a/.github/workflows/wheels.yml +++ /dev/null @@ -1,312 +0,0 @@ -name: Wheels - -on: - schedule: - # ┌───────────── minute (0 - 59) - # │ ┌───────────── hour (0 - 23) - # │ │ ┌───────────── day of the month (1 - 31) - # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) - # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) - # │ │ │ │ │ - - cron: "42 1 * * 0,3" - push: - paths: - - ".ci/requirements-cibw.txt" - - ".github/workflows/wheel*" - - "setup.py" - - "wheels/*" - - "winbuild/build_prepare.py" - - "winbuild/fribidi.cmake" - tags: - - "*" - pull_request: - paths: - - ".ci/requirements-cibw.txt" - - ".github/workflows/wheel*" - - "setup.py" - - "wheels/*" - - "winbuild/build_prepare.py" - - "winbuild/fribidi.cmake" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - FORCE_COLOR: 1 - -jobs: - build-1-QEMU-emulated-wheels: - if: github.event_name != 'schedule' - name: aarch64 ${{ matrix.python-version }} ${{ matrix.spec }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: - - pp310 - - cp3{9,10,11} - - cp3{12,13} - spec: - - manylinux2014 - - manylinux_2_28 - - musllinux - exclude: - - { python-version: pp310, spec: musllinux } - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - submodules: true - - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Install cibuildwheel - run: | - python3 -m pip install -r .ci/requirements-cibw.txt - - - name: Build wheels - run: | - python3 -m cibuildwheel --output-dir wheelhouse - env: - # Build only the currently selected Linux architecture (so we can - # parallelise for speed). - CIBW_ARCHS: "aarch64" - # Likewise, select only one Python version per job to speed this up. - CIBW_BUILD: "${{ matrix.python-version }}-${{ matrix.spec == 'musllinux' && 'musllinux' || 'manylinux' }}*" - CIBW_ENABLE: cpython-prerelease - # Extra options for manylinux. - CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.spec }} - CIBW_MANYLINUX_PYPY_AARCH64_IMAGE: ${{ matrix.spec }} - - - uses: actions/upload-artifact@v4 - with: - name: dist-qemu-${{ matrix.python-version }}-${{ matrix.spec }} - path: ./wheelhouse/*.whl - - build-2-native-wheels: - if: github.event_name != 'schedule' || github.repository_owner == 'python-pillow' - name: ${{ matrix.name }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - name: "macOS 10.10 x86_64" - os: macos-13 - cibw_arch: x86_64 - build: "cp3{9,10,11}*" - macosx_deployment_target: "10.10" - - name: "macOS 10.13 x86_64" - os: macos-13 - cibw_arch: x86_64 - build: "cp3{12,13}*" - macosx_deployment_target: "10.13" - - name: "macOS 10.15 x86_64" - os: macos-13 - cibw_arch: x86_64 - build: "pp310*" - macosx_deployment_target: "10.15" - - name: "macOS arm64" - os: macos-latest - cibw_arch: arm64 - macosx_deployment_target: "11.0" - - name: "manylinux2014 and musllinux x86_64" - os: ubuntu-latest - cibw_arch: x86_64 - - name: "manylinux_2_28 x86_64" - os: ubuntu-latest - cibw_arch: x86_64 - build: "*manylinux*" - manylinux: "manylinux_2_28" - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - submodules: true - - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - - name: Install cibuildwheel - run: | - python3 -m pip install -r .ci/requirements-cibw.txt - - - name: Build wheels - run: | - python3 -m cibuildwheel --output-dir wheelhouse - env: - CIBW_ARCHS: ${{ matrix.cibw_arch }} - CIBW_BUILD: ${{ matrix.build }} - CIBW_ENABLE: cpython-prerelease cpython-freethreading - CIBW_MANYLINUX_PYPY_X86_64_IMAGE: ${{ matrix.manylinux }} - CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux }} - CIBW_SKIP: pp39-* - MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }} - - - uses: actions/upload-artifact@v4 - with: - name: dist-${{ matrix.os }}${{ matrix.macosx_deployment_target && format('-{0}', matrix.macosx_deployment_target) }}-${{ matrix.cibw_arch }}${{ matrix.manylinux && format('-{0}', matrix.manylinux) }} - path: ./wheelhouse/*.whl - - windows: - if: github.event_name != 'schedule' || github.repository_owner == 'python-pillow' - name: Windows ${{ matrix.cibw_arch }} - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - include: - - cibw_arch: x86 - - cibw_arch: AMD64 - - cibw_arch: ARM64 - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Checkout extra test images - uses: actions/checkout@v4 - with: - persist-credentials: false - repository: python-pillow/test-images - path: Tests\test-images - - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - - name: Install cibuildwheel - run: | - python.exe -m pip install -r .ci/requirements-cibw.txt - - - name: Prepare for build - run: | - choco install nasm --no-progress - echo "C:\Program Files\NASM" >> $env:GITHUB_PATH - - # Install extra test images - xcopy /S /Y Tests\test-images\* Tests\images - - & python.exe winbuild\build_prepare.py -v --no-imagequant --architecture=${{ matrix.cibw_arch }} - shell: pwsh - - - name: Build wheels - run: | - setlocal EnableDelayedExpansion - for %%f in (winbuild\build\license\*) do ( - set x=%%~nf - rem Skip FriBiDi license, it is not included in the wheel. - set fribidi=!x:~0,7! - if NOT !fribidi!==fribidi ( - rem Skip imagequant license, it is not included in the wheel. - set libimagequant=!x:~0,13! - if NOT !libimagequant!==libimagequant ( - echo. >> LICENSE - echo ===== %%~nf ===== >> LICENSE - echo. >> LICENSE - type %%f >> LICENSE - ) - ) - ) - call winbuild\\build\\build_env.cmd - %pythonLocation%\python.exe -m cibuildwheel . --output-dir wheelhouse - env: - CIBW_ARCHS: ${{ matrix.cibw_arch }} - CIBW_BEFORE_ALL: "{package}\\winbuild\\build\\build_dep_all.cmd" - CIBW_CACHE_PATH: "C:\\cibw" - CIBW_ENABLE: cpython-prerelease cpython-freethreading - CIBW_SKIP: pp39-* - CIBW_TEST_SKIP: "*-win_arm64" - CIBW_TEST_COMMAND: 'docker run --rm - -v {project}:C:\pillow - -v C:\cibw:C:\cibw - -v %CD%\..\venv-test:%CD%\..\venv-test - -e CI -e GITHUB_ACTIONS - mcr.microsoft.com/windows/servercore:ltsc2022 - powershell C:\pillow\.github\workflows\wheels-test.ps1 %CD%\..\venv-test' - shell: cmd - - - name: Upload wheels - uses: actions/upload-artifact@v4 - with: - name: dist-windows-${{ matrix.cibw_arch }} - path: ./wheelhouse/*.whl - - - name: Upload fribidi.dll - uses: actions/upload-artifact@v4 - with: - name: fribidi-windows-${{ matrix.cibw_arch }} - path: winbuild\build\bin\fribidi* - - sdist: - if: github.event_name != 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.x" - cache: pip - cache-dependency-path: "Makefile" - - - run: make sdist - - - uses: actions/upload-artifact@v4 - with: - name: dist-sdist - path: dist/*.tar.gz - - scientific-python-nightly-wheels-publish: - if: github.repository_owner == 'python-pillow' && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') - needs: [build-2-native-wheels, windows] - runs-on: ubuntu-latest - name: Upload wheels to scientific-python-nightly-wheels - steps: - - uses: actions/download-artifact@v4 - with: - pattern: dist-* - path: dist - merge-multiple: true - - name: Upload wheels to scientific-python-nightly-wheels - uses: scientific-python/upload-nightly-action@82396a2ed4269ba06c6b2988bb4fd568ef3c3d6b # 0.6.1 - with: - artifacts_path: dist - anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} - - pypi-publish: - if: github.repository_owner == 'python-pillow' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - needs: [build-1-QEMU-emulated-wheels, build-2-native-wheels, windows, sdist] - runs-on: ubuntu-latest - name: Upload release to PyPI - environment: - name: release-pypi - url: https://pypi.org/p/Pillow - permissions: - id-token: write - steps: - - uses: actions/download-artifact@v4 - with: - pattern: dist-* - path: dist - merge-multiple: true - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - attestations: true diff --git a/Tests/test_file_avif.py b/Tests/test_file_avif.py index 1bc7299b62e..44585b4813e 100644 --- a/Tests/test_file_avif.py +++ b/Tests/test_file_avif.py @@ -147,7 +147,7 @@ def test_read(self) -> None: # generated with: # avifdec hopper.avif hopper_avif_write.png assert_image_similar_tofile( - image, "Tests/images/avif/hopper_avif_write.png", 12.0 + image, "Tests/images/avif/hopper_avif_write.png", 11.5 ) def _roundtrip(self, tmp_path: Path, mode: str, epsilon: float) -> None: @@ -163,7 +163,7 @@ def _roundtrip(self, tmp_path: Path, mode: str, epsilon: float) -> None: if mode == "RGB": # avifdec hopper.avif avif/hopper_avif_write.png assert_image_similar_tofile( - image, "Tests/images/avif/hopper_avif_write.png", 12.0 + image, "Tests/images/avif/hopper_avif_write.png", 5.81 ) # This test asserts that the images are similar. If the average pixel @@ -181,7 +181,7 @@ def test_write_rgb(self, tmp_path: Path) -> None: Does it have the bits we expect? """ - self._roundtrip(tmp_path, "RGB", 12.5) + self._roundtrip(tmp_path, "RGB", 8.41) def test_AvifEncoder_with_invalid_args(self) -> None: """ @@ -574,7 +574,7 @@ def test_p_mode_transparency(self) -> None: im_png.save(buf_out, format="AVIF", quality=100) with Image.open(buf_out) as expected: - assert_image_similar(im_png.convert("RGBA"), expected, 1) + assert_image_similar(im_png.convert("RGBA"), expected, 0.17) def test_decoder_strict_flags(self) -> None: # This would fail if full avif strictFlags were enabled @@ -633,10 +633,10 @@ def test_write_animation_L(self, tmp_path: Path) -> None: assert im.n_frames == orig.n_frames # Compare first and second-to-last frames to the original animated GIF - assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0) + assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 2.25) orig.seek(orig.n_frames - 2) im.seek(im.n_frames - 2) - assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0) + assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 2.54) def test_write_animation_RGB(self, tmp_path: Path) -> None: """ @@ -649,11 +649,11 @@ def check(temp_file: str) -> None: assert im.n_frames == 4 # Compare first frame to original - assert_image_similar(im, frame1.convert("RGBA"), 25.0) + assert_image_similar(im, frame1.convert("RGBA"), 2.7) # Compare second frame to original im.seek(1) - assert_image_similar(im, frame2.convert("RGBA"), 25.0) + assert_image_similar(im, frame2.convert("RGBA"), 4.1) with self.star_frames() as frames: frame1 = frames[0]