Merge branch 'master' into gitignore-review
|
@ -13,13 +13,9 @@ environment:
|
|||
TEST_OPTIONS:
|
||||
DEPLOY: YES
|
||||
matrix:
|
||||
- PYTHON: C:/vp/pypy2
|
||||
EXECUTABLE: bin/pypy.exe
|
||||
PIP_DIR: bin
|
||||
VENV: YES
|
||||
- PYTHON: C:/Python27-x64
|
||||
- PYTHON: C:/Python38
|
||||
- PYTHON: C:/Python38-x64
|
||||
- PYTHON: C:/Python37
|
||||
- PYTHON: C:/Python27
|
||||
- PYTHON: C:/Python37-x64
|
||||
- PYTHON: C:/Python36
|
||||
- PYTHON: C:/Python36-x64
|
||||
|
@ -30,6 +26,10 @@ environment:
|
|||
PIP_DIR: bin
|
||||
TEST_OPTIONS: --processes=0
|
||||
DEPLOY: NO
|
||||
- PYTHON: C:/vp/pypy3
|
||||
EXECUTABLE: bin/pypy.exe
|
||||
PIP_DIR: bin
|
||||
VENV: YES
|
||||
|
||||
|
||||
install:
|
||||
|
@ -41,9 +41,9 @@ install:
|
|||
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
|
||||
- cd c:\pillow\winbuild\
|
||||
- ps: |
|
||||
if ($env:PYTHON -eq "c:/vp/pypy2")
|
||||
if ($env:PYTHON -eq "c:/vp/pypy3")
|
||||
{
|
||||
c:\pillow\winbuild\appveyor_install_pypy.cmd
|
||||
c:\pillow\winbuild\appveyor_install_pypy3.cmd
|
||||
}
|
||||
- ps: |
|
||||
if ($env:PYTHON -eq "c:/msys64/mingw32")
|
||||
|
@ -52,10 +52,13 @@ install:
|
|||
}
|
||||
else
|
||||
{
|
||||
c:\python34\python.exe c:\pillow\winbuild\build_dep.py
|
||||
c:\python37\python.exe c:\pillow\winbuild\build_dep.py
|
||||
c:\pillow\winbuild\build_deps.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
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
|
@ -76,6 +79,7 @@ build_script:
|
|||
test_script:
|
||||
- cd c:\pillow
|
||||
- '%PYTHON%\%PIP_DIR%\pip.exe 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% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest?
|
||||
|
||||
|
|
28
.azure-pipelines/jobs/lint.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
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'
|
22
.azure-pipelines/jobs/test-docker.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
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'
|
|
@ -6,4 +6,6 @@ codecov:
|
|||
# https://docs.codecov.io/v4.3.6/docs/comparing-commits
|
||||
allow_coverage_offsets: true
|
||||
|
||||
token: 6dafc396-e7f5-4221-a38a-8b07a49fbdae
|
||||
|
||||
comment: off
|
||||
|
|
8
.github/CONTRIBUTING.md
vendored
|
@ -9,14 +9,14 @@ 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 on Python 2.7 and 3.x. 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 [Coveralls](https://coveralls.io/repos/new) to see if the changed code is covered by tests.
|
||||
- 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.
|
||||
- Create a pull request to pull the changes from your branch to the Pillow master.
|
||||
|
||||
### Guidelines
|
||||
|
||||
- Separate code commits from reformatting commits.
|
||||
- Provide tests for any newly added code.
|
||||
- Follow PEP8.
|
||||
- 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.
|
||||
|
||||
## Reporting Issues
|
||||
|
@ -34,6 +34,4 @@ The best reproductions are self-contained scripts with minimal dependencies. If
|
|||
|
||||
## Security vulnerabilities
|
||||
|
||||
To report sensitive vulnerability information, email security@python-pillow.org.
|
||||
|
||||
If your organisation/employer is a distributor of Pillow and would like advance notification of security-related bugs, please let us know your preferred contact method.
|
||||
Please see our [security policy](https://github.com/python-pillow/Pillow/blob/master/.github/SECURITY.md).
|
||||
|
|
1
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
tidelift: "pypi/Pillow"
|
19
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,19 +0,0 @@
|
|||
### What did you do?
|
||||
|
||||
### What did you expect to happen?
|
||||
|
||||
### What actually happened?
|
||||
|
||||
### What are your OS, Python and Pillow versions?
|
||||
|
||||
* OS:
|
||||
* Python:
|
||||
* Pillow:
|
||||
|
||||
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.
|
||||
|
||||
The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as plone, Django, or buildout, try to replicate the issue just using Pillow.
|
||||
|
||||
```python
|
||||
code goes here
|
||||
```
|
59
.github/ISSUE_TEMPLATE/ISSUE_REPORT.md
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
name: Issue report
|
||||
about: Create a report to help us improve Pillow
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for reporting an issue.
|
||||
|
||||
Follow these guidelines to ensure your issue is handled properly.
|
||||
|
||||
If you have a ...
|
||||
|
||||
1. General question: consider asking the question on Stack Overflow
|
||||
with the python-imaging-library tag:
|
||||
|
||||
* https://stackoverflow.com/questions/tagged/python-imaging-library
|
||||
|
||||
Do not ask a question in both places.
|
||||
|
||||
If you think you have found a bug or have an unexplained exception
|
||||
then file a bug report here.
|
||||
|
||||
2. Bug report: include a self-contained, copy-pastable example that
|
||||
generates the issue if possible. Be concise with code posted.
|
||||
Guidelines on how to provide a good bug report:
|
||||
|
||||
* https://stackoverflow.com/help/mcve
|
||||
|
||||
Bug reports which follow these guidelines are easier to diagnose,
|
||||
and are often handled much more quickly.
|
||||
|
||||
3. Feature request: do a quick search of existing issues
|
||||
to make sure this has not been asked before.
|
||||
|
||||
We know asking good questions takes effort, and we appreciate your time.
|
||||
Thank you.
|
||||
-->
|
||||
|
||||
### What did you do?
|
||||
|
||||
### What did you expect to happen?
|
||||
|
||||
### What actually happened?
|
||||
|
||||
### What are your OS, Python and Pillow versions?
|
||||
|
||||
* OS:
|
||||
* Python:
|
||||
* Pillow:
|
||||
|
||||
<!--
|
||||
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.
|
||||
|
||||
The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as Plone, Django, or Buildout, try to replicate the issue just using Pillow.
|
||||
-->
|
||||
|
||||
```python
|
||||
code goes here
|
||||
```
|
5
.github/SECURITY.md
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Security policy
|
||||
|
||||
To report sensitive vulnerability information, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
If your organisation/employer is a distributor of Pillow and would like advance notification of security-related bugs, please let us know your preferred contact method.
|
29
.github/workflows/lint.yml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
name: Lint
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8"]
|
||||
|
||||
name: Python ${{ matrix.python-version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade tox
|
||||
|
||||
- name: Lint
|
||||
run: tox -e lint
|
17
.github/workflows/macos-install.sh
vendored
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype
|
||||
|
||||
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
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
40
.github/workflows/test-docker.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
name: Test Docker
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
docker: [
|
||||
alpine,
|
||||
arch,
|
||||
ubuntu-16.04-xenial-amd64,
|
||||
ubuntu-18.04-bionic-amd64,
|
||||
debian-9-stretch-x86,
|
||||
debian-10-buster-x86,
|
||||
centos-6-amd64,
|
||||
centos-7-amd64,
|
||||
amazon-1-amd64,
|
||||
amazon-2-amd64,
|
||||
fedora-30-amd64,
|
||||
fedora-31-amd64,
|
||||
]
|
||||
dockerTag: [master]
|
||||
|
||||
name: ${{ matrix.docker }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Docker pull
|
||||
run: |
|
||||
docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
|
||||
|
||||
- name: Docker build
|
||||
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 }}
|
380
.github/workflows/test-windows.yml
vendored
Normal file
|
@ -0,0 +1,380 @@
|
|||
name: Test Windows
|
||||
|
||||
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"]
|
||||
architecture: ["x86", "x64"]
|
||||
include:
|
||||
- architecture: "x86"
|
||||
platform-vcvars: "x86"
|
||||
platform-msbuild: "Win32"
|
||||
- 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"
|
||||
architecture: "x64"
|
||||
timeout-minutes: 30
|
||||
|
||||
name: Python ${{ matrix.python-version }} ${{ matrix.architecture }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
repository: python-pillow/pillow-depends
|
||||
ref: master
|
||||
|
||||
- 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
|
||||
|
||||
# sets env: pythonLocation
|
||||
- name: Set up Python
|
||||
if: "!contains(matrix.python-version, 'pypy')"
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
||||
- name: pip install wheel pytest pytest-cov codecov
|
||||
run: |
|
||||
"%pythonLocation%\python.exe" -m pip install wheel pytest pytest-cov
|
||||
pip install codecov
|
||||
shell: cmd
|
||||
|
||||
- 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"
|
||||
|
||||
..\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
|
||||
shell: pwsh
|
||||
|
||||
- name: Build dependencies / libjpeg
|
||||
if: false
|
||||
run: |
|
||||
REM FIXME uses /MT not /MD, see makefile.vc and win32.mak for more info
|
||||
|
||||
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: 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
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
# GPL licensed; skip if building wheels
|
||||
- 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
|
||||
|
||||
# for Raqm
|
||||
- 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
|
||||
- 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
|
||||
|
||||
- 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%
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
- 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
|
||||
shell: cmd
|
||||
|
||||
- name: Upload errors
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure()
|
||||
with:
|
||||
name: errors
|
||||
path: Tests/errors
|
||||
|
||||
- name: Upload coverage
|
||||
run: 'codecov --file "%GITHUB_WORKSPACE%\coverage.xml" --name "%pythonLocation%"'
|
||||
shell: cmd
|
||||
|
||||
- name: Build wheel
|
||||
id: wheel
|
||||
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
|
||||
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
|
||||
shell: cmd
|
||||
|
||||
- uses: actions/upload-artifact@v1
|
||||
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
|
||||
with:
|
||||
name: ${{ steps.wheel.outputs.dist }}
|
||||
path: dist
|
76
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [
|
||||
"ubuntu-latest",
|
||||
"macOS-latest",
|
||||
]
|
||||
python-version: [
|
||||
"pypy3",
|
||||
"3.8",
|
||||
"3.7",
|
||||
"3.6",
|
||||
"3.5",
|
||||
]
|
||||
include:
|
||||
- python-version: "3.5"
|
||||
env: PYTHONOPTIMIZE=2
|
||||
- python-version: "3.6"
|
||||
env: PYTHONOPTIMIZE=1
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
.travis/install.sh
|
||||
|
||||
- name: Install macOS dependencies
|
||||
if: startsWith(matrix.os, 'macOS')
|
||||
run: |
|
||||
.github/workflows/macos-install.sh
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
.travis/build.sh
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
.travis/test.sh
|
||||
|
||||
- name: Upload errors
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure()
|
||||
with:
|
||||
name: errors
|
||||
path: Tests/errors
|
||||
|
||||
- name: Docs
|
||||
if: matrix.python-version == 3.8
|
||||
run: |
|
||||
pip install sphinx-rtd-theme
|
||||
make doccheck
|
||||
|
||||
- name: After success
|
||||
if: success()
|
||||
run: |
|
||||
.travis/after_success.sh
|
||||
env:
|
||||
MATRIX_OS: ${{ matrix.os }}
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
3
.gitignore
vendored
|
@ -73,6 +73,9 @@ pip-delete-this-directory.txt
|
|||
\#*#
|
||||
.#*
|
||||
|
||||
#VS Code
|
||||
.vscode
|
||||
|
||||
#Komodo
|
||||
*.komodoproject
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
strictness: medium
|
||||
test-warnings: yes
|
||||
max-line-length: 80
|
59
.travis.yml
|
@ -6,8 +6,8 @@ notifications:
|
|||
irc: "chat.freenode.net#pil"
|
||||
|
||||
# Run fast lint first to get fast feedback.
|
||||
# Run slow PyPy* next, to give them a headstart and reduce waiting time.
|
||||
# Run latest 3.x and 2.x next, to get quick compatibility results.
|
||||
# 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.
|
||||
|
||||
matrix:
|
||||
|
@ -16,50 +16,34 @@ matrix:
|
|||
- python: "3.6"
|
||||
name: "Lint"
|
||||
env: LINT="true"
|
||||
- python: "pypy2.7-6.0"
|
||||
name: "PyPy2 Xenial"
|
||||
dist: xenial
|
||||
- python: "pypy3.5-6.0"
|
||||
- python: "pypy3"
|
||||
name: "PyPy3 Xenial"
|
||||
dist: xenial
|
||||
- python: "3.8"
|
||||
name: "3.8 Xenial"
|
||||
services: xvfb
|
||||
- python: '3.7'
|
||||
name: "3.7 Xenial"
|
||||
- python: '2.7'
|
||||
name: "2.7 Xenial"
|
||||
- python: '2.7'
|
||||
name: "2.7 Trusty"
|
||||
dist: trusty
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
name: "2.7_with_system_site_packages Xenial"
|
||||
services: xvfb
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
name: "2.7_with_system_site_packages Trusty"
|
||||
dist: trusty
|
||||
- python: '3.6'
|
||||
name: "3.6 Xenial"
|
||||
- python: '3.6'
|
||||
name: "3.6 Trusty PYTHONOPTIMIZE=1"
|
||||
dist: trusty
|
||||
name: "3.6 Xenial PYTHONOPTIMIZE=1"
|
||||
env: PYTHONOPTIMIZE=1
|
||||
services: xvfb
|
||||
- python: '3.5'
|
||||
name: "3.5 Xenial"
|
||||
- python: '3.5'
|
||||
name: "3.5 Trusty PYTHONOPTIMIZE=2"
|
||||
dist: trusty
|
||||
name: "3.5 Xenial PYTHONOPTIMIZE=2"
|
||||
env: PYTHONOPTIMIZE=2
|
||||
- python: "3.8-dev"
|
||||
name: "3.8-dev Xenial"
|
||||
services: xvfb
|
||||
- env: DOCKER="alpine" DOCKER_TAG="master"
|
||||
- env: DOCKER="arch" DOCKER_TAG="master" # contains PyQt5
|
||||
- env: DOCKER="ubuntu-trusty-x86" DOCKER_TAG="master"
|
||||
- env: DOCKER="ubuntu-xenial-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="debian-stretch-x86" DOCKER_TAG="master"
|
||||
- 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-28-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-29-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-30-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-31-amd64" DOCKER_TAG="master"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
@ -75,20 +59,13 @@ install:
|
|||
.travis/install.sh;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
# Qt needs a display for some of the tests, and it's only run on the system site packages install
|
||||
- |
|
||||
if [ "$TRAVIS_JOB_NAME" == "2.7_with_system_site_packages Trusty" ]; then
|
||||
export DISPLAY=:99.0
|
||||
sh -e /etc/init.d/xvfb start
|
||||
fi
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ "$LINT" == "true" ]; then
|
||||
tox -e lint
|
||||
elif [ "$DOCKER" == "" ]; then
|
||||
.travis/script.sh
|
||||
.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
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
# gather the coverage data
|
||||
sudo apt-get -qq install lcov
|
||||
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
|
||||
|
@ -15,9 +20,8 @@ pip install coveralls-merge
|
|||
coveralls-merge coverage.c.json
|
||||
codecov
|
||||
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ] && [ "$DOCKER" == "" ]; then
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ] && [ "$DOCKER" == "" ]; then
|
||||
# Coverage and quality reports on just the latest diff.
|
||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
||||
depends/diffcover-install.sh
|
||||
depends/diffcover-run.sh
|
||||
fi
|
||||
|
|
10
.travis/build.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
coverage erase
|
||||
if [ $(uname) == "Darwin" ]; then
|
||||
export CPPFLAGS="-I/usr/local/miniconda/include";
|
||||
fi
|
||||
make clean
|
||||
make install-coverage
|
|
@ -4,11 +4,10 @@ set -e
|
|||
|
||||
sudo apt-get update
|
||||
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\
|
||||
python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick\
|
||||
libharfbuzz-dev libfribidi-dev
|
||||
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
|
||||
cmake imagemagick libharfbuzz-dev libfribidi-dev
|
||||
|
||||
PYTHONOPTIMIZE=0 pip install cffi
|
||||
pip install check-manifest
|
||||
pip install coverage
|
||||
pip install olefile
|
||||
pip install -U pytest
|
||||
|
@ -16,22 +15,22 @@ 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 2.7
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi
|
||||
|
||||
# clean checkout for manifest
|
||||
mkdir /tmp/check-manifest && cp -a . /tmp/check-manifest
|
||||
# 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
|
||||
|
||||
# openjpeg
|
||||
pushd depends && ./install_openjpeg.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,15 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
coverage erase
|
||||
make clean
|
||||
make install-coverage
|
||||
|
||||
python selftest.py
|
||||
python -m pytest -vx --cov PIL --cov-report term Tests
|
||||
|
||||
pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd
|
||||
|
||||
# Docs
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make doccheck; fi
|
8
.travis/test.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/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
|
421
CHANGES.rst
|
@ -2,9 +2,410 @@
|
|||
Changelog (Pillow)
|
||||
==================
|
||||
|
||||
6.0.0 (unreleased)
|
||||
7.0.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Drop support for EOL Python 2.7 #4109
|
||||
[hugovk, radarhere, jdufresne]
|
||||
|
||||
- Added UnidentifiedImageError #4182
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Remove deprecated __version__ from plugins #4197
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Fixed freeing unallocated pointer when resizing with height too large #4116
|
||||
[radarhere]
|
||||
|
||||
- Copy info in Image.transform #4128
|
||||
[radarhere]
|
||||
|
||||
- Corrected DdsImagePlugin setting info gamma #4171
|
||||
[radarhere]
|
||||
|
||||
- Depends: Update libtiff to 4.1.0 #4195, Tk Tcl to 8.6.10 #4229
|
||||
[radarhere]
|
||||
|
||||
- Improve handling of file resources #3577
|
||||
[jdufresne]
|
||||
|
||||
- Removed CI testing of Fedora 29 #4165
|
||||
[hugovk]
|
||||
|
||||
- Added pypy3 to tox envlist #4137
|
||||
[jdufresne]
|
||||
|
||||
- Drop support for EOL PyQt4 and PySide #4108
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Removed deprecated setting of TIFF image sizes #4114
|
||||
[radarhere]
|
||||
|
||||
- Removed deprecated PILLOW_VERSION #4107
|
||||
[hugovk]
|
||||
|
||||
- Changed default frombuffer raw decoder args #1730
|
||||
[radarhere]
|
||||
|
||||
6.2.1 (2019-10-21)
|
||||
------------------
|
||||
|
||||
- This is the last Pillow release to support Python 2.7 #3642
|
||||
|
||||
- Add support for Python 3.8 #4141
|
||||
[hugovk]
|
||||
|
||||
6.2.0 (2019-10-01)
|
||||
------------------
|
||||
|
||||
- Catch buffer overruns #4104
|
||||
[radarhere]
|
||||
|
||||
- Initialize rows_per_strip when RowsPerStrip tag is missing #4034
|
||||
[cgohlke, radarhere]
|
||||
|
||||
- Raise error if TIFF dimension is a string #4103
|
||||
[radarhere]
|
||||
|
||||
- Added decompression bomb checks #4102
|
||||
[radarhere]
|
||||
|
||||
- Fix ImageGrab.grab DPI scaling on Windows 10 version 1607+ #4000
|
||||
[nulano, radarhere]
|
||||
|
||||
- Corrected negative seeks #4101
|
||||
[radarhere]
|
||||
|
||||
- Added argument to capture all screens on Windows #3950
|
||||
[nulano, radarhere]
|
||||
|
||||
- Updated warning to specify when Image.frombuffer defaults will change #4086
|
||||
[radarhere]
|
||||
|
||||
- Changed WindowsViewer format to PNG #4080
|
||||
[radarhere]
|
||||
|
||||
- Use TIFF orientation #4063
|
||||
[radarhere]
|
||||
|
||||
- Raise the same error if a truncated image is loaded a second time #3965
|
||||
[radarhere]
|
||||
|
||||
- Lazily use ImageFileDirectory_v1 values from Exif #4031
|
||||
[radarhere]
|
||||
|
||||
- Improved HSV conversion #4004
|
||||
[radarhere]
|
||||
|
||||
- Added text stroking #3978
|
||||
[radarhere, hugovk]
|
||||
|
||||
- No more deprecated bdist_wininst .exe installers #4029
|
||||
[hugovk]
|
||||
|
||||
- Do not allow floodfill to extend into negative coordinates #4017
|
||||
[radarhere]
|
||||
|
||||
- Fixed arc drawing bug for a non-whole number of degrees #4014
|
||||
[radarhere]
|
||||
|
||||
- Fix bug when merging identical images to GIF with a list of durations #4003
|
||||
[djy0, radarhere]
|
||||
|
||||
- Fix bug in TIFF loading of BufferedReader #3998
|
||||
[chadawagner]
|
||||
|
||||
- Added fallback for finding ld on MinGW Cygwin #4019
|
||||
[radarhere]
|
||||
|
||||
- Remove indirect dependencies from requirements.txt #3976
|
||||
[hugovk]
|
||||
|
||||
- Depends: Update libwebp to 1.0.3 #3983, libimagequant to 2.12.5 #3993, freetype to 2.10.1 #3991
|
||||
[radarhere]
|
||||
|
||||
- Change overflow check to use PY_SSIZE_T_MAX #3964
|
||||
[radarhere]
|
||||
|
||||
- Report reason for pytest skips #3942
|
||||
[hugovk]
|
||||
|
||||
6.1.0 (2019-07-01)
|
||||
------------------
|
||||
|
||||
- Deprecate Image.__del__ #3929
|
||||
[jdufresne]
|
||||
|
||||
- Tiff: Add support for JPEG quality #3886
|
||||
[olt]
|
||||
|
||||
- Respect the PKG_CONFIG environment variable when building #3928
|
||||
[chewi]
|
||||
|
||||
- Use explicit memcpy() to avoid unaligned memory accesses #3225
|
||||
[DerDakon]
|
||||
|
||||
- Improve encoding of TIFF tags #3861
|
||||
[olt]
|
||||
|
||||
- Update Py_UNICODE to Py_UCS4 #3780
|
||||
[nulano]
|
||||
|
||||
- Consider I;16 pixel size when drawing #3899
|
||||
[radarhere]
|
||||
|
||||
- Add TIFFTAG_SAMPLEFORMAT to blocklist #3926
|
||||
[cgohlke, radarhere]
|
||||
|
||||
- Create GIF deltas from background colour of GIF frames if disposal mode is 2 #3708
|
||||
[sircinnamon, radarhere]
|
||||
|
||||
- Added ImageSequence all_frames #3778
|
||||
[radarhere]
|
||||
|
||||
- Use unsigned int to store TIFF IFD offsets #3923
|
||||
[cgohlke]
|
||||
|
||||
- Include CPPFLAGS when searching for libraries #3819
|
||||
[jefferyto]
|
||||
|
||||
- Updated TIFF tile descriptors to match current decoding functionality #3795
|
||||
[dmnisson]
|
||||
|
||||
- Added an ``image.entropy()`` method (second revision) #3608
|
||||
[fish2000]
|
||||
|
||||
- Pass the correct types to PyArg_ParseTuple #3880
|
||||
[QuLogic]
|
||||
|
||||
- Fixed crash when loading non-font bytes #3912
|
||||
[radarhere]
|
||||
|
||||
- Fix SPARC memory alignment issues in Pack/Unpack functions #3858
|
||||
[kulikjak]
|
||||
|
||||
- Added CMYK;16B and CMYK;16N unpackers #3913
|
||||
[radarhere]
|
||||
|
||||
- Fixed bugs in calculating text size #3864
|
||||
[radarhere]
|
||||
|
||||
- Add __main__.py to output basic format and support information #3870
|
||||
[jdufresne]
|
||||
|
||||
- Added variation font support #3802
|
||||
[radarhere]
|
||||
|
||||
- Do not down-convert if image is LA when showing with PNG format #3869
|
||||
[radarhere]
|
||||
|
||||
- Improve handling of PSD frames #3759
|
||||
[radarhere]
|
||||
|
||||
- Improved ICO and ICNS loading #3897
|
||||
[radarhere]
|
||||
|
||||
- Changed Preview application path so that it is no longer static #3896
|
||||
[radarhere]
|
||||
|
||||
- Corrected ttb text positioning #3856
|
||||
[radarhere]
|
||||
|
||||
- Handle unexpected ICO image sizes #3836
|
||||
[radarhere]
|
||||
|
||||
- Fixed bits value for RGB;16N unpackers #3837
|
||||
[kkopachev]
|
||||
|
||||
- Travis CI: Add Fedora 30, remove Fedora 28 #3821
|
||||
[hugovk]
|
||||
|
||||
- Added reading of CMYK;16L TIFF images #3817
|
||||
[radarhere]
|
||||
|
||||
- Fixed dimensions of 1-bit PDFs #3827
|
||||
[radarhere]
|
||||
|
||||
- Fixed opening mmap image through Path on Windows #3825
|
||||
[radarhere]
|
||||
|
||||
- Fixed ImageDraw arc gaps #3824
|
||||
[radarhere]
|
||||
|
||||
- Expand GIF to include frames with extents outside the image size #3822
|
||||
[radarhere]
|
||||
|
||||
- Fixed ImageTk getimage #3814
|
||||
[radarhere]
|
||||
|
||||
- Fixed bug in decoding large images #3791
|
||||
[radarhere]
|
||||
|
||||
- Fixed reading APP13 marker without Photoshop data #3771
|
||||
[radarhere]
|
||||
|
||||
- Added option to include layered windows in ImageGrab.grab on Windows #3808
|
||||
[radarhere]
|
||||
|
||||
- Detect libimagequant when installed by pacman on MingW #3812
|
||||
[radarhere]
|
||||
|
||||
- Fixed raqm layout bug #3787
|
||||
[radarhere]
|
||||
|
||||
- Fixed loading font with non-Unicode path on Windows #3785
|
||||
[radarhere]
|
||||
|
||||
- Travis CI: Upgrade PyPy from 6.0.0 to 7.1.1 #3783
|
||||
[hugovk, johnthagen]
|
||||
|
||||
- Depends: Updated openjpeg to 2.3.1 #3794, raqm to 0.7.0 #3877, libimagequant to 2.12.3 #3889
|
||||
[radarhere]
|
||||
|
||||
- Fix numpy bool bug #3790
|
||||
[radarhere]
|
||||
|
||||
6.0.0 (2019-04-01)
|
||||
------------------
|
||||
|
||||
- Python 2.7 support will be removed in Pillow 7.0.0 #3682
|
||||
[hugovk]
|
||||
|
||||
- Add EXIF class #3625
|
||||
[radarhere]
|
||||
|
||||
- Add ImageOps exif_transpose method #3687
|
||||
[radarhere]
|
||||
|
||||
- Added warnings to deprecated CMSProfile attributes #3615
|
||||
[hugovk]
|
||||
|
||||
- Documented reading TIFF multiframe images #3720
|
||||
[akuchling]
|
||||
|
||||
- Improved speed of opening an MPO file #3658
|
||||
[Glandos]
|
||||
|
||||
- Update palette in quantize #3721
|
||||
[radarhere]
|
||||
|
||||
- Improvements to TIFF is_animated and n_frames #3714
|
||||
[radarhere]
|
||||
|
||||
- Fixed incompatible pointer type warnings #3754
|
||||
[radarhere]
|
||||
|
||||
- Improvements to PA and LA conversion and palette operations #3728
|
||||
[radarhere]
|
||||
|
||||
- Consistent DPI rounding #3709
|
||||
[radarhere]
|
||||
|
||||
- Change size of MPO image to match frame #3588
|
||||
[radarhere]
|
||||
|
||||
- Read Photoshop resolution data #3701
|
||||
[radarhere]
|
||||
|
||||
- Ensure image is mutable before saving #3724
|
||||
[radarhere]
|
||||
|
||||
- Correct remap_palette documentation #3740
|
||||
[radarhere]
|
||||
|
||||
- Promote P images to PA in putalpha #3726
|
||||
[radarhere]
|
||||
|
||||
- Allow RGB and RGBA values for new P images #3719
|
||||
[radarhere]
|
||||
|
||||
- Fixed TIFF bug when seeking backwards and then forwards #3713
|
||||
[radarhere]
|
||||
|
||||
- Cache EXIF information #3498
|
||||
[Glandos]
|
||||
|
||||
- Added transparency for all PNG greyscale modes #3744
|
||||
[radarhere]
|
||||
|
||||
- Fix deprecation warnings in Python 3.8 #3749
|
||||
[radarhere]
|
||||
|
||||
- Fixed GIF bug when rewinding to a non-zero frame #3716
|
||||
[radarhere]
|
||||
|
||||
- Only close original fp in __del__ and __exit__ if original fp is exclusive #3683
|
||||
[radarhere]
|
||||
|
||||
- Fix BytesWarning in Tests/test_numpy.py #3725
|
||||
[jdufresne]
|
||||
|
||||
- Add missing MIME types and extensions #3520
|
||||
[pirate486743186]
|
||||
|
||||
- Add I;16 PNG save #3566
|
||||
[radarhere]
|
||||
|
||||
- Add support for BMP RGBA bitfield compression #3705
|
||||
[radarhere]
|
||||
|
||||
- Added ability to set language for text rendering #3693
|
||||
[iwsfutcmd]
|
||||
|
||||
- Only close exclusive fp on Image __exit__ #3698
|
||||
[radarhere]
|
||||
|
||||
- Changed EPS subprocess stdout from devnull to None #3635
|
||||
[radarhere]
|
||||
|
||||
- Add reading old-JPEG compressed TIFFs #3489
|
||||
[kkopachev]
|
||||
|
||||
- Add EXIF support for PNG #3674
|
||||
[radarhere]
|
||||
|
||||
- Add option to set dither param on quantize #3699
|
||||
[glasnt]
|
||||
|
||||
- Add reading of DDS uncompressed RGB data #3673
|
||||
[radarhere]
|
||||
|
||||
- Correct length of Tiff BYTE tags #3672
|
||||
[radarhere]
|
||||
|
||||
- Add DIB saving and loading through Image open #3691
|
||||
[radarhere]
|
||||
|
||||
- Removed deprecated VERSION #3624
|
||||
[hugovk]
|
||||
|
||||
- Fix 'BytesWarning: Comparison between bytes and string' in PdfDict #3580
|
||||
[jdufresne]
|
||||
|
||||
- Do not resize in Image.thumbnail if already the destination size #3632
|
||||
[radarhere]
|
||||
|
||||
- Replace .seek() magic numbers with io.SEEK_* constants #3572
|
||||
[jdufresne]
|
||||
|
||||
- Make ContainerIO.isatty() return a bool, not int #3568
|
||||
[jdufresne]
|
||||
|
||||
- Add support to all transpose operations for I;16 modes #3563, #3741
|
||||
[radarhere]
|
||||
|
||||
- Deprecate support for PyQt4 and PySide #3655
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Add TIFF compression codecs: LZMA, Zstd, WebP #3555
|
||||
[cgohlke]
|
||||
|
||||
- Fixed pickling of iTXt class with protocol > 1 #3537
|
||||
[radarhere]
|
||||
|
||||
- _util.isPath returns True for pathlib.Path objects #3616
|
||||
[wbadart]
|
||||
|
||||
- Remove unnecessary unittest.main() boilerplate from test files #3631
|
||||
[jdufresne]
|
||||
|
||||
|
@ -407,7 +808,7 @@ Changelog (Pillow)
|
|||
- Enable background colour parameter on rotate #3057
|
||||
[storesource]
|
||||
|
||||
- Remove unnecessary `#if 1` directive #3072
|
||||
- Remove unnecessary ``#if 1`` directive #3072
|
||||
[jdufresne]
|
||||
|
||||
- Remove unused Python class, Path #3070
|
||||
|
@ -944,7 +1345,7 @@ Changelog (Pillow)
|
|||
- Add decompression bomb check to Image.crop #2410
|
||||
[wiredfool]
|
||||
|
||||
- ImageFile: Ensure that the `err_code` variable is initialized in case of exception. #2363
|
||||
- ImageFile: Ensure that the ``err_code`` variable is initialized in case of exception. #2363
|
||||
[alexkiro]
|
||||
|
||||
- Tiff: Support append_images for saving multipage TIFFs #2406
|
||||
|
@ -1181,7 +1582,7 @@ Changelog (Pillow)
|
|||
- Removed PIL 1.0 era TK readme that concerns Windows 95/NT #2360
|
||||
[wiredfool]
|
||||
|
||||
- Prevent `nose -v` printing docstrings #2369
|
||||
- Prevent ``nose -v`` printing docstrings #2369
|
||||
[hugovk]
|
||||
|
||||
- Replaced absolute PIL imports with relative imports #2349
|
||||
|
@ -1270,7 +1671,7 @@ Changelog (Pillow)
|
|||
- Test: Faster assert_image_similar #2279
|
||||
[homm]
|
||||
|
||||
- Removed depreciated internal "stretch" method #2276
|
||||
- Removed deprecated internal "stretch" method #2276
|
||||
[homm]
|
||||
|
||||
- Removed the handles_eof flag in decode.c #2223
|
||||
|
@ -1626,7 +2027,7 @@ Changelog (Pillow)
|
|||
- Changed depends/install_*.sh urls to point to github pillow-depends repo #1983
|
||||
[wiredfool]
|
||||
|
||||
- Allow ICC profile from `encoderinfo` while saving PNGs #1909
|
||||
- Allow ICC profile from ``encoderinfo`` while saving PNGs #1909
|
||||
[homm]
|
||||
|
||||
- Fix integer overflow on ILP32 systems (32-bit Linux). #1975
|
||||
|
@ -2069,7 +2470,7 @@ Changelog (Pillow)
|
|||
- Added PDF multipage saving #1445
|
||||
[radarhere]
|
||||
|
||||
- Removed deprecated code, Image.tostring, Image.fromstring, Image.offset, ImageDraw.setink, ImageDraw.setfill, ImageFileIO, ImageFont.FreeTypeFont and ImageFont.truetype `file` kwarg, ImagePalette private _make functions, ImageWin.fromstring and ImageWin.tostring #1343
|
||||
- Removed deprecated code, Image.tostring, Image.fromstring, Image.offset, ImageDraw.setink, ImageDraw.setfill, ImageFileIO, ImageFont.FreeTypeFont and ImageFont.truetype ``file`` kwarg, ImagePalette private _make functions, ImageWin.fromstring and ImageWin.tostring #1343
|
||||
[radarhere]
|
||||
|
||||
- Load more broken images #1428
|
||||
|
@ -2561,7 +2962,7 @@ Changelog (Pillow)
|
|||
- Doc cleanup
|
||||
[wiredfool]
|
||||
|
||||
- Fix `ImageStat` docs #796
|
||||
- Fix ``ImageStat`` docs #796
|
||||
[akx]
|
||||
|
||||
- Added docs for ExifTags #794
|
||||
|
@ -2998,7 +3399,7 @@ Changelog (Pillow)
|
|||
- Add RGBA support to ImageColor #309
|
||||
[yoavweiss]
|
||||
|
||||
- Test for `str`, not `"utf-8"` #306 (fixes #304)
|
||||
- Test for ``str``, not ``"utf-8"`` #306 (fixes #304)
|
||||
[mjpieters]
|
||||
|
||||
- Fix missing import os in _util.py #303
|
||||
|
@ -3104,7 +3505,7 @@ Changelog (Pillow)
|
|||
|
||||
- Partial work to add a wrapper for WebPGetFeatures to correctly support #220 (fixes #204)
|
||||
|
||||
- Significant performance improvement of `alpha_composite` function #156
|
||||
- Significant performance improvement of ``alpha_composite`` function #156
|
||||
[homm]
|
||||
|
||||
- Support explicitly disabling features via --disable-* options #240
|
||||
|
|
10
MANIFEST.in
|
@ -1,4 +1,3 @@
|
|||
|
||||
include *.c
|
||||
include *.h
|
||||
include *.in
|
||||
|
@ -9,23 +8,22 @@ include *.sh
|
|||
include *.txt
|
||||
include LICENSE
|
||||
include Makefile
|
||||
include tox.ini
|
||||
graft Tests
|
||||
graft src
|
||||
graft depends
|
||||
graft winbuild
|
||||
graft docs
|
||||
prune docs/_static
|
||||
|
||||
# build/src control detritus
|
||||
exclude .appveyor.yml
|
||||
exclude .coveragerc
|
||||
exclude .codecov.yml
|
||||
exclude .editorconfig
|
||||
exclude .landscape.yaml
|
||||
exclude .readthedocs.yml
|
||||
exclude .travis
|
||||
exclude .travis/*
|
||||
exclude tox.ini
|
||||
exclude azure-pipelines.yml
|
||||
global-exclude .git*
|
||||
global-exclude *.pyc
|
||||
global-exclude *.so
|
||||
prune .azure-pipelines
|
||||
prune .travis
|
||||
|
|
36
Makefile
|
@ -3,7 +3,7 @@
|
|||
.DEFAULT_GOAL := release-test
|
||||
|
||||
clean:
|
||||
python setup.py clean
|
||||
python3 setup.py clean
|
||||
rm src/PIL/*.so || true
|
||||
rm -r build || true
|
||||
find . -name __pycache__ | xargs rm -r || true
|
||||
|
@ -15,8 +15,8 @@ co:
|
|||
done
|
||||
|
||||
coverage:
|
||||
python selftest.py
|
||||
python setup.py test
|
||||
python3 selftest.py
|
||||
python3 setup.py test
|
||||
rm -r htmlcov || true
|
||||
coverage report
|
||||
|
||||
|
@ -30,7 +30,7 @@ doccheck:
|
|||
$(MAKE) -C docs linkcheck || true
|
||||
|
||||
docserve:
|
||||
cd docs/_build/html && python -mSimpleHTTPServer 2> /dev/null&
|
||||
cd docs/_build/html && python3 -mSimpleHTTPServer 2> /dev/null&
|
||||
|
||||
help:
|
||||
@echo "Welcome to Pillow development. Please use \`make <target>\` where <target> is one of"
|
||||
|
@ -50,22 +50,22 @@ help:
|
|||
@echo " upload-test build and upload sdists to test.pythonpackages.com"
|
||||
|
||||
inplace: clean
|
||||
python setup.py develop build_ext --inplace
|
||||
python3 setup.py develop build_ext --inplace
|
||||
|
||||
install:
|
||||
python setup.py install
|
||||
python selftest.py
|
||||
python3 setup.py install
|
||||
python3 selftest.py
|
||||
|
||||
install-coverage:
|
||||
CFLAGS="-coverage" python setup.py build_ext install
|
||||
python selftest.py
|
||||
CFLAGS="-coverage" python3 setup.py build_ext install
|
||||
python3 selftest.py
|
||||
|
||||
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
|
||||
# see any build failures.
|
||||
make clean > /dev/null
|
||||
CFLAGS='-g -O0' python setup.py build_ext install > /dev/null
|
||||
CFLAGS='-g -O0' python3 setup.py build_ext install > /dev/null
|
||||
|
||||
install-req:
|
||||
pip install -r requirements.txt
|
||||
|
@ -76,17 +76,17 @@ install-venv:
|
|||
|
||||
release-test:
|
||||
$(MAKE) install-req
|
||||
python setup.py develop
|
||||
python selftest.py
|
||||
python -m pytest Tests
|
||||
python setup.py install
|
||||
python -m pytest -qq
|
||||
python3 setup.py develop
|
||||
python3 selftest.py
|
||||
python3 -m pytest Tests
|
||||
python3 setup.py install
|
||||
python3 -m pytest -qq
|
||||
check-manifest
|
||||
pyroma .
|
||||
viewdoc
|
||||
|
||||
sdist:
|
||||
python setup.py sdist --format=gztar
|
||||
python3 setup.py sdist --format=gztar
|
||||
|
||||
test:
|
||||
pytest -qq
|
||||
|
@ -97,10 +97,10 @@ upload-test:
|
|||
# username:
|
||||
# password:
|
||||
# repository = http://test.pythonpackages.com
|
||||
python setup.py sdist --format=gztar upload -r test
|
||||
python3 setup.py sdist --format=gztar upload -r test
|
||||
|
||||
upload:
|
||||
python setup.py sdist --format=gztar upload
|
||||
python3 setup.py sdist --format=gztar upload
|
||||
|
||||
readme:
|
||||
viewdoc
|
||||
|
|
107
README.rst
|
@ -4,7 +4,7 @@ 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.
|
||||
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
|
||||
|
||||
|
@ -14,58 +14,14 @@ Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.
|
|||
* - docs
|
||||
- |docs|
|
||||
* - tests
|
||||
- |linux| |macos| |windows| |coverage|
|
||||
- |linux| |macos| |windows| |gha_lint| |gha| |gha_windows| |gha_docker| |coverage|
|
||||
* - package
|
||||
- |zenodo| |tidelift| |version| |downloads|
|
||||
* - social
|
||||
- |gitter| |twitter|
|
||||
|
||||
.. |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)
|
||||
|
||||
.. |coverage| image:: https://coveralls.io/repos/python-pillow/Pillow/badge.svg?branch=master&service=github
|
||||
:target: https://coveralls.io/github/python-pillow/Pillow?branch=master
|
||||
: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/github/python-pillow/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
|
||||
|
||||
.. end-badges
|
||||
|
||||
|
||||
|
||||
More Information
|
||||
----------------
|
||||
|
||||
|
@ -82,3 +38,62 @@ More Information
|
|||
- `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
|
||||
|
|
14
RELEASING.md
|
@ -51,6 +51,7 @@ Released as needed for security, installation or critical bug fixes.
|
|||
make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
|
||||
* [ ] Upload all binaries and source distributions e.g. `twine upload dist/Pillow-5.2.1*`
|
||||
* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
|
||||
|
||||
## Embargoed Release
|
||||
|
@ -88,18 +89,11 @@ Released as needed privately to individual vendors for critical security-related
|
|||
```bash
|
||||
git clone https://github.com/python-pillow/pillow-wheels
|
||||
cd pillow-wheels
|
||||
git submodule init
|
||||
git submodule update Pillow
|
||||
cd Pillow
|
||||
git fetch --all
|
||||
git checkout [[release tag]]
|
||||
cd ..
|
||||
git commit -m "Pillow -> 5.2.0" Pillow
|
||||
git push
|
||||
./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>*' \
|
||||
wget -m -A 'Pillow-<VERSION>-*' \
|
||||
http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
|
||||
```
|
||||
|
||||
|
@ -109,4 +103,4 @@ Released as needed privately to individual vendors for critical security-related
|
|||
|
||||
## Documentation
|
||||
|
||||
* [ ] Make sure the default version for Read the Docs is the latest tagged release e.g. `d2d43879` (5.4.0)
|
||||
* [ ] Make sure the [default version for Read the Docs](https://pillow.readthedocs.io/en/stable/) is up-to-date with the release changes
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from PIL import Image
|
||||
import sys
|
||||
|
||||
from PIL import Image
|
||||
|
||||
if sys.maxsize < 2**32:
|
||||
im = Image.new('L', (999999, 999999), 0)
|
||||
if sys.maxsize < 2 ** 32:
|
||||
im = Image.new("L", (999999, 999999), 0)
|
||||
|
|
|
@ -4,7 +4,7 @@ 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``.
|
||||
|
||||
Dependencies
|
||||
-----------
|
||||
------------
|
||||
|
||||
Install::
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from .helper import unittest, PillowTestCase, hopper
|
||||
|
||||
# Not running this test by default. No DOS against Travis CI.
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from PIL import PyAccess
|
||||
|
||||
import time
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
# Not running this test by default. No DOS against Travis CI.
|
||||
|
||||
|
||||
def iterate_get(size, access):
|
||||
|
@ -26,18 +27,21 @@ def timer(func, label, *args):
|
|||
starttime = time.time()
|
||||
for x in range(iterations):
|
||||
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)))
|
||||
if time.time() - starttime > 10:
|
||||
print(
|
||||
"%s: breaking at %s iterations, %.6f per iteration"
|
||||
% (label, x + 1, (time.time() - starttime) / (x + 1.0))
|
||||
)
|
||||
break
|
||||
if x == iterations-1:
|
||||
if x == iterations - 1:
|
||||
endtime = time.time()
|
||||
print("%s: %.4f s %.6f per iteration" % (
|
||||
label, endtime-starttime, (endtime-starttime)/(x+1.0)))
|
||||
print(
|
||||
"%s: %.4f s %.6f per iteration"
|
||||
% (label, endtime - starttime, (endtime - starttime) / (x + 1.0))
|
||||
)
|
||||
|
||||
|
||||
class BenchCffiAccess(PillowTestCase):
|
||||
|
||||
def test_direct(self):
|
||||
im = hopper()
|
||||
im.load()
|
||||
|
@ -48,11 +52,11 @@ class BenchCffiAccess(PillowTestCase):
|
|||
self.assertEqual(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)
|
||||
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__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from . import helper
|
||||
import sys
|
||||
import timeit
|
||||
|
||||
import sys
|
||||
from . import helper
|
||||
|
||||
sys.path.insert(0, ".")
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from .helper import unittest, PillowTestCase
|
||||
import unittest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
TEST_FILE = "Tests/images/fli_overflow.fli"
|
||||
|
||||
|
||||
|
@ -12,5 +15,5 @@ class TestFliOverflow(PillowTestCase):
|
|||
im.load()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# Tests potential DOS of IcnsImagePlugin with 0 length block.
|
||||
# Run from anywhere that PIL is importable.
|
||||
|
||||
from PIL import Image
|
||||
from PIL._util import py3
|
||||
from io import BytesIO
|
||||
|
||||
if py3:
|
||||
Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00',
|
||||
'latin-1')))
|
||||
else:
|
||||
Image.open(BytesIO(bytes('icns\x00\x00\x00\x10hang\x00\x00\x00\x00')))
|
||||
from PIL import Image
|
||||
|
||||
Image.open(BytesIO(b"icns\x00\x00\x00\x10hang\x00\x00\x00\x00"))
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
import unittest
|
||||
|
||||
from __future__ import division
|
||||
from .helper import unittest, PillowTestCase
|
||||
import sys
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, is_win32
|
||||
|
||||
min_iterations = 100
|
||||
max_iterations = 10000
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "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
|
||||
|
||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||
return mem * getpagesize() / 1024 / 1024
|
||||
|
||||
|
@ -25,20 +25,22 @@ class TestImagingLeaks(PillowTestCase):
|
|||
if i < min_iterations:
|
||||
mem_limit = mem + 1
|
||||
continue
|
||||
msg = 'memory usage limit exceeded after %d iterations' % (i + 1)
|
||||
msg = "memory usage limit exceeded after %d iterations" % (i + 1)
|
||||
self.assertLessEqual(mem, mem_limit, msg)
|
||||
|
||||
def test_leak_putdata(self):
|
||||
im = Image.new('RGB', (25, 25))
|
||||
self._test_leak(min_iterations, max_iterations,
|
||||
im.putdata, im.getdata())
|
||||
im = Image.new("RGB", (25, 25))
|
||||
self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata())
|
||||
|
||||
def test_leak_getlist(self):
|
||||
im = Image.new('P', (25, 25))
|
||||
self._test_leak(min_iterations, max_iterations,
|
||||
# Pass a new list at each iteration.
|
||||
lambda: im.point(range(256)))
|
||||
im = Image.new("P", (25, 25))
|
||||
self._test_leak(
|
||||
min_iterations,
|
||||
max_iterations,
|
||||
# Pass a new list at each iteration.
|
||||
lambda: im.point(range(256)),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
# Tests potential DOS of Jpeg2kImagePlugin with 0 length block.
|
||||
# Run from anywhere that PIL is importable.
|
||||
|
||||
from PIL import Image
|
||||
from PIL._util import py3
|
||||
from io import BytesIO
|
||||
|
||||
if py3:
|
||||
Image.open(BytesIO(bytes(
|
||||
'\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang',
|
||||
'latin-1')))
|
||||
from PIL import Image
|
||||
|
||||
else:
|
||||
Image.open(BytesIO(bytes(
|
||||
'\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang')))
|
||||
Image.open(BytesIO(b"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang"))
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
from .helper import unittest, PillowTestCase
|
||||
import sys
|
||||
from PIL import Image
|
||||
import unittest
|
||||
from io import BytesIO
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase, is_win32
|
||||
|
||||
# Limits for testing the leak
|
||||
mem_limit = 1024*1048576
|
||||
stack_size = 8*1048576
|
||||
iterations = int((mem_limit/stack_size)*2)
|
||||
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"
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
||||
@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')
|
||||
self.skipTest("JPEG 2000 support not available")
|
||||
|
||||
def test_leak_load(self):
|
||||
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||
|
||||
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||
for _ in range(iterations):
|
||||
|
@ -27,6 +30,7 @@ class TestJpegLeaks(PillowTestCase):
|
|||
|
||||
def test_leak_save(self):
|
||||
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
|
||||
|
||||
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
|
||||
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
|
||||
for _ in range(iterations):
|
||||
|
@ -38,5 +42,5 @@ class TestJpegLeaks(PillowTestCase):
|
|||
test_output.read()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import unittest
|
||||
|
||||
from PIL import Image
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
|
||||
class TestJ2kEncodeOverflow(PillowTestCase):
|
||||
def test_j2k_overflow(self):
|
||||
|
||||
im = Image.new('RGBA', (1024, 131584))
|
||||
target = self.tempfile('temp.jpc')
|
||||
im = Image.new("RGBA", (1024, 131584))
|
||||
target = self.tempfile("temp.jpc")
|
||||
with self.assertRaises(IOError):
|
||||
im.save(target)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from .helper import unittest, PillowTestCase, hopper
|
||||
import unittest
|
||||
from io import BytesIO
|
||||
import sys
|
||||
|
||||
from .helper import PillowTestCase, hopper, is_win32
|
||||
|
||||
iterations = 5000
|
||||
|
||||
|
@ -14,7 +15,7 @@ valgrind --tool=massif python test-installed.py -s -v Tests/check_jpeg_leaks.py
|
|||
"""
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
||||
@unittest.skipIf(is_win32(), "requires Unix or macOS")
|
||||
class TestJpegLeaks(PillowTestCase):
|
||||
|
||||
"""
|
||||
|
@ -74,9 +75,11 @@ post-patch:
|
|||
"""
|
||||
|
||||
def test_qtables_leak(self):
|
||||
im = hopper('RGB')
|
||||
im = hopper("RGB")
|
||||
|
||||
standard_l_qtable = [int(s) for s in """
|
||||
standard_l_qtable = [
|
||||
int(s)
|
||||
for s in """
|
||||
16 11 10 16 24 40 51 61
|
||||
12 12 14 19 26 58 60 55
|
||||
14 13 16 24 40 57 69 56
|
||||
|
@ -85,9 +88,14 @@ post-patch:
|
|||
24 35 55 64 81 104 113 92
|
||||
49 64 78 87 103 121 120 101
|
||||
72 92 95 98 112 100 103 99
|
||||
""".split(None)]
|
||||
""".split(
|
||||
None
|
||||
)
|
||||
]
|
||||
|
||||
standard_chrominance_qtable = [int(s) for s in """
|
||||
standard_chrominance_qtable = [
|
||||
int(s)
|
||||
for s in """
|
||||
17 18 24 47 99 99 99 99
|
||||
18 21 26 66 99 99 99 99
|
||||
24 26 56 99 99 99 99 99
|
||||
|
@ -96,10 +104,12 @@ post-patch:
|
|||
99 99 99 99 99 99 99 99
|
||||
99 99 99 99 99 99 99 99
|
||||
99 99 99 99 99 99 99 99
|
||||
""".split(None)]
|
||||
""".split(
|
||||
None
|
||||
)
|
||||
]
|
||||
|
||||
qtables = [standard_l_qtable,
|
||||
standard_chrominance_qtable]
|
||||
qtables = [standard_l_qtable, standard_chrominance_qtable]
|
||||
|
||||
for _ in range(iterations):
|
||||
test_output = BytesIO()
|
||||
|
@ -161,8 +171,8 @@ post patch:
|
|||
0 11.33
|
||||
|
||||
"""
|
||||
im = hopper('RGB')
|
||||
exif = b'12345678'*4096
|
||||
im = hopper("RGB")
|
||||
exif = b"12345678" * 4096
|
||||
|
||||
for _ in range(iterations):
|
||||
test_output = BytesIO()
|
||||
|
@ -195,12 +205,12 @@ base case:
|
|||
0 +----------------------------------------------------------------------->Gi
|
||||
0 7.882
|
||||
"""
|
||||
im = hopper('RGB')
|
||||
im = hopper("RGB")
|
||||
|
||||
for _ in range(iterations):
|
||||
test_output = BytesIO()
|
||||
im.save(test_output, "JPEG")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
# This test is not run automatically.
|
||||
#
|
||||
|
@ -11,17 +14,21 @@ from .helper import unittest, PillowTestCase
|
|||
# Raspberry Pis). It does succeed on a 3gb Ubuntu 12.04x64 VM on Python
|
||||
# 2.7 and 3.2.
|
||||
|
||||
from PIL import Image
|
||||
|
||||
try:
|
||||
import numpy
|
||||
except ImportError:
|
||||
numpy = None
|
||||
|
||||
YDIM = 32769
|
||||
XDIM = 48000
|
||||
|
||||
|
||||
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64-bit system")
|
||||
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
||||
class LargeMemoryTest(PillowTestCase):
|
||||
|
||||
def _write_png(self, xdim, ydim):
|
||||
f = self.tempfile('temp.png')
|
||||
im = Image.new('L', (xdim, ydim), 0)
|
||||
f = self.tempfile("temp.png")
|
||||
im = Image.new("L", (xdim, ydim), 0)
|
||||
im.save(f)
|
||||
|
||||
def test_large(self):
|
||||
|
@ -32,6 +39,11 @@ class LargeMemoryTest(PillowTestCase):
|
|||
"""failed prepatch"""
|
||||
self._write_png(XDIM, XDIM)
|
||||
|
||||
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
||||
def test_size_greater_than_int(self):
|
||||
arr = numpy.ndarray(shape=(16394, 16394))
|
||||
Image.fromarray(arr)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
# This test is not run automatically.
|
||||
#
|
||||
|
@ -10,7 +13,7 @@ from .helper import unittest, PillowTestCase
|
|||
# on any 32-bit machine, as well as any smallish things (like
|
||||
# Raspberry Pis).
|
||||
|
||||
from PIL import Image
|
||||
|
||||
try:
|
||||
import numpy as np
|
||||
except ImportError:
|
||||
|
@ -20,14 +23,13 @@ YDIM = 32769
|
|||
XDIM = 48000
|
||||
|
||||
|
||||
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64-bit system")
|
||||
@unittest.skipIf(sys.maxsize <= 2 ** 32, "requires 64-bit system")
|
||||
class LargeMemoryNumpyTest(PillowTestCase):
|
||||
|
||||
def _write_png(self, xdim, ydim):
|
||||
dtype = np.uint8
|
||||
a = np.zeros((xdim, ydim), dtype=dtype)
|
||||
f = self.tempfile('temp.png')
|
||||
im = Image.fromarray(a, 'L')
|
||||
f = self.tempfile("temp.png")
|
||||
im = Image.fromarray(a, "L")
|
||||
im.save(f)
|
||||
|
||||
def test_large(self):
|
||||
|
@ -39,5 +41,5 @@ class LargeMemoryNumpyTest(PillowTestCase):
|
|||
self._write_png(XDIM, XDIM)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from .helper import unittest, PillowTestCase
|
||||
import unittest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import PillowTestCase
|
||||
|
||||
TEST_FILE = "Tests/images/libtiff_segfault.tif"
|
||||
|
||||
|
||||
|
@ -15,5 +18,5 @@ class TestLibtiffSegfault(PillowTestCase):
|
|||
im.load()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image, PngImagePlugin, ImageFile
|
||||
from io import BytesIO
|
||||
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"
|
||||
|
||||
|
@ -17,10 +20,10 @@ 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")
|
||||
self.assertLess(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")
|
||||
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||
|
||||
def test_dos_text(self):
|
||||
|
||||
|
@ -32,20 +35,20 @@ class TestPngDos(PillowTestCase):
|
|||
return
|
||||
|
||||
for s in im.text.values():
|
||||
self.assertLess(len(s), 1024*1024, "Text chunk larger than 1M")
|
||||
self.assertLess(len(s), 1024 * 1024, "Text chunk larger than 1M")
|
||||
|
||||
def test_dos_total_memory(self):
|
||||
im = Image.new('L', (1, 1))
|
||||
compressed_data = zlib.compress(b'a'*1024*1023)
|
||||
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("t%s" % x, compressed_data, zip=True)
|
||||
info.add_itxt("i%s" % x, compressed_data, zip=True)
|
||||
|
||||
b = BytesIO()
|
||||
im.save(b, 'PNG', pnginfo=info)
|
||||
im.save(b, "PNG", pnginfo=info)
|
||||
b.seek(0)
|
||||
|
||||
try:
|
||||
|
@ -57,9 +60,10 @@ class TestPngDos(PillowTestCase):
|
|||
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")
|
||||
self.assertLess(
|
||||
total_len, 64 * 1024 * 1024, "Total text chunks greater than 64M"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
11
Tests/conftest.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
def pytest_report_header(config):
|
||||
import io
|
||||
|
||||
try:
|
||||
from PIL import features
|
||||
|
||||
with io.StringIO() as out:
|
||||
features.pilinfo(out=out, supported_formats=False)
|
||||
return out.getvalue()
|
||||
except Exception as e:
|
||||
return "pytest_report_header failed: %s" % str(e)
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
import base64
|
||||
import os
|
||||
|
||||
|
|
BIN
Tests/fonts/AdobeVFPrototype.ttf
Normal file
BIN
Tests/fonts/ArefRuqaa-Regular.ttf
Normal file
BIN
Tests/fonts/KhmerOSBattambang-Regular.ttf
Executable file
|
@ -1,13 +1,13 @@
|
|||
|
||||
NotoNastaliqUrdu-Regular.ttf:
|
||||
NotoNastaliqUrdu-Regular.ttf and NotoSansSymbols-Regular.ttf, from https://github.com/googlei18n/noto-fonts
|
||||
NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/
|
||||
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
|
||||
|
||||
(from https://github.com/googlei18n/noto-fonts)
|
||||
|
||||
All Noto 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.
|
||||
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.
|
||||
|
||||
|
||||
10x20-ISO8859-1.pcf
|
||||
|
||||
(from https://packages.ubuntu.com/xenial/xfonts-base)
|
||||
10x20-ISO8859-1.pcf, from https://packages.ubuntu.com/xenial/xfonts-base
|
||||
|
||||
"Public domain font. Share and enjoy."
|
||||
|
|
BIN
Tests/fonts/NotoSansJP-Regular.otf
Normal file
BIN
Tests/fonts/NotoSansSymbols-Regular.ttf
Normal file
BIN
Tests/fonts/TINY5x3GX.ttf
Executable file
245
Tests/helper.py
|
@ -1,33 +1,51 @@
|
|||
"""
|
||||
Helper functions.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import tempfile
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from PIL import Image, ImageMath
|
||||
from PIL._util import py3
|
||||
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from io import BytesIO
|
||||
|
||||
from PIL import Image, ImageMath
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
HAS_UPLOADER = False
|
||||
|
||||
if os.environ.get('SHOW_ERRORS', None):
|
||||
if os.environ.get("SHOW_ERRORS", None):
|
||||
# local img.show for errors.
|
||||
HAS_UPLOADER = True
|
||||
|
||||
class test_image_results:
|
||||
@classmethod
|
||||
def upload(self, a, b):
|
||||
@staticmethod
|
||||
def upload(a, b):
|
||||
a.show()
|
||||
b.show()
|
||||
|
||||
|
||||
elif "GITHUB_ACTIONS" in os.environ:
|
||||
HAS_UPLOADER = True
|
||||
|
||||
class test_image_results:
|
||||
@staticmethod
|
||||
def upload(a, b):
|
||||
dir_errors = os.path.join(os.path.dirname(__file__), "errors")
|
||||
os.makedirs(dir_errors, exist_ok=True)
|
||||
tmpdir = tempfile.mkdtemp(dir=dir_errors)
|
||||
a.save(os.path.join(tmpdir, "a.png"))
|
||||
b.save(os.path.join(tmpdir, "b.png"))
|
||||
return tmpdir
|
||||
|
||||
|
||||
else:
|
||||
try:
|
||||
import test_image_results
|
||||
|
||||
HAS_UPLOADER = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
@ -35,72 +53,60 @@ else:
|
|||
|
||||
def convert_to_comparable(a, b):
|
||||
new_a, new_b = a, b
|
||||
if a.mode == 'P':
|
||||
new_a = Image.new('L', a.size)
|
||||
new_b = Image.new('L', b.size)
|
||||
if a.mode == "P":
|
||||
new_a = Image.new("L", a.size)
|
||||
new_b = Image.new("L", b.size)
|
||||
new_a.putdata(a.getdata())
|
||||
new_b.putdata(b.getdata())
|
||||
elif a.mode == 'I;16':
|
||||
new_a = a.convert('I')
|
||||
new_b = b.convert('I')
|
||||
elif a.mode == "I;16":
|
||||
new_a = a.convert("I")
|
||||
new_b = b.convert("I")
|
||||
return new_a, new_b
|
||||
|
||||
|
||||
class PillowTestCase(unittest.TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
unittest.TestCase.__init__(self, *args, **kwargs)
|
||||
# holds last result object passed to run method:
|
||||
self.currentResult = None
|
||||
|
||||
def run(self, result=None):
|
||||
self.currentResult = result # remember result for use later
|
||||
unittest.TestCase.run(self, result) # call superclass run method
|
||||
|
||||
def delete_tempfile(self, path):
|
||||
try:
|
||||
ok = self.currentResult.wasSuccessful()
|
||||
except AttributeError: # for pytest
|
||||
ok = True
|
||||
|
||||
if ok:
|
||||
# only clean out tempfiles if test passed
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
pass # report?
|
||||
else:
|
||||
print("=== orphaned temp file: %s" % path)
|
||||
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 %s, expected %s" % (len(a), len(b)))
|
||||
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 %s, expected %s" % (a, b))
|
||||
msg or "got {}, expected {}".format(a, b),
|
||||
)
|
||||
except Exception:
|
||||
self.assertEqual(a, b, msg)
|
||||
|
||||
def assert_image(self, im, mode, size, msg=None):
|
||||
if mode is not None:
|
||||
self.assertEqual(
|
||||
im.mode, mode,
|
||||
msg or "got mode %r, expected %r" % (im.mode, mode))
|
||||
im.mode,
|
||||
mode,
|
||||
msg or "got mode {!r}, expected {!r}".format(im.mode, mode),
|
||||
)
|
||||
|
||||
if size is not None:
|
||||
self.assertEqual(
|
||||
im.size, size,
|
||||
msg or "got size %r, expected %r" % (im.size, size))
|
||||
im.size,
|
||||
size,
|
||||
msg or "got size {!r}, expected {!r}".format(im.size, size),
|
||||
)
|
||||
|
||||
def assert_image_equal(self, a, b, msg=None):
|
||||
self.assertEqual(
|
||||
a.mode, b.mode,
|
||||
msg or "got mode %r, expected %r" % (a.mode, b.mode))
|
||||
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" % (a.size, b.size))
|
||||
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
|
||||
)
|
||||
if a.tobytes() != b.tobytes():
|
||||
if HAS_UPLOADER:
|
||||
try:
|
||||
|
@ -120,26 +126,28 @@ class PillowTestCase(unittest.TestCase):
|
|||
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" % (a.mode, b.mode))
|
||||
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" % (a.size, b.size))
|
||||
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
|
||||
)
|
||||
|
||||
a, b = convert_to_comparable(a, b)
|
||||
|
||||
diff = 0
|
||||
for ach, bch in zip(a.split(), b.split()):
|
||||
chdiff = ImageMath.eval("abs(a - b)", a=ach, b=bch).convert('L')
|
||||
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 = float(diff) / (a.size[0] * a.size[1])
|
||||
try:
|
||||
self.assertGreaterEqual(
|
||||
epsilon, ave_diff,
|
||||
(msg or '') +
|
||||
" average pixel value difference %.4f > epsilon %.4f" % (
|
||||
ave_diff, epsilon))
|
||||
epsilon,
|
||||
ave_diff,
|
||||
(msg or "")
|
||||
+ " average pixel value difference %.4f > epsilon %.4f"
|
||||
% (ave_diff, epsilon),
|
||||
)
|
||||
except Exception as e:
|
||||
if HAS_UPLOADER:
|
||||
try:
|
||||
|
@ -149,8 +157,7 @@ class PillowTestCase(unittest.TestCase):
|
|||
pass
|
||||
raise e
|
||||
|
||||
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None,
|
||||
mode=None):
|
||||
def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, mode=None):
|
||||
with Image.open(filename) as img:
|
||||
if mode:
|
||||
img = img.convert(mode)
|
||||
|
@ -168,9 +175,9 @@ class PillowTestCase(unittest.TestCase):
|
|||
|
||||
# Verify some things.
|
||||
if warn_class is None:
|
||||
self.assertEqual(len(w), 0,
|
||||
"Expected no warnings, got %s" %
|
||||
[v.category for v in w])
|
||||
self.assertEqual(
|
||||
len(w), 0, "Expected no warnings, got %s" % [v.category for v in w]
|
||||
)
|
||||
else:
|
||||
self.assertGreaterEqual(len(w), 1)
|
||||
found = False
|
||||
|
@ -192,29 +199,17 @@ class PillowTestCase(unittest.TestCase):
|
|||
|
||||
value = True
|
||||
for i, target in enumerate(targets):
|
||||
value *= (target - threshold <= actuals[i] <= target + threshold)
|
||||
value *= target - threshold <= actuals[i] <= target + threshold
|
||||
|
||||
self.assertTrue(value,
|
||||
msg + ': ' + repr(actuals) + ' != ' + repr(targets))
|
||||
self.assertTrue(value, msg + ": " + repr(actuals) + " != " + repr(targets))
|
||||
|
||||
def skipKnownBadTest(self, msg=None, platform=None,
|
||||
travis=None, interpreter=None):
|
||||
# Skip if platform/travis matches, and
|
||||
# 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))
|
||||
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
|
||||
|
||||
skip = True
|
||||
if platform is not None:
|
||||
skip = sys.platform.startswith(platform)
|
||||
if travis is not None:
|
||||
skip = skip and (travis == bool(os.environ.get('TRAVIS', False)))
|
||||
if interpreter is not None:
|
||||
skip = skip and (interpreter == 'pypy' and
|
||||
hasattr(sys, 'pypy_version_info'))
|
||||
if skip:
|
||||
self.skipTest(msg or "Known Bad Test")
|
||||
self.skipTest(msg or "Known Bad Test")
|
||||
|
||||
def tempfile(self, template):
|
||||
assert template[:5] in ("temp.", "temp_")
|
||||
|
@ -226,15 +221,15 @@ class PillowTestCase(unittest.TestCase):
|
|||
|
||||
def open_withImagemagick(self, f):
|
||||
if not imagemagick_available():
|
||||
raise IOError()
|
||||
raise OSError()
|
||||
|
||||
outfile = self.tempfile("temp.png")
|
||||
if command_succeeds([IMCONVERT, f, outfile]):
|
||||
return Image.open(outfile)
|
||||
raise IOError()
|
||||
raise OSError()
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
||||
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||
class PillowLeakTestCase(PillowTestCase):
|
||||
# requires unix/macOS
|
||||
iterations = 100 # count
|
||||
|
@ -249,8 +244,9 @@ class PillowLeakTestCase(PillowTestCase):
|
|||
"""
|
||||
|
||||
from resource import getrusage, RUSAGE_SELF
|
||||
|
||||
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||
if sys.platform == 'darwin':
|
||||
if sys.platform == "darwin":
|
||||
# man 2 getrusage:
|
||||
# ru_maxrss
|
||||
# This is the maximum resident set size utilized (in bytes).
|
||||
|
@ -266,26 +262,19 @@ class PillowLeakTestCase(PillowTestCase):
|
|||
start_mem = self._get_mem_usage()
|
||||
for cycle in range(self.iterations):
|
||||
core()
|
||||
mem = (self._get_mem_usage() - start_mem)
|
||||
msg = 'memory usage limit exceeded in iteration %d' % cycle
|
||||
mem = self._get_mem_usage() - start_mem
|
||||
msg = "memory usage limit exceeded in iteration %d" % cycle
|
||||
self.assertLess(mem, self.mem_limit, msg)
|
||||
|
||||
|
||||
# helpers
|
||||
|
||||
if not py3:
|
||||
# Remove DeprecationWarning in Python 3
|
||||
PillowTestCase.assertRaisesRegex = PillowTestCase.assertRaisesRegexp
|
||||
PillowTestCase.assertRegex = PillowTestCase.assertRegexpMatches
|
||||
|
||||
|
||||
def fromstring(data):
|
||||
from io import BytesIO
|
||||
return Image.open(BytesIO(data))
|
||||
|
||||
|
||||
def tostring(im, string_format, **options):
|
||||
from io import BytesIO
|
||||
out = BytesIO()
|
||||
im.save(out, string_format, **options)
|
||||
return out.getvalue()
|
||||
|
@ -317,53 +306,73 @@ 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.
|
||||
"""
|
||||
import subprocess
|
||||
with open(os.devnull, 'wb') as f:
|
||||
try:
|
||||
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)
|
||||
except OSError:
|
||||
return False
|
||||
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 command_succeeds(["djpeg", "-version"])
|
||||
|
||||
|
||||
def cjpeg_available():
|
||||
return command_succeeds(['cjpeg', '-version'])
|
||||
return command_succeeds(["cjpeg", "-version"])
|
||||
|
||||
|
||||
def netpbm_available():
|
||||
return (command_succeeds(["ppmquant", "--version"]) and
|
||||
command_succeeds(["ppmtogif", "--version"]))
|
||||
return command_succeeds(["ppmquant", "--version"]) and command_succeeds(
|
||||
["ppmtogif", "--version"]
|
||||
)
|
||||
|
||||
|
||||
def imagemagick_available():
|
||||
return IMCONVERT and command_succeeds([IMCONVERT, '-version'])
|
||||
return IMCONVERT and command_succeeds([IMCONVERT, "-version"])
|
||||
|
||||
|
||||
def on_appveyor():
|
||||
return 'APPVEYOR' in os.environ
|
||||
return "APPVEYOR" in os.environ
|
||||
|
||||
|
||||
if sys.platform == 'win32':
|
||||
IMCONVERT = os.environ.get('MAGICK_HOME', '')
|
||||
def on_github_actions():
|
||||
return "GITHUB_ACTIONS" in os.environ
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
def is_win32():
|
||||
return sys.platform.startswith("win32")
|
||||
|
||||
|
||||
def is_pypy():
|
||||
return hasattr(sys, "pypy_translation_info")
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
IMCONVERT = os.environ.get("MAGICK_HOME", "")
|
||||
if IMCONVERT:
|
||||
IMCONVERT = os.path.join(IMCONVERT, 'convert.exe')
|
||||
IMCONVERT = os.path.join(IMCONVERT, "convert.exe")
|
||||
else:
|
||||
IMCONVERT = 'convert'
|
||||
IMCONVERT = "convert"
|
||||
|
||||
|
||||
def distro():
|
||||
if os.path.exists('/etc/os-release'):
|
||||
with open('/etc/os-release', 'r') as f:
|
||||
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]
|
||||
if "ID=" in line:
|
||||
return line.strip().split("=")[1]
|
||||
|
||||
|
||||
class cached_property(object):
|
||||
class cached_property:
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
|
||||
|
|
BIN
Tests/images/1_trns.png
Normal file
After Width: | Height: | Size: 612 B |
BIN
Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds
Normal file
BIN
Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.png
Normal file
After Width: | Height: | Size: 106 B |
BIN
Tests/images/app13.jpg
Normal file
After Width: | Height: | Size: 563 B |
BIN
Tests/images/combined_larger_than_size.psd
Normal file
BIN
Tests/images/decompression_bomb.gif
Normal file
After Width: | Height: | Size: 44 B |
BIN
Tests/images/decompression_bomb.ico
Normal file
After Width: | Height: | Size: 58 B |
BIN
Tests/images/drawing_roundDown.emf
Normal file
BIN
Tests/images/exif.png
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
Tests/images/fli_overrun.bin
Normal file
BIN
Tests/images/fujifilm.mpo
Normal file
After Width: | Height: | Size: 9.5 MiB |
BIN
Tests/images/g4_orientation_1.tif
Executable file
BIN
Tests/images/g4_orientation_2.tif
Executable file
BIN
Tests/images/g4_orientation_3.tif
Executable file
BIN
Tests/images/g4_orientation_4.tif
Executable file
BIN
Tests/images/g4_orientation_5.tif
Executable file
BIN
Tests/images/g4_orientation_6.tif
Executable file
BIN
Tests/images/g4_orientation_7.tif
Executable file
BIN
Tests/images/g4_orientation_8.tif
Executable file
BIN
Tests/images/hopper.pnm
Normal file
BIN
Tests/images/hopper_draw.ico
Normal file
After Width: | Height: | Size: 846 B |
BIN
Tests/images/hopper_orientation_2.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
Tests/images/hopper_orientation_2.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
Tests/images/hopper_orientation_3.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
Tests/images/hopper_orientation_3.webp
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
Tests/images/hopper_orientation_4.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
Tests/images/hopper_orientation_4.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
Tests/images/hopper_orientation_5.jpg
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
Tests/images/hopper_orientation_5.webp
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
Tests/images/hopper_orientation_6.jpg
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
Tests/images/hopper_orientation_6.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
Tests/images/hopper_orientation_7.jpg
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
Tests/images/hopper_orientation_7.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
Tests/images/hopper_orientation_8.jpg
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
Tests/images/hopper_orientation_8.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
Tests/images/hopper_roundDown.bmp
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
Tests/images/hopper_roundDown_2.tif
Normal file
BIN
Tests/images/hopper_roundDown_3.tif
Normal file
BIN
Tests/images/hopper_roundDown_None.tif
Normal file
BIN
Tests/images/hopper_roundUp_2.tif
Normal file
BIN
Tests/images/hopper_roundUp_3.tif
Normal file
BIN
Tests/images/hopper_roundUp_None.tif
Normal file
BIN
Tests/images/hopper_unexpected.ico
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Tests/images/i_trns.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Tests/images/imagedraw_arc_width_non_whole_angle.png
Normal file
After Width: | Height: | Size: 439 B |
BIN
Tests/images/imagedraw_arc_width_pieslice.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
Tests/images/imagedraw_ellipse_width_large.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
Tests/images/imagedraw_floodfill_not_negative.png
Normal file
After Width: | Height: | Size: 214 B |