Merge branch 'master' into gitignore-review
|
@ -6,86 +6,51 @@ init:
|
|||
# Uncomment previous line to get RDP access during the build.
|
||||
|
||||
environment:
|
||||
X64_EXT: -x64
|
||||
EXECUTABLE: python.exe
|
||||
PIP_DIR: Scripts
|
||||
VENV: NO
|
||||
TEST_OPTIONS:
|
||||
DEPLOY: YES
|
||||
matrix:
|
||||
- PYTHON: C:/Python38
|
||||
- PYTHON: C:/Python38-x64
|
||||
- PYTHON: C:/Python37
|
||||
- PYTHON: C:/Python37-x64
|
||||
- PYTHON: C:/Python36
|
||||
- PYTHON: C:/Python39
|
||||
ARCHITECTURE: x86
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
- PYTHON: C:/Python36-x64
|
||||
- PYTHON: C:/Python35
|
||||
- PYTHON: C:/Python35-x64
|
||||
- PYTHON: C:/msys64/mingw32
|
||||
EXECUTABLE: bin/python3
|
||||
PIP_DIR: bin
|
||||
TEST_OPTIONS: --processes=0
|
||||
DEPLOY: NO
|
||||
- PYTHON: C:/vp/pypy3
|
||||
EXECUTABLE: bin/pypy.exe
|
||||
PIP_DIR: bin
|
||||
VENV: YES
|
||||
ARCHITECTURE: x64
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
|
||||
|
||||
install:
|
||||
- curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/master.zip
|
||||
- 7z x pillow-depends.zip -oc:\
|
||||
- mv c:\pillow-depends-master c:\pillow-depends
|
||||
- xcopy c:\pillow-depends\*.zip c:\pillow\winbuild\
|
||||
- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\
|
||||
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
|
||||
- xcopy /S /Y c:\pillow-depends\test_images\* c:\pillow\tests\images
|
||||
- 7z x ..\pillow-depends\nasm-2.14.02-win64.zip -oc:\
|
||||
- ..\pillow-depends\gs9533w32.exe /S
|
||||
- path c:\nasm-2.14.02;C:\Program Files (x86)\gs\gs9.53.3\bin;%PATH%
|
||||
- cd c:\pillow\winbuild\
|
||||
- ps: |
|
||||
if ($env:PYTHON -eq "c:/vp/pypy3")
|
||||
{
|
||||
c:\pillow\winbuild\appveyor_install_pypy3.cmd
|
||||
}
|
||||
- ps: |
|
||||
if ($env:PYTHON -eq "c:/msys64/mingw32")
|
||||
{
|
||||
c:\msys64\usr\bin\bash -l -c c:\\pillow\\winbuild\\appveyor_install_msys2_deps.sh
|
||||
}
|
||||
else
|
||||
{
|
||||
c:\python37\python.exe c:\pillow\winbuild\build_dep.py
|
||||
c:\pillow\winbuild\build_deps.cmd
|
||||
c:\python37\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\
|
||||
c:\pillow\winbuild\build\build_dep_all.cmd
|
||||
$host.SetShouldExit(0)
|
||||
}
|
||||
- curl -fsSL -o gs950.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs950/gs950w32.exe
|
||||
- gs950.exe /S
|
||||
- path %path%;C:\Program Files (x86)\gs\gs9.50\bin
|
||||
- path C:\pillow\winbuild\build\bin;%PATH%
|
||||
- '%PYTHON%\%EXECUTABLE% -m pip install -U "setuptools>=49.3.2"'
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
if ($env:PYTHON -eq "c:/msys64/mingw32")
|
||||
{
|
||||
c:\msys64\usr\bin\bash -l -c c:\\pillow\\winbuild\\appveyor_build_msys2.sh
|
||||
Write-Host "through install"
|
||||
c:\pillow\winbuild\build\build_pillow.cmd install
|
||||
$host.SetShouldExit(0)
|
||||
}
|
||||
else
|
||||
{
|
||||
& $env:PYTHON/$env:EXECUTABLE c:\pillow\winbuild\build.py
|
||||
$host.SetShouldExit(0)
|
||||
}
|
||||
- cd c:\pillow
|
||||
- '%PYTHON%\%EXECUTABLE% selftest.py --installed'
|
||||
|
||||
test_script:
|
||||
- cd c:\pillow
|
||||
- '%PYTHON%\%PIP_DIR%\pip.exe install pytest pytest-cov'
|
||||
- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov'
|
||||
- c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE%
|
||||
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov-report term --cov-report xml Tests'
|
||||
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests'
|
||||
#- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest?
|
||||
|
||||
after_test:
|
||||
- pip install codecov
|
||||
- codecov --file coverage.xml --name %PYTHON%
|
||||
- python -m pip install codecov
|
||||
- codecov --file coverage.xml --name %PYTHON% --flags AppVeyor
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
@ -101,9 +66,9 @@ artifacts:
|
|||
|
||||
before_deploy:
|
||||
- cd c:\pillow
|
||||
- '%PYTHON%\%PIP_DIR%\pip.exe install wheel'
|
||||
- '%PYTHON%\%EXECUTABLE% -m pip install wheel'
|
||||
- cd c:\pillow\winbuild\
|
||||
- '%PYTHON%\%EXECUTABLE% c:\pillow\winbuild\build.py --wheel'
|
||||
- c:\pillow\winbuild\build\build_pillow.cmd bdist_wheel
|
||||
- cd c:\pillow
|
||||
- ps: Get-ChildItem .\dist\*.* | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
parameters:
|
||||
name: '' # defaults for any parameters that aren't specified
|
||||
vmImage: ''
|
||||
|
||||
jobs:
|
||||
|
||||
- job: ${{ parameters.name }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.vmImage }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
Python37:
|
||||
python.version: '3.7'
|
||||
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '$(python.version)'
|
||||
architecture: 'x64'
|
||||
|
||||
- script: |
|
||||
python -m pip install --upgrade tox
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: |
|
||||
tox -e lint
|
||||
displayName: 'Lint'
|
|
@ -1,22 +0,0 @@
|
|||
parameters:
|
||||
docker: '' # defaults for any parameters that aren't specified
|
||||
dockerTag: 'master'
|
||||
name: ''
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
|
||||
jobs:
|
||||
|
||||
- job: ${{ parameters.name }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.vmImage }}
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
docker pull pythonpillow/${{ parameters.docker }}:${{ parameters.dockerTag }}
|
||||
displayName: 'Docker pull'
|
||||
|
||||
- script: |
|
||||
# The Pillow user in the docker container is UID 1000
|
||||
sudo chown -R 1000 $(Build.SourcesDirectory)
|
||||
docker run -v $(Build.SourcesDirectory):/Pillow pythonpillow/${{ parameters.docker }}:${{ parameters.dockerTag }}
|
||||
displayName: 'Docker build'
|
19
.ci/after_success.sh
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
# gather the coverage data
|
||||
pip3 install codecov
|
||||
if [[ $MATRIX_DOCKER ]]; then
|
||||
coverage xml --ignore-errors
|
||||
else
|
||||
coverage xml
|
||||
fi
|
||||
|
||||
if [[ $TRAVIS ]]; then
|
||||
codecov --flags TravisCI
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.9" ]; then
|
||||
# Coverage and quality reports on just the latest diff.
|
||||
depends/diffcover-install.sh
|
||||
depends/diffcover-run.sh
|
||||
fi
|
64
.ci/install.sh
Executable file
|
@ -0,0 +1,64 @@
|
|||
#!/bin/bash
|
||||
|
||||
aptget_update()
|
||||
{
|
||||
if [ ! -z $1 ]; then
|
||||
echo ""
|
||||
echo "Retrying apt-get update..."
|
||||
echo ""
|
||||
fi
|
||||
output=`sudo apt-get update 2>&1`
|
||||
echo "$output"
|
||||
if [[ $output == *[WE]:\ * ]]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
aptget_update || aptget_update retry || aptget_update retry
|
||||
|
||||
set -e
|
||||
|
||||
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
|
||||
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
|
||||
cmake imagemagick libharfbuzz-dev libfribidi-dev
|
||||
|
||||
if [[ $TRAVIS_CPU_ARCH == "s390x" ]]; then sudo chown $USER ~/.cache/pip/wheels ; fi
|
||||
|
||||
python3 -m pip install --upgrade pip
|
||||
PYTHONOPTIMIZE=0 python3 -m pip install cffi
|
||||
python3 -m pip install coverage
|
||||
python3 -m pip install olefile
|
||||
python3 -m pip install -U pytest
|
||||
python3 -m pip install -U pytest-cov
|
||||
python3 -m pip install pyroma
|
||||
python3 -m pip install test-image-results
|
||||
# TODO Remove condition when numpy supports 3.10
|
||||
if ! [ "$GHA_PYTHON_VERSION" == "3.10-dev" ]; then python3 -m pip install numpy ; fi
|
||||
|
||||
# TODO Remove when 3.8 / 3.9 / PyPy3 includes setuptools 49.3.2+:
|
||||
if [ "$GHA_PYTHON_VERSION" == "3.8" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi
|
||||
if [ "$GHA_PYTHON_VERSION" == "3.9" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "pypy3.6-7.3.1" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi
|
||||
|
||||
if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
|
||||
# arm64, ppc64le, s390x CPUs:
|
||||
# "ERROR: Could not find a version that satisfies the requirement pyqt5"
|
||||
if [[ $TRAVIS_CPU_ARCH == "amd64" ]]; then
|
||||
sudo apt-get -qq install libxcb-xinerama0 pyqt5-dev-tools
|
||||
python3 -m pip install pyqt5
|
||||
fi
|
||||
fi
|
||||
|
||||
# docs only on Python 3.9
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.9" ]; then python3 -m pip install -r requirements.txt ; fi
|
||||
|
||||
# webp
|
||||
pushd depends && ./install_webp.sh && popd
|
||||
|
||||
# libimagequant
|
||||
pushd depends && ./install_imagequant.sh && popd
|
||||
|
||||
# raqm
|
||||
pushd depends && ./install_raqm.sh && popd
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
10
.ci/test.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
python -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests
|
||||
|
||||
# Docs
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.9" ] && [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then
|
||||
make doccheck
|
||||
fi
|
11
.codecov.yml
|
@ -1,11 +0,0 @@
|
|||
# Documentation: https://docs.codecov.io/docs/codecov-yaml
|
||||
|
||||
codecov:
|
||||
# Avoid "Missing base report" due to committing CHANGES.rst with "[CI skip]"
|
||||
# https://github.com/codecov/support/issues/363
|
||||
# https://docs.codecov.io/v4.3.6/docs/comparing-commits
|
||||
allow_coverage_offsets: true
|
||||
|
||||
token: 6dafc396-e7f5-4221-a38a-8b07a49fbdae
|
||||
|
||||
comment: off
|
|
@ -10,5 +10,11 @@ exclude_lines =
|
|||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
# Don't complain about debug code
|
||||
if Image.DEBUG:
|
||||
if DEBUG:
|
||||
|
||||
[run]
|
||||
omit =
|
||||
Tests/32bit_segfault_check.py
|
||||
Tests/bench_cffi_access.py
|
||||
Tests/check_*.py
|
||||
Tests/createfontdatachunk.py
|
||||
|
|
4
.github/CONTRIBUTING.md
vendored
|
@ -9,7 +9,7 @@ Please send a pull request to the master branch. Please include [documentation](
|
|||
- Fork the Pillow repository.
|
||||
- Create a branch from master.
|
||||
- Develop bug fixes, features, tests, etc.
|
||||
- Run the test suite. You can enable [Travis CI](https://travis-ci.org/profile/) and [AppVeyor](https://ci.appveyor.com/projects/new) on your repo to catch test failures prior to the pull request, and [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
|
||||
- Run the test suite. You can enable [Travis CI](https://travis-ci.com/account/repositories) and [AppVeyor](https://ci.appveyor.com/projects/new) on your repo to catch test failures prior to the pull request, and [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
|
||||
- Create a pull request to pull the changes from your branch to the Pillow master.
|
||||
|
||||
### Guidelines
|
||||
|
@ -17,7 +17,7 @@ Please send a pull request to the master branch. Please include [documentation](
|
|||
- Separate code commits from reformatting commits.
|
||||
- Provide tests for any newly added code.
|
||||
- Follow PEP 8.
|
||||
- When committing only documentation changes please include [ci skip] in the commit message to avoid running tests on Travis-CI and AppVeyor.
|
||||
- When committing only documentation changes please include `[ci skip]` in the commit message to avoid running tests on Travis CI and AppVeyor.
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
|
|
14
.github/mergify.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
pull_request_rules:
|
||||
- name: Automatic merge
|
||||
conditions:
|
||||
- "#approved-reviews-by>=1"
|
||||
- label=automerge
|
||||
- status-success=Lint
|
||||
- status-success=Test Successful
|
||||
- status-success=Docker Test Successful
|
||||
- status-success=Windows Test Successful
|
||||
- status-success=Travis CI - Pull Request
|
||||
- status-success=continuous-integration/appveyor/pr
|
||||
actions:
|
||||
merge:
|
||||
method: merge
|
39
.github/workflows/lint.yml
vendored
|
@ -6,24 +6,43 @@ jobs:
|
|||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8"]
|
||||
|
||||
name: Python ${{ matrix.python-version }}
|
||||
name: Lint
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
- name: pip cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
path: ~/.cache/pip
|
||||
key: lint-pip-${{ hashFiles('**/setup.py') }}
|
||||
restore-keys: |
|
||||
lint-pip-
|
||||
|
||||
- name: pre-commit cache
|
||||
uses: actions/cache@v2
|
||||
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@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Build system information
|
||||
run: python .github/workflows/system-info.py
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade tox
|
||||
python -m pip install -U pip
|
||||
python -m pip install -U tox
|
||||
|
||||
- name: Lint
|
||||
run: tox -e lint
|
||||
env:
|
||||
PRE_COMMIT_COLOR: always
|
||||
|
||||
|
|
25
.github/workflows/macos-install.sh
vendored
|
@ -2,16 +2,23 @@
|
|||
|
||||
set -e
|
||||
|
||||
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype
|
||||
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype openblas
|
||||
|
||||
PYTHONOPTIMIZE=0 pip install cffi
|
||||
pip install coverage
|
||||
pip install olefile
|
||||
pip install -U pytest
|
||||
pip install -U pytest-cov
|
||||
pip install pyroma
|
||||
pip install test-image-results
|
||||
pip install numpy
|
||||
PYTHONOPTIMIZE=0 python3 -m pip install cffi
|
||||
python3 -m pip install coverage
|
||||
python3 -m pip install olefile
|
||||
python3 -m pip install -U pytest
|
||||
python3 -m pip install -U pytest-cov
|
||||
python3 -m pip install pyroma
|
||||
python3 -m pip install test-image-results
|
||||
|
||||
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
|
||||
# TODO Remove condition when numpy supports 3.10
|
||||
if ! [ "$GHA_PYTHON_VERSION" == "3.10-dev" ]; then python3 -m pip install numpy ; fi
|
||||
|
||||
# TODO Remove when 3.8 / 3.9 includes setuptools 49.3.2+:
|
||||
if [ "$GHA_PYTHON_VERSION" == "3.8" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi
|
||||
if [ "$GHA_PYTHON_VERSION" == "3.9" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
||||
|
|
25
.github/workflows/system-info.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
"""
|
||||
Print out some handy system info like Travis CI does.
|
||||
|
||||
This sort of info is missing from GitHub Actions.
|
||||
|
||||
Requested here:
|
||||
https://github.com/actions/virtual-environments/issues/79
|
||||
"""
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
print("Build system information")
|
||||
print()
|
||||
|
||||
print("sys.version\t\t", sys.version.split("\n"))
|
||||
print("os.name\t\t\t", os.name)
|
||||
print("sys.platform\t\t", sys.platform)
|
||||
print("platform.system()\t", platform.system())
|
||||
print("platform.machine()\t", platform.machine())
|
||||
print("platform.platform()\t", platform.platform())
|
||||
print("platform.version()\t", platform.version())
|
||||
print("platform.uname()\t", platform.uname())
|
||||
if sys.platform == "darwin":
|
||||
print("platform.mac_ver()\t", platform.mac_ver())
|
43
.github/workflows/test-docker.yml
vendored
|
@ -7,27 +7,31 @@ jobs:
|
|||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
docker: [
|
||||
alpine,
|
||||
arch,
|
||||
ubuntu-16.04-xenial-amd64,
|
||||
ubuntu-18.04-bionic-amd64,
|
||||
debian-9-stretch-x86,
|
||||
ubuntu-20.04-focal-amd64,
|
||||
debian-10-buster-x86,
|
||||
centos-6-amd64,
|
||||
centos-7-amd64,
|
||||
centos-8-amd64,
|
||||
amazon-1-amd64,
|
||||
amazon-2-amd64,
|
||||
fedora-30-amd64,
|
||||
fedora-31-amd64,
|
||||
fedora-32-amd64,
|
||||
fedora-33-amd64,
|
||||
]
|
||||
dockerTag: [master]
|
||||
|
||||
name: ${{ matrix.docker }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Build system information
|
||||
run: python .github/workflows/system-info.py
|
||||
|
||||
- name: Docker pull
|
||||
run: |
|
||||
|
@ -37,4 +41,31 @@ jobs:
|
|||
run: |
|
||||
# The Pillow user in the docker container is UID 1000
|
||||
sudo chown -R 1000 $GITHUB_WORKSPACE
|
||||
docker run -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
|
||||
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@v1
|
||||
with:
|
||||
flags: GHA_Docker
|
||||
name: ${{ matrix.docker }}
|
||||
|
||||
success:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
name: Docker Test Successful
|
||||
steps:
|
||||
- name: Success
|
||||
run: echo Docker Test Successful
|
||||
|
|
490
.github/workflows/test-windows.yml
vendored
|
@ -4,12 +4,11 @@ on: [push, pull_request]
|
|||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.5", "3.6", "3.7", "3.8", "pypy3.6"]
|
||||
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev", "pypy3"]
|
||||
architecture: ["x86", "x64"]
|
||||
include:
|
||||
- architecture: "x86"
|
||||
|
@ -18,363 +17,262 @@ jobs:
|
|||
- architecture: "x64"
|
||||
platform-vcvars: "x86_amd64"
|
||||
platform-msbuild: "x64"
|
||||
- python-version: "pypy3.6"
|
||||
pypy-version: "pypy3.6-v7.2.0-win32"
|
||||
pypy-url: "https://bitbucket.org/pypy/pypy/downloads/pypy3.6-v7.2.0-win32.zip"
|
||||
exclude:
|
||||
- python-version: "pypy3.6"
|
||||
# PyPy does not support 64-bit on Windows
|
||||
- python-version: "pypy3"
|
||||
architecture: "x64"
|
||||
timeout-minutes: 30
|
||||
|
||||
name: Python ${{ matrix.python-version }} ${{ matrix.architecture }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Checkout Pillow
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
- name: Checkout cached dependencies
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: python-pillow/pillow-depends
|
||||
ref: master
|
||||
path: winbuild\depends
|
||||
|
||||
- name: Install PyPy
|
||||
if: "contains(matrix.python-version, 'pypy')"
|
||||
run: |
|
||||
curl -fsSL -o pypy3.zip "${{ matrix.pypy-url }}"
|
||||
7z x pypy3.zip "-o$env:RUNNER_WORKSPACE\"
|
||||
mv "$env:RUNNER_WORKSPACE\${{ matrix.pypy-version }}" "$env:RUNNER_WORKSPACE\${{ matrix.python-version }}"
|
||||
$env:PYTHON="$env:RUNNER_WORKSPACE\${{ matrix.python-version }}"
|
||||
# set env: pythonLocation
|
||||
Write-Host "`#`#[set-env name=pythonLocation;]$env:PYTHON" # old syntax https://github.com/actions/toolkit/issues/61
|
||||
Write-Host "::set-env name=pythonLocation::$env:PYTHON" # new syntax https://github.com/actions/toolkit/blob/5bb77ec03fea98332e41f9347c8fbb1ce1e48f4a/docs/commands.md
|
||||
New-Item -ItemType SymbolicLink -Path "$env:PYTHON\python.exe" -Target "$env:PYTHON\pypy3.exe"
|
||||
curl -fsSL -o get-pip.py https://bootstrap.pypa.io/get-pip.py
|
||||
$env:PATH = "$env:PYTHON\bin;$env:PATH"
|
||||
& $env:PYTHON\python.exe get-pip.py
|
||||
shell: pwsh
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~\AppData\Local\pip\Cache
|
||||
key:
|
||||
${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.architecture }}-${{ hashFiles('**/.github/workflows/test-windows.yml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.architecture }}-
|
||||
${{ runner.os }}-${{ matrix.python-version }}-
|
||||
|
||||
# sets env: pythonLocation
|
||||
- name: Set up Python
|
||||
if: "!contains(matrix.python-version, 'pypy')"
|
||||
uses: actions/setup-python@v1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
||||
- name: pip install wheel pytest pytest-cov codecov
|
||||
- name: Print build system information
|
||||
run: python .github/workflows/system-info.py
|
||||
|
||||
- name: python -m pip install wheel pytest pytest-cov
|
||||
run: python -m pip install wheel pytest pytest-cov
|
||||
|
||||
# TODO Remove when 3.8 / 3.9 includes setuptools 49.3.2+:
|
||||
- name: Upgrade setuptools
|
||||
if: "contains(matrix.python-version, '3.8') || contains(matrix.python-version, '3.9')"
|
||||
run: python -m pip install -U "setuptools>=49.3.2"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
"%pythonLocation%\python.exe" -m pip install wheel pytest pytest-cov
|
||||
pip install codecov
|
||||
shell: cmd
|
||||
7z x winbuild\depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\"
|
||||
echo "$env:RUNNER_WORKSPACE\nasm-2.14.02" >> $env:GITHUB_PATH
|
||||
|
||||
- name: Fetch dependencies
|
||||
run: |
|
||||
7z x ..\pillow-depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\"
|
||||
Write-Host "`#`#[add-path]$env:RUNNER_WORKSPACE\nasm-2.14.02"
|
||||
Write-Host "::add-path::$env:RUNNER_WORKSPACE\nasm-2.14.02"
|
||||
winbuild\depends\gs9533w32.exe /S
|
||||
echo "C:\Program Files (x86)\gs\gs9.53.3\bin" >> $env:GITHUB_PATH
|
||||
|
||||
..\pillow-depends\gs950w32.exe /S
|
||||
Write-Host "`#`#[add-path]C:\Program Files (x86)\gs\gs9.50\bin"
|
||||
Write-Host "::add-path::C:\Program Files (x86)\gs\gs9.50\bin"
|
||||
|
||||
$env:PYTHON=$env:pythonLocation
|
||||
xcopy ..\pillow-depends\*.zip $env:GITHUB_WORKSPACE\winbuild\
|
||||
xcopy ..\pillow-depends\*.tar.gz $env:GITHUB_WORKSPACE\winbuild\
|
||||
xcopy /s ..\pillow-depends\test_images\* $env:GITHUB_WORKSPACE\tests\images\
|
||||
cd $env:GITHUB_WORKSPACE/winbuild/
|
||||
python.exe $env:GITHUB_WORKSPACE\winbuild\build_dep.py
|
||||
env:
|
||||
EXECUTABLE: bin\python.exe
|
||||
xcopy /S /Y winbuild\depends\test_images\* Tests\images\
|
||||
shell: pwsh
|
||||
|
||||
- name: Build dependencies / libjpeg
|
||||
if: false
|
||||
run: |
|
||||
REM FIXME uses /MT not /MD, see makefile.vc and win32.mak for more info
|
||||
- name: Cache build
|
||||
id: build-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: winbuild\build
|
||||
key:
|
||||
${{ hashFiles('winbuild\build_prepare.py') }}-${{ hashFiles('.github\workflows\test-windows.yml') }}-${{ env.pythonLocation }}
|
||||
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\jpeg-9c
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
nmake -nologo -f makefile.vc setup-vc6
|
||||
nmake -nologo -f makefile.vc clean
|
||||
nmake -nologo -f makefile.vc nodebug=1 libjpeg.lib cjpeg.exe djpeg.exe
|
||||
copy /Y /B j*.h %INCLIB%
|
||||
copy /Y /B *.lib %INCLIB%
|
||||
copy /Y /B *.exe %INCLIB%
|
||||
shell: cmd
|
||||
- name: Prepare build
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
& python.exe winbuild\build_prepare.py -v --python=$env:pythonLocation --srcdir
|
||||
shell: pwsh
|
||||
|
||||
- name: Build dependencies / libjpeg-turbo
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\libjpeg-turbo-2.0.3
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DENABLE_SHARED:BOOL=OFF -DWITH_JPEG8:BOOL=TRUE -DWITH_CRT_DLL:BOOL=TRUE -DCMAKE_BUILD_TYPE=Release
|
||||
%CMAKE% -G "NMake Makefiles" .
|
||||
nmake -nologo -f Makefile clean
|
||||
nmake -nologo -f Makefile jpeg-static cjpeg-static djpeg-static
|
||||
copy /Y /B j*.h %INCLIB%
|
||||
copy /Y /B jpeg-static.lib %INCLIB%\libjpeg.lib
|
||||
copy /Y /B cjpeg-static.exe %INCLIB%\cjpeg.exe
|
||||
copy /Y /B djpeg-static.exe %INCLIB%\djpeg.exe
|
||||
shell: cmd
|
||||
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_libjpeg.cmd"
|
||||
- name: Build dependencies / zlib
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\zlib-1.2.11
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
nmake -nologo -f win32\Makefile.msc clean
|
||||
nmake -nologo -f win32\Makefile.msc zlib.lib
|
||||
copy /Y /B z*.h %INCLIB%
|
||||
copy /Y /B *.lib %INCLIB%
|
||||
copy /Y /B zlib.lib %INCLIB%\z.lib
|
||||
shell: cmd
|
||||
|
||||
- name: Build dependencies / LibTIFF
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\tiff-4.1.0
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
copy %GITHUB_WORKSPACE%\winbuild\tiff.opt nmake.opt
|
||||
nmake -nologo -f makefile.vc clean
|
||||
nmake -nologo -f makefile.vc lib
|
||||
copy /Y /B libtiff\tiff*.h %INCLIB%
|
||||
copy /Y /B libtiff\*.dll %INCLIB%
|
||||
copy /Y /B libtiff\*.lib %INCLIB%
|
||||
shell: cmd
|
||||
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_zlib.cmd"
|
||||
- name: Build dependencies / LibTiff
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_libtiff.cmd"
|
||||
- name: Build dependencies / WebP
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\libwebp-1.0.3
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
rmdir /S /Q output\release-static
|
||||
nmake -nologo -f Makefile.vc CFG=release-static OBJDIR=output ARCH=${{ matrix.architecture }} all
|
||||
mkdir %INCLIB%\webp
|
||||
copy /Y /B src\webp\*.h %INCLIB%\webp
|
||||
copy /Y /B output\release-static\${{ matrix.architecture }}\lib\* %INCLIB%
|
||||
shell: cmd
|
||||
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_libwebp.cmd"
|
||||
# for FreeType CBDT font support
|
||||
- name: Build dependencies / libpng
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_libpng.cmd"
|
||||
- name: Build dependencies / FreeType
|
||||
run: |
|
||||
REM Toolkit v100 not available; missing VCTargetsPath; Clean fails
|
||||
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\freetype-2.10.1
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
rmdir /S /Q objs
|
||||
set DefaultPlatformToolset=v142
|
||||
set VCTargetsPath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\
|
||||
set MSBUILD="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
|
||||
powershell -Command "(gc builds\windows\vc2010\freetype.vcxproj) -replace 'MultiThreaded<', 'MultiThreadedDLL<' | Out-File -encoding ASCII builds\windows\vc2010\freetype.vcxproj"
|
||||
%MSBUILD% builds\windows\vc2010\freetype.sln /t:Build /p:Configuration="Release Static" /p:Platform=${{ matrix.platform-msbuild }} /m
|
||||
xcopy /Y /E /Q include %INCLIB%
|
||||
copy /Y /B "objs\${{ matrix.platform-msbuild }}\Release Static\freetype.lib" %INCLIB%
|
||||
shell: cmd
|
||||
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_freetype.cmd"
|
||||
- name: Build dependencies / LCMS2
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\lcms2-2.8
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
rmdir /S /Q Lib
|
||||
rmdir /S /Q Projects\VC2015\Release
|
||||
set VCTargetsPath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\
|
||||
set MSBUILD="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
|
||||
powershell %GITHUB_WORKSPACE%\winbuild\lcms2_patch.ps1
|
||||
%MSBUILD% Projects\VC2015\lcms2.sln /t:Clean;lcms2_static /p:Configuration="Release" /p:Platform=${{ matrix.platform-msbuild }} /m
|
||||
xcopy /Y /E /Q include %INCLIB%
|
||||
copy /Y /B Lib\MS\*.lib %INCLIB%
|
||||
shell: cmd
|
||||
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_lcms2.cmd"
|
||||
- name: Build dependencies / OpenJPEG
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\openjpeg-2.3.1msvcr10-x32
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DBUILD_THIRDPARTY:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
|
||||
%CMAKE% -G "NMake Makefiles" .
|
||||
nmake -nologo -f Makefile clean
|
||||
nmake -nologo -f Makefile
|
||||
mkdir %INCLIB%\openjpeg-2.3.1
|
||||
copy /Y /B src\lib\openjp2\*.h %INCLIB%\openjpeg-2.3.1
|
||||
copy /Y /B bin\*.lib %INCLIB%
|
||||
shell: cmd
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_openjpeg.cmd"
|
||||
|
||||
# GPL licensed; skip if building wheels
|
||||
# GPL licensed
|
||||
- name: Build dependencies / libimagequant
|
||||
if: "github.event_name != 'push' || contains(matrix.python-version, 'pypy')"
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
rem ba653c8: Merge tag '2.12.5' into msvc
|
||||
cd /D %BUILD%\libimagequant-ba653c8ccb34dde4e21c6076d85a72d21ed9d971
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
echo (gc CMakeLists.txt) -replace 'add_library', "add_compile_options(-openmp-)`r`nadd_library" ^| Out-File -encoding ASCII CMakeLists.txt > patch.ps1
|
||||
echo (gc CMakeLists.txt) -replace ' SHARED', ' STATIC' ^| Out-File -encoding ASCII CMakeLists.txt >> patch.ps1
|
||||
powershell .\patch.ps1
|
||||
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
|
||||
%CMAKE% -G "NMake Makefiles" .
|
||||
nmake -nologo -f Makefile clean
|
||||
nmake -nologo -f Makefile
|
||||
copy /Y /B *.h %INCLIB%
|
||||
copy /Y /B *.lib %INCLIB%
|
||||
shell: cmd
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_libimagequant.cmd"
|
||||
|
||||
# for Raqm
|
||||
# Raqm dependencies
|
||||
- name: Build dependencies / HarfBuzz
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
set INCLUDE=%INCLUDE%;%INCLIB%
|
||||
set LIB=%LIB%;%INCLIB%
|
||||
cd /D %BUILD%\harfbuzz-2.6.1
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DHB_HAVE_FREETYPE:BOOL=ON -DCMAKE_BUILD_TYPE=Release
|
||||
%CMAKE% -G "NMake Makefiles" .
|
||||
nmake -nologo -f Makefile clean
|
||||
nmake -nologo -f Makefile harfbuzz
|
||||
copy /Y /B src\*.h %INCLIB%
|
||||
copy /Y /B *.lib %INCLIB%
|
||||
shell: cmd
|
||||
|
||||
# for Raqm
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_harfbuzz.cmd"
|
||||
- name: Build dependencies / FriBidi
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
cd /D %BUILD%\fribidi-1.0.7
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
copy /Y /B %GITHUB_WORKSPACE%\winbuild\fribidi.cmake CMakeLists.txt
|
||||
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
|
||||
%CMAKE% -G "NMake Makefiles" .
|
||||
nmake -nologo -f Makefile clean
|
||||
nmake -nologo -f Makefile fribidi
|
||||
copy /Y /B lib\*.h %INCLIB%
|
||||
copy /Y /B *.lib %INCLIB%
|
||||
shell: cmd
|
||||
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_fribidi.cmd"
|
||||
- name: Build dependencies / Raqm
|
||||
run: |
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
|
||||
set INCLUDE=%INCLUDE%;%INCLIB%
|
||||
set LIB=%LIB%;%INCLIB%
|
||||
cd /D %BUILD%\libraqm-0.7.0
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
echo on
|
||||
copy /Y /B %GITHUB_WORKSPACE%\winbuild\raqm.cmake CMakeLists.txt
|
||||
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
|
||||
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
|
||||
%CMAKE% -G "NMake Makefiles" .
|
||||
nmake -nologo -f Makefile clean
|
||||
nmake -nologo -f Makefile libraqm
|
||||
copy /Y /B src\*.h %INCLIB%
|
||||
copy /Y /B libraqm.dll %INCLIB%
|
||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||
run: "& winbuild\\build\\build_dep_libraqm.cmd"
|
||||
|
||||
# trim ~150MB x 9
|
||||
- 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: |
|
||||
set PYTHON=%pythonLocation%
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set MPLSRC=%GITHUB_WORKSPACE%
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
cd /D %GITHUB_WORKSPACE%
|
||||
set LIB=%INCLIB%;%PYTHON%\tcl
|
||||
set INCLUDE=%INCLIB%;%GITHUB_WORKSPACE%\depends\tcl86\include;%INCLUDE%
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
set MSSdk=1
|
||||
set DISTUTILS_USE_SDK=1
|
||||
set py_vcruntime_redist=true
|
||||
%PYTHON%\python.exe setup.py build_ext install
|
||||
rem Add libraqm.dll (copied to INCLIB) to PATH.
|
||||
path %INCLIB%;%PATH%
|
||||
%PYTHON%\python.exe selftest.py --installed
|
||||
shell: cmd
|
||||
$FLAGS=""
|
||||
if ('${{ github.event_name }}' -eq 'push') { $FLAGS="--disable-imagequant" }
|
||||
& winbuild\build\build_pillow.cmd $FLAGS install
|
||||
& $env:pythonLocation\python.exe selftest.py --installed
|
||||
shell: pwsh
|
||||
|
||||
# failing with PyPy3
|
||||
- name: Enable heap verification
|
||||
if: "!contains(matrix.python-version, 'pypy')"
|
||||
run: |
|
||||
c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\python.exe
|
||||
shell: cmd
|
||||
run: "& 'C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x86\\gflags.exe' /p /enable $env:pythonLocation\\python.exe"
|
||||
|
||||
- name: Test Pillow
|
||||
run: |
|
||||
set PYTHON=%pythonLocation%
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
rem Add libraqm.dll (copied to INCLIB) to PATH.
|
||||
path %INCLIB%;%PATH%
|
||||
cd /D %GITHUB_WORKSPACE%
|
||||
%PYTHON%\python.exe -m pytest -vx --cov PIL --cov-report term --cov-report xml Tests
|
||||
path %GITHUB_WORKSPACE%\\winbuild\\build\\bin;%PATH%
|
||||
python.exe -m pytest -vx -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests
|
||||
shell: cmd
|
||||
|
||||
- name: Prepare to upload errors
|
||||
if: failure()
|
||||
run: |
|
||||
mkdir -p Tests/errors
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload errors
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: errors
|
||||
path: Tests/errors
|
||||
|
||||
- name: After success
|
||||
run: |
|
||||
.ci/after_success.sh
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload coverage
|
||||
run: 'codecov --file "%GITHUB_WORKSPACE%\coverage.xml" --name "%pythonLocation%"'
|
||||
shell: cmd
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./coverage.xml
|
||||
flags: GHA_Windows
|
||||
name: ${{ runner.os }} Python ${{ matrix.python-version }} ${{ matrix.architecture }}
|
||||
|
||||
- name: Build wheel
|
||||
id: wheel
|
||||
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
|
||||
# Skip wheels on 3.10 due to https://github.com/pypa/wheel/issues/354
|
||||
if: "github.event_name == 'push' && !contains(matrix.python-version, '3.10')"
|
||||
run: |
|
||||
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ##[set-output name=dist;]dist-%%a
|
||||
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ::set-output name=dist::dist-%%a
|
||||
set PYTHON=%pythonLocation%
|
||||
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
|
||||
set MPLSRC=%GITHUB_WORKSPACE%
|
||||
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
|
||||
cd /D %GITHUB_WORKSPACE%
|
||||
set LIB=%INCLIB%;%PYTHON%\tcl
|
||||
set INCLUDE=%INCLIB%;%GITHUB_WORKSPACE%\depends\tcl86\include;%INCLUDE%
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
|
||||
%PYTHON%\python.exe setup.py bdist_wheel
|
||||
winbuild\\build\\build_pillow.cmd --disable-imagequant bdist_wheel
|
||||
shell: cmd
|
||||
|
||||
- uses: actions/upload-artifact@v1
|
||||
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
|
||||
- uses: actions/upload-artifact@v2
|
||||
# Skip wheels on 3.10 due to https://github.com/pypa/wheel/issues/354
|
||||
if: "github.event_name == 'push' && !contains(matrix.python-version, '3.10')"
|
||||
with:
|
||||
name: ${{ steps.wheel.outputs.dist }}
|
||||
path: dist
|
||||
path: dist\*.whl
|
||||
|
||||
msys:
|
||||
runs-on: windows-2019
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mingw: ["MINGW32", "MINGW64"]
|
||||
include:
|
||||
- mingw: "MINGW32"
|
||||
name: "MSYS2 MinGW 32-bit"
|
||||
package: "mingw-w64-i686"
|
||||
- mingw: "MINGW64"
|
||||
name: "MSYS2 MinGW 64-bit"
|
||||
package: "mingw-w64-x86_64"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash.exe --login -eo pipefail "{0}"
|
||||
env:
|
||||
MSYSTEM: ${{ matrix.mingw }}
|
||||
CHERE_INVOKING: 1
|
||||
|
||||
timeout-minutes: 30
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up shell
|
||||
run: echo "C:\msys64\usr\bin\" >> $env:GITHUB_PATH
|
||||
shell: pwsh
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
pacman -S --noconfirm \
|
||||
${{ matrix.package }}-python3-cffi \
|
||||
${{ matrix.package }}-python3-numpy \
|
||||
${{ matrix.package }}-python3-olefile \
|
||||
${{ matrix.package }}-python3-pip \
|
||||
${{ matrix.package }}-python3-pyqt5 \
|
||||
${{ matrix.package }}-python3-pytest \
|
||||
${{ matrix.package }}-python3-pytest-cov \
|
||||
${{ matrix.package }}-python3-setuptools \
|
||||
${{ matrix.package }}-freetype \
|
||||
${{ matrix.package }}-ghostscript \
|
||||
${{ matrix.package }}-lcms2 \
|
||||
${{ matrix.package }}-libimagequant \
|
||||
${{ matrix.package }}-libjpeg-turbo \
|
||||
${{ matrix.package }}-libraqm \
|
||||
${{ matrix.package }}-libtiff \
|
||||
${{ matrix.package }}-libwebp \
|
||||
${{ matrix.package }}-openjpeg2 \
|
||||
subversion
|
||||
|
||||
python3 -m pip install pyroma
|
||||
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
||||
|
||||
- name: Build Pillow
|
||||
run: CFLAGS="-coverage" python3 setup.py build_ext install
|
||||
|
||||
- name: Test Pillow
|
||||
run: |
|
||||
python3 selftest.py --installed
|
||||
python3 -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests
|
||||
|
||||
- name: Upload coverage
|
||||
run: |
|
||||
python3 -m pip install codecov
|
||||
bash <(curl -s https://codecov.io/bash) -F GHA_Windows
|
||||
env:
|
||||
CODECOV_NAME: ${{ matrix.name }}
|
||||
|
||||
success:
|
||||
needs: [build, msys]
|
||||
runs-on: ubuntu-latest
|
||||
name: Windows Test Successful
|
||||
steps:
|
||||
- name: Success
|
||||
run: echo Windows Test Successful
|
||||
|
|
74
.github/workflows/test.yml
vendored
|
@ -14,63 +14,105 @@ jobs:
|
|||
]
|
||||
python-version: [
|
||||
"pypy3",
|
||||
"3.10-dev",
|
||||
"3.9",
|
||||
"3.8",
|
||||
"3.7",
|
||||
"3.6",
|
||||
"3.5",
|
||||
]
|
||||
include:
|
||||
- python-version: "3.5"
|
||||
env: PYTHONOPTIMIZE=2
|
||||
- python-version: "3.6"
|
||||
env: PYTHONOPTIMIZE=1
|
||||
- python-version: "3.7"
|
||||
env: PYTHONOPTIMIZE=2
|
||||
# Include new variables for Codecov
|
||||
- os: ubuntu-latest
|
||||
codecov-flag: GHA_Ubuntu
|
||||
- os: macOS-latest
|
||||
codecov-flag: GHA_macOS
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(python3 -m pip cache dir)"
|
||||
|
||||
- name: pip cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key:
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.ci/*.sh') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-
|
||||
|
||||
- name: Build system information
|
||||
run: python .github/workflows/system-info.py
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
.travis/install.sh
|
||||
.ci/install.sh
|
||||
env:
|
||||
GHA_PYTHON_VERSION: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install macOS dependencies
|
||||
if: startsWith(matrix.os, 'macOS')
|
||||
run: |
|
||||
.github/workflows/macos-install.sh
|
||||
env:
|
||||
GHA_PYTHON_VERSION: ${{ matrix.python-version }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
.travis/build.sh
|
||||
.ci/build.sh
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
.travis/test.sh
|
||||
.ci/test.sh
|
||||
|
||||
- name: Prepare to upload errors
|
||||
if: failure()
|
||||
run: |
|
||||
mkdir -p Tests/errors
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload errors
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: errors
|
||||
path: Tests/errors
|
||||
|
||||
- name: Docs
|
||||
if: matrix.python-version == 3.8
|
||||
if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.9
|
||||
run: |
|
||||
pip install sphinx-rtd-theme
|
||||
python3 -m pip install sphinx-removed-in sphinx-rtd-theme
|
||||
make doccheck
|
||||
|
||||
- name: After success
|
||||
if: success()
|
||||
run: |
|
||||
.travis/after_success.sh
|
||||
.ci/after_success.sh
|
||||
|
||||
- name: Upload coverage
|
||||
run: bash <(curl -s https://codecov.io/bash) -F ${{ matrix.codecov-flag }}
|
||||
env:
|
||||
MATRIX_OS: ${{ matrix.os }}
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
||||
CODECOV_NAME: ${{ matrix.os }} Python ${{ matrix.python-version }}
|
||||
|
||||
success:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
name: Test Successful
|
||||
steps:
|
||||
- name: Success
|
||||
run: echo Test Successful
|
||||
|
|
4
.gitignore
vendored
|
@ -37,6 +37,10 @@ pip-delete-this-directory.txt
|
|||
# Extra test images installed from pillow-depends/test_images
|
||||
/depends/test_images
|
||||
/Tests/images/README.md
|
||||
/Tests/images/crash_1.tif
|
||||
/Tests/images/crash_2.tif
|
||||
/Tests/images/string_dimension.tiff
|
||||
/Tests/images/jpeg2000
|
||||
/Tests/images/msp
|
||||
/Tests/images/picins
|
||||
/Tests/images/sunraster
|
||||
|
|
43
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,43 @@
|
|||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: e66be67b9b6811913470f70c28b4d50f94d05b22 # frozen: 20.8b1
|
||||
hooks:
|
||||
- id: black
|
||||
args: ["--target-version", "py36"]
|
||||
# Only .py files, until https://github.com/psf/black/issues/402 resolved
|
||||
files: \.py$
|
||||
types: []
|
||||
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 377d260ffa6f746693f97b46d95025afc4bd8275 # frozen: 5.4.2
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/asottile/yesqa
|
||||
rev: 7a009f3ee493c796827ee334f9058b110a0e0db8 # frozen: v1.2.1
|
||||
hooks:
|
||||
- id: yesqa
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: f30f4974a08a6b2f6a1eeaf30a4d501cf909163a # frozen: v1.1.9
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.opt$)
|
||||
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 05f6544aef321e2fee03a1277ce2eef8880fb927 # frozen: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [flake8-2020, flake8-implicit-str-concat]
|
||||
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: eae6397e4c259ed3d057511f6dd5330b92867e62 # frozen: v1.6.0
|
||||
hooks:
|
||||
- id: python-check-blanket-noqa
|
||||
- id: rst-backticks
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: e1668fe86af3810fbca72b8653fe478e66a0afdc # frozen: v3.2.0
|
||||
hooks:
|
||||
- id: check-merge-conflict
|
||||
- id: check-yaml
|
66
.travis.yml
|
@ -1,14 +1,16 @@
|
|||
dist: xenial
|
||||
language: python
|
||||
cache: pip
|
||||
cache:
|
||||
pip: true
|
||||
directories:
|
||||
- $HOME/.cache/pre-commit
|
||||
|
||||
notifications:
|
||||
irc: "chat.freenode.net#pil"
|
||||
|
||||
# Run fast lint first to get fast feedback.
|
||||
# Run slow PyPy next, to give it a headstart and reduce waiting time.
|
||||
# Run latest 3.x next, to get quick compatibility results.
|
||||
# Then run the remainder, with fastest Docker jobs last.
|
||||
# Run slower CPUs next, to give them a headstart and reduce waiting time.
|
||||
# Then run the remainder.
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
@ -16,64 +18,50 @@ matrix:
|
|||
- python: "3.6"
|
||||
name: "Lint"
|
||||
env: LINT="true"
|
||||
- python: "pypy3"
|
||||
|
||||
- python: "3.6"
|
||||
arch: arm64
|
||||
- python: "3.7"
|
||||
arch: ppc64le
|
||||
- python: "3.8"
|
||||
arch: s390x
|
||||
|
||||
- python: "pypy3.6-7.3.1"
|
||||
name: "PyPy3 Xenial"
|
||||
- python: "3.9"
|
||||
name: "3.9 Xenial"
|
||||
services: xvfb
|
||||
- python: "3.8"
|
||||
name: "3.8 Xenial"
|
||||
services: xvfb
|
||||
- python: '3.7'
|
||||
name: "3.7 Xenial"
|
||||
name: "3.7 Xenial PYTHONOPTIMIZE=2"
|
||||
env: PYTHONOPTIMIZE=2
|
||||
services: xvfb
|
||||
- python: '3.6'
|
||||
name: "3.6 Xenial PYTHONOPTIMIZE=1"
|
||||
env: PYTHONOPTIMIZE=1
|
||||
services: xvfb
|
||||
- python: '3.5'
|
||||
name: "3.5 Xenial PYTHONOPTIMIZE=2"
|
||||
env: PYTHONOPTIMIZE=2
|
||||
services: xvfb
|
||||
- env: DOCKER="alpine" DOCKER_TAG="master"
|
||||
- env: DOCKER="arch" DOCKER_TAG="master" # contains PyQt5
|
||||
- env: DOCKER="ubuntu-16.04-xenial-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="ubuntu-18.04-bionic-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="debian-9-stretch-x86" DOCKER_TAG="master"
|
||||
- env: DOCKER="debian-10-buster-x86" DOCKER_TAG="master"
|
||||
- env: DOCKER="centos-6-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="centos-7-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="amazon-1-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="amazon-2-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-30-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-31-amd64" DOCKER_TAG="master"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_install:
|
||||
- if [ "$DOCKER" ]; then travis_retry docker pull pythonpillow/$DOCKER:$DOCKER_TAG; fi
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ "$LINT" == "true" ]; then
|
||||
pip install tox
|
||||
elif [ "$DOCKER" == "" ]; then
|
||||
.travis/install.sh;
|
||||
python3 -m pip install tox
|
||||
else
|
||||
.ci/install.sh;
|
||||
fi
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ "$LINT" == "true" ]; then
|
||||
tox -e lint
|
||||
elif [ "$DOCKER" == "" ]; then
|
||||
.travis/build.sh
|
||||
.travis/test.sh
|
||||
elif [ "$DOCKER" ]; then
|
||||
# the Pillow user in the docker container is UID 1000
|
||||
sudo chown -R 1000 $TRAVIS_BUILD_DIR
|
||||
docker run -v $TRAVIS_BUILD_DIR:/Pillow pythonpillow/$DOCKER:$DOCKER_TAG
|
||||
else
|
||||
.ci/build.sh
|
||||
.ci/test.sh
|
||||
fi
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [ "$LINT" == "" ]; then
|
||||
.travis/after_success.sh
|
||||
.ci/after_success.sh
|
||||
fi
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# gather the coverage data
|
||||
if [[ "$MATRIX_OS" == "macOS-latest" ]]; then
|
||||
brew install lcov
|
||||
else
|
||||
sudo apt-get -qq install lcov
|
||||
fi
|
||||
|
||||
lcov --capture --directory . -b . --output-file coverage.info
|
||||
# filter to remove system headers
|
||||
lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
|
||||
# convert to json
|
||||
gem install coveralls-lcov
|
||||
coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
|
||||
|
||||
coverage report
|
||||
pip install codecov
|
||||
pip install coveralls-merge
|
||||
coveralls-merge coverage.c.json
|
||||
codecov
|
||||
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ] && [ "$DOCKER" == "" ]; then
|
||||
# Coverage and quality reports on just the latest diff.
|
||||
depends/diffcover-install.sh
|
||||
depends/diffcover-run.sh
|
||||
fi
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\
|
||||
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
|
||||
cmake imagemagick libharfbuzz-dev libfribidi-dev
|
||||
|
||||
PYTHONOPTIMIZE=0 pip install cffi
|
||||
pip install coverage
|
||||
pip install olefile
|
||||
pip install -U pytest
|
||||
pip install -U pytest-cov
|
||||
pip install pyroma
|
||||
pip install test-image-results
|
||||
pip install numpy
|
||||
if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
|
||||
sudo apt-get -qq install pyqt5-dev-tools
|
||||
pip install pyqt5
|
||||
fi
|
||||
|
||||
# docs only on Python 3.7
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then pip install -r requirements.txt ; fi
|
||||
|
||||
# webp
|
||||
pushd depends && ./install_webp.sh && popd
|
||||
|
||||
# libimagequant
|
||||
pushd depends && ./install_imagequant.sh && popd
|
||||
|
||||
# raqm
|
||||
pushd depends && ./install_raqm.sh && popd
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
python -m pytest -v -x --cov PIL --cov-report term Tests
|
||||
|
||||
# Docs
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then make doccheck; fi
|
406
CHANGES.rst
|
@ -2,12 +2,366 @@
|
|||
Changelog (Pillow)
|
||||
==================
|
||||
|
||||
7.0.0 (unreleased)
|
||||
8.1.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Support raw rgba8888 for DDS #4760
|
||||
[qiankanglai]
|
||||
|
||||
8.0.1 (2020-10-22)
|
||||
------------------
|
||||
|
||||
- Update FreeType used in binary wheels to 2.10.4 to fix CVE-2020-15999.
|
||||
[radarhere]
|
||||
|
||||
- Moved string_dimension image to pillow-depends #4993
|
||||
[radarhere]
|
||||
|
||||
8.0.0 (2020-10-15)
|
||||
------------------
|
||||
|
||||
- Drop support for EOL Python 3.5 #4746, #4794
|
||||
[hugovk, radarhere, nulano]
|
||||
|
||||
- Drop support for PyPy3 < 7.2.0 #4964
|
||||
[nulano]
|
||||
|
||||
- Remove ImageCms.CmsProfile attributes deprecated since 3.2.0 #4768
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Remove long-deprecated Image.py functions #4798
|
||||
[hugovk, nulano, radarhere]
|
||||
|
||||
- Add support for 16-bit precision JPEG quantization values #4918
|
||||
[gofr]
|
||||
|
||||
- Added reading of IFD tag type #4979
|
||||
[radarhere]
|
||||
|
||||
- Initialize offset memory for PyImagingPhotoPut #4806
|
||||
[nqbit]
|
||||
|
||||
- Fix TiffDecode comparison warnings #4756
|
||||
[nulano]
|
||||
|
||||
- Docs: Add dark mode #4968
|
||||
[hugovk, nulano]
|
||||
|
||||
- Added macOS SDK install path to library and include directories #4974
|
||||
[radarhere, fxcoudert]
|
||||
|
||||
- Imaging.h: prevent confusion with system #4923
|
||||
[ax3l, ,radarhere]
|
||||
|
||||
- Avoid using pkg_resources in PIL.features.pilinfo #4975
|
||||
[nulano]
|
||||
|
||||
- Add getlength and getbbox functions for TrueType fonts #4959
|
||||
[nulano, radarhere, hugovk]
|
||||
|
||||
- Allow tuples with one item to give single color value in getink #4927
|
||||
[radarhere, nulano]
|
||||
|
||||
- Add support for CBDT and COLR fonts #4955
|
||||
[nulano, hugovk]
|
||||
|
||||
- Removed OSError in favour of DecompressionBombError for BMP #4966
|
||||
[radarhere]
|
||||
|
||||
- Implemented another ellipse drawing algorithm #4523
|
||||
[xtsm, radarhere]
|
||||
|
||||
- Removed unused JpegImagePlugin._fixup_dict function #4957
|
||||
[radarhere]
|
||||
|
||||
- Added reading and writing of private PNG chunks #4292
|
||||
[radarhere]
|
||||
|
||||
- Implement anchor for TrueType fonts #4930
|
||||
[nulano, hugovk]
|
||||
|
||||
- Fixed bug in Exif __delitem__ #4942
|
||||
[radarhere]
|
||||
|
||||
- Fix crash in ImageTk.PhotoImage on MinGW 64-bit #4946
|
||||
[nulano]
|
||||
|
||||
- Moved CVE images to pillow-depends #4929
|
||||
[radarhere]
|
||||
|
||||
- Refactor font_getsize and font_render #4910
|
||||
[nulano]
|
||||
|
||||
- Fixed loading profile with non-ASCII path on Windows #4914
|
||||
[radarhere]
|
||||
|
||||
- Fixed effect_spread bug for zero distance #4908
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Added formats parameter to Image.open #4837
|
||||
[nulano, radarhere]
|
||||
|
||||
- Added regular_polygon draw method #4846
|
||||
[comhar]
|
||||
|
||||
- Raise proper TypeError in putpixel #4882
|
||||
[nulano, hugovk]
|
||||
|
||||
- Added writing of subIFDs #4862
|
||||
[radarhere]
|
||||
|
||||
- Fix IFDRational __eq__ bug #4888
|
||||
[luphord, radarhere]
|
||||
|
||||
- Fixed duplicate variable name #4885
|
||||
[liZe, radarhere]
|
||||
|
||||
- Added homebrew zlib include directory #4842
|
||||
[radarhere]
|
||||
|
||||
- Corrected inverted PDF CMYK colors #4866
|
||||
[radarhere]
|
||||
|
||||
- Do not try to close file pointer if file pointer is empty #4823
|
||||
[radarhere]
|
||||
|
||||
- ImageOps.autocontrast: add mask parameter #4843
|
||||
[navneeth, hugovk]
|
||||
|
||||
- Read EXIF data tEXt chunk into info as bytes instead of string #4828
|
||||
[radarhere]
|
||||
|
||||
- Replaced distutils with setuptools #4797, #4809, #4814, #4817, #4829, #4890
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Add MIME type to PsdImagePlugin #4788
|
||||
[samamorgan]
|
||||
|
||||
- Allow ImageOps.autocontrast to specify low and high cutoffs separately #4749
|
||||
[millionhz, radarhere]
|
||||
|
||||
7.2.0 (2020-07-01)
|
||||
------------------
|
||||
|
||||
- Do not convert I;16 images when showing PNGs #4744
|
||||
[radarhere]
|
||||
|
||||
- Fixed ICNS file pointer saving #4741
|
||||
[radarhere]
|
||||
|
||||
- Fixed loading non-RGBA mode APNGs with dispose background #4742
|
||||
[radarhere]
|
||||
|
||||
- Deprecated _showxv #4714
|
||||
[radarhere]
|
||||
|
||||
- Deprecate Image.show(command="...") #4646
|
||||
[nulano, hugovk, radarhere]
|
||||
|
||||
- Updated JPEG magic number #4707
|
||||
[Cykooz, radarhere]
|
||||
|
||||
- Change STRIPBYTECOUNTS to LONG if necessary when saving #4626
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Write JFIF header when saving JPEG #4639
|
||||
[radarhere]
|
||||
|
||||
- Replaced tiff_jpeg with jpeg compression when saving TIFF images #4627
|
||||
[radarhere]
|
||||
|
||||
- Writing TIFF tags: improved BYTE, added UNDEFINED #4605
|
||||
[radarhere]
|
||||
|
||||
- Consider transparency when pasting text on an RGBA image #4566
|
||||
[radarhere]
|
||||
|
||||
- Added method argument to single frame WebP saving #4547
|
||||
[radarhere]
|
||||
|
||||
- Use ImageFileDirectory_v2 in Image.Exif #4637
|
||||
[radarhere]
|
||||
|
||||
- Corrected reading EXIF metadata without prefix #4677
|
||||
[radarhere]
|
||||
|
||||
- Fixed drawing a jointed line with a sequence of numeric values #4580
|
||||
[radarhere]
|
||||
|
||||
- Added support for 1-D NumPy arrays #4608
|
||||
[radarhere]
|
||||
|
||||
- Parse orientation from XMP tags #4560
|
||||
[radarhere]
|
||||
|
||||
- Speed up text layout by not rendering glyphs #4652
|
||||
[nulano]
|
||||
|
||||
- Fixed ZeroDivisionError in Image.thumbnail #4625
|
||||
[radarhere]
|
||||
|
||||
- Replaced TiffImagePlugin DEBUG with logging #4550
|
||||
[radarhere]
|
||||
|
||||
- Fix repeatedly loading .gbr #4620
|
||||
[ElinksFr, radarhere]
|
||||
|
||||
- JPEG: Truncate icclist instead of setting to None #4613
|
||||
[homm]
|
||||
|
||||
- Fixes default offset for Exif #4594
|
||||
[rodrigob, radarhere]
|
||||
|
||||
- Fixed bug when unpickling TIFF images #4565
|
||||
[radarhere]
|
||||
|
||||
- Fix pickling WebP #4561
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Replace IOError and WindowsError aliases with OSError #4536
|
||||
[hugovk, radarhere]
|
||||
|
||||
7.1.2 (2020-04-25)
|
||||
------------------
|
||||
|
||||
- Raise an EOFError when seeking too far in PNG #4528
|
||||
[radarhere]
|
||||
|
||||
7.1.1 (2020-04-02)
|
||||
------------------
|
||||
|
||||
- Fix regression seeking and telling PNGs #4512 #4514
|
||||
[hugovk, radarhere]
|
||||
|
||||
7.1.0 (2020-04-01)
|
||||
------------------
|
||||
|
||||
- Fix multiple OOB reads in FLI decoding #4503
|
||||
[wiredfool]
|
||||
|
||||
- Fix buffer overflow in SGI-RLE decoding #4504
|
||||
[wiredfool, hugovk]
|
||||
|
||||
- Fix bounds overflow in JPEG 2000 decoding #4505
|
||||
[wiredfool]
|
||||
|
||||
- Fix bounds overflow in PCX decoding #4506
|
||||
[wiredfool]
|
||||
|
||||
- Fix 2 buffer overflows in TIFF decoding #4507
|
||||
[wiredfool]
|
||||
|
||||
- Add APNG support #4243
|
||||
[pmrowla, radarhere, hugovk]
|
||||
|
||||
- ImageGrab.grab() for Linux with XCB #4260
|
||||
[nulano, radarhere]
|
||||
|
||||
- Added three new channel operations #4230
|
||||
[dwastberg, radarhere]
|
||||
|
||||
- Prevent masking of Image reduce method in Jpeg2KImagePlugin #4474
|
||||
[radarhere, homm]
|
||||
|
||||
- Added reading of earlier ImageMagick PNG EXIF data #4471
|
||||
[radarhere]
|
||||
|
||||
- Fixed endian handling for I;16 getextrema #4457
|
||||
[radarhere]
|
||||
|
||||
- Release buffer if function returns prematurely #4381
|
||||
[radarhere]
|
||||
|
||||
- Add JPEG comment to info dictionary #4455
|
||||
[radarhere]
|
||||
|
||||
- Fix size calculation of Image.thumbnail() #4404
|
||||
[orlnub123]
|
||||
|
||||
- Fixed stroke on FreeType < 2.9 #4401
|
||||
[radarhere]
|
||||
|
||||
- If present, only use alpha channel for bounding box #4454
|
||||
[radarhere]
|
||||
|
||||
- Warn if an unknown feature is passed to features.check() #4438
|
||||
[jdufresne]
|
||||
|
||||
- Fix Name field length when saving IM images #4424
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Allow saving of zero quality JPEG images #4440
|
||||
[radarhere]
|
||||
|
||||
- Allow explicit zero width to hide outline #4334
|
||||
[radarhere]
|
||||
|
||||
- Change ContainerIO return type to match file object mode #4297
|
||||
[jdufresne, radarhere]
|
||||
|
||||
- Only draw each polygon pixel once #4333
|
||||
[radarhere]
|
||||
|
||||
- Add support for shooting situation Exif IFD tags #4398
|
||||
[alexagv]
|
||||
|
||||
- Handle multiple and malformed JPEG APP13 markers #4370
|
||||
[homm]
|
||||
|
||||
- Depends: Update libwebp to 1.1.0 #4342, libjpeg to 9d #4352
|
||||
[radarhere]
|
||||
|
||||
7.0.0 (2020-01-02)
|
||||
------------------
|
||||
|
||||
- Drop support for EOL Python 2.7 #4109
|
||||
[hugovk, radarhere, jdufresne]
|
||||
|
||||
- Fix rounding error on RGB to L conversion #4320
|
||||
[homm]
|
||||
|
||||
- Exif writing fixes: Rational boundaries and signed/unsigned types #3980
|
||||
[kkopachev, radarhere]
|
||||
|
||||
- Allow loading of WMF images at a given DPI #4311
|
||||
[radarhere]
|
||||
|
||||
- Added reduce operation #4251
|
||||
[homm]
|
||||
|
||||
- Raise ValueError for io.StringIO in Image.open #4302
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Fix thumbnail geometry when DCT scaling is used #4231
|
||||
[homm, radarhere]
|
||||
|
||||
- Use default DPI when exif provides invalid x_resolution #4147
|
||||
[beipang2, radarhere]
|
||||
|
||||
- Change default resize resampling filter from NEAREST to BICUBIC #4255
|
||||
[homm]
|
||||
|
||||
- Fixed black lines on upscaled images with the BOX filter #4278
|
||||
[homm]
|
||||
|
||||
- Better thumbnail aspect ratio preservation #4256
|
||||
[homm]
|
||||
|
||||
- Add La mode packing and unpacking #4248
|
||||
[homm]
|
||||
|
||||
- Include tests in coverage reports #4173
|
||||
[hugovk]
|
||||
|
||||
- Handle broken Photoshop data #4239
|
||||
[radarhere]
|
||||
|
||||
- Raise a specific exception if no data is found for an MPO frame #4240
|
||||
[radarhere]
|
||||
|
||||
- Fix Unicode support for PyPy #4145
|
||||
[nulano]
|
||||
|
||||
- Added UnidentifiedImageError #4182
|
||||
[radarhere, hugovk]
|
||||
|
||||
|
@ -23,7 +377,7 @@ Changelog (Pillow)
|
|||
- Corrected DdsImagePlugin setting info gamma #4171
|
||||
[radarhere]
|
||||
|
||||
- Depends: Update libtiff to 4.1.0 #4195, Tk Tcl to 8.6.10 #4229
|
||||
- Depends: Update libtiff to 4.1.0 #4195, Tk Tcl to 8.6.10 #4229, libimagequant to 2.12.6 #4318
|
||||
[radarhere]
|
||||
|
||||
- Improve handling of file resources #3577
|
||||
|
@ -47,11 +401,29 @@ Changelog (Pillow)
|
|||
- Changed default frombuffer raw decoder args #1730
|
||||
[radarhere]
|
||||
|
||||
6.2.1 (2019-10-21)
|
||||
6.2.2 (2020-01-02)
|
||||
------------------
|
||||
|
||||
- This is the last Pillow release to support Python 2.7 #3642
|
||||
|
||||
- Overflow checks for realloc for tiff decoding. CVE-2020-5310
|
||||
[wiredfool, radarhere]
|
||||
|
||||
- Catch SGI buffer overrun. CVE-2020-5311
|
||||
[radarhere]
|
||||
|
||||
- Catch PCX P mode buffer overrun. CVE-2020-5312
|
||||
[radarhere]
|
||||
|
||||
- Catch FLI buffer overrun. CVE-2020-5313
|
||||
[radarhere]
|
||||
|
||||
- Raise an error for an invalid number of bands in FPX image. CVE-2019-19911
|
||||
[wiredfool, radarhere]
|
||||
|
||||
6.2.1 (2019-10-21)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.8 #4141
|
||||
[hugovk]
|
||||
|
||||
|
@ -3714,7 +4086,7 @@ Pre-fork
|
|||
This section may not be fully complete. For changes since this file
|
||||
was last updated, see the repository revision history:
|
||||
|
||||
https://bitbucket.org/effbot/pil-2009-raclette/commits/all
|
||||
http://svn.effbot.org/public/pil/
|
||||
|
||||
(1.1.7 final)
|
||||
|
||||
|
@ -5148,22 +5520,22 @@ Pre-fork
|
|||
+ Added keyword options to the "save" method. The following options
|
||||
are currently supported:
|
||||
|
||||
format option description
|
||||
Format Option Description
|
||||
--------------------------------------------------------
|
||||
JPEG optimize minimize output file at the
|
||||
JPEG optimize Minimize output file at the
|
||||
expense of compression speed.
|
||||
|
||||
JPEG progressive enable progressive output. the
|
||||
option value is ignored.
|
||||
JPEG progressive Enable progressive output.
|
||||
The option value is ignored.
|
||||
|
||||
JPEG quality set compression quality (1-100).
|
||||
the default value is 75.
|
||||
JPEG quality Set compression quality (1-100).
|
||||
The default value is 75.
|
||||
|
||||
JPEG smooth smooth dithered images. value
|
||||
is strength (1-100). default is
|
||||
off (0).
|
||||
JPEG smooth Smooth dithered images.
|
||||
Value is strength (1-100).
|
||||
Default is off (0).
|
||||
|
||||
PNG optimize minimize output file at the
|
||||
PNG optimize Minimize output file at the
|
||||
expense of compression speed.
|
||||
|
||||
Expect more options in future releases. Also note that
|
||||
|
@ -5347,7 +5719,7 @@ Pre-fork
|
|||
any other pixel value means opaque. This is faster than using an
|
||||
"L" transparency mask.
|
||||
|
||||
+ Properly writes EPS files (and properly prints images to postscript
|
||||
+ Properly writes EPS files (and properly prints images to PostScript
|
||||
printers as well).
|
||||
|
||||
+ Reads 4-bit BMP files, as well as 4 and 8-bit Windows ICO and CUR
|
||||
|
@ -5430,7 +5802,7 @@ Pre-fork
|
|||
+ Added the "pilfile" utility, which quickly identifies image files
|
||||
(without loading them, in most cases).
|
||||
|
||||
+ Added the "pilprint" utility, which prints image files to Postscript
|
||||
+ Added the "pilprint" utility, which prints image files to PostScript
|
||||
printers.
|
||||
|
||||
+ Added a rudimentary version of the "pilview" utility, which is
|
||||
|
@ -5444,5 +5816,5 @@ Pre-fork
|
|||
Jack). This allows you to read images through the Img extensions file
|
||||
format handlers. See the file "Lib/ImgExtImagePlugin.py" for details.
|
||||
|
||||
+ Postscript printing is provided through the PSDraw module. See the
|
||||
+ PostScript printing is provided through the PSDraw module. See the
|
||||
handbook for details.
|
||||
|
|
24
LICENSE
|
@ -5,12 +5,26 @@ The Python Imaging Library (PIL) is
|
|||
|
||||
Pillow is the friendly PIL fork. It is
|
||||
|
||||
Copyright © 2010-2019 by Alex Clark and contributors
|
||||
Copyright © 2010-2020 by Alex Clark and contributors
|
||||
|
||||
Like PIL, Pillow is licensed under the open source PIL Software License:
|
||||
Like PIL, Pillow is licensed under the open source HPND License:
|
||||
|
||||
By obtaining, using, and/or copying this software and/or its associated documentation, you agree that you have read, understood, and will comply with the following terms and conditions:
|
||||
By obtaining, using, and/or copying this software and/or its associated
|
||||
documentation, you agree that you have read, understood, and will comply
|
||||
with the following terms and conditions:
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its associated documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies, and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Secret Labs AB or the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
associated documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appears in all copies, and that
|
||||
both that copyright notice and this permission notice appear in supporting
|
||||
documentation, and that the name of Secret Labs AB or the author not be
|
||||
used in advertising or publicity pertaining to distribution of the software
|
||||
without specific, written prior permission.
|
||||
|
||||
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
|
||||
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
|
|
@ -6,6 +6,7 @@ include *.py
|
|||
include *.rst
|
||||
include *.sh
|
||||
include *.txt
|
||||
include *.yaml
|
||||
include LICENSE
|
||||
include Makefile
|
||||
include tox.ini
|
||||
|
@ -18,12 +19,10 @@ graft docs
|
|||
# build/src control detritus
|
||||
exclude .appveyor.yml
|
||||
exclude .coveragerc
|
||||
exclude .codecov.yml
|
||||
exclude .editorconfig
|
||||
exclude .readthedocs.yml
|
||||
exclude azure-pipelines.yml
|
||||
exclude codecov.yml
|
||||
global-exclude .git*
|
||||
global-exclude *.pyc
|
||||
global-exclude *.so
|
||||
prune .azure-pipelines
|
||||
prune .travis
|
||||
prune .ci
|
||||
|
|
39
Makefile
|
@ -1,7 +1,6 @@
|
|||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||
.PHONY: clean coverage doc docserve help inplace install install-req release-test sdist test upload upload-test
|
||||
.DEFAULT_GOAL := release-test
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
python3 setup.py clean
|
||||
rm src/PIL/*.so || true
|
||||
|
@ -9,29 +8,34 @@ clean:
|
|||
find . -name __pycache__ | xargs rm -r || true
|
||||
|
||||
BRANCHES=`git branch -a | grep -v HEAD | grep -v master | grep remote`
|
||||
.PHONY: co
|
||||
co:
|
||||
-for i in $(BRANCHES) ; do \
|
||||
git checkout -t $$i ; \
|
||||
done
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
python3 selftest.py
|
||||
python3 setup.py test
|
||||
pytest -qq
|
||||
rm -r htmlcov || true
|
||||
coverage report
|
||||
|
||||
.PHONY: doc
|
||||
doc:
|
||||
$(MAKE) -C docs html
|
||||
|
||||
.PHONY: doccheck
|
||||
doccheck:
|
||||
$(MAKE) -C docs html
|
||||
# Don't make our tests rely on the links in the docs being up every single build.
|
||||
# We don't control them. But do check, and update them to the target of their redirects.
|
||||
$(MAKE) -C docs linkcheck || true
|
||||
|
||||
.PHONY: docserve
|
||||
docserve:
|
||||
cd docs/_build/html && python3 -mSimpleHTTPServer 2> /dev/null&
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Welcome to Pillow development. Please use \`make <target>\` where <target> is one of"
|
||||
@echo " clean remove build products"
|
||||
|
@ -49,17 +53,21 @@ help:
|
|||
@echo " upload build and upload sdists to PyPI"
|
||||
@echo " upload-test build and upload sdists to test.pythonpackages.com"
|
||||
|
||||
.PHONY: inplace
|
||||
inplace: clean
|
||||
python3 setup.py develop build_ext --inplace
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
python3 setup.py install
|
||||
python3 selftest.py
|
||||
|
||||
.PHONY: install-coverage
|
||||
install-coverage:
|
||||
CFLAGS="-coverage" python3 setup.py build_ext install
|
||||
CFLAGS="-coverage -Werror=implicit-function-declaration" python3 setup.py build_ext install
|
||||
python3 selftest.py
|
||||
|
||||
.PHONY: debug
|
||||
debug:
|
||||
# make a debug version if we don't have a -dbg python. Leaves in symbols
|
||||
# for our stuff, kills optimization, and redirects to dev null so we
|
||||
|
@ -67,40 +75,37 @@ debug:
|
|||
make clean > /dev/null
|
||||
CFLAGS='-g -O0' python3 setup.py build_ext install > /dev/null
|
||||
|
||||
.PHONY: install-req
|
||||
install-req:
|
||||
pip install -r requirements.txt
|
||||
python3 -m pip install -r requirements.txt
|
||||
|
||||
.PHONY: install-venv
|
||||
install-venv:
|
||||
virtualenv .
|
||||
bin/pip install -r requirements.txt
|
||||
|
||||
.PHONY: release-test
|
||||
release-test:
|
||||
$(MAKE) install-req
|
||||
python3 setup.py develop
|
||||
python3 selftest.py
|
||||
python3 -m pytest Tests
|
||||
python3 setup.py install
|
||||
-rm dist/*.egg
|
||||
-rmdir dist
|
||||
python3 -m pytest -qq
|
||||
check-manifest
|
||||
pyroma .
|
||||
viewdoc
|
||||
|
||||
.PHONY: sdist
|
||||
sdist:
|
||||
python3 setup.py sdist --format=gztar
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
pytest -qq
|
||||
|
||||
# https://docs.python.org/3/distutils/packageindex.html#the-pypirc-file
|
||||
upload-test:
|
||||
# [test]
|
||||
# username:
|
||||
# password:
|
||||
# repository = http://test.pythonpackages.com
|
||||
python3 setup.py sdist --format=gztar upload -r test
|
||||
|
||||
upload:
|
||||
python3 setup.py sdist --format=gztar upload
|
||||
|
||||
.PHONY: readme
|
||||
readme:
|
||||
viewdoc
|
||||
|
|
104
README.md
Normal file
|
@ -0,0 +1,104 @@
|
|||
<p align="center">
|
||||
<img width="248" height="250" src="https://raw.githubusercontent.com/python-pillow/pillow-logo/master/pillow-logo-248x250.png" alt="Pillow logo">
|
||||
</p>
|
||||
|
||||
# Pillow
|
||||
|
||||
## Python Imaging Library (Fork)
|
||||
|
||||
Pillow is the friendly PIL fork by [Alex Clark and
|
||||
Contributors](https://github.com/python-pillow/Pillow/graphs/contributors).
|
||||
PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
||||
As of 2019, Pillow development is
|
||||
[supported by Tidelift](https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>docs</th>
|
||||
<td>
|
||||
<a href="https://pillow.readthedocs.io/?badge=latest"><img
|
||||
alt="Documentation Status"
|
||||
src="https://readthedocs.org/projects/pillow/badge/?version=latest"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>tests</th>
|
||||
<td>
|
||||
<a href="https://travis-ci.com/github/python-pillow/Pillow"><img
|
||||
alt="Travis CI build status (Linux)"
|
||||
src="https://img.shields.io/travis/com/python-pillow/Pillow/master.svg?label=Linux%20build"></a>
|
||||
<a href="https://travis-ci.com/github/python-pillow/pillow-wheels"><img
|
||||
alt="Travis CI build status (macOS)"
|
||||
src="https://img.shields.io/travis/com/python-pillow/pillow-wheels/master.svg?label=macOS%20build"></a>
|
||||
<a href="https://ci.appveyor.com/project/python-pillow/Pillow"><img
|
||||
alt="AppVeyor CI build status (Windows)"
|
||||
src="https://img.shields.io/appveyor/build/python-pillow/Pillow/master.svg?label=Windows%20build"></a>
|
||||
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3ALint"><img
|
||||
alt="GitHub Actions build status (Lint)"
|
||||
src="https://github.com/python-pillow/Pillow/workflows/Lint/badge.svg"></a>
|
||||
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3ATest"><img
|
||||
alt="GitHub Actions build status (Test Linux and macOS)"
|
||||
src="https://github.com/python-pillow/Pillow/workflows/Test/badge.svg"></a>
|
||||
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3A%22Test+Windows%22"><img
|
||||
alt="GitHub Actions build status (Test Windows)"
|
||||
src="https://github.com/python-pillow/Pillow/workflows/Test%20Windows/badge.svg"></a>
|
||||
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3A%22Test+Docker%22"><img
|
||||
alt="GitHub Actions build status (Test Docker)"
|
||||
src="https://github.com/python-pillow/Pillow/workflows/Test%20Docker/badge.svg"></a>
|
||||
<a href="https://codecov.io/gh/python-pillow/Pillow"><img
|
||||
alt="Code coverage"
|
||||
src="https://codecov.io/gh/python-pillow/Pillow/branch/master/graph/badge.svg"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>package</th>
|
||||
<td>
|
||||
<a href="https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow"><img
|
||||
alt="Zenodo"
|
||||
src="https://zenodo.org/badge/17549/python-pillow/Pillow.svg"></a>
|
||||
<a href="https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=badge"><img
|
||||
alt="Tidelift"
|
||||
src="https://tidelift.com/badges/package/pypi/Pillow?style=flat"></a>
|
||||
<a href="https://pypi.org/project/Pillow/"><img
|
||||
alt="Newest PyPI version"
|
||||
src="https://img.shields.io/pypi/v/pillow.svg"></a>
|
||||
<a href="https://pypi.org/project/Pillow/"><img
|
||||
alt="Number of PyPI downloads"
|
||||
src="https://img.shields.io/pypi/dm/pillow.svg"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>social</th>
|
||||
<td>
|
||||
<a href="https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img
|
||||
alt="Join the chat at https://gitter.im/python-pillow/Pillow"
|
||||
src="https://badges.gitter.im/python-pillow/Pillow.svg"></a>
|
||||
<a href="https://twitter.com/PythonPillow"><img
|
||||
alt="Follow on https://twitter.com/PythonPillow"
|
||||
src="https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Overview
|
||||
|
||||
The Python Imaging Library adds image processing capabilities to your Python interpreter.
|
||||
|
||||
This library provides extensive file format support, an efficient internal representation, and fairly powerful image processing capabilities.
|
||||
|
||||
The core image library is designed for fast access to data stored in a few basic pixel formats. It should provide a solid foundation for a general image processing tool.
|
||||
|
||||
## More Information
|
||||
|
||||
- [Documentation](https://pillow.readthedocs.io/)
|
||||
- [Installation](https://pillow.readthedocs.io/en/latest/installation.html)
|
||||
- [Handbook](https://pillow.readthedocs.io/en/latest/handbook/index.html)
|
||||
- [Contribute](https://github.com/python-pillow/Pillow/blob/master/.github/CONTRIBUTING.md)
|
||||
- [Issues](https://github.com/python-pillow/Pillow/issues)
|
||||
- [Pull requests](https://github.com/python-pillow/Pillow/pulls)
|
||||
- [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst)
|
||||
- [Pre-fork](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#pre-fork)
|
||||
|
||||
## Report a Vulnerability
|
||||
|
||||
To report a security vulnerability, please follow the procedure described in the [Tidelift security policy](https://tidelift.com/docs/security).
|
99
README.rst
|
@ -1,99 +0,0 @@
|
|||
Pillow
|
||||
======
|
||||
|
||||
Python Imaging Library (Fork)
|
||||
-----------------------------
|
||||
|
||||
Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. As of 2019, Pillow development is `supported by Tidelift <https://tidelift.com/subscription/pkg/pypi-pillow>`_.
|
||||
|
||||
.. start-badges
|
||||
|
||||
.. list-table::
|
||||
:stub-columns: 1
|
||||
|
||||
* - docs
|
||||
- |docs|
|
||||
* - tests
|
||||
- |linux| |macos| |windows| |gha_lint| |gha| |gha_windows| |gha_docker| |coverage|
|
||||
* - package
|
||||
- |zenodo| |tidelift| |version| |downloads|
|
||||
* - social
|
||||
- |gitter| |twitter|
|
||||
|
||||
.. end-badges
|
||||
|
||||
More Information
|
||||
----------------
|
||||
|
||||
- `Documentation <https://pillow.readthedocs.io/>`_
|
||||
|
||||
- `Installation <https://pillow.readthedocs.io/en/latest/installation.html>`_
|
||||
- `Handbook <https://pillow.readthedocs.io/en/latest/handbook/index.html>`_
|
||||
|
||||
- `Contribute <https://github.com/python-pillow/Pillow/blob/master/.github/CONTRIBUTING.md>`_
|
||||
|
||||
- `Issues <https://github.com/python-pillow/Pillow/issues>`_
|
||||
- `Pull requests <https://github.com/python-pillow/Pillow/pulls>`_
|
||||
|
||||
- `Changelog <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst>`_
|
||||
|
||||
- `Pre-fork <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#pre-fork>`_
|
||||
|
||||
Report a Vulnerability
|
||||
----------------------
|
||||
|
||||
To report a security vulnerability, please follow the procedure described in the `Tidelift security policy <https://tidelift.com/docs/security>`_.
|
||||
|
||||
.. |docs| image:: https://readthedocs.org/projects/pillow/badge/?version=latest
|
||||
:target: https://pillow.readthedocs.io/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. |linux| image:: https://img.shields.io/travis/python-pillow/Pillow/master.svg?label=Linux%20build
|
||||
:target: https://travis-ci.org/python-pillow/Pillow
|
||||
:alt: Travis CI build status (Linux)
|
||||
|
||||
.. |macos| image:: https://img.shields.io/travis/python-pillow/pillow-wheels/master.svg?label=macOS%20build
|
||||
:target: https://travis-ci.org/python-pillow/pillow-wheels
|
||||
:alt: Travis CI build status (macOS)
|
||||
|
||||
.. |windows| image:: https://img.shields.io/appveyor/ci/python-pillow/Pillow/master.svg?label=Windows%20build
|
||||
:target: https://ci.appveyor.com/project/python-pillow/Pillow
|
||||
:alt: AppVeyor CI build status (Windows)
|
||||
|
||||
.. |gha_lint| image:: https://github.com/python-pillow/Pillow/workflows/Lint/badge.svg
|
||||
:alt: GitHub Actions build status (Lint)
|
||||
|
||||
.. |gha_docker| image:: https://github.com/python-pillow/Pillow/workflows/Test%20Docker/badge.svg
|
||||
:alt: GitHub Actions build status (Test Docker)
|
||||
|
||||
.. |gha| image:: https://github.com/python-pillow/Pillow/workflows/Test/badge.svg
|
||||
:alt: GitHub Actions build status (Test Linux and macOS)
|
||||
|
||||
.. |gha_windows| image:: https://github.com/python-pillow/Pillow/workflows/Test%20Windows/badge.svg
|
||||
:alt: GitHub Actions build status (Test Windows)
|
||||
|
||||
.. |coverage| image:: https://codecov.io/gh/python-pillow/Pillow/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/python-pillow/Pillow
|
||||
:alt: Code coverage
|
||||
|
||||
.. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg
|
||||
:target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow
|
||||
|
||||
.. |tidelift| image:: https://tidelift.com/badges/package/pypi/Pillow?style=flat
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
.. |version| image:: https://img.shields.io/pypi/v/pillow.svg
|
||||
:target: https://pypi.org/project/Pillow/
|
||||
:alt: Latest PyPI version
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/pillow.svg
|
||||
:target: https://pypi.org/project/Pillow/
|
||||
:alt: Number of PyPI downloads
|
||||
|
||||
.. |gitter| image:: https://badges.gitter.im/python-pillow/Pillow.svg
|
||||
:target: https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
:alt: Join the chat at https://gitter.im/python-pillow/Pillow
|
||||
|
||||
.. |twitter| image:: https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg
|
||||
:target: https://twitter.com/PythonPillow
|
||||
:alt: Follow on https://twitter.com/PythonPillow
|
27
RELEASING.md
|
@ -2,11 +2,11 @@
|
|||
|
||||
## Main Release
|
||||
|
||||
Released quarterly on the first day of January, April, July, October.
|
||||
Released quarterly on January 2nd, April 1st, July 1st and October 15th.
|
||||
|
||||
* [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/3154
|
||||
* [ ] Develop and prepare release in `master` branch.
|
||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) and [AppVeyor CI](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in `master` branch.
|
||||
* [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions), [Travis CI](https://travis-ci.com/github/python-pillow/Pillow) and [AppVeyor](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in `master` branch.
|
||||
* [ ] Check that all of the wheel builds [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels) pass the tests in Travis CI.
|
||||
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py`
|
||||
* [ ] Update `CHANGES.rst`.
|
||||
|
@ -37,13 +37,17 @@ Released as needed for security, installation or critical bug fixes.
|
|||
```bash
|
||||
git checkout -t remotes/origin/5.2.x
|
||||
```
|
||||
* [ ] Cherry pick individual commits from `master` branch to release branch e.g. `5.2.x`.
|
||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in release branch e.g. `5.2.x`.
|
||||
* [ ] Cherry pick individual commits from `master` branch to release branch e.g. `5.2.x`, then `git push`.
|
||||
|
||||
|
||||
|
||||
* [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions), [Travis CI](https://travis-ci.com/github/python-pillow/Pillow) and [AppVeyor](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in release branch e.g. `5.2.x`.
|
||||
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py`
|
||||
* [ ] Run pre-release check via `make release-test`.
|
||||
* [ ] Create tag for release e.g.:
|
||||
```bash
|
||||
git tag 5.2.1
|
||||
git push
|
||||
git push --tags
|
||||
```
|
||||
* [ ] Create source distributions e.g.:
|
||||
|
@ -91,11 +95,7 @@ Released as needed privately to individual vendors for critical security-related
|
|||
cd pillow-wheels
|
||||
./update-pillow-tag.sh [[release tag]]
|
||||
```
|
||||
* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).
|
||||
```bash
|
||||
wget -m -A 'Pillow-<VERSION>-*' \
|
||||
http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
|
||||
```
|
||||
* [ ] Download wheels from the [Pillow Wheel Builder release](https://github.com/python-pillow/pillow-wheels/releases).
|
||||
|
||||
## Publicize Release
|
||||
|
||||
|
@ -104,3 +104,12 @@ Released as needed privately to individual vendors for critical security-related
|
|||
## Documentation
|
||||
|
||||
* [ ] Make sure the [default version for Read the Docs](https://pillow.readthedocs.io/en/stable/) is up-to-date with the release changes
|
||||
|
||||
## Docker Images
|
||||
|
||||
* [ ] Update Pillow in the Docker Images repository
|
||||
```bash
|
||||
git clone https://github.com/python-pillow/docker-images
|
||||
cd docker-images
|
||||
./update-pillow-tag.sh [[release tag]]
|
||||
```
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
Pillow Tests
|
||||
============
|
||||
|
||||
Test scripts are named ``test_xxx.py`` and use the ``unittest`` module. A base class and helper functions can be found in ``helper.py``.
|
||||
Test scripts are named ``test_xxx.py``. Helper classes and functions can be found in ``helper.py``.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
Install::
|
||||
|
||||
pip install pytest pytest-cov
|
||||
python3 -m pip install pytest pytest-cov
|
||||
|
||||
Execution
|
||||
---------
|
||||
|
@ -27,6 +27,6 @@ Run all the tests from the root of the Pillow source distribution::
|
|||
|
||||
Or with coverage::
|
||||
|
||||
pytest --cov PIL --cov-report term
|
||||
pytest --cov PIL --cov Tests --cov-report term
|
||||
coverage html
|
||||
open htmlcov/index.html
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import time
|
||||
import unittest
|
||||
|
||||
from PIL import PyAccess
|
||||
|
||||
from .helper import PillowTestCase, hopper
|
||||
from .helper import hopper
|
||||
|
||||
# Not running this test by default. No DOS against Travis CI.
|
||||
|
||||
|
@ -29,34 +28,31 @@ def timer(func, label, *args):
|
|||
func(*args)
|
||||
if time.time() - starttime > 10:
|
||||
print(
|
||||
"%s: breaking at %s iterations, %.6f per iteration"
|
||||
% (label, x + 1, (time.time() - starttime) / (x + 1.0))
|
||||
"{}: breaking at {} iterations, {:.6f} per iteration".format(
|
||||
label, x + 1, (time.time() - starttime) / (x + 1.0)
|
||||
)
|
||||
)
|
||||
break
|
||||
if x == iterations - 1:
|
||||
endtime = time.time()
|
||||
print(
|
||||
"%s: %.4f s %.6f per iteration"
|
||||
% (label, endtime - starttime, (endtime - starttime) / (x + 1.0))
|
||||
"{}: {:.4f} s {:.6f} per iteration".format(
|
||||
label, endtime - starttime, (endtime - starttime) / (x + 1.0)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class BenchCffiAccess(PillowTestCase):
|
||||
def test_direct(self):
|
||||
def test_direct():
|
||||
im = hopper()
|
||||
im.load()
|
||||
# im = Image.new( "RGB", (2000, 2000), (1, 3, 2))
|
||||
caccess = im.im.pixel_access(False)
|
||||
access = PyAccess.new(im, False)
|
||||
|
||||
self.assertEqual(caccess[(0, 0)], access[(0, 0)])
|
||||
assert caccess[(0, 0)] == access[(0, 0)]
|
||||
|
||||
print("Size: %sx%s" % im.size)
|
||||
timer(iterate_get, "PyAccess - get", im.size, access)
|
||||
timer(iterate_set, "PyAccess - set", im.size, access)
|
||||
timer(iterate_get, "C-api - get", im.size, caccess)
|
||||
timer(iterate_set, "C-api - set", im.size, caccess)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import sys
|
||||
import timeit
|
||||
|
||||
from . import helper
|
||||
|
||||
sys.path.insert(0, ".")
|
||||
|
||||
|
||||
def bench(mode):
|
||||
im = helper.hopper(mode)
|
||||
get = im.im.getpixel
|
||||
xy = 50, 50 # position shouldn't really matter
|
||||
t0 = timeit.default_timer()
|
||||
for _ in range(1000000):
|
||||
get(xy)
|
||||
print(mode, timeit.default_timer() - t0, "us")
|
||||
|
||||
|
||||
bench("L")
|
||||
bench("I")
|
||||
bench("I;16")
|
||||
bench("F")
|
||||
bench("RGB")
|
68
Tests/check_fli_oob.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
repro_ss2 = (
|
||||
"images/fli_oob/06r/06r00.fli",
|
||||
"images/fli_oob/06r/others/06r01.fli",
|
||||
"images/fli_oob/06r/others/06r02.fli",
|
||||
"images/fli_oob/06r/others/06r03.fli",
|
||||
"images/fli_oob/06r/others/06r04.fli",
|
||||
)
|
||||
|
||||
repro_lc = (
|
||||
"images/fli_oob/05r/05r00.fli",
|
||||
"images/fli_oob/05r/others/05r03.fli",
|
||||
"images/fli_oob/05r/others/05r06.fli",
|
||||
"images/fli_oob/05r/others/05r05.fli",
|
||||
"images/fli_oob/05r/others/05r01.fli",
|
||||
"images/fli_oob/05r/others/05r04.fli",
|
||||
"images/fli_oob/05r/others/05r02.fli",
|
||||
"images/fli_oob/05r/others/05r07.fli",
|
||||
"images/fli_oob/patch0/000000",
|
||||
"images/fli_oob/patch0/000001",
|
||||
"images/fli_oob/patch0/000002",
|
||||
"images/fli_oob/patch0/000003",
|
||||
)
|
||||
|
||||
|
||||
repro_advance = (
|
||||
"images/fli_oob/03r/03r00.fli",
|
||||
"images/fli_oob/03r/others/03r01.fli",
|
||||
"images/fli_oob/03r/others/03r09.fli",
|
||||
"images/fli_oob/03r/others/03r11.fli",
|
||||
"images/fli_oob/03r/others/03r05.fli",
|
||||
"images/fli_oob/03r/others/03r10.fli",
|
||||
"images/fli_oob/03r/others/03r06.fli",
|
||||
"images/fli_oob/03r/others/03r08.fli",
|
||||
"images/fli_oob/03r/others/03r03.fli",
|
||||
"images/fli_oob/03r/others/03r07.fli",
|
||||
"images/fli_oob/03r/others/03r02.fli",
|
||||
"images/fli_oob/03r/others/03r04.fli",
|
||||
)
|
||||
|
||||
repro_brun = (
|
||||
"images/fli_oob/04r/initial.fli",
|
||||
"images/fli_oob/04r/others/04r02.fli",
|
||||
"images/fli_oob/04r/others/04r05.fli",
|
||||
"images/fli_oob/04r/others/04r04.fli",
|
||||
"images/fli_oob/04r/others/04r03.fli",
|
||||
"images/fli_oob/04r/others/04r01.fli",
|
||||
"images/fli_oob/04r/04r00.fli",
|
||||
)
|
||||
|
||||
repro_copy = (
|
||||
"images/fli_oob/02r/others/02r02.fli",
|
||||
"images/fli_oob/02r/others/02r04.fli",
|
||||
"images/fli_oob/02r/others/02r03.fli",
|
||||
"images/fli_oob/02r/others/02r01.fli",
|
||||
"images/fli_oob/02r/02r00.fli",
|
||||
)
|
||||
|
||||
|
||||
for path in repro_ss2 + repro_lc + repro_advance + repro_brun + repro_copy:
|
||||
im = Image.open(path)
|
||||
try:
|
||||
im.load()
|
||||
except Exception as msg:
|
||||
print(msg)
|
|
@ -1,19 +1,10 @@
|
|||
import unittest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
TEST_FILE = "Tests/images/fli_overflow.fli"
|
||||
|
||||
|
||||
class TestFliOverflow(PillowTestCase):
|
||||
def test_fli_overflow(self):
|
||||
def test_fli_overflow():
|
||||
|
||||
# this should not crash with a malloc error or access violation
|
||||
im = Image.open(TEST_FILE)
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.load()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,46 +1,45 @@
|
|||
#!/usr/bin/env python
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, is_win32
|
||||
from .helper import is_win32
|
||||
|
||||
min_iterations = 100
|
||||
max_iterations = 10000
|
||||
|
||||
pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
|
||||
|
||||
@unittest.skipIf(is_win32(), "requires Unix or macOS")
|
||||
class TestImagingLeaks(PillowTestCase):
|
||||
def _get_mem_usage(self):
|
||||
from resource import getpagesize, getrusage, RUSAGE_SELF
|
||||
|
||||
def _get_mem_usage():
|
||||
from resource import RUSAGE_SELF, getpagesize, getrusage
|
||||
|
||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||
return mem * getpagesize() / 1024 / 1024
|
||||
|
||||
def _test_leak(self, min_iterations, max_iterations, fn, *args, **kwargs):
|
||||
|
||||
def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs):
|
||||
mem_limit = None
|
||||
for i in range(max_iterations):
|
||||
fn(*args, **kwargs)
|
||||
mem = self._get_mem_usage()
|
||||
mem = _get_mem_usage()
|
||||
if i < min_iterations:
|
||||
mem_limit = mem + 1
|
||||
continue
|
||||
msg = "memory usage limit exceeded after %d iterations" % (i + 1)
|
||||
self.assertLessEqual(mem, mem_limit, msg)
|
||||
msg = f"memory usage limit exceeded after {i + 1} iterations"
|
||||
assert mem <= mem_limit, msg
|
||||
|
||||
def test_leak_putdata(self):
|
||||
|
||||
def test_leak_putdata():
|
||||
im = Image.new("RGB", (25, 25))
|
||||
self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
|
||||
_test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
|
||||
|
||||
def test_leak_getlist(self):
|
||||
|
||||
def test_leak_getlist():
|
||||
im = Image.new("P", (25, 25))
|
||||
self._test_leak(
|
||||
_test_leak(
|
||||
min_iterations,
|
||||
max_iterations,
|
||||
# Pass a new list at each iteration.
|
||||
lambda: im.point(range(256)),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
import unittest
|
||||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, is_win32
|
||||
from .helper import is_win32, skip_unless_feature
|
||||
|
||||
# Limits for testing the leak
|
||||
mem_limit = 1024 * 1048576
|
||||
stack_size = 8 * 1048576
|
||||
iterations = int((mem_limit / stack_size) * 2)
|
||||
codecs = dir(Image.core)
|
||||
test_file = "Tests/images/rgb_trns_ycbc.jp2"
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.skipif(is_win32(), reason="requires Unix or macOS"),
|
||||
skip_unless_feature("jpg_2000"),
|
||||
]
|
||||
|
||||
@unittest.skipIf(is_win32(), "requires Unix or macOS")
|
||||
class TestJpegLeaks(PillowTestCase):
|
||||
def setUp(self):
|
||||
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:
|
||||
self.skipTest("JPEG 2000 support not available")
|
||||
|
||||
def test_leak_load(self):
|
||||
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||
def test_leak_load():
|
||||
from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit
|
||||
|
||||
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||
|
@ -28,8 +27,9 @@ class TestJpegLeaks(PillowTestCase):
|
|||
with Image.open(test_file) as im:
|
||||
im.load()
|
||||
|
||||
def test_leak_save(self):
|
||||
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||
|
||||
def test_leak_save():
|
||||
from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit
|
||||
|
||||
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||
|
@ -40,7 +40,3 @@ class TestJpegLeaks(PillowTestCase):
|
|||
im.save(test_output, "JPEG2000")
|
||||
test_output.seek(0)
|
||||
test_output.read()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
|
||||
class TestJ2kEncodeOverflow(PillowTestCase):
|
||||
def test_j2k_overflow(self):
|
||||
|
||||
def test_j2k_overflow(tmp_path):
|
||||
im = Image.new("RGBA", (1024, 131584))
|
||||
target = self.tempfile("temp.jpc")
|
||||
with self.assertRaises(IOError):
|
||||
target = str(tmp_path / "temp.jpc")
|
||||
with pytest.raises(OSError):
|
||||
im.save(target)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
26
Tests/check_jp2_overflow.py
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Reproductions/tests for OOB read errors in FliDecode.c
|
||||
|
||||
# When run in python, all of these images should fail for
|
||||
# one reason or another, either as a buffer overrun,
|
||||
# unrecognized datastream, or truncated image file.
|
||||
# There shouldn't be any segfaults.
|
||||
#
|
||||
# if run like
|
||||
# `valgrind --tool=memcheck python check_jp2_overflow.py 2>&1 | grep Decode.c`
|
||||
# the output should be empty. There may be python issues
|
||||
# in the valgrind especially if run in a debug python
|
||||
# version.
|
||||
|
||||
|
||||
from PIL import Image
|
||||
|
||||
repro = ("00r0_gray_l.jp2", "00r1_graya_la.jp2")
|
||||
|
||||
for path in repro:
|
||||
im = Image.open(path)
|
||||
try:
|
||||
im.load()
|
||||
except Exception as msg:
|
||||
print(msg)
|
|
@ -1,7 +1,8 @@
|
|||
import unittest
|
||||
from io import BytesIO
|
||||
|
||||
from .helper import PillowTestCase, hopper, is_win32
|
||||
import pytest
|
||||
|
||||
from .helper import hopper, is_win32
|
||||
|
||||
iterations = 5000
|
||||
|
||||
|
@ -15,8 +16,7 @@ valgrind --tool=massif python test-installed.py -s -v Tests/check_jpeg_leaks.py
|
|||
"""
|
||||
|
||||
|
||||
@unittest.skipIf(is_win32(), "requires Unix or macOS")
|
||||
class TestJpegLeaks(PillowTestCase):
|
||||
pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
|
||||
|
||||
"""
|
||||
pre patch:
|
||||
|
@ -74,7 +74,8 @@ post-patch:
|
|||
|
||||
"""
|
||||
|
||||
def test_qtables_leak(self):
|
||||
|
||||
def test_qtables_leak():
|
||||
im = hopper("RGB")
|
||||
|
||||
standard_l_qtable = [
|
||||
|
@ -115,7 +116,8 @@ post-patch:
|
|||
test_output = BytesIO()
|
||||
im.save(test_output, "JPEG", qtables=qtables)
|
||||
|
||||
def test_exif_leak(self):
|
||||
|
||||
def test_exif_leak():
|
||||
"""
|
||||
pre patch:
|
||||
|
||||
|
@ -169,7 +171,6 @@ post patch:
|
|||
| @ @@@# ::: ::::: : ::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
|
||||
0 +----------------------------------------------------------------------->Gi
|
||||
0 11.33
|
||||
|
||||
"""
|
||||
im = hopper("RGB")
|
||||
exif = b"12345678" * 4096
|
||||
|
@ -178,7 +179,8 @@ post patch:
|
|||
test_output = BytesIO()
|
||||
im.save(test_output, "JPEG", exif=exif)
|
||||
|
||||
def test_base_save(self):
|
||||
|
||||
def test_base_save():
|
||||
"""
|
||||
base case:
|
||||
MB
|
||||
|
@ -203,14 +205,9 @@ base case:
|
|||
| :@ @@ @ # : : :: :: @:: :::: :::: :::: : : : : : : :::::::::::: :::@:::
|
||||
| :@ @@ @ # : : :: :: @:: :::: :::: :::: : : : : : : :::::::::::: :::@:::
|
||||
0 +----------------------------------------------------------------------->Gi
|
||||
0 7.882
|
||||
"""
|
||||
0 7.882"""
|
||||
im = hopper("RGB")
|
||||
|
||||
for _ in range(iterations):
|
||||
test_output = BytesIO()
|
||||
im.save(test_output, "JPEG")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
# This test is not run automatically.
|
||||
#
|
||||
# It requires > 2gb memory for the >2 gigapixel image generated in the
|
||||
|
@ -24,26 +23,26 @@ YDIM = 32769
|
|||
XDIM = 48000
|
||||
|
||||
|
||||
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
||||
class LargeMemoryTest(PillowTestCase):
|
||||
def _write_png(self, xdim, ydim):
|
||||
f = self.tempfile("temp.png")
|
||||
pytestmark = pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="requires 64-bit system")
|
||||
|
||||
|
||||
def _write_png(tmp_path, xdim, ydim):
|
||||
f = str(tmp_path / "temp.png")
|
||||
im = Image.new("L", (xdim, ydim), 0)
|
||||
im.save(f)
|
||||
|
||||
def test_large(self):
|
||||
|
||||
def test_large(tmp_path):
|
||||
""" succeeded prepatch"""
|
||||
self._write_png(XDIM, YDIM)
|
||||
_write_png(tmp_path, XDIM, YDIM)
|
||||
|
||||
def test_2gpx(self):
|
||||
|
||||
def test_2gpx(tmp_path):
|
||||
"""failed prepatch"""
|
||||
self._write_png(XDIM, XDIM)
|
||||
_write_png(tmp_path, XDIM, XDIM)
|
||||
|
||||
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
||||
def test_size_greater_than_int(self):
|
||||
|
||||
@pytest.mark.skipif(numpy is None, reason="Numpy is not installed")
|
||||
def test_size_greater_than_int():
|
||||
arr = numpy.ndarray(shape=(16394, 16394))
|
||||
Image.fromarray(arr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
# This test is not run automatically.
|
||||
#
|
||||
# It requires > 2gb memory for the >2 gigapixel image generated in the
|
||||
|
@ -14,32 +13,28 @@ from .helper import PillowTestCase
|
|||
# Raspberry Pis).
|
||||
|
||||
|
||||
try:
|
||||
import numpy as np
|
||||
except ImportError:
|
||||
raise unittest.SkipTest("numpy not installed")
|
||||
np = pytest.importorskip("numpy", reason="NumPy not installed")
|
||||
|
||||
YDIM = 32769
|
||||
XDIM = 48000
|
||||
|
||||
|
||||
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
||||
class LargeMemoryNumpyTest(PillowTestCase):
|
||||
def _write_png(self, xdim, ydim):
|
||||
pytestmark = pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="requires 64-bit system")
|
||||
|
||||
|
||||
def _write_png(tmp_path, xdim, ydim):
|
||||
dtype = np.uint8
|
||||
a = np.zeros((xdim, ydim), dtype=dtype)
|
||||
f = self.tempfile("temp.png")
|
||||
f = str(tmp_path / "temp.png")
|
||||
im = Image.fromarray(a, "L")
|
||||
im.save(f)
|
||||
|
||||
def test_large(self):
|
||||
|
||||
def test_large(tmp_path):
|
||||
""" succeeded prepatch"""
|
||||
self._write_png(XDIM, YDIM)
|
||||
_write_png(tmp_path, XDIM, YDIM)
|
||||
|
||||
def test_2gpx(self):
|
||||
|
||||
def test_2gpx(tmp_path):
|
||||
"""failed prepatch"""
|
||||
self._write_png(XDIM, XDIM)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
_write_png(tmp_path, XDIM, XDIM)
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
TEST_FILE = "Tests/images/libtiff_segfault.tif"
|
||||
|
||||
|
||||
class TestLibtiffSegfault(PillowTestCase):
|
||||
def test_segfault(self):
|
||||
def test_libtiff_segfault():
|
||||
"""This test should not segfault. It will on Pillow <= 3.1.0 and
|
||||
libtiff >= 4.0.0
|
||||
"""
|
||||
|
||||
with self.assertRaises(IOError):
|
||||
im = Image.open(TEST_FILE)
|
||||
with pytest.raises(OSError):
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.load()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
import unittest
|
||||
import zlib
|
||||
from io import BytesIO
|
||||
|
||||
from PIL import Image, ImageFile, PngImagePlugin
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
TEST_FILE = "Tests/images/png_decompression_dos.png"
|
||||
|
||||
|
||||
class TestPngDos(PillowTestCase):
|
||||
def test_ignore_dos_text(self):
|
||||
def test_ignore_dos_text():
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
|
||||
try:
|
||||
|
@ -20,32 +16,34 @@ class TestPngDos(PillowTestCase):
|
|||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||
|
||||
for s in im.text.values():
|
||||
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||
assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
|
||||
|
||||
for s in im.info.values():
|
||||
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||
assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
|
||||
|
||||
def test_dos_text(self):
|
||||
|
||||
def test_dos_text():
|
||||
|
||||
try:
|
||||
im = Image.open(TEST_FILE)
|
||||
im.load()
|
||||
except ValueError as msg:
|
||||
self.assertTrue(msg, "Decompressed Data Too Large")
|
||||
assert msg, "Decompressed Data Too Large"
|
||||
return
|
||||
|
||||
for s in im.text.values():
|
||||
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||
assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
|
||||
|
||||
def test_dos_total_memory(self):
|
||||
|
||||
def test_dos_total_memory():
|
||||
im = Image.new("L", (1, 1))
|
||||
compressed_data = zlib.compress(b"a" * 1024 * 1023)
|
||||
|
||||
info = PngImagePlugin.PngInfo()
|
||||
|
||||
for x in range(64):
|
||||
info.add_text("t%s" % x, compressed_data, zip=True)
|
||||
info.add_itxt("i%s" % x, compressed_data, zip=True)
|
||||
info.add_text(f"t{x}", compressed_data, zip=True)
|
||||
info.add_itxt(f"i{x}", compressed_data, zip=True)
|
||||
|
||||
b = BytesIO()
|
||||
im.save(b, "PNG", pnginfo=info)
|
||||
|
@ -54,16 +52,10 @@ class TestPngDos(PillowTestCase):
|
|||
try:
|
||||
im2 = Image.open(b)
|
||||
except ValueError as msg:
|
||||
self.assertIn("Too much memory", msg)
|
||||
assert "Too much memory" in msg
|
||||
return
|
||||
|
||||
total_len = 0
|
||||
for txt in im2.text.values():
|
||||
total_len += len(txt)
|
||||
self.assertLess(
|
||||
total_len, 64 * 1024 * 1024, "Total text chunks greater than 64M"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
assert total_len < 64 * 1024 * 1024, "Total text chunks greater than 64M"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
def pytest_report_header(config):
|
||||
import io
|
||||
|
||||
|
||||
def pytest_report_header(config):
|
||||
try:
|
||||
from PIL import features
|
||||
|
||||
|
@ -8,4 +9,4 @@ def pytest_report_header(config):
|
|||
features.pilinfo(out=out, supported_formats=False)
|
||||
return out.getvalue()
|
||||
except Exception as e:
|
||||
return "pytest_report_header failed: %s" % str(e)
|
||||
return f"pytest_report_header failed: {e}"
|
||||
|
|
|
@ -6,7 +6,7 @@ if __name__ == "__main__":
|
|||
# create font data chunk for embedding
|
||||
font = "Tests/images/courB08"
|
||||
print(" f._load_pilfont_data(")
|
||||
print(" # %s" % os.path.basename(font))
|
||||
print(f" # {os.path.basename(font)}")
|
||||
print(" BytesIO(base64.decodestring(b'''")
|
||||
with open(font + ".pil", "rb") as fp:
|
||||
print(base64.b64encode(fp.read()).decode())
|
||||
|
|
BIN
Tests/fonts/BungeeColor-Regular_colr_Windows.ttf
Normal file
BIN
Tests/fonts/DejaVuSans-24-1-stripped.ttf
Normal file
BIN
Tests/fonts/DejaVuSans-24-2-stripped.ttf
Normal file
BIN
Tests/fonts/DejaVuSans-24-4-stripped.ttf
Normal file
BIN
Tests/fonts/DejaVuSans-24-8-stripped.ttf
Normal file
|
@ -1,12 +1,22 @@
|
|||
|
||||
NotoNastaliqUrdu-Regular.ttf and NotoSansSymbols-Regular.ttf, from https://github.com/googlei18n/noto-fonts
|
||||
NotoSans-Regular.ttf, from https://www.google.com/get/noto/
|
||||
NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/
|
||||
NotoColorEmoji.ttf, from https://github.com/googlefonts/noto-emoji
|
||||
AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype
|
||||
TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny
|
||||
ArefRuqaa-Regular.ttf, from https://github.com/google/fonts/tree/master/ofl/arefruqaa
|
||||
ter-x20b.pcf, from http://terminus-font.sourceforge.net/
|
||||
BungeeColor-Regular_colr_Windows.ttf, from https://github.com/djrrb/bungee
|
||||
|
||||
All of the above fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to.
|
||||
|
||||
FreeMono.ttf is licensed under GPLv3, with the GPL font exception.
|
||||
|
||||
OpenSansCondensed-LightItalic.tt, from https://fonts.google.com/specimen/Open+Sans, under Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
DejaVuSans-24-{1,2,4,8}-stripped.ttf are based on DejaVuSans.ttf converted using FontForge to add bitmap strikes and keep only the ASCII range.
|
||||
|
||||
|
||||
10x20-ISO8859-1.pcf, from https://packages.ubuntu.com/xenial/xfonts-base
|
||||
|
||||
|
|
BIN
Tests/fonts/NotoColorEmoji.ttf
Normal file
BIN
Tests/fonts/NotoSans-Regular.ttf
Normal file
BIN
Tests/fonts/OpenSansCondensed-LightItalic.ttf
Normal file
BIN
Tests/fonts/ter-x20b-cp1250.pbm
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
Tests/fonts/ter-x20b-cp1250.pil
Normal file
BIN
Tests/fonts/ter-x20b-iso8859-1.pbm
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
Tests/fonts/ter-x20b-iso8859-1.pil
Normal file
BIN
Tests/fonts/ter-x20b-iso8859-2.pbm
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Tests/fonts/ter-x20b-iso8859-2.pil
Normal file
BIN
Tests/fonts/ter-x20b.pcf
Normal file
224
Tests/helper.py
|
@ -4,13 +4,16 @@ Helper functions.
|
|||
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
import sys
|
||||
import sysconfig
|
||||
import tempfile
|
||||
import unittest
|
||||
from io import BytesIO
|
||||
|
||||
from PIL import Image, ImageMath
|
||||
import pytest
|
||||
from packaging.version import parse as parse_version
|
||||
|
||||
from PIL import Image, ImageMath, features
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -64,73 +67,49 @@ def convert_to_comparable(a, b):
|
|||
return new_a, new_b
|
||||
|
||||
|
||||
class PillowTestCase(unittest.TestCase):
|
||||
def delete_tempfile(self, path):
|
||||
def assert_deep_equal(a, b, msg=None):
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
pass # report?
|
||||
|
||||
def assert_deep_equal(self, a, b, msg=None):
|
||||
try:
|
||||
self.assertEqual(
|
||||
len(a),
|
||||
len(b),
|
||||
msg or "got length {}, expected {}".format(len(a), len(b)),
|
||||
)
|
||||
self.assertTrue(
|
||||
all(x == y for x, y in zip(a, b)),
|
||||
msg or "got {}, expected {}".format(a, b),
|
||||
)
|
||||
assert len(a) == len(b), msg or f"got length {len(a)}, expected {len(b)}"
|
||||
except Exception:
|
||||
self.assertEqual(a, b, msg)
|
||||
assert a == b, msg
|
||||
|
||||
def assert_image(self, im, mode, size, msg=None):
|
||||
|
||||
def assert_image(im, mode, size, msg=None):
|
||||
if mode is not None:
|
||||
self.assertEqual(
|
||||
im.mode,
|
||||
mode,
|
||||
msg or "got mode {!r}, expected {!r}".format(im.mode, mode),
|
||||
assert im.mode == mode, (
|
||||
msg or f"got mode {repr(im.mode)}, expected {repr(mode)}"
|
||||
)
|
||||
|
||||
if size is not None:
|
||||
self.assertEqual(
|
||||
im.size,
|
||||
size,
|
||||
msg or "got size {!r}, expected {!r}".format(im.size, size),
|
||||
assert im.size == size, (
|
||||
msg or f"got size {repr(im.size)}, expected {repr(size)}"
|
||||
)
|
||||
|
||||
def assert_image_equal(self, a, b, msg=None):
|
||||
self.assertEqual(
|
||||
a.mode, b.mode, msg or "got mode {!r}, expected {!r}".format(a.mode, b.mode)
|
||||
)
|
||||
self.assertEqual(
|
||||
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
|
||||
)
|
||||
|
||||
def assert_image_equal(a, b, msg=None):
|
||||
assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
|
||||
assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}"
|
||||
if a.tobytes() != b.tobytes():
|
||||
if HAS_UPLOADER:
|
||||
try:
|
||||
url = test_image_results.upload(a, b)
|
||||
logger.error("Url for test images: %s" % url)
|
||||
logger.error(f"Url for test images: {url}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.fail(msg or "got different content")
|
||||
assert False, msg or "got different content"
|
||||
|
||||
def assert_image_equal_tofile(self, a, filename, msg=None, mode=None):
|
||||
|
||||
def assert_image_equal_tofile(a, filename, msg=None, mode=None):
|
||||
with Image.open(filename) as img:
|
||||
if mode:
|
||||
img = img.convert(mode)
|
||||
self.assert_image_equal(a, img, msg)
|
||||
assert_image_equal(a, img, msg)
|
||||
|
||||
def assert_image_similar(self, a, b, epsilon, msg=None):
|
||||
epsilon = float(epsilon)
|
||||
self.assertEqual(
|
||||
a.mode, b.mode, msg or "got mode {!r}, expected {!r}".format(a.mode, b.mode)
|
||||
)
|
||||
self.assertEqual(
|
||||
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
|
||||
)
|
||||
|
||||
def assert_image_similar(a, b, epsilon, msg=None):
|
||||
assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
|
||||
assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}"
|
||||
|
||||
a, b = convert_to_comparable(a, b)
|
||||
|
||||
|
@ -139,98 +118,63 @@ class PillowTestCase(unittest.TestCase):
|
|||
chdiff = ImageMath.eval("abs(a - b)", a=ach, b=bch).convert("L")
|
||||
diff += sum(i * num for i, num in enumerate(chdiff.histogram()))
|
||||
|
||||
ave_diff = float(diff) / (a.size[0] * a.size[1])
|
||||
ave_diff = diff / (a.size[0] * a.size[1])
|
||||
try:
|
||||
self.assertGreaterEqual(
|
||||
epsilon,
|
||||
ave_diff,
|
||||
assert epsilon >= ave_diff, (
|
||||
(msg or "")
|
||||
+ " average pixel value difference %.4f > epsilon %.4f"
|
||||
% (ave_diff, epsilon),
|
||||
+ f" average pixel value difference {ave_diff:.4f} > epsilon {epsilon:.4f}"
|
||||
)
|
||||
except Exception as e:
|
||||
if HAS_UPLOADER:
|
||||
try:
|
||||
url = test_image_results.upload(a, b)
|
||||
logger.error("Url for test images: %s" % url)
|
||||
logger.error(f"Url for test images: {url}")
|
||||
except Exception:
|
||||
pass
|
||||
raise e
|
||||
|
||||
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, mode=None):
|
||||
|
||||
def assert_image_similar_tofile(a, filename, epsilon, msg=None, mode=None):
|
||||
with Image.open(filename) as img:
|
||||
if mode:
|
||||
img = img.convert(mode)
|
||||
self.assert_image_similar(a, img, epsilon, msg)
|
||||
assert_image_similar(a, img, epsilon, msg)
|
||||
|
||||
def assert_warning(self, warn_class, func, *args, **kwargs):
|
||||
import warnings
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
def assert_all_same(items, msg=None):
|
||||
assert items.count(items[0]) == len(items), msg
|
||||
|
||||
# Hopefully trigger a warning.
|
||||
result = func(*args, **kwargs)
|
||||
|
||||
# Verify some things.
|
||||
if warn_class is None:
|
||||
self.assertEqual(
|
||||
len(w), 0, "Expected no warnings, got %s" % [v.category for v in w]
|
||||
)
|
||||
else:
|
||||
self.assertGreaterEqual(len(w), 1)
|
||||
found = False
|
||||
for v in w:
|
||||
if issubclass(v.category, warn_class):
|
||||
found = True
|
||||
break
|
||||
self.assertTrue(found)
|
||||
return result
|
||||
def assert_not_all_same(items, msg=None):
|
||||
assert items.count(items[0]) != len(items), msg
|
||||
|
||||
def assert_all_same(self, items, msg=None):
|
||||
self.assertEqual(items.count(items[0]), len(items), msg)
|
||||
|
||||
def assert_not_all_same(self, items, msg=None):
|
||||
self.assertNotEqual(items.count(items[0]), len(items), msg)
|
||||
|
||||
def assert_tuple_approx_equal(self, actuals, targets, threshold, msg):
|
||||
def assert_tuple_approx_equal(actuals, targets, threshold, msg):
|
||||
"""Tests if actuals has values within threshold from targets"""
|
||||
|
||||
value = True
|
||||
for i, target in enumerate(targets):
|
||||
value *= target - threshold <= actuals[i] <= target + threshold
|
||||
|
||||
self.assertTrue(value, msg + ": " + repr(actuals) + " != " + repr(targets))
|
||||
|
||||
def skipKnownBadTest(self, msg=None):
|
||||
# Skip if PILLOW_RUN_KNOWN_BAD is not true in the environment.
|
||||
if os.environ.get("PILLOW_RUN_KNOWN_BAD", False):
|
||||
print(os.environ.get("PILLOW_RUN_KNOWN_BAD", False))
|
||||
return
|
||||
|
||||
self.skipTest(msg or "Known Bad Test")
|
||||
|
||||
def tempfile(self, template):
|
||||
assert template[:5] in ("temp.", "temp_")
|
||||
fd, path = tempfile.mkstemp(template[4:], template[:4])
|
||||
os.close(fd)
|
||||
|
||||
self.addCleanup(self.delete_tempfile, path)
|
||||
return path
|
||||
|
||||
def open_withImagemagick(self, f):
|
||||
if not imagemagick_available():
|
||||
raise OSError()
|
||||
|
||||
outfile = self.tempfile("temp.png")
|
||||
if command_succeeds([IMCONVERT, f, outfile]):
|
||||
return Image.open(outfile)
|
||||
raise OSError()
|
||||
assert value, msg + ": " + repr(actuals) + " != " + repr(targets)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||
class PillowLeakTestCase(PillowTestCase):
|
||||
def skip_unless_feature(feature):
|
||||
reason = f"{feature} not available"
|
||||
return pytest.mark.skipif(not features.check(feature), reason=reason)
|
||||
|
||||
|
||||
def skip_unless_feature_version(feature, version_required, reason=None):
|
||||
if not features.check(feature):
|
||||
return pytest.mark.skip(f"{feature} not available")
|
||||
if reason is None:
|
||||
reason = f"{feature} is older than {version_required}"
|
||||
version_required = parse_version(version_required)
|
||||
version_available = parse_version(features.version(feature))
|
||||
return pytest.mark.skipif(version_available < version_required, reason=reason)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS")
|
||||
class PillowLeakTestCase:
|
||||
# requires unix/macOS
|
||||
iterations = 100 # count
|
||||
mem_limit = 512 # k
|
||||
|
@ -243,7 +187,7 @@ class PillowLeakTestCase(PillowTestCase):
|
|||
:returns: memory usage in kilobytes
|
||||
"""
|
||||
|
||||
from resource import getrusage, RUSAGE_SELF
|
||||
from resource import RUSAGE_SELF, getrusage
|
||||
|
||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||
if sys.platform == "darwin":
|
||||
|
@ -263,8 +207,8 @@ class PillowLeakTestCase(PillowTestCase):
|
|||
for cycle in range(self.iterations):
|
||||
core()
|
||||
mem = self._get_mem_usage() - start_mem
|
||||
msg = "memory usage limit exceeded in iteration %d" % cycle
|
||||
self.assertLess(mem, self.mem_limit, msg)
|
||||
msg = f"memory usage limit exceeded in iteration {cycle}"
|
||||
assert mem < self.mem_limit, msg
|
||||
|
||||
|
||||
# helpers
|
||||
|
@ -301,34 +245,20 @@ def hopper(mode=None, cache={}):
|
|||
return im.copy()
|
||||
|
||||
|
||||
def command_succeeds(cmd):
|
||||
"""
|
||||
Runs the command, which must be a list of strings. Returns True if the
|
||||
command succeeds, or False if an OSError was raised by subprocess.Popen.
|
||||
"""
|
||||
try:
|
||||
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def djpeg_available():
|
||||
return command_succeeds(["djpeg", "-version"])
|
||||
return bool(shutil.which("djpeg"))
|
||||
|
||||
|
||||
def cjpeg_available():
|
||||
return command_succeeds(["cjpeg", "-version"])
|
||||
return bool(shutil.which("cjpeg"))
|
||||
|
||||
|
||||
def netpbm_available():
|
||||
return command_succeeds(["ppmquant", "--version"]) and command_succeeds(
|
||||
["ppmtogif", "--version"]
|
||||
)
|
||||
return bool(shutil.which("ppmquant") and shutil.which("ppmtogif"))
|
||||
|
||||
|
||||
def imagemagick_available():
|
||||
return IMCONVERT and command_succeeds([IMCONVERT, "-version"])
|
||||
return bool(IMCONVERT and shutil.which(IMCONVERT))
|
||||
|
||||
|
||||
def on_appveyor():
|
||||
|
@ -340,12 +270,12 @@ def on_github_actions():
|
|||
|
||||
|
||||
def on_ci():
|
||||
# Travis and AppVeyor have "CI"
|
||||
# Azure Pipelines has "TF_BUILD"
|
||||
# GitHub Actions has "GITHUB_ACTIONS"
|
||||
return (
|
||||
"CI" in os.environ or "TF_BUILD" in os.environ or "GITHUB_ACTIONS" in os.environ
|
||||
)
|
||||
# GitHub Actions, Travis and AppVeyor have "CI"
|
||||
return "CI" in os.environ
|
||||
|
||||
|
||||
def is_big_endian():
|
||||
return sys.byteorder == "big"
|
||||
|
||||
|
||||
def is_win32():
|
||||
|
@ -356,6 +286,10 @@ def is_pypy():
|
|||
return hasattr(sys, "pypy_translation_info")
|
||||
|
||||
|
||||
def is_mingw():
|
||||
return sysconfig.get_platform() == "mingw"
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
IMCONVERT = os.environ.get("MAGICK_HOME", "")
|
||||
if IMCONVERT:
|
||||
|
@ -364,14 +298,6 @@ else:
|
|||
IMCONVERT = "convert"
|
||||
|
||||
|
||||
def distro():
|
||||
if os.path.exists("/etc/os-release"):
|
||||
with open("/etc/os-release", "r") as f:
|
||||
for line in f:
|
||||
if "ID=" in line:
|
||||
return line.strip().split("=")[1]
|
||||
|
||||
|
||||
class cached_property:
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
|
|
BIN
Tests/images/00r0_gray_l.jp2
Normal file
BIN
Tests/images/00r1_graya_la.jp2
Normal file
BIN
Tests/images/01r_00.pcx
Normal file
BIN
Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds
Normal file
BIN
Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.png
Normal file
After Width: | Height: | Size: 106 B |
BIN
Tests/images/apng/blend_op_over.png
Normal file
After Width: | Height: | Size: 579 B |
BIN
Tests/images/apng/blend_op_over_near_transparent.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
Tests/images/apng/blend_op_source_near_transparent.png
Normal file
After Width: | Height: | Size: 614 B |
BIN
Tests/images/apng/blend_op_source_solid.png
Normal file
After Width: | Height: | Size: 671 B |
BIN
Tests/images/apng/blend_op_source_transparent.png
Normal file
After Width: | Height: | Size: 534 B |
BIN
Tests/images/apng/chunk_actl_after_idat.png
Normal file
After Width: | Height: | Size: 470 B |
BIN
Tests/images/apng/chunk_multi_actl.png
Normal file
After Width: | Height: | Size: 490 B |
BIN
Tests/images/apng/chunk_no_actl.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
Tests/images/apng/chunk_no_fctl.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
Tests/images/apng/chunk_no_fdat.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
Tests/images/apng/chunk_repeat_fctl.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
Tests/images/apng/delay.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
Tests/images/apng/delay_round.png
Normal file
After Width: | Height: | Size: 646 B |
BIN
Tests/images/apng/delay_short_max.png
Normal file
After Width: | Height: | Size: 646 B |
BIN
Tests/images/apng/delay_zero_denom.png
Normal file
After Width: | Height: | Size: 646 B |
BIN
Tests/images/apng/delay_zero_numer.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
Tests/images/apng/dispose_op_background.png
Normal file
After Width: | Height: | Size: 572 B |
BIN
Tests/images/apng/dispose_op_background_before_region.png
Normal file
After Width: | Height: | Size: 327 B |
BIN
Tests/images/apng/dispose_op_background_final.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
Tests/images/apng/dispose_op_background_p_mode.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Tests/images/apng/dispose_op_background_region.png
Normal file
After Width: | Height: | Size: 492 B |
BIN
Tests/images/apng/dispose_op_none.png
Normal file
After Width: | Height: | Size: 617 B |
BIN
Tests/images/apng/dispose_op_none_region.png
Normal file
After Width: | Height: | Size: 613 B |
BIN
Tests/images/apng/dispose_op_previous.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
Tests/images/apng/dispose_op_previous_final.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
Tests/images/apng/dispose_op_previous_first.png
Normal file
After Width: | Height: | Size: 371 B |
BIN
Tests/images/apng/dispose_op_previous_region.png
Normal file
After Width: | Height: | Size: 677 B |
BIN
Tests/images/apng/fctl_actl.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
Tests/images/apng/mode_16bit.png
Normal file
After Width: | Height: | Size: 915 B |
BIN
Tests/images/apng/mode_greyscale.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
Tests/images/apng/mode_greyscale_alpha.png
Normal file
After Width: | Height: | Size: 668 B |