Merge branch 'refs/heads/master' into box-in-thumbnail

# Conflicts:
#	Tests/test_image_thumbnail.py
This commit is contained in:
Alexander 2019-11-24 05:27:13 +03:00
commit fd21de7dc4
276 changed files with 3899 additions and 3949 deletions

View File

@ -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
@ -44,11 +40,6 @@ install:
- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
- cd c:\pillow\winbuild\
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy2")
{
c:\pillow\winbuild\appveyor_install_pypy2.cmd
}
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy3")
{
@ -85,6 +76,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?

View File

@ -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

View File

@ -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 [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
- Run the test suite. You can enable [Travis CI](https://travis-ci.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

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
tidelift: pypi/pillow
tidelift: "pypi/Pillow"

View File

@ -8,17 +8,17 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python: [3.7]
python-version: ["3.8"]
name: Python ${{ matrix.python }}
name: Python ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python }}
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python }}
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |

17
.github/workflows/macos-install.sh vendored Executable file
View 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
View 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 }}

385
.github/workflows/test-windows.yml vendored Normal file
View File

@ -0,0 +1,385 @@
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
- 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: |
curl -fsSL -o nasm.zip https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/win64/nasm-2.14.02-win64.zip
7z x nasm.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"
# 32-bit should work on both platforms
curl -fsSL -o gs950.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs950/gs950w32.exe
./gs950.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
curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/master.zip
7z x pillow-depends.zip -oc:\
mv c:\pillow-depends-master c:\pillow-depends
xcopy c:\pillow-depends\*.zip $env:GITHUB_WORKSPACE\winbuild\
xcopy c:\pillow-depends\*.tar.gz $env:GITHUB_WORKSPACE\winbuild\
xcopy /s c:\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
if: "!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
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
if: "!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
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
# failing with PyPy3
- name: Build dependencies / Raqm
if: "!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
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

75
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,75 @@
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:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

View File

@ -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,25 +16,22 @@ matrix:
- python: "3.6"
name: "Lint"
env: LINT="true"
- python: "pypy"
name: "PyPy2 Xenial"
- python: "pypy3"
name: "PyPy3 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_with_system_site_packages" # For PyQt4
name: "2.7_with_system_site_packages Xenial"
services: xvfb
- python: '3.6'
name: "3.6 Xenial PYTHONOPTIMIZE=1"
env: PYTHONOPTIMIZE=1
services: xvfb
- python: '3.5'
name: "3.5 Xenial PYTHONOPTIMIZE=2"
env: PYTHONOPTIMIZE=2
- 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-16.04-xenial-amd64" DOCKER_TAG="master"
@ -45,8 +42,8 @@ matrix:
- 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-29-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-30-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-31-amd64" DOCKER_TAG="master"
services:
- docker
@ -67,7 +64,8 @@ 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

View File

@ -11,16 +11,12 @@ coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
coverage report
pip install codecov
if [[ $TRAVIS_PYTHON_VERSION != "2.7_with_system_site_packages" ]]; then
# Not working here. Just skip it, it's being removed soon.
pip install coveralls-merge
coveralls-merge coverage.c.json
fi
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
View 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

View File

@ -3,7 +3,7 @@
set -e
sudo apt-get update
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk python-qt4\
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake imagemagick libharfbuzz-dev libfribidi-dev
@ -15,9 +15,13 @@ 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
# 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

View File

@ -1,12 +0,0 @@
#!/bin/bash
set -e
coverage erase
make clean
make install-coverage
python -m pytest -v -x --cov PIL --cov-report term Tests
# Docs
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make doccheck; fi

8
.travis/test.sh Executable file
View 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

View File

@ -2,11 +2,62 @@
Changelog (Pillow)
==================
6.2.0 (2019-10-01)
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]

View File

@ -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

View File

@ -14,7 +14,7 @@ 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
@ -60,6 +60,18 @@ To report a security vulnerability, please follow the procedure described in the
: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

View File

@ -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
@ -92,7 +93,7 @@ Released as needed privately to individual vendors for critical security-related
```
* [ ] 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
```

View File

@ -1,8 +1,9 @@
import time
import unittest
from PIL import PyAccess
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
# Not running this test by default. No DOS against Travis CI.

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
TEST_FILE = "Tests/images/fli_overflow.fli"

View File

@ -4,9 +4,5 @@
from io import BytesIO
from PIL import Image
from PIL._util import py3
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")))
Image.open(BytesIO(b"icns\x00\x00\x00\x10hang\x00\x00\x00\x00"))

View File

@ -1,18 +1,15 @@
#!/usr/bin/env python
from __future__ import division
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
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

View File

@ -4,19 +4,5 @@
from io import BytesIO
from PIL import Image
from PIL._util import py3
if py3:
Image.open(
BytesIO(
bytes(
"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang",
"latin-1",
)
)
)
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"))

View File

@ -1,9 +1,9 @@
import sys
import unittest
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase, is_win32
# Limits for testing the leak
mem_limit = 1024 * 1048576
@ -13,7 +13,7 @@ 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:

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
class TestJ2kEncodeOverflow(PillowTestCase):

View File

@ -1,7 +1,7 @@
import sys
import unittest
from io import BytesIO
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper, is_win32
iterations = 5000
@ -15,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):
"""

View File

@ -1,8 +1,9 @@
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
# This test is not run automatically.
#

View File

@ -1,8 +1,9 @@
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
# This test is not run automatically.
#

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
TEST_FILE = "Tests/images/libtiff_segfault.tif"

View File

@ -1,9 +1,10 @@
import unittest
import zlib
from io import BytesIO
from PIL import Image, ImageFile, PngImagePlugin
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
TEST_FILE = "Tests/images/png_decompression_dos.png"

11
Tests/conftest.py Normal file
View 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)

View File

@ -1,6 +1,4 @@
#!/usr/bin/env python
from __future__ import print_function
import base64
import os

View File

@ -1,16 +1,16 @@
"""
Helper functions.
"""
from __future__ import print_function
import logging
import os
import subprocess
import sys
import tempfile
import unittest
from io import BytesIO
from PIL import Image, ImageMath
from PIL._util import py3
logger = logging.getLogger(__name__)
@ -22,12 +22,26 @@ if os.environ.get("SHOW_ERRORS", None):
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
@ -51,37 +65,22 @@ def convert_to_comparable(a, 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)
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)
all(x == y for x, y in zip(a, b)),
msg or "got {}, expected {}".format(a, b),
)
except Exception:
self.assertEqual(a, b, msg)
@ -89,20 +88,24 @@ class PillowTestCase(unittest.TestCase):
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:
@ -123,10 +126,10 @@ 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)
@ -200,23 +203,12 @@ class PillowTestCase(unittest.TestCase):
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.
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")
def tempfile(self, template):
@ -229,12 +221,12 @@ 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")
@ -277,21 +269,12 @@ class PillowLeakTestCase(PillowTestCase):
# 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()
@ -323,11 +306,8 @@ 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)
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
except OSError:
return False
return True
@ -355,10 +335,25 @@ def on_appveyor():
return "APPVEYOR" in os.environ
def on_github_actions():
return "GITHUB_ACTIONS" in os.environ
def on_ci():
# Travis and AppVeyor have "CI"
# Azure Pipelines has "TF_BUILD"
return "CI" in os.environ or "TF_BUILD" in os.environ
# 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":
@ -377,7 +372,7 @@ def distro():
return line.strip().split("=")[1]
class cached_property(object):
class cached_property:
def __init__(self, func):
self.func = func

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import glob
import os
import sys

View File

@ -1,7 +1,5 @@
# brute-force search for access descriptor hash table
from __future__ import print_function
modes = [
"1",
"L",

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import os
from PIL import Image
@ -24,7 +22,7 @@ class TestBmpReference(PillowTestCase):
def open(f):
try:
im = Image.open(f)
with Image.open(f) as im:
im.load()
except Exception: # as msg:
pass
@ -48,7 +46,7 @@ class TestBmpReference(PillowTestCase):
]
for f in self.get_files("q"):
try:
im = Image.open(f)
with Image.open(f) as im:
im.load()
if os.path.basename(f) not in supported:
print("Please add %s to the partially supported bmp specs." % f)
@ -89,9 +87,9 @@ class TestBmpReference(PillowTestCase):
for f in self.get_files("g"):
try:
im = Image.open(f)
with Image.open(f) as im:
im.load()
compare = Image.open(get_compare(f))
with Image.open(get_compare(f)) as compare:
compare.load()
if im.mode == "P":
# assert image similar doesn't really work
@ -109,4 +107,4 @@ class TestBmpReference(PillowTestCase):
os.path.join(base, "g", "pal4rle.bmp"),
)
if f not in unsupported:
self.fail("Unsupported Image %s: %s" % (f, msg))
self.fail("Unsupported Image {}: {}".format(f, msg))

View File

@ -1,10 +1,9 @@
from __future__ import division
import unittest
from array import array
from PIL import Image, ImageFilter
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
try:
import numpy

View File

@ -1,12 +1,9 @@
from __future__ import division, print_function
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
is_pypy = hasattr(sys, "pypy_version_info")
from .helper import PillowTestCase, is_pypy
class TestCoreStats(PillowTestCase):
@ -87,7 +84,7 @@ class TestCoreMemory(PillowTestCase):
stats = Image.core.get_stats()
self.assertGreaterEqual(stats["new_count"], 1)
self.assertGreaterEqual(stats["allocated_blocks"], 64)
if not is_pypy:
if not is_pypy():
self.assertGreaterEqual(stats["freed_blocks"], 64)
def test_get_blocks_max(self):
@ -108,7 +105,7 @@ class TestCoreMemory(PillowTestCase):
if sys.maxsize < 2 ** 32:
self.assertRaises(ValueError, Image.core.set_blocks_max, 2 ** 29)
@unittest.skipIf(is_pypy, "images are not collected")
@unittest.skipIf(is_pypy(), "images are not collected")
def test_set_blocks_max_stats(self):
Image.core.reset_stats()
Image.core.set_blocks_max(128)
@ -123,7 +120,7 @@ class TestCoreMemory(PillowTestCase):
self.assertEqual(stats["freed_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 64)
@unittest.skipIf(is_pypy, "images are not collected")
@unittest.skipIf(is_pypy(), "images are not collected")
def test_clear_cache_stats(self):
Image.core.reset_stats()
Image.core.clear_cache()
@ -153,7 +150,7 @@ class TestCoreMemory(PillowTestCase):
self.assertGreaterEqual(stats["allocated_blocks"], 16)
self.assertGreaterEqual(stats["reused_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 0)
if not is_pypy:
if not is_pypy():
self.assertGreaterEqual(stats["freed_blocks"], 16)

View File

@ -14,8 +14,8 @@ class TestDecompressionBomb(PillowTestCase):
def test_no_warning_small_file(self):
# Implicit assert: no warning.
# A warning would cause a failure.
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
Image.open(TEST_FILE)
with Image.open(TEST_FILE):
pass
def test_no_warning_no_limit(self):
# Arrange
@ -26,21 +26,28 @@ class TestDecompressionBomb(PillowTestCase):
# Act / Assert
# Implicit assert: no warning.
# A warning would cause a failure.
Image.open(TEST_FILE)
with Image.open(TEST_FILE):
pass
def test_warning(self):
# Set limit to trigger warning on the test file
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1)
self.assert_warning(Image.DecompressionBombWarning, Image.open, TEST_FILE)
def open():
with Image.open(TEST_FILE):
pass
self.assert_warning(Image.DecompressionBombWarning, open)
def test_exception(self):
# Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1)
self.assertRaises(Image.DecompressionBombError, lambda: Image.open(TEST_FILE))
with self.assertRaises(Image.DecompressionBombError):
with Image.open(TEST_FILE):
pass
def test_exception_ico(self):
with self.assertRaises(Image.DecompressionBombError):
@ -54,6 +61,7 @@ class TestDecompressionBomb(PillowTestCase):
class TestDecompressionCrop(PillowTestCase):
def setUp(self):
self.src = hopper()
self.addCleanup(self.src.close)
Image.MAX_IMAGE_PIXELS = self.src.height * self.src.width * 4 - 1
def tearDown(self):

View File

@ -1,10 +1,9 @@
from __future__ import unicode_literals
import io
import unittest
from PIL import features
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
try:
from PIL import _webp
@ -70,11 +69,14 @@ class TestFeatures(PillowTestCase):
lines = out.splitlines()
self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Pillow "))
self.assertEqual(lines[2], "-" * 68)
self.assertTrue(lines[3].startswith("Python modules loaded from "))
self.assertTrue(lines[4].startswith("Binary modules loaded from "))
self.assertEqual(lines[5], "-" * 68)
self.assertTrue(lines[6].startswith("Python "))
self.assertTrue(lines[2].startswith("Python "))
lines = lines[3:]
while lines[0].startswith(" "):
lines = lines[1:]
self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Python modules loaded from "))
self.assertTrue(lines[2].startswith("Binary modules loaded from "))
self.assertEqual(lines[3], "-" * 68)
jpeg = (
"\n"
+ "-" * 68

View File

@ -5,13 +5,13 @@ from .helper import PillowTestCase
class TestFileBlp(PillowTestCase):
def test_load_blp2_raw(self):
im = Image.open("Tests/images/blp/blp2_raw.blp")
target = Image.open("Tests/images/blp/blp2_raw.png")
with Image.open("Tests/images/blp/blp2_raw.blp") as im:
with Image.open("Tests/images/blp/blp2_raw.png") as target:
self.assert_image_equal(im, target)
def test_load_blp2_dxt1(self):
im = Image.open("Tests/images/blp/blp2_dxt1.blp")
target = Image.open("Tests/images/blp/blp2_dxt1.png")
with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
with Image.open("Tests/images/blp/blp2_dxt1.png") as target:
self.assert_image_equal(im, target)
def test_load_blp2_dxt1a(self):

View File

@ -46,12 +46,11 @@ class TestFileBmp(PillowTestCase):
dpi = (72, 72)
output = io.BytesIO()
im = hopper()
with hopper() as im:
im.save(output, "BMP", dpi=dpi)
output.seek(0)
reloaded = Image.open(output)
with Image.open(output) as reloaded:
self.assertEqual(reloaded.info["dpi"], dpi)
def test_save_bmp_with_dpi(self):
@ -72,11 +71,11 @@ class TestFileBmp(PillowTestCase):
def test_load_dpi_rounding(self):
# Round up
im = Image.open("Tests/images/hopper.bmp")
with Image.open("Tests/images/hopper.bmp") as im:
self.assertEqual(im.info["dpi"], (96, 96))
# Round down
im = Image.open("Tests/images/hopper_roundDown.bmp")
with Image.open("Tests/images/hopper_roundDown.bmp") as im:
self.assertEqual(im.info["dpi"], (72, 72))
def test_save_dpi_rounding(self):
@ -84,11 +83,11 @@ class TestFileBmp(PillowTestCase):
im = Image.open("Tests/images/hopper.bmp")
im.save(outfile, dpi=(72.2, 72.2))
reloaded = Image.open(outfile)
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (72, 72))
im.save(outfile, dpi=(72.8, 72.8))
reloaded = Image.open(outfile)
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (73, 73))
def test_load_dib(self):

View File

@ -8,7 +8,7 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
class TestFileBufrStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "BUFR")
@ -28,7 +28,7 @@ class TestFileBufrStub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)

View File

@ -11,7 +11,7 @@ class TestFileContainer(PillowTestCase):
dir(ContainerIO)
def test_isatty(self):
im = hopper()
with hopper() as im:
container = ContainerIO.ContainerIO(im, 0, 0)
self.assertFalse(container.isatty())

View File

@ -1,6 +1,8 @@
import unittest
from PIL import DcxImagePlugin, Image
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
# Created with ImageMagick: convert hopper.ppm hopper.dcx
TEST_FILE = "Tests/images/hopper.dcx"
@ -11,7 +13,7 @@ class TestFileDcx(PillowTestCase):
# Arrange
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.size, (128, 128))
@ -19,11 +21,27 @@ class TestFileDcx(PillowTestCase):
orig = hopper()
self.assert_image_equal(im, orig)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_FILE) as im:
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
@ -32,7 +50,7 @@ class TestFileDcx(PillowTestCase):
def test_tell(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act
frame = im.tell()
@ -41,12 +59,12 @@ class TestFileDcx(PillowTestCase):
self.assertEqual(frame, 0)
def test_n_frames(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
def test_eoferror(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
n_frames = im.n_frames
# Test seeking past the last frame
@ -58,7 +76,7 @@ class TestFileDcx(PillowTestCase):
def test_seek_too_far(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
frame = 999 # too big on purpose
# Act / Assert

View File

@ -8,6 +8,7 @@ TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds"
TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds"
TEST_FILE_DX10_BC7 = "Tests/images/bc7-argb-8bpp_MipMaps-1.dds"
TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds"
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds"
@ -69,6 +70,21 @@ class TestFileDds(PillowTestCase):
self.assert_image_equal(target, im)
def test_dx10_bc7_unorm_srgb(self):
"""Check DX10 unsigned normalized integer images can be opened"""
target = Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png"))
im = Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB)
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (16, 16))
self.assertEqual(im.info["gamma"], 1 / 2.2)
self.assert_image_equal(target, im)
def test_unimplemented_dxgi_format(self):
self.assertRaises(
NotImplementedError,

View File

@ -1,8 +1,9 @@
import io
import unittest
from PIL import EpsImagePlugin, Image
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
@ -25,26 +26,26 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_sanity(self):
# Regular scale
image1 = Image.open(file1)
with Image.open(file1) as image1:
image1.load()
self.assertEqual(image1.mode, "RGB")
self.assertEqual(image1.size, (460, 352))
self.assertEqual(image1.format, "EPS")
image2 = Image.open(file2)
with Image.open(file2) as image2:
image2.load()
self.assertEqual(image2.mode, "RGB")
self.assertEqual(image2.size, (360, 252))
self.assertEqual(image2.format, "EPS")
# Double scale
image1_scale2 = Image.open(file1)
with Image.open(file1) as image1_scale2:
image1_scale2.load(scale=2)
self.assertEqual(image1_scale2.mode, "RGB")
self.assertEqual(image1_scale2.size, (920, 704))
self.assertEqual(image1_scale2.format, "EPS")
image2_scale2 = Image.open(file2)
with Image.open(file2) as image2_scale2:
image2_scale2.load(scale=2)
self.assertEqual(image2_scale2.mode, "RGB")
self.assertEqual(image2_scale2.size, (720, 504))
@ -57,7 +58,7 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_cmyk(self):
cmyk_image = Image.open("Tests/images/pil_sample_cmyk.eps")
with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image:
self.assertEqual(cmyk_image.mode, "CMYK")
self.assertEqual(cmyk_image.size, (100, 100))
@ -73,9 +74,8 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_showpage(self):
# See https://github.com/python-pillow/Pillow/issues/2615
plot_image = Image.open("Tests/images/reqd_showpage.eps")
target = Image.open("Tests/images/reqd_showpage.png")
with Image.open("Tests/images/reqd_showpage.eps") as plot_image:
with Image.open("Tests/images/reqd_showpage.png") as target:
# should not crash/hang
plot_image.load()
# fonts could be slightly different
@ -84,15 +84,15 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_file_object(self):
# issue 479
image1 = Image.open(file1)
with Image.open(file1) as image1:
with open(self.tempfile("temp_file.eps"), "wb") as fh:
image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_iobase_object(self):
# issue 479
image1 = Image.open(file1)
with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh:
with Image.open(file1) as image1:
with open(self.tempfile("temp_iobase.eps"), "wb") as fh:
image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@ -120,14 +120,14 @@ class TestFileEps(PillowTestCase):
self.skipTest("zip/deflate support not available")
# Zero bounding box
image1_scale1 = Image.open(file1)
with Image.open(file1) as image1_scale1:
image1_scale1.load()
image1_scale1_compare = Image.open(file1_compare).convert("RGB")
image1_scale1_compare.load()
self.assert_image_similar(image1_scale1, image1_scale1_compare, 5)
# Non-Zero bounding box
image2_scale1 = Image.open(file2)
with Image.open(file2) as image2_scale1:
image2_scale1.load()
image2_scale1_compare = Image.open(file2_compare).convert("RGB")
image2_scale1_compare.load()
@ -141,14 +141,14 @@ class TestFileEps(PillowTestCase):
self.skipTest("zip/deflate support not available")
# Zero bounding box
image1_scale2 = Image.open(file1)
with Image.open(file1) as image1_scale2:
image1_scale2.load(scale=2)
image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB")
image1_scale2_compare.load()
self.assert_image_similar(image1_scale2, image1_scale2_compare, 5)
# Non-Zero bounding box
image2_scale2 = Image.open(file2)
with Image.open(file2) as image2_scale2:
image2_scale2.load(scale=2)
image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB")
image2_scale2_compare.load()
@ -156,42 +156,29 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_resize(self):
# Arrange
image1 = Image.open(file1)
image2 = Image.open(file2)
image3 = Image.open("Tests/images/illu10_preview.eps")
files = [file1, file2, "Tests/images/illu10_preview.eps"]
for fn in files:
with Image.open(fn) as im:
new_size = (100, 100)
# Act
image1 = image1.resize(new_size)
image2 = image2.resize(new_size)
image3 = image3.resize(new_size)
# Assert
self.assertEqual(image1.size, new_size)
self.assertEqual(image2.size, new_size)
self.assertEqual(image3.size, new_size)
im = im.resize(new_size)
self.assertEqual(im.size, new_size)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_thumbnail(self):
# Issue #619
# Arrange
image1 = Image.open(file1)
image2 = Image.open(file2)
files = [file1, file2]
for fn in files:
with Image.open(file1) as im:
new_size = (100, 100)
# Act
image1.thumbnail(new_size)
image2.thumbnail(new_size)
# Assert
self.assertEqual(max(image1.size), max(new_size))
self.assertEqual(max(image2.size), max(new_size))
im.thumbnail(new_size)
self.assertEqual(max(im.size), max(new_size))
def test_read_binary_preview(self):
# Issue 302
# open image with binary preview
Image.open(file3)
with Image.open(file3):
pass
def _test_readline(self, t, ending):
ending = "Failure with line ending: %s" % (
@ -239,7 +226,7 @@ class TestFileEps(PillowTestCase):
# Act / Assert
for filename in FILES:
img = Image.open(filename)
with Image.open(filename) as img:
self.assertEqual(img.mode, "RGB")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
@ -247,7 +234,7 @@ class TestFileEps(PillowTestCase):
# Test file includes an empty line in the header data
emptyline_file = "Tests/images/zero_bb_emptyline.eps"
image = Image.open(emptyline_file)
with Image.open(emptyline_file) as image:
image.load()
self.assertEqual(image.mode, "RGB")
self.assertEqual(image.size, (460, 352))

View File

@ -8,7 +8,7 @@ TEST_FILE = "Tests/images/hopper.fits"
class TestFileFitsStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "FITS")
@ -28,14 +28,14 @@ class TestFileFitsStub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
def test_save(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
dummy_fp = None
dummy_filename = "dummy.filename"

View File

@ -1,6 +1,8 @@
import unittest
from PIL import FliImagePlugin, Image
from .helper import PillowTestCase
from .helper import PillowTestCase, is_pypy
# created as an export of a palette image from Gimp2.6
# save as...-> hopper.fli, default options.
@ -12,30 +14,46 @@ animated_test_file = "Tests/images/a.fli"
class TestFileFli(PillowTestCase):
def test_sanity(self):
im = Image.open(static_test_file)
with Image.open(static_test_file) as im:
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "FLI")
self.assertFalse(im.is_animated)
im = Image.open(animated_test_file)
with Image.open(animated_test_file) as im:
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (320, 200))
self.assertEqual(im.format, "FLI")
self.assertEqual(im.info["duration"], 71)
self.assertTrue(im.is_animated)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(static_test_file)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(static_test_file)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(static_test_file) as im:
im.load()
self.assert_warning(None, open)
def test_tell(self):
# Arrange
im = Image.open(static_test_file)
with Image.open(static_test_file) as im:
# Act
frame = im.tell()
@ -49,16 +67,16 @@ class TestFileFli(PillowTestCase):
self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
def test_n_frames(self):
im = Image.open(static_test_file)
with Image.open(static_test_file) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
im = Image.open(animated_test_file)
with Image.open(animated_test_file) as im:
self.assertEqual(im.n_frames, 384)
self.assertTrue(im.is_animated)
def test_eoferror(self):
im = Image.open(animated_test_file)
with Image.open(animated_test_file) as im:
n_frames = im.n_frames
# Test seeking past the last frame
@ -69,7 +87,7 @@ class TestFileFli(PillowTestCase):
im.seek(n_frames - 1)
def test_seek_tell(self):
im = Image.open(animated_test_file)
with Image.open(animated_test_file) as im:
layer_number = im.tell()
self.assertEqual(layer_number, 0)
@ -91,8 +109,8 @@ class TestFileFli(PillowTestCase):
self.assertEqual(layer_number, 1)
def test_seek(self):
im = Image.open(animated_test_file)
with Image.open(animated_test_file) as im:
im.seek(50)
expected = Image.open("Tests/images/a_fli.png")
with Image.open("Tests/images/a_fli.png") as expected:
self.assert_image_equal(im, expected)

View File

@ -1,4 +1,6 @@
from .helper import PillowTestCase, unittest
import unittest
from .helper import PillowTestCase
try:
from PIL import FpxImagePlugin

View File

@ -10,8 +10,6 @@ class TestFileGbr(PillowTestCase):
self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file)
def test_gbr_file(self):
im = Image.open("Tests/images/gbr.gbr")
target = Image.open("Tests/images/gbr.png")
with Image.open("Tests/images/gbr.gbr") as im:
with Image.open("Tests/images/gbr.png") as target:
self.assert_image_equal(target, im)

View File

@ -1,4 +1,4 @@
from PIL import GdImageFile
from PIL import GdImageFile, UnidentifiedImageError
from .helper import PillowTestCase
@ -7,7 +7,7 @@ TEST_GD_FILE = "Tests/images/hopper.gd"
class TestFileGd(PillowTestCase):
def test_sanity(self):
im = GdImageFile.open(TEST_GD_FILE)
with GdImageFile.open(TEST_GD_FILE) as im:
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GD")
@ -17,4 +17,4 @@ class TestFileGd(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(IOError, GdImageFile.open, invalid_file)
self.assertRaises(UnidentifiedImageError, GdImageFile.open, invalid_file)

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO
from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette
from .helper import PillowTestCase, hopper, netpbm_available, unittest
from .helper import PillowTestCase, hopper, is_pypy, netpbm_available
try:
from PIL import _webp
@ -26,18 +27,34 @@ class TestFileGif(PillowTestCase):
self.skipTest("gif support not available") # can this happen?
def test_sanity(self):
im = Image.open(TEST_GIF)
with Image.open(TEST_GIF) as im:
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GIF")
self.assertEqual(im.info["version"], b"GIF89a")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_GIF)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_GIF)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_GIF) as im:
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
@ -71,9 +88,7 @@ class TestFileGif(PillowTestCase):
def check(colors, size, expected_palette_length):
# make an image with empty colors in the start of the palette range
im = Image.frombytes(
"P",
(colors, colors),
bytes(bytearray(range(256 - colors, 256)) * colors),
"P", (colors, colors), bytes(range(256 - colors, 256)) * colors
)
im = im.resize((size, size))
outfile = BytesIO()
@ -103,7 +118,7 @@ class TestFileGif(PillowTestCase):
check(256, 511, 256)
def test_optimize_full_l(self):
im = Image.frombytes("L", (16, 16), bytes(bytearray(range(256))))
im = Image.frombytes("L", (16, 16), bytes(range(256)))
test_file = BytesIO()
im.save(test_file, "GIF", optimize=True)
self.assertEqual(im.mode, "L")
@ -112,17 +127,17 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im = hopper()
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_similar(reread.convert("RGB"), im, 50)
def test_roundtrip2(self):
# see https://github.com/python-pillow/Pillow/issues/403
out = self.tempfile("temp.gif")
im = Image.open(TEST_GIF)
with Image.open(TEST_GIF) as im:
im2 = im.copy()
im2.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_similar(reread.convert("RGB"), hopper(), 50)
@ -131,29 +146,29 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im = hopper()
im.save(out, save_all=True)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_similar(reread.convert("RGB"), im, 50)
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 5)
def test_headers_saving_for_animated_gifs(self):
important_headers = ["background", "version", "duration", "loop"]
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
info = im.info.copy()
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
reread = Image.open(out)
with Image.open(out) as reread:
for header in important_headers:
self.assertEqual(info[header], reread.info[header])
@ -161,7 +176,7 @@ class TestFileGif(PillowTestCase):
def test_palette_handling(self):
# see https://github.com/python-pillow/Pillow/issues/513
im = Image.open(TEST_GIF)
with Image.open(TEST_GIF) as im:
im = im.convert("RGB")
im = im.resize((100, 100), Image.LANCZOS)
@ -170,7 +185,7 @@ class TestFileGif(PillowTestCase):
f = self.tempfile("temp.gif")
im2.save(f, optimize=True)
reloaded = Image.open(f)
with Image.open(f) as reloaded:
self.assert_image_similar(im, reloaded.convert("RGB"), 10)
@ -185,34 +200,41 @@ class TestFileGif(PillowTestCase):
return reloaded
orig = "Tests/images/test.colors.gif"
im = Image.open(orig)
with Image.open(orig) as im:
self.assert_image_similar(im, roundtrip(im), 1)
self.assert_image_similar(im, roundtrip(im, optimize=True), 1)
with roundtrip(im) as reloaded:
self.assert_image_similar(im, reloaded, 1)
with roundtrip(im, optimize=True) as reloaded:
self.assert_image_similar(im, reloaded, 1)
im = im.convert("RGB")
# check automatic P conversion
reloaded = roundtrip(im).convert("RGB")
with roundtrip(im) as reloaded:
reloaded = reloaded.convert("RGB")
self.assert_image_equal(im, reloaded)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
def test_save_netpbm_bmp_mode(self):
img = Image.open(TEST_GIF).convert("RGB")
with Image.open(TEST_GIF) as img:
img = img.convert("RGB")
tempfile = self.tempfile("temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
self.assert_image_similar(img, Image.open(tempfile).convert("RGB"), 0)
with Image.open(tempfile) as reloaded:
self.assert_image_similar(img, reloaded.convert("RGB"), 0)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
def test_save_netpbm_l_mode(self):
img = Image.open(TEST_GIF).convert("L")
with Image.open(TEST_GIF) as img:
img = img.convert("L")
tempfile = self.tempfile("temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
self.assert_image_similar(img, Image.open(tempfile).convert("L"), 0)
with Image.open(tempfile) as reloaded:
self.assert_image_similar(img, reloaded.convert("L"), 0)
def test_seek(self):
img = Image.open("Tests/images/dispose_none.gif")
with Image.open("Tests/images/dispose_none.gif") as img:
framecount = 0
try:
while True:
@ -222,7 +244,7 @@ class TestFileGif(PillowTestCase):
self.assertEqual(framecount, 5)
def test_seek_info(self):
im = Image.open("Tests/images/iss634.gif")
with Image.open("Tests/images/iss634.gif") as im:
info = im.info.copy()
im.seek(1)
@ -231,27 +253,27 @@ class TestFileGif(PillowTestCase):
self.assertEqual(im.info, info)
def test_seek_rewind(self):
im = Image.open("Tests/images/iss634.gif")
with Image.open("Tests/images/iss634.gif") as im:
im.seek(2)
im.seek(1)
expected = Image.open("Tests/images/iss634.gif")
with Image.open("Tests/images/iss634.gif") as expected:
expected.seek(1)
self.assert_image_equal(im, expected)
def test_n_frames(self):
for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]:
# Test is_animated before n_frames
im = Image.open(path)
with Image.open(path) as im:
self.assertEqual(im.is_animated, n_frames != 1)
# Test is_animated after n_frames
im = Image.open(path)
with Image.open(path) as im:
self.assertEqual(im.n_frames, n_frames)
self.assertEqual(im.is_animated, n_frames != 1)
def test_eoferror(self):
im = Image.open(TEST_GIF)
with Image.open(TEST_GIF) as im:
n_frames = im.n_frames
# Test seeking past the last frame
@ -262,7 +284,7 @@ class TestFileGif(PillowTestCase):
im.seek(n_frames - 1)
def test_dispose_none(self):
img = Image.open("Tests/images/dispose_none.gif")
with Image.open("Tests/images/dispose_none.gif") as img:
try:
while True:
img.seek(img.tell() + 1)
@ -271,7 +293,7 @@ class TestFileGif(PillowTestCase):
pass
def test_dispose_background(self):
img = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as img:
try:
while True:
img.seek(img.tell() + 1)
@ -280,7 +302,7 @@ class TestFileGif(PillowTestCase):
pass
def test_dispose_previous(self):
img = Image.open("Tests/images/dispose_prev.gif")
with Image.open("Tests/images/dispose_prev.gif") as img:
try:
while True:
img.seek(img.tell() + 1)
@ -299,7 +321,7 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], disposal=method
)
img = Image.open(out)
with Image.open(out) as img:
for _ in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, method)
@ -312,7 +334,7 @@ class TestFileGif(PillowTestCase):
disposal=tuple(range(len(im_list))),
)
img = Image.open(out)
with Image.open(out) as img:
for i in range(2):
img.seek(img.tell() + 1)
@ -336,8 +358,7 @@ class TestFileGif(PillowTestCase):
im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=2)
img = Image.open(out)
with Image.open(out) as img:
for i, circle in enumerate(circles):
img.seek(i)
rgb_img = img.convert("RGB")
@ -375,8 +396,7 @@ class TestFileGif(PillowTestCase):
out, save_all=True, append_images=im_list[1:], disposal=2, transparency=0
)
img = Image.open(out)
with Image.open(out) as img:
for i, colours in enumerate(circles):
img.seek(i)
rgb_img = img.convert("RGBA")
@ -411,12 +431,12 @@ class TestFileGif(PillowTestCase):
out, save_all=True, append_images=im_list[1:], disposal=[0, 2], background=1
)
im = Image.open(out)
with Image.open(out) as im:
im.seek(1)
self.assertEqual(im.getpixel((0, 0)), 0)
def test_iss634(self):
img = Image.open("Tests/images/iss634.gif")
with Image.open("Tests/images/iss634.gif") as img:
# seek to the second frame
img.seek(img.tell() + 1)
# all transparent pixels should be replaced with the color from the
@ -433,7 +453,7 @@ class TestFileGif(PillowTestCase):
im.info["duration"] = 100
im.save(out, duration=duration)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["duration"], duration)
def test_multiple_duration(self):
@ -450,7 +470,7 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration_list
)
reread = Image.open(out)
with Image.open(out) as reread:
for duration in duration_list:
self.assertEqual(reread.info["duration"], duration)
@ -463,7 +483,7 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
)
reread = Image.open(out)
with Image.open(out) as reread:
for duration in duration_list:
self.assertEqual(reread.info["duration"], duration)
@ -487,7 +507,7 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration_list
)
reread = Image.open(out)
with Image.open(out) as reread:
# Assert that the first three frames were combined
self.assertEqual(reread.n_frames, 2)
@ -507,8 +527,7 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration
)
reread = Image.open(out)
with Image.open(out) as reread:
# Assert that all frames were combined
self.assertEqual(reread.n_frames, 1)
@ -521,7 +540,7 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.save(out, loop=number_of_loops)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["loop"], number_of_loops)
@ -530,7 +549,7 @@ class TestFileGif(PillowTestCase):
im = Image.new("L", (100, 100), "#000")
im.info["background"] = 1
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["background"], im.info["background"])
@ -540,14 +559,16 @@ class TestFileGif(PillowTestCase):
im.save(out)
def test_comment(self):
im = Image.open(TEST_GIF)
self.assertEqual(im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0")
with Image.open(TEST_GIF) as im:
self.assertEqual(
im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0"
)
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.info["comment"] = b"Test comment text"
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["comment"], im.info["comment"])
@ -559,13 +580,13 @@ class TestFileGif(PillowTestCase):
comment += comment
im.info["comment"] = comment
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["comment"], comment)
def test_zero_comment_subblocks(self):
im = Image.open("Tests/images/hopper_zero_comment_subblocks.gif")
expected = Image.open(TEST_GIF)
with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im:
with Image.open(TEST_GIF) as expected:
self.assert_image_equal(im, expected)
def test_version(self):
@ -573,7 +594,7 @@ class TestFileGif(PillowTestCase):
def assertVersionAfterSave(im, version):
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["version"], version)
# Test that GIF87a is used by default
@ -590,7 +611,7 @@ class TestFileGif(PillowTestCase):
assertVersionAfterSave(im, b"GIF89a")
# Test that a GIF87a image is also saved in that format
im = Image.open("Tests/images/test.colors.gif")
with Image.open("Tests/images/test.colors.gif") as im:
assertVersionAfterSave(im, b"GIF87a")
# Test that a GIF89a image is also saved in that format
@ -605,25 +626,24 @@ class TestFileGif(PillowTestCase):
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
im.copy().save(out, save_all=True, append_images=ims)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 3)
# Tests appending using a generator
def imGenerator(ims):
for im in ims:
yield im
yield from ims
im.save(out, save_all=True, append_images=imGenerator(ims))
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 3)
# Tests appending single and multiple frame images
im = Image.open("Tests/images/dispose_none.gif")
ims = [Image.open("Tests/images/dispose_prev.gif")]
im.save(out, save_all=True, append_images=ims)
with Image.open("Tests/images/dispose_none.gif") as im:
with Image.open("Tests/images/dispose_prev.gif") as im2:
im.save(out, save_all=True, append_images=[im2])
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 10)
def test_transparent_optimize(self):
@ -633,7 +653,7 @@ class TestFileGif(PillowTestCase):
# that's > 128 items where the transparent color is actually
# the top palette entry to trigger the bug.
data = bytes(bytearray(range(1, 254)))
data = bytes(range(1, 254))
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
im = Image.new("L", (253, 1))
@ -642,7 +662,7 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im.save(out, transparency=253)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertEqual(reloaded.info["transparency"], 253)
@ -654,7 +674,7 @@ class TestFileGif(PillowTestCase):
im.info["transparency"] = (255, 0, 0)
self.assert_warning(UserWarning, im.save, out)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertNotIn("transparency", reloaded.info)
# Multiple frames
@ -663,7 +683,7 @@ class TestFileGif(PillowTestCase):
ims = [Image.new("RGB", (1, 1))]
self.assert_warning(UserWarning, im.save, out, save_all=True, append_images=ims)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertNotIn("transparency", reloaded.info)
def test_bbox(self):
@ -673,7 +693,7 @@ class TestFileGif(PillowTestCase):
ims = [Image.new("RGB", (100, 100), "#000")]
im.save(out, save_all=True, append_images=ims)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 2)
def test_palette_save_L(self):
@ -681,12 +701,12 @@ class TestFileGif(PillowTestCase):
im = hopper("P")
im_l = Image.frombytes("L", im.size, im.tobytes())
palette = bytes(bytearray(im.getpalette()))
palette = bytes(im.getpalette())
out = self.tempfile("temp.gif")
im_l.save(out, palette=palette)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assert_image_equal(reloaded.convert("RGB"), im.convert("RGB"))
@ -696,12 +716,12 @@ class TestFileGif(PillowTestCase):
# Forcing a non-straight grayscale palette.
im = hopper("P")
palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
palette = bytes([255 - i // 3 for i in range(768)])
out = self.tempfile("temp.gif")
im.save(out, palette=palette)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
im.putpalette(palette)
self.assert_image_equal(reloaded, im)
@ -715,7 +735,7 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im.save(out, palette=palette)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
im.putpalette(palette)
self.assert_image_equal(reloaded, im)
@ -727,7 +747,7 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im.save(out)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assert_image_equal(reloaded.convert("L"), im.convert("L"))
def test_getdata(self):
@ -737,7 +757,7 @@ class TestFileGif(PillowTestCase):
im.putpalette(ImagePalette.ImagePalette("RGB"))
im.info = {"background": 0}
passed_palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
passed_palette = bytes([255 - i // 3 for i in range(768)])
GifImagePlugin._FORCE_OPTIMIZE = True
try:
@ -759,14 +779,13 @@ class TestFileGif(PillowTestCase):
def test_lzw_bits(self):
# see https://github.com/python-pillow/Pillow/issues/2811
im = Image.open("Tests/images/issue_2811.gif")
with Image.open("Tests/images/issue_2811.gif") as im:
self.assertEqual(im.tile[0][3][0], 11) # LZW bits
# codec error prepatch
im.load()
def test_extents(self):
im = Image.open("Tests/images/test_extents.gif")
with Image.open("Tests/images/test_extents.gif") as im:
self.assertEqual(im.size, (100, 100))
im.seek(1)
self.assertEqual(im.size, (150, 150))

View File

@ -8,7 +8,7 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
class TestFileGribStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "GRIB")
@ -28,7 +28,7 @@ class TestFileGribStub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)

View File

@ -8,7 +8,7 @@ TEST_FILE = "Tests/images/hdf5.h5"
class TestFileHdf5Stub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "HDF5")
@ -28,14 +28,14 @@ class TestFileHdf5Stub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
def test_save(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
dummy_fp = None
dummy_filename = "dummy.filename"

View File

@ -1,9 +1,10 @@
import io
import sys
import unittest
from PIL import IcnsImagePlugin, Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
# sample icon file
TEST_FILE = "Tests/images/pillow.icns"
@ -15,7 +16,7 @@ class TestFileIcns(PillowTestCase):
def test_sanity(self):
# Loading this icon by default should result in the largest size
# (512x512@2x) being loaded
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert that there is no unclosed file warning
self.assert_warning(None, im.load)
@ -56,7 +57,7 @@ class TestFileIcns(PillowTestCase):
def test_sizes(self):
# Check that we can load all of the sizes, and that the final pixel
# dimensions are as expected
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
@ -72,11 +73,11 @@ class TestFileIcns(PillowTestCase):
def test_older_icon(self):
# This icon was made with Icon Composer rather than iconutil; it still
# uses PNG rather than JP2, however (since it was made on 10.9).
im = Image.open("Tests/images/pillow2.icns")
with Image.open("Tests/images/pillow2.icns") as im:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open("Tests/images/pillow2.icns")
with Image.open("Tests/images/pillow2.icns") as im2:
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, "RGBA")
@ -93,11 +94,11 @@ class TestFileIcns(PillowTestCase):
if not enable_jpeg2k:
return
im = Image.open("Tests/images/pillow3.icns")
with Image.open("Tests/images/pillow3.icns") as im:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open("Tests/images/pillow3.icns")
with Image.open("Tests/images/pillow3.icns") as im2:
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, "RGBA")

View File

@ -9,7 +9,7 @@ TEST_ICO_FILE = "Tests/images/hopper.ico"
class TestFileIco(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_ICO_FILE)
with Image.open(TEST_ICO_FILE) as im:
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (16, 16))
@ -46,19 +46,19 @@ class TestFileIco(PillowTestCase):
self.assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
def test_incorrect_size(self):
im = Image.open(TEST_ICO_FILE)
with Image.open(TEST_ICO_FILE) as im:
with self.assertRaises(ValueError):
im.size = (1, 1)
def test_save_256x256(self):
"""Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
# Arrange
im = Image.open("Tests/images/hopper_256x256.ico")
with Image.open("Tests/images/hopper_256x256.ico") as im:
outfile = self.tempfile("temp_saved_hopper_256x256.ico")
# Act
im.save(outfile)
im_saved = Image.open(outfile)
with Image.open(outfile) as im_saved:
# Assert
self.assertEqual(im_saved.size, (256, 256))
@ -69,13 +69,12 @@ class TestFileIco(PillowTestCase):
and not in 16x16, 24x24, 32x32, 48x48, 48x48, 48x48, 48x48 sizes
"""
# Arrange
im = Image.open("Tests/images/python.ico") # 16x16, 32x32, 48x48
with Image.open("Tests/images/python.ico") as im: # 16x16, 32x32, 48x48
outfile = self.tempfile("temp_saved_python.ico")
# Act
im.save(outfile)
im_saved = Image.open(outfile)
with Image.open(outfile) as im_saved:
# Assert
self.assertEqual(
im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)}
@ -84,20 +83,21 @@ class TestFileIco(PillowTestCase):
def test_unexpected_size(self):
# This image has been manually hexedited to state that it is 16x32
# while the image within is still 16x16
im = self.assert_warning(
UserWarning, Image.open, "Tests/images/hopper_unexpected.ico"
)
def open():
with Image.open("Tests/images/hopper_unexpected.ico") as im:
self.assertEqual(im.size, (16, 16))
self.assert_warning(UserWarning, open)
def test_draw_reloaded(self):
im = Image.open(TEST_ICO_FILE)
with Image.open(TEST_ICO_FILE) as im:
outfile = self.tempfile("temp_saved_hopper_draw.ico")
draw = ImageDraw.Draw(im)
draw.line((0, 0) + im.size, "#f00")
im.save(outfile)
im = Image.open(outfile)
with Image.open(outfile) as im:
im.save("Tests/images/hopper_draw.ico")
reloaded = Image.open("Tests/images/hopper_draw.ico")
with Image.open("Tests/images/hopper_draw.ico") as reloaded:
self.assert_image_equal(im, reloaded)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImImagePlugin
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
# sample im
TEST_IM = "Tests/images/hopper.im"
@ -8,22 +10,38 @@ TEST_IM = "Tests/images/hopper.im"
class TestFileIm(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_IM)
with Image.open(TEST_IM) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "IM")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_IM)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_IM)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_IM) as im:
im.load()
self.assert_warning(None, open)
def test_tell(self):
# Arrange
im = Image.open(TEST_IM)
with Image.open(TEST_IM) as im:
# Act
frame = im.tell()
@ -32,12 +50,12 @@ class TestFileIm(PillowTestCase):
self.assertEqual(frame, 0)
def test_n_frames(self):
im = Image.open(TEST_IM)
with Image.open(TEST_IM) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
def test_eoferror(self):
im = Image.open(TEST_IM)
with Image.open(TEST_IM) as im:
n_frames = im.n_frames
# Test seeking past the last frame
@ -52,7 +70,7 @@ class TestFileIm(PillowTestCase):
out = self.tempfile("temp.im")
im = hopper(mode)
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_equal(reread, im)

View File

@ -1,3 +1,6 @@
import sys
from io import StringIO
from PIL import Image, IptcImagePlugin
from .helper import PillowTestCase, hopper
@ -8,7 +11,7 @@ TEST_FILE = "Tests/images/iptc.jpg"
class TestFileIptc(PillowTestCase):
def test_getiptcinfo_jpg_none(self):
# Arrange
im = hopper()
with hopper() as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
@ -18,7 +21,7 @@ class TestFileIptc(PillowTestCase):
def test_getiptcinfo_jpg_found(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
@ -30,7 +33,7 @@ class TestFileIptc(PillowTestCase):
def test_getiptcinfo_tiff_none(self):
# Arrange
im = Image.open("Tests/images/hopper.tif")
with Image.open("Tests/images/hopper.tif") as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
@ -52,12 +55,6 @@ class TestFileIptc(PillowTestCase):
# Arrange
c = b"abc"
# Temporarily redirect stdout
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import sys
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()

View File

@ -1,10 +1,16 @@
import os
import sys
from io import BytesIO
from PIL import Image, ImageFile, JpegImagePlugin
from .helper import PillowTestCase, cjpeg_available, djpeg_available, hopper, unittest
from .helper import (
PillowTestCase,
cjpeg_available,
djpeg_available,
hopper,
is_win32,
unittest,
)
codecs = dir(Image.core)
@ -47,7 +53,7 @@ class TestFileJpeg(PillowTestCase):
def test_app(self):
# Test APP/COM reader (@PIL135)
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(
im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")
)
@ -93,13 +99,13 @@ class TestFileJpeg(PillowTestCase):
def test_icc(self):
# Test ICC support
im1 = Image.open("Tests/images/rgb.jpg")
with Image.open("Tests/images/rgb.jpg") as im1:
icc_profile = im1.info["icc_profile"]
self.assertEqual(len(icc_profile), 3144)
# Roundtrip via physical file.
f = self.tempfile("temp.jpg")
im1.save(f, icc_profile=icc_profile)
im2 = Image.open(f)
with Image.open(f) as im2:
self.assertEqual(im2.info.get("icc_profile"), icc_profile)
# Roundtrip via memory buffer.
im1 = self.roundtrip(hopper())
@ -199,13 +205,13 @@ class TestFileJpeg(PillowTestCase):
im.save(f, "JPEG", quality=90, exif=b"1" * 65532)
def test_exif_typeerror(self):
im = Image.open("Tests/images/exif_typeerror.jpg")
with Image.open("Tests/images/exif_typeerror.jpg") as im:
# Should not raise a TypeError
im._getexif()
def test_exif_gps(self):
# Arrange
im = Image.open("Tests/images/exif_gps.jpg")
with Image.open("Tests/images/exif_gps.jpg") as im:
gps_index = 34853
expected_exif_gps = {
0: b"\x00\x00\x00\x01",
@ -250,14 +256,14 @@ class TestFileJpeg(PillowTestCase):
33434: (4294967295, 1),
}
im = Image.open("Tests/images/exif_gps.jpg")
with Image.open("Tests/images/exif_gps.jpg") as im:
exif = im._getexif()
for tag, value in expected_exif.items():
self.assertEqual(value, exif[tag])
def test_exif_gps_typeerror(self):
im = Image.open("Tests/images/exif_gps_typeerror.jpg")
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
# Should not raise a TypeError
im._getexif()
@ -323,12 +329,12 @@ class TestFileJpeg(PillowTestCase):
self.assertRaises(TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
def test_exif(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
info = im._getexif()
self.assertEqual(info[305], "Adobe Photoshop CS Macintosh")
def test_mp(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
self.assertIsNone(im._getmp())
def test_quality_keep(self):
@ -348,11 +354,13 @@ class TestFileJpeg(PillowTestCase):
def test_junk_jpeg_header(self):
# https://github.com/python-pillow/Pillow/issues/630
filename = "Tests/images/junk_jpeg_header.jpg"
Image.open(filename)
with Image.open(filename):
pass
def test_ff00_jpeg_header(self):
filename = "Tests/images/jpeg_ff00_header.jpg"
Image.open(filename)
with Image.open(filename):
pass
def test_truncated_jpeg_should_read_all_the_data(self):
filename = "Tests/images/truncated_jpeg.jpg"
@ -364,8 +372,7 @@ class TestFileJpeg(PillowTestCase):
def test_truncated_jpeg_throws_IOError(self):
filename = "Tests/images/truncated_jpeg.jpg"
im = Image.open(filename)
with Image.open(filename) as im:
with self.assertRaises(IOError):
im.load()
@ -477,7 +484,7 @@ class TestFileJpeg(PillowTestCase):
@unittest.skipUnless(djpeg_available(), "djpeg not available")
def test_load_djpeg(self):
img = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as img:
img.load_djpeg()
self.assert_image_similar(img, Image.open(TEST_FILE), 0)
@ -519,7 +526,7 @@ class TestFileJpeg(PillowTestCase):
# Act
# Shouldn't raise error
fn = "Tests/images/sugarshack_bad_mpo_header.jpg"
im = self.assert_warning(UserWarning, Image.open, fn)
with self.assert_warning(UserWarning, Image.open, fn) as im:
# Assert
self.assertEqual(im.format, "JPEG")
@ -552,11 +559,11 @@ class TestFileJpeg(PillowTestCase):
def test_load_dpi_rounding(self):
# Round up
im = Image.open("Tests/images/iptc_roundUp.jpg")
with Image.open("Tests/images/iptc_roundUp.jpg") as im:
self.assertEqual(im.info["dpi"], (44, 44))
# Round down
im = Image.open("Tests/images/iptc_roundDown.jpg")
with Image.open("Tests/images/iptc_roundDown.jpg") as im:
self.assertEqual(im.info["dpi"], (2, 2))
def test_save_dpi_rounding(self):
@ -564,18 +571,18 @@ class TestFileJpeg(PillowTestCase):
im = Image.open("Tests/images/hopper.jpg")
im.save(outfile, dpi=(72.2, 72.2))
reloaded = Image.open(outfile)
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (72, 72))
im.save(outfile, dpi=(72.8, 72.8))
reloaded = Image.open(outfile)
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (73, 73))
def test_dpi_tuple_from_exif(self):
# Arrange
# This Photoshop CC 2017 image has DPI in EXIF not metadata
# EXIF XResolution is (2000000, 10000)
im = Image.open("Tests/images/photoshop-200dpi.jpg")
with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
# Act / Assert
self.assertEqual(im.info.get("dpi"), (200, 200))
@ -584,7 +591,7 @@ class TestFileJpeg(PillowTestCase):
# Arrange
# This image has DPI in EXIF not metadata
# EXIF XResolution is 72
im = Image.open("Tests/images/exif-72dpi-int.jpg")
with Image.open("Tests/images/exif-72dpi-int.jpg") as im:
# Act / Assert
self.assertEqual(im.info.get("dpi"), (72, 72))
@ -593,7 +600,7 @@ class TestFileJpeg(PillowTestCase):
# Arrange
# This is photoshop-200dpi.jpg with EXIF resolution unit set to cm:
# exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg
im = Image.open("Tests/images/exif-200dpcm.jpg")
with Image.open("Tests/images/exif-200dpcm.jpg") as im:
# Act / Assert
self.assertEqual(im.info.get("dpi"), (508, 508))
@ -602,7 +609,7 @@ class TestFileJpeg(PillowTestCase):
# Arrange
# This is photoshop-200dpi.jpg with EXIF resolution set to 0/0:
# exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg
im = Image.open("Tests/images/exif-dpi-zerodivision.jpg")
with Image.open("Tests/images/exif-dpi-zerodivision.jpg") as im:
# Act / Assert
# This should return the default, and not raise a ZeroDivisionError
@ -612,7 +619,7 @@ class TestFileJpeg(PillowTestCase):
# Arrange
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
# exiftool "-*resolution*"= photoshop-200dpi.jpg
im = Image.open("Tests/images/no-dpi-in-exif.jpg")
with Image.open("Tests/images/no-dpi-in-exif.jpg") as im:
# Act / Assert
# "When the image resolution is unknown, 72 [dpi] is designated."
@ -622,7 +629,7 @@ class TestFileJpeg(PillowTestCase):
def test_invalid_exif(self):
# This is no-dpi-in-exif with the tiff header of the exif block
# hexedited from MM * to FF FF FF FF
im = Image.open("Tests/images/invalid-exif.jpg")
with Image.open("Tests/images/invalid-exif.jpg") as im:
# This should return the default, and not a SyntaxError or
# OSError for unidentified image.
@ -632,13 +639,13 @@ class TestFileJpeg(PillowTestCase):
# Arrange
# This image has been manually hexedited to have an IFD offset of 10,
# in contrast to normal 8
im = Image.open("Tests/images/exif-ifd-offset.jpg")
with Image.open("Tests/images/exif-ifd-offset.jpg") as im:
# Act / Assert
self.assertEqual(im._getexif()[306], "2017:03:13 23:03:09")
def test_photoshop(self):
im = Image.open("Tests/images/photoshop-200dpi.jpg")
with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
self.assertEqual(
im.info["photoshop"][0x03ED],
{
@ -650,11 +657,11 @@ class TestFileJpeg(PillowTestCase):
)
# This image does not contain a Photoshop header string
im = Image.open("Tests/images/app13.jpg")
with Image.open("Tests/images/app13.jpg") as im:
self.assertNotIn("photoshop", im.info)
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
@unittest.skipUnless(is_win32(), "Windows only")
class TestFileCloseW32(PillowTestCase):
def setUp(self):
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:

View File

@ -42,7 +42,7 @@ class TestFileJpeg2k(PillowTestCase):
self.assertEqual(im.get_format_mimetype(), "image/jp2")
def test_jpf(self):
im = Image.open("Tests/images/balloon.jpf")
with Image.open("Tests/images/balloon.jpf") as im:
self.assertEqual(im.format, "JPEG2000")
self.assertEqual(im.get_format_mimetype(), "image/jpx")

View File

@ -1,5 +1,4 @@
from __future__ import print_function
import base64
import distutils.version
import io
import itertools
@ -9,7 +8,6 @@ from collections import namedtuple
from ctypes import c_float
from PIL import Image, TiffImagePlugin, TiffTags, features
from PIL._util import py3
from .helper import PillowTestCase, hopper
@ -143,9 +141,8 @@ class TestFileLibTiff(LibTiffTestCase):
def test_write_metadata(self):
""" Test metadata writing through libtiff """
for legacy_api in [False, True]:
img = Image.open("Tests/images/hopper_g4.tif")
f = self.tempfile("temp.tiff")
with Image.open("Tests/images/hopper_g4.tif") as img:
img.save(f, tiffinfo=img.tag)
if legacy_api:
@ -162,7 +159,7 @@ class TestFileLibTiff(LibTiffTestCase):
"PhotometricInterpretation",
]
loaded = Image.open(f)
with Image.open(f) as loaded:
if legacy_api:
reloaded = loaded.tag.named()
else:
@ -263,7 +260,6 @@ class TestFileLibTiff(LibTiffTestCase):
tc(4.25, TiffTags.FLOAT, True),
tc(4.25, TiffTags.DOUBLE, True),
tc("custom tag value", TiffTags.ASCII, True),
tc(u"custom tag value", TiffTags.ASCII, True),
tc(b"custom tag value", TiffTags.BYTE, True),
tc((4, 5, 6), TiffTags.SHORT, True),
tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
@ -301,7 +297,7 @@ class TestFileLibTiff(LibTiffTestCase):
out = self.tempfile("temp.tif")
im.save(out, tiffinfo=tiffinfo)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
for tag, value in tiffinfo.items():
reloaded_value = reloaded.tag_v2[tag]
if (
@ -342,7 +338,7 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out, dpi=(72, 72))
TiffImagePlugin.WRITE_LIBTIFF = False
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertEqual(reloaded.info["dpi"], (72.0, 72.0))
def test_g3_compression(self):
@ -361,12 +357,8 @@ class TestFileLibTiff(LibTiffTestCase):
b = im.tobytes()
# Bytes are in image native order (little endian)
if py3:
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
else:
self.assertEqual(b[0], b"\xe0")
self.assertEqual(b[1], b"\x01")
out = self.tempfile("temp.tif")
# out = "temp.le.tif"
@ -387,12 +379,8 @@ class TestFileLibTiff(LibTiffTestCase):
b = im.tobytes()
# Bytes are in image native order (big endian)
if py3:
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
else:
self.assertEqual(b[0], b"\x01")
self.assertEqual(b[1], b"\xe0")
out = self.tempfile("temp.tif")
im.save(out)
@ -411,7 +399,7 @@ class TestFileLibTiff(LibTiffTestCase):
orig.tag[269] = "temp.tif"
orig.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual("temp.tif", reread.tag_v2[269])
self.assertEqual("temp.tif", reread.tag[269][0])
@ -520,7 +508,7 @@ class TestFileLibTiff(LibTiffTestCase):
def test_multipage(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open("Tests/images/multipage.tiff")
with Image.open("Tests/images/multipage.tiff") as im:
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
im.seek(0)
@ -543,7 +531,7 @@ class TestFileLibTiff(LibTiffTestCase):
def test_multipage_nframes(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open("Tests/images/multipage.tiff")
with Image.open("Tests/images/multipage.tiff") as im:
frames = im.n_frames
self.assertEqual(frames, 3)
for _ in range(frames):
@ -655,7 +643,7 @@ class TestFileLibTiff(LibTiffTestCase):
# /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
# -dNOPAUSE /tmp/test.pdf -c quit
infile = "Tests/images/total-pages-zero.tif"
im = Image.open(infile)
with Image.open(infile) as im:
# Should not divide by zero
im.save(outfile)
@ -685,7 +673,7 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(icc, icc_libtiff)
def test_multipage_compression(self):
im = Image.open("Tests/images/compression.tif")
with Image.open("Tests/images/compression.tif") as im:
im.seek(0)
self.assertEqual(im._compression, "tiff_ccitt")
@ -835,7 +823,7 @@ class TestFileLibTiff(LibTiffTestCase):
def test_no_rows_per_strip(self):
# This image does not have a RowsPerStrip TIFF tag
infile = "Tests/images/no_rows_per_strip.tif"
im = Image.open(infile)
with Image.open(infile) as im:
im.load()
self.assertEqual(im.size, (950, 975))
@ -852,8 +840,6 @@ class TestFileLibTiff(LibTiffTestCase):
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
# when saving to a new file.
# Pillow 6.0 fails with "OSError: cannot identify image file".
import base64
tiff = io.BytesIO(
base64.b64decode(
b"SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAAQAAAAEBBAABAAAAAQAA"

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .test_file_libtiff import LibTiffTestCase
@ -25,8 +27,6 @@ class TestFileLibTiffSmall(LibTiffTestCase):
def test_g4_hopper_bytesio(self):
"""Testing the bytesio loading code path"""
from io import BytesIO
test_file = "Tests/images/hopper_g4.tif"
s = BytesIO()
with open(test_file, "rb") as f:

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImagePalette, features
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
try:
from PIL import MicImagePlugin
@ -16,7 +18,7 @@ TEST_FILE = "Tests/images/hopper.mic"
@unittest.skipUnless(features.check("libtiff"), "libtiff not installed")
class TestFileMic(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (128, 128))
@ -30,22 +32,22 @@ class TestFileMic(PillowTestCase):
self.assert_image_similar(im, im2, 10)
def test_n_frames(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.n_frames, 1)
def test_is_animated(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertFalse(im.is_animated)
def test_tell(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.tell(), 0)
def test_seek(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
im.seek(0)
self.assertEqual(im.tell(), 0)

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
from .helper import PillowTestCase, is_pypy
test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
@ -25,33 +26,50 @@ class TestFileMpo(PillowTestCase):
def test_sanity(self):
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (640, 480))
self.assertEqual(im.format, "MPO")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(test_files[0])
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(test_files[0])
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(test_files[0]) as im:
im.load()
self.assert_warning(None, open)
def test_app(self):
for test_file in test_files:
# Test APP/COM reader (@PIL135)
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.applist[0][0], "APP1")
self.assertEqual(im.applist[1][0], "APP2")
self.assertEqual(
im.applist[1][1][:16], b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
im.applist[1][1][:16],
b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00",
)
self.assertEqual(len(im.applist), 2)
def test_exif(self):
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
info = im._getexif()
self.assertEqual(info[272], "Nintendo 3DS")
self.assertEqual(info[296], 2)
@ -60,7 +78,7 @@ class TestFileMpo(PillowTestCase):
def test_frame_size(self):
# This image has been hexedited to contain a different size
# in the EXIF data of the second frame
im = Image.open("Tests/images/sugarshack_frame_size.mpo")
with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
self.assertEqual(im.size, (640, 480))
im.seek(1)
@ -68,19 +86,21 @@ class TestFileMpo(PillowTestCase):
def test_parallax(self):
# Nintendo
im = Image.open("Tests/images/sugarshack.mpo")
with Image.open("Tests/images/sugarshack.mpo") as im:
exif = im.getexif()
self.assertEqual(exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375)
self.assertEqual(
exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375
)
# Fujifilm
im = Image.open("Tests/images/fujifilm.mpo")
with Image.open("Tests/images/fujifilm.mpo") as im:
im.seek(1)
exif = im.getexif()
self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125)
def test_mp(self):
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
mpinfo = im._getmp()
self.assertEqual(mpinfo[45056], b"0100")
self.assertEqual(mpinfo[45057], 2)
@ -88,14 +108,14 @@ class TestFileMpo(PillowTestCase):
def test_mp_offset(self):
# This image has been manually hexedited to have an IFD offset of 10
# in APP2 data, in contrast to normal 8
im = Image.open("Tests/images/sugarshack_ifd_offset.mpo")
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
mpinfo = im._getmp()
self.assertEqual(mpinfo[45056], b"0100")
self.assertEqual(mpinfo[45057], 2)
def test_mp_attribute(self):
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
mpinfo = im._getmp()
frameNumber = 0
for mpentry in mpinfo[45058]:
@ -113,7 +133,7 @@ class TestFileMpo(PillowTestCase):
def test_seek(self):
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.tell(), 0)
# prior to first image raises an error, both blatant and borderline
self.assertRaises(EOFError, im.seek, -1)
@ -132,12 +152,12 @@ class TestFileMpo(PillowTestCase):
self.assertEqual(im.tell(), 0)
def test_n_frames(self):
im = Image.open("Tests/images/sugarshack.mpo")
with Image.open("Tests/images/sugarshack.mpo") as im:
self.assertEqual(im.n_frames, 2)
self.assertTrue(im.is_animated)
def test_eoferror(self):
im = Image.open("Tests/images/sugarshack.mpo")
with Image.open("Tests/images/sugarshack.mpo") as im:
n_frames = im.n_frames
# Test seeking past the last frame
@ -149,7 +169,7 @@ class TestFileMpo(PillowTestCase):
def test_image_grab(self):
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.tell(), 0)
im0 = im.tobytes()
im.seek(1)
@ -164,7 +184,7 @@ class TestFileMpo(PillowTestCase):
def test_save(self):
# Note that only individual frames can be saved at present
for test_file in test_files:
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.tell(), 0)
jpg0 = self.frame_roundtrip(im)
self.assert_image_similar(im, jpg0, 30)

View File

@ -1,8 +1,9 @@
import os
import unittest
from PIL import Image, MspImagePlugin
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
TEST_FILE = "Tests/images/hopper.msp"
EXTRA_DIR = "Tests/images/picins"

View File

@ -82,7 +82,7 @@ class TestFilePdf(PillowTestCase):
self.helper_save_as_pdf("RGB", save_all=True)
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = self.tempfile("temp.pdf")
im.save(outfile, save_all=True)
@ -99,8 +99,7 @@ class TestFilePdf(PillowTestCase):
# Test appending using a generator
def imGenerator(ims):
for im in ims:
yield im
yield from ims
im.save(outfile, save_all=True, append_images=imGenerator(ims))
@ -116,7 +115,7 @@ class TestFilePdf(PillowTestCase):
def test_multiframe_normal_save(self):
# Test saving a multiframe image without save_all
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = self.tempfile("temp.pdf")
im.save(outfile)
@ -163,13 +162,10 @@ class TestFilePdf(PillowTestCase):
def test_pdf_append_fails_on_nonexistent_file(self):
im = hopper("RGB")
temp_dir = tempfile.mkdtemp()
try:
with tempfile.TemporaryDirectory() as temp_dir:
self.assertRaises(
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
)
finally:
os.rmdir(temp_dir)
def check_pdf_pages_consistency(self, pdf):
pages_info = pdf.read_indirect(pdf.pages_ref)
@ -207,7 +203,7 @@ class TestFilePdf(PillowTestCase):
# append some info
pdf.info.Title = "abc"
pdf.info.Author = "def"
pdf.info.Subject = u"ghi\uABCD"
pdf.info.Subject = "ghi\uABCD"
pdf.info.Keywords = "qw)e\\r(ty"
pdf.info.Creator = "hopper()"
pdf.start_writing()
@ -235,7 +231,7 @@ class TestFilePdf(PillowTestCase):
self.assertEqual(pdf.info.Title, "abc")
self.assertEqual(pdf.info.Producer, "PdfParser")
self.assertEqual(pdf.info.Keywords, "qw)e\\r(ty")
self.assertEqual(pdf.info.Subject, u"ghi\uABCD")
self.assertEqual(pdf.info.Subject, "ghi\uABCD")
self.assertIn(b"CreationDate", pdf.info)
self.assertIn(b"ModDate", pdf.info)
self.check_pdf_pages_consistency(pdf)

View File

@ -1,11 +1,10 @@
import sys
import unittest
import zlib
from io import BytesIO
from PIL import Image, ImageFile, PngImagePlugin
from PIL._util import py3
from .helper import PillowLeakTestCase, PillowTestCase, hopper, unittest
from .helper import PillowLeakTestCase, PillowTestCase, hopper, is_win32
try:
from PIL import _webp
@ -82,7 +81,7 @@ class TestFilePng(PillowTestCase):
hopper("RGB").save(test_file)
im = Image.open(test_file)
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
@ -394,11 +393,11 @@ class TestFilePng(PillowTestCase):
def test_load_dpi_rounding(self):
# Round up
im = Image.open(TEST_PNG_FILE)
with Image.open(TEST_PNG_FILE) as im:
self.assertEqual(im.info["dpi"], (96, 96))
# Round down
im = Image.open("Tests/images/icc_profile_none.png")
with Image.open("Tests/images/icc_profile_none.png") as im:
self.assertEqual(im.info["dpi"], (72, 72))
def test_save_dpi_rounding(self):
@ -449,9 +448,7 @@ class TestFilePng(PillowTestCase):
self.assertIsInstance(im.info["Text"], str)
def test_unicode_text(self):
# Check preservation of non-ASCII characters on Python 3
# This cannot really be meaningfully tested on Python 2,
# since it didn't preserve charsets to begin with.
# Check preservation of non-ASCII characters
def rt_text(value):
im = Image.new("RGB", (32, 32))
@ -460,7 +457,6 @@ class TestFilePng(PillowTestCase):
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"Text": value})
if py3:
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
# CJK:
@ -510,15 +506,15 @@ class TestFilePng(PillowTestCase):
def test_trns_null(self):
# Check reading images with null tRNS value, issue #1239
test_file = "Tests/images/tRNS_null_1x1.png"
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.info["transparency"], 0)
def test_save_icc_profile(self):
im = Image.open("Tests/images/icc_profile_none.png")
with Image.open("Tests/images/icc_profile_none.png") as im:
self.assertIsNone(im.info["icc_profile"])
with_icc = Image.open("Tests/images/icc_profile.png")
with Image.open("Tests/images/icc_profile.png") as with_icc:
expected_icc = with_icc.info["icc_profile"]
im = roundtrip(im, icc_profile=expected_icc)
@ -615,7 +611,7 @@ class TestFilePng(PillowTestCase):
test_file = self.tempfile("temp.png")
im.save(test_file)
reloaded = Image.open(test_file)
with Image.open(test_file) as reloaded:
exif = reloaded._getexif()
self.assertEqual(exif[274], 1)
@ -625,7 +621,7 @@ class TestFilePng(PillowTestCase):
test_file = self.tempfile("temp.png")
im.save(test_file)
reloaded = Image.open(test_file)
with Image.open(test_file) as reloaded:
exif = reloaded._getexif()
self.assertEqual(exif[305], "Adobe Photoshop CS Macintosh")
@ -635,7 +631,7 @@ class TestFilePng(PillowTestCase):
test_file = self.tempfile("temp.png")
im.save(test_file, exif=b"exifstring")
reloaded = Image.open(test_file)
with Image.open(test_file) as reloaded:
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
@unittest.skipUnless(
@ -650,7 +646,7 @@ class TestFilePng(PillowTestCase):
self.assert_image_similar(im, expected, 0.23)
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestTruncatedPngPLeaks(PillowLeakTestCase):
mem_limit = 2 * 1024 # max increase in K
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs

View File

@ -66,10 +66,10 @@ class TestFilePpm(PillowTestCase):
with open(path, "w") as f:
f.write("P4\n128 128\n255")
im = Image.open(path)
with Image.open(path) as im:
self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap")
with open(path, "w") as f:
f.write("PyCMYK\n128 128\n255")
im = Image.open(path)
with Image.open(path) as im:
self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap")

View File

@ -1,13 +1,15 @@
import unittest
from PIL import Image, PsdImagePlugin
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
test_file = "Tests/images/hopper.psd"
class TestImagePsd(PillowTestCase):
def test_sanity(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
@ -16,11 +18,27 @@ class TestImagePsd(PillowTestCase):
im2 = hopper()
self.assert_image_similar(im, im2, 4.8)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(test_file)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(test_file)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(test_file) as im:
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
@ -29,16 +47,16 @@ class TestImagePsd(PillowTestCase):
self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file)
def test_n_frames(self):
im = Image.open("Tests/images/hopper_merged.psd")
with Image.open("Tests/images/hopper_merged.psd") as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.n_frames, 2)
self.assertTrue(im.is_animated)
def test_eoferror(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
# PSD seek index starts at 1 rather than 0
n_frames = im.n_frames + 1
@ -50,7 +68,7 @@ class TestImagePsd(PillowTestCase):
im.seek(n_frames - 1)
def test_seek_tell(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
layer_number = im.tell()
self.assertEqual(layer_number, 1)
@ -66,26 +84,25 @@ class TestImagePsd(PillowTestCase):
self.assertEqual(layer_number, 2)
def test_seek_eoferror(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertRaises(EOFError, im.seek, -1)
def test_open_after_exclusive_load(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
im.load()
im.seek(im.tell() + 1)
im.load()
def test_icc_profile(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertIn("icc_profile", im.info)
icc_profile = im.info["icc_profile"]
self.assertEqual(len(icc_profile), 3144)
def test_no_icc_profile(self):
im = Image.open("Tests/images/hopper_merged.psd")
with Image.open("Tests/images/hopper_merged.psd") as im:
self.assertNotIn("icc_profile", im.info)
def test_combined_larger_than_size(self):

View File

@ -1,26 +1,43 @@
import tempfile
import unittest
from io import BytesIO
from PIL import Image, ImageSequence, SpiderImagePlugin
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
TEST_FILE = "Tests/images/hopper.spider"
class TestImageSpider(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "SPIDER")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_FILE) as im:
im.load()
self.assert_warning(None, open)
def test_save(self):
@ -32,7 +49,7 @@ class TestImageSpider(PillowTestCase):
im.save(temp, "SPIDER")
# Assert
im2 = Image.open(temp)
with Image.open(temp) as im2:
self.assertEqual(im2.mode, "F")
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.format, "SPIDER")
@ -57,7 +74,7 @@ class TestImageSpider(PillowTestCase):
def test_tell(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act
index = im.tell()
@ -66,7 +83,7 @@ class TestImageSpider(PillowTestCase):
self.assertEqual(index, 0)
def test_n_frames(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
@ -109,12 +126,11 @@ class TestImageSpider(PillowTestCase):
self.assertRaises(IOError, Image.open, invalid_file)
def test_nonstack_file(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertRaises(EOFError, im.seek, 0)
def test_nonstack_dos(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
for i, frame in enumerate(ImageSequence.Iterator(im)):
if i > 1:
self.fail("Non-stack DOS file test failed")

View File

@ -1,8 +1,9 @@
import os
import unittest
from PIL import Image, SunImagePlugin
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
EXTRA_DIR = "Tests/images/sunraster"

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, TarIO
from .helper import PillowTestCase
from .helper import PillowTestCase, is_pypy
codecs = dir(Image.core)
@ -19,17 +21,30 @@ class TestFileTar(PillowTestCase):
["jpeg_decoder", "hopper.jpg", "JPEG"],
]:
if codec in codecs:
tar = TarIO.TarIO(TEST_TAR_FILE, test_path)
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
im = Image.open(tar)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, format)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
self.assert_warning(ResourceWarning, open)
def test_close(self):
def open():
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
tar.close()
self.assert_warning(None, open)
def test_contextmanager(self):
def open():
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
pass
self.assert_warning(None, open)

View File

@ -76,7 +76,7 @@ class TestFileTga(PillowTestCase):
test_file = "Tests/images/tga_id_field.tga"
# Act
im = Image.open(test_file)
with Image.open(test_file) as im:
# Assert
self.assertEqual(im.size, (100, 100))
@ -86,7 +86,7 @@ class TestFileTga(PillowTestCase):
test_file = "Tests/images/rgb32rle.tga"
# Act
im = Image.open(test_file)
with Image.open(test_file) as im:
# Assert
self.assertEqual(im.size, (199, 199))
@ -99,13 +99,13 @@ class TestFileTga(PillowTestCase):
# Save
im.save(out)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (100, 100))
self.assertEqual(test_im.info["id_section"], im.info["id_section"])
# RGBA save
im.convert("RGBA").save(out)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (100, 100))
def test_save_id_section(self):
@ -116,26 +116,26 @@ class TestFileTga(PillowTestCase):
# Check there is no id section
im.save(out)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertNotIn("id_section", test_im.info)
# Save with custom id section
im.save(out, id_section=b"Test content")
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.info["id_section"], b"Test content")
# Save with custom id section greater than 255 characters
id_section = b"Test content" * 25
self.assert_warning(UserWarning, lambda: im.save(out, id_section=id_section))
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.info["id_section"], id_section[:255])
test_file = "Tests/images/tga_id_field.tga"
im = Image.open(test_file)
with Image.open(test_file) as im:
# Save with no id section
im.save(out, id_section="")
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertNotIn("id_section", test_im.info)
def test_save_orientation(self):
@ -146,7 +146,7 @@ class TestFileTga(PillowTestCase):
out = self.tempfile("temp.tga")
im.save(out, orientation=1)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.info["orientation"], 1)
def test_save_rle(self):
@ -158,18 +158,18 @@ class TestFileTga(PillowTestCase):
# Save
im.save(out)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (199, 199))
self.assertEqual(test_im.info["compression"], "tga_rle")
# Save without compression
im.save(out, compression=None)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertNotIn("compression", test_im.info)
# RGBA save
im.convert("RGBA").save(out)
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (199, 199))
test_file = "Tests/images/tga_id_field.tga"
@ -178,7 +178,7 @@ class TestFileTga(PillowTestCase):
# Save with compression
im.save(out, compression="tga_rle")
test_im = Image.open(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.info["compression"], "tga_rle")
def test_save_l_transparency(self):

View File

@ -1,12 +1,13 @@
import logging
import sys
import os
import unittest
from io import BytesIO
import pytest
from PIL import Image, TiffImagePlugin
from PIL._util import py3
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper, is_pypy, is_win32
logger = logging.getLogger(__name__)
@ -18,32 +19,53 @@ class TestFileTiff(PillowTestCase):
hopper("RGB").save(filename)
im = Image.open(filename)
with Image.open(filename) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "TIFF")
hopper("1").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("L").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("P").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("RGB").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("I").save(filename)
Image.open(filename)
with Image.open(filename):
pass
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open("Tests/images/multipage.tiff")
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open("Tests/images/multipage.tiff")
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open("Tests/images/multipage.tiff") as im:
im.load()
self.assert_warning(None, open)
def test_mac_tiff(self):
@ -73,18 +95,9 @@ class TestFileTiff(PillowTestCase):
ifd.legacy_api = None
self.assertEqual(str(e.exception), "Not allowing setting of legacy api")
def test_size(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
def set_size():
im.size = (256, 256)
self.assert_warning(DeprecationWarning, set_size)
def test_xyres_tiff(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
with Image.open(filename) as im:
# legacy api
self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple)
@ -98,7 +111,7 @@ class TestFileTiff(PillowTestCase):
def test_xyres_fallback_tiff(self):
filename = "Tests/images/compression.tif"
im = Image.open(filename)
with Image.open(filename) as im:
# v2 api
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
@ -112,7 +125,7 @@ class TestFileTiff(PillowTestCase):
def test_int_resolution(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
with Image.open(filename) as im:
# Try to read a file where X,Y_RESOLUTION are ints
im.tag_v2[X_RESOLUTION] = 71
@ -122,15 +135,15 @@ class TestFileTiff(PillowTestCase):
def test_load_dpi_rounding(self):
for resolutionUnit, dpi in ((None, (72, 73)), (2, (72, 73)), (3, (183, 185))):
im = Image.open(
with Image.open(
"Tests/images/hopper_roundDown_" + str(resolutionUnit) + ".tif"
)
) as im:
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
self.assertEqual(im.info["dpi"], (dpi[0], dpi[0]))
im = Image.open(
with Image.open(
"Tests/images/hopper_roundUp_" + str(resolutionUnit) + ".tif"
)
) as im:
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
self.assertEqual(im.info["dpi"], (dpi[1], dpi[1]))
@ -164,7 +177,7 @@ class TestFileTiff(PillowTestCase):
TiffImagePlugin.PREFIXES.pop()
def test_bad_exif(self):
i = Image.open("Tests/images/hopper_bad_exif.jpg")
with Image.open("Tests/images/hopper_bad_exif.jpg") as i:
# Should not raise struct.error.
self.assert_warning(UserWarning, i._getexif)
@ -185,12 +198,8 @@ class TestFileTiff(PillowTestCase):
b = im.tobytes()
# Bytes are in image native order (little endian)
if py3:
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
else:
self.assertEqual(b[0], b"\xe0")
self.assertEqual(b[1], b"\x01")
def test_big_endian(self):
im = Image.open("Tests/images/16bit.MM.cropped.tif")
@ -200,12 +209,8 @@ class TestFileTiff(PillowTestCase):
b = im.tobytes()
# Bytes are in image native order (big endian)
if py3:
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
else:
self.assertEqual(b[0], b"\x01")
self.assertEqual(b[1], b"\xe0")
def test_16bit_s(self):
im = Image.open("Tests/images/16bit.s.tif")
@ -247,12 +252,12 @@ class TestFileTiff(PillowTestCase):
["Tests/images/multipage-lastframe.tif", 1],
["Tests/images/multipage.tiff", 3],
]:
im = Image.open(path)
with Image.open(path) as im:
self.assertEqual(im.n_frames, n_frames)
self.assertEqual(im.is_animated, n_frames != 1)
def test_eoferror(self):
im = Image.open("Tests/images/multipage-lastframe.tif")
with Image.open("Tests/images/multipage-lastframe.tif") as im:
n_frames = im.n_frames
# Test seeking past the last frame
@ -264,7 +269,7 @@ class TestFileTiff(PillowTestCase):
def test_multipage(self):
# issue #862
im = Image.open("Tests/images/multipage.tiff")
with Image.open("Tests/images/multipage.tiff") as im:
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
im.seek(0)
@ -294,7 +299,7 @@ class TestFileTiff(PillowTestCase):
def test___str__(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
# Act
ret = str(im.ifd)
@ -305,7 +310,7 @@ class TestFileTiff(PillowTestCase):
def test_dict(self):
# Arrange
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
# v2 interface
v2_tags = {
@ -345,7 +350,7 @@ class TestFileTiff(PillowTestCase):
def test__delitem__(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
len_before = len(dict(im.ifd))
del im.ifd[256]
len_after = len(dict(im.ifd))
@ -378,13 +383,13 @@ class TestFileTiff(PillowTestCase):
def test_seek(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
im.seek(0)
self.assertEqual(im.tell(), 0)
def test_seek_eof(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
self.assertEqual(im.tell(), 0)
self.assertRaises(EOFError, im.seek, -1)
self.assertRaises(EOFError, im.seek, 1)
@ -448,7 +453,7 @@ class TestFileTiff(PillowTestCase):
kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
filename = self.tempfile("temp.tif")
hopper("RGB").save(filename, **kwargs)
im = Image.open(filename)
with Image.open(filename) as im:
# legacy interface
self.assertEqual(im.tag[X_RESOLUTION][0][0], 72)
@ -489,8 +494,7 @@ class TestFileTiff(PillowTestCase):
def test_strip_planar_raw_with_overviews(self):
# gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16
infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif"
im = Image.open(infile)
with Image.open(infile) as im:
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_tiled_planar_raw(self):
@ -513,10 +517,7 @@ class TestFileTiff(PillowTestCase):
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
def test_tiff_save_all(self):
import io
import os
mp = io.BytesIO()
mp = BytesIO()
with Image.open("Tests/images/multipage.tiff") as im:
im.save(mp, format="tiff", save_all=True)
@ -525,7 +526,7 @@ class TestFileTiff(PillowTestCase):
self.assertEqual(im.n_frames, 3)
# Test appending images
mp = io.BytesIO()
mp = BytesIO()
im = Image.new("RGB", (100, 100), "#f00")
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
im.copy().save(mp, format="TIFF", save_all=True, append_images=ims)
@ -536,10 +537,9 @@ class TestFileTiff(PillowTestCase):
# Test appending using a generator
def imGenerator(ims):
for im in ims:
yield im
yield from ims
mp = io.BytesIO()
mp = BytesIO()
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
mp.seek(0, os.SEEK_SET)
@ -557,8 +557,7 @@ class TestFileTiff(PillowTestCase):
# Try save-load round trip to make sure both handle icc_profile.
tmpfile = self.tempfile("temp.tif")
im.save(tmpfile, "TIFF", compression="raw")
reloaded = Image.open(tmpfile)
with Image.open(tmpfile) as reloaded:
self.assertEqual(b"Dummy value", reloaded.info["icc_profile"])
def test_close_on_load_exclusive(self):
@ -587,17 +586,19 @@ class TestFileTiff(PillowTestCase):
im.load()
self.assertFalse(fp.closed)
# Ignore this UserWarning which triggers for four tags:
# "Possibly corrupt EXIF data. Expecting to read 50404352 bytes but..."
@pytest.mark.filterwarnings("ignore:Possibly corrupt EXIF data")
def test_string_dimension(self):
# Assert that an error is raised if one of the dimensions is a string
with self.assertRaises(ValueError):
Image.open("Tests/images/string_dimension.tiff")
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
@unittest.skipUnless(is_win32(), "Windows only")
class TestFileTiffW32(PillowTestCase):
def test_fd_leak(self):
tmpfile = self.tempfile("temp.tif")
import os
# this is an mmaped file.
with Image.open("Tests/images/uint16_1_4660.tif") as im:

View File

@ -52,7 +52,7 @@ class TestFileTiffMetadata(PillowTestCase):
img.save(f, tiffinfo=info)
loaded = Image.open(f)
with Image.open(f) as loaded:
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),))
@ -72,13 +72,17 @@ class TestFileTiffMetadata(PillowTestCase):
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
img.save(f, tiffinfo=info)
loaded = Image.open(f)
with Image.open(f) as loaded:
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
self.assertEqual(
loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8)
)
self.assertEqual(
loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8)
)
def test_read_metadata(self):
img = Image.open("Tests/images/hopper_g4.tif")
with Image.open("Tests/images/hopper_g4.tif") as img:
self.assertEqual(
{
@ -131,7 +135,7 @@ class TestFileTiffMetadata(PillowTestCase):
f = self.tempfile("temp.tiff")
img.save(f, tiffinfo=img.tag)
loaded = Image.open(f)
with Image.open(f) as loaded:
original = img.tag_v2.named()
reloaded = loaded.tag_v2.named()
@ -157,13 +161,13 @@ class TestFileTiffMetadata(PillowTestCase):
self.assert_deep_equal(
original[tag],
value,
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
)
else:
self.assertEqual(
original[tag],
value,
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
)
for tag, value in original.items():
@ -187,7 +191,7 @@ class TestFileTiffMetadata(PillowTestCase):
out = self.tempfile("temp.tiff")
im.save(out)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertNotIsInstance(im.info["icc_profile"], tuple)
self.assertEqual(im.info["icc_profile"], reloaded.info["icc_profile"])
@ -196,7 +200,7 @@ class TestFileTiffMetadata(PillowTestCase):
# We should be able to load this,
# but probably won't be able to save it.
im = Image.open("Tests/images/hopper.iccprofile_binary.tif")
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
self.assertEqual(im.tag_v2.tagtype[34675], 1)
self.assertTrue(im.info["icc_profile"])
@ -218,7 +222,7 @@ class TestFileTiffMetadata(PillowTestCase):
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertEqual(0, reloaded.tag_v2[41988].numerator)
self.assertEqual(0, reloaded.tag_v2[41988].denominator)
@ -243,7 +247,7 @@ class TestFileTiffMetadata(PillowTestCase):
self.assertIsInstance(im.tag_v2[34377][0], bytes)
out = self.tempfile("temp.tiff")
im.save(out)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertEqual(len(reloaded.tag_v2[34377]), 1)
self.assertIsInstance(reloaded.tag_v2[34377][0], bytes)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, WebPImagePlugin
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
try:
from PIL import _webp
@ -158,7 +160,7 @@ class TestFileWebp(PillowTestCase):
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP save all not available"
)
def test_background_from_gif(self):
im = Image.open("Tests/images/chi.gif")
with Image.open("Tests/images/chi.gif") as im:
original_value = im.convert("RGB").getpixel((1, 1))
# Save as WEBP
@ -169,7 +171,7 @@ class TestFileWebp(PillowTestCase):
out_gif = self.tempfile("temp.gif")
Image.open(out_webp).save(out_gif)
reread = Image.open(out_gif)
with Image.open(out_gif) as reread:
reread_value = reread.convert("RGB").getpixel((1, 1))
difference = sum(
[abs(original_value[i] - reread_value[i]) for i in range(0, 3)]

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
try:
from PIL import _webp
@ -103,7 +105,8 @@ class TestFileWebpAlpha(PillowTestCase):
temp_file = self.tempfile("temp.webp")
file_path = "Tests/images/transparent.gif"
Image.open(file_path).save(temp_file)
with Image.open(file_path) as im:
im.save(temp_file)
image = Image.open(temp_file)
self.assertEqual(image.mode, "RGBA")
@ -112,6 +115,7 @@ class TestFileWebpAlpha(PillowTestCase):
image.load()
image.getdata()
target = Image.open(file_path).convert("RGBA")
with Image.open(file_path) as im:
target = im.convert("RGBA")
self.assert_image_similar(image, target, 25.0)

View File

@ -28,11 +28,11 @@ class TestFileWebpAnimation(PillowTestCase):
attributes correctly.
"""
im = Image.open("Tests/images/hopper.webp")
with Image.open("Tests/images/hopper.webp") as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
im = Image.open("Tests/images/iss634.webp")
with Image.open("Tests/images/iss634.webp") as im:
self.assertEqual(im.n_frames, 42)
self.assertTrue(im.is_animated)
@ -43,7 +43,7 @@ class TestFileWebpAnimation(PillowTestCase):
visually similar.
"""
orig = Image.open("Tests/images/iss634.gif")
with Image.open("Tests/images/iss634.gif") as orig:
self.assertGreater(orig.n_frames, 1)
temp_file = self.tempfile("temp.webp")
@ -91,8 +91,7 @@ class TestFileWebpAnimation(PillowTestCase):
# Tests appending using a generator
def imGenerator(ims):
for im in ims:
yield im
yield from ims
temp_file2 = self.tempfile("temp_generator.webp")
frame1.copy().save(

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
@ -22,7 +24,7 @@ class TestFileWebpMetadata(PillowTestCase):
def test_read_exif_metadata(self):
file_path = "Tests/images/flower.webp"
image = Image.open(file_path)
with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP")
exif_data = image.info.get("exif", None)
@ -33,14 +35,12 @@ class TestFileWebpMetadata(PillowTestCase):
# camera make
self.assertEqual(exif[271], "Canon")
jpeg_image = Image.open("Tests/images/flower.jpg")
with Image.open("Tests/images/flower.jpg") as jpeg_image:
expected_exif = jpeg_image.info["exif"]
self.assertEqual(exif_data, expected_exif)
def test_write_exif_metadata(self):
from io import BytesIO
file_path = "Tests/images/flower.jpg"
image = Image.open(file_path)
expected_exif = image.info["exif"]
@ -60,21 +60,19 @@ class TestFileWebpMetadata(PillowTestCase):
def test_read_icc_profile(self):
file_path = "Tests/images/flower2.webp"
image = Image.open(file_path)
with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP")
self.assertTrue(image.info.get("icc_profile", None))
icc = image.info["icc_profile"]
jpeg_image = Image.open("Tests/images/flower2.jpg")
with Image.open("Tests/images/flower2.jpg") as jpeg_image:
expected_icc = jpeg_image.info["icc_profile"]
self.assertEqual(icc, expected_icc)
def test_write_icc_metadata(self):
from io import BytesIO
file_path = "Tests/images/flower2.jpg"
image = Image.open(file_path)
expected_icc_profile = image.info["icc_profile"]
@ -95,8 +93,6 @@ class TestFileWebpMetadata(PillowTestCase):
)
def test_read_no_exif(self):
from io import BytesIO
file_path = "Tests/images/flower.jpg"
image = Image.open(file_path)
self.assertIn("exif", image.info)
@ -114,9 +110,9 @@ class TestFileWebpMetadata(PillowTestCase):
if not _webp.HAVE_WEBPANIM:
self.skipTest("WebP animation support not available")
iccp_data = "<iccp_data>".encode("utf-8")
exif_data = "<exif_data>".encode("utf-8")
xmp_data = "<xmp_data>".encode("utf-8")
iccp_data = b"<iccp_data>"
exif_data = b"<exif_data>"
xmp_data = b"<xmp_data>"
temp_file = self.tempfile("temp.webp")
frame1 = Image.open("Tests/images/anim_frame1.webp")
@ -130,7 +126,7 @@ class TestFileWebpMetadata(PillowTestCase):
xmp=xmp_data,
)
image = Image.open(temp_file)
with Image.open(temp_file) as image:
self.assertIn("icc_profile", image.info)
self.assertIn("exif", image.info)
self.assertIn("xmp", image.info)

View File

@ -7,7 +7,7 @@ class TestFileWmf(PillowTestCase):
def test_load_raw(self):
# Test basic EMF open and rendering
im = Image.open("Tests/images/drawing.emf")
with Image.open("Tests/images/drawing.emf") as im:
if hasattr(Image.core, "drawwmf"):
# Currently, support for WMF/EMF is Windows-only
im.load()
@ -17,7 +17,7 @@ class TestFileWmf(PillowTestCase):
self.assert_image_similar(im, imref, 0)
# Test basic WMF open and rendering
im = Image.open("Tests/images/drawing.wmf")
with Image.open("Tests/images/drawing.wmf") as im:
if hasattr(Image.core, "drawwmf"):
# Currently, support for WMF/EMF is Windows-only
im.load()
@ -46,11 +46,11 @@ class TestFileWmf(PillowTestCase):
def test_load_dpi_rounding(self):
# Round up
im = Image.open("Tests/images/drawing.emf")
with Image.open("Tests/images/drawing.emf") as im:
self.assertEqual(im.info["dpi"], 1424)
# Round down
im = Image.open("Tests/images/drawing_roundDown.emf")
with Image.open("Tests/images/drawing_roundDown.emf") as im:
self.assertEqual(im.info["dpi"], 1426)
def test_save(self):

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
@ -28,8 +30,6 @@ static char basic_bits[] = {
class TestFileXbm(PillowTestCase):
def test_pil151(self):
from io import BytesIO
im = Image.open(BytesIO(PIL151))
im.load()
@ -42,7 +42,7 @@ class TestFileXbm(PillowTestCase):
filename = "Tests/images/hopper.xbm"
# Act
im = Image.open(filename)
with Image.open(filename) as im:
# Assert
self.assertEqual(im.mode, "1")
@ -54,7 +54,7 @@ class TestFileXbm(PillowTestCase):
filename = "Tests/images/hopper_underscore.xbm"
# Act
im = Image.open(filename)
with Image.open(filename) as im:
# Assert
self.assertEqual(im.mode, "1")

View File

@ -23,7 +23,7 @@ class TestFileXpm(PillowTestCase):
def test_load_read(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
dummy_bytes = 1
# Act

View File

@ -1,13 +1,11 @@
from __future__ import division
import sys
import unittest
from PIL import Image, ImageDraw, ImageFont, features
from .helper import PillowLeakTestCase, unittest
from .helper import PillowLeakTestCase, is_win32
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestTTypeFontLeak(PillowLeakTestCase):
# fails at iteration 3 in master
iterations = 10

View File

@ -1,5 +1,4 @@
from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile
from PIL._util import py3
from .helper import PillowTestCase
@ -74,6 +73,5 @@ class TestFontPcf(PillowTestCase):
def test_high_characters(self):
message = "".join(chr(i + 1) for i in range(140, 232))
self._test_high_characters(message)
# accept bytes instances in Py3.
if py3:
# accept bytes instances.
self._test_high_characters(message.encode("latin1"))

View File

@ -2,7 +2,6 @@ import colorsys
import itertools
from PIL import Image
from PIL._util import py3
from .helper import PillowTestCase, hopper
@ -49,27 +48,18 @@ class TestFormatHSV(PillowTestCase):
(r, g, b) = im.split()
if py3:
conv_func = self.int_to_float
else:
conv_func = self.str_to_float
if hasattr(itertools, "izip"):
iter_helper = itertools.izip
else:
iter_helper = itertools.zip_longest
converted = [
self.tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
for (_r, _g, _b) in iter_helper(r.tobytes(), g.tobytes(), b.tobytes())
for (_r, _g, _b) in itertools.zip_longest(
r.tobytes(), g.tobytes(), b.tobytes()
)
]
if py3:
new_bytes = b"".join(
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
)
else:
new_bytes = b"".join(chr(h) + chr(s) + chr(v) for (h, s, v) in converted)
hsv = Image.frombytes(mode, r.size, new_bytes)

View File

@ -1,11 +1,11 @@
import os
import shutil
import sys
import tempfile
import unittest
from PIL import Image
from PIL._util import py3
from PIL import Image, UnidentifiedImageError
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper, is_win32
class TestImage(PillowTestCase):
@ -48,6 +48,9 @@ class TestImage(PillowTestCase):
Image.new(mode, (1, 1))
self.assertEqual(str(e.exception), "unrecognized image mode")
def test_exception_inheritance(self):
self.assertTrue(issubclass(UnidentifiedImageError, IOError))
def test_sanity(self):
im = Image.new("L", (100, 100))
@ -80,24 +83,18 @@ class TestImage(PillowTestCase):
im.size = (3, 4)
def test_invalid_image(self):
if py3:
import io
im = io.BytesIO(b"")
else:
import StringIO
im = StringIO.StringIO("")
self.assertRaises(IOError, Image.open, im)
self.assertRaises(UnidentifiedImageError, Image.open, im)
def test_bad_mode(self):
self.assertRaises(ValueError, Image.open, "filename", "bad mode")
@unittest.skipUnless(Image.HAS_PATHLIB, "requires pathlib/pathlib2")
def test_pathlib(self):
from PIL.Image import Path
im = Image.open(Path("Tests/images/multipage-mmap.tiff"))
with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im:
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (10, 10))
@ -113,7 +110,7 @@ class TestImage(PillowTestCase):
def test_fp_name(self):
temp_file = self.tempfile("temp.jpg")
class FP(object):
class FP:
def write(a, b):
pass
@ -126,8 +123,6 @@ class TestImage(PillowTestCase):
def test_tempfile(self):
# see #1460, pathlib support breaks tempfile.TemporaryFile on py27
# Will error out on save on 3.0.0
import tempfile
im = hopper()
with tempfile.TemporaryFile() as fp:
im.save(fp, "JPEG")
@ -150,9 +145,7 @@ class TestImage(PillowTestCase):
im.paste(0, (0, 0, 100, 100))
self.assertFalse(im.readonly)
@unittest.skipIf(
sys.platform.startswith("win32"), "Test requires opening tempfile twice"
)
@unittest.skipIf(is_win32(), "Test requires opening tempfile twice")
def test_readonly_save(self):
temp_file = self.tempfile("temp.bmp")
shutil.copy("Tests/images/rgb32bf-rgba.bmp", temp_file)
@ -350,7 +343,8 @@ class TestImage(PillowTestCase):
def test_registered_extensions(self):
# Arrange
# Open an image to trigger plugin registration
Image.open("Tests/images/rgb.jpg")
with Image.open("Tests/images/rgb.jpg"):
pass
# Act
extensions = Image.registered_extensions()
@ -452,7 +446,7 @@ class TestImage(PillowTestCase):
def test_offset_not_implemented(self):
# Arrange
im = hopper()
with hopper() as im:
# Act / Assert
self.assertRaises(NotImplementedError, im.offset, None)
@ -526,7 +520,7 @@ class TestImage(PillowTestCase):
def test_remap_palette(self):
# Test illegal image mode
im = hopper()
with hopper() as im:
self.assertRaises(ValueError, im.remap_palette, None)
def test__new(self):
@ -591,15 +585,15 @@ class TestImage(PillowTestCase):
def test_overrun(self):
for file in ["fli_overrun.bin", "sgi_overrun.bin", "pcx_overrun.bin"]:
im = Image.open(os.path.join("Tests/images", file))
with Image.open(os.path.join("Tests/images", file)) as im:
try:
im.load()
self.assertFail()
except IOError as e:
except OSError as e:
self.assertEqual(str(e), "buffer overrun when reading image file")
class MockEncoder(object):
class MockEncoder:
pass

View File

@ -1,9 +1,13 @@
import ctypes
import os
import subprocess
import sys
import unittest
from distutils import ccompiler, sysconfig
from PIL import Image
from .helper import PillowTestCase, hopper, on_appveyor, unittest
from .helper import PillowTestCase, hopper, is_win32, on_ci
# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
@ -122,7 +126,7 @@ class TestImageGetPixel(AccessTest):
self.assertEqual(
im.getpixel((0, 0)),
c,
"put/getpixel roundtrip failed for mode %s, color %s" % (mode, c),
"put/getpixel roundtrip failed for mode {}, color {}".format(mode, c),
)
# check putpixel negative index
@ -151,7 +155,7 @@ class TestImageGetPixel(AccessTest):
self.assertEqual(
im.getpixel((0, 0)),
c,
"initial color failed for mode %s, color %s " % (mode, c),
"initial color failed for mode {}, color {} ".format(mode, c),
)
# check initial color negative index
self.assertEqual(
@ -333,14 +337,10 @@ class TestCffi(AccessTest):
class TestEmbeddable(unittest.TestCase):
@unittest.skipIf(
not sys.platform.startswith("win32") or on_appveyor(),
"Failing on AppVeyor when run from subprocess, not from shell",
not is_win32() or on_ci(),
"Failing on AppVeyor / GitHub Actions when run from subprocess, not from shell",
)
def test_embeddable(self):
import subprocess
import ctypes
from distutils import ccompiler, sysconfig
with open("embed_pil.c", "w") as fh:
fh.write(
"""
@ -349,12 +349,8 @@ class TestEmbeddable(unittest.TestCase):
int main(int argc, char* argv[])
{
char *home = "%s";
#if PY_MAJOR_VERSION >= 3
wchar_t *whome = Py_DecodeLocale(home, NULL);
Py_SetPythonHome(whome);
#else
Py_SetPythonHome(home);
#endif
Py_InitializeEx(0);
Py_DECREF(PyImport_ImportModule("PIL.Image"));
@ -364,9 +360,7 @@ int main(int argc, char* argv[])
Py_DECREF(PyImport_ImportModule("PIL.Image"));
Py_Finalize();
#if PY_MAJOR_VERSION >= 3
PyMem_RawFree(whome);
#endif
return 0;
}

View File

@ -25,7 +25,7 @@ class TestImageArray(PillowTestCase):
self.assertEqual(test("RGBX"), (3, (100, 128, 4), "|u1", 51200))
def test_fromarray(self):
class Wrapper(object):
class Wrapper:
""" Class with API matching Image.fromarray """
def __init__(self, img, arr_params):

View File

@ -144,7 +144,7 @@ class TestImageConvert(PillowTestCase):
def test_gif_with_rgba_palette_to_p(self):
# See https://github.com/python-pillow/Pillow/issues/2433
im = Image.open("Tests/images/hopper.gif")
with Image.open("Tests/images/hopper.gif") as im:
im.info["transparency"] = 255
im.load()
self.assertEqual(im.palette.mode, "RGBA")

View File

@ -5,12 +5,15 @@ from .test_imageqt import PillowQtTestCase
class TestFromQImage(PillowQtTestCase, PillowTestCase):
files_to_test = [
def setUp(self):
super().setUp()
self.files_to_test = [
hopper(),
Image.open("Tests/images/transparent.png"),
Image.open("Tests/images/7x13.png"),
]
for im in self.files_to_test:
self.addCleanup(im.close)
def roundtrip(self, expected):
# PIL -> Qt

View File

@ -1,5 +1,3 @@
from PIL._util import py3
from .helper import PillowTestCase, hopper
@ -8,7 +6,5 @@ class TestImageGetIm(PillowTestCase):
im = hopper()
type_repr = repr(type(im.getim()))
if py3:
self.assertIn("PyCapsule", type_repr)
self.assertIsInstance(im.im.id, int)

View File

@ -6,7 +6,7 @@ from .helper import PillowTestCase, hopper
class TestImageMode(PillowTestCase):
def test_sanity(self):
im = hopper()
with hopper() as im:
im.mode
from PIL import ImageMode

View File

@ -1,18 +1,21 @@
from __future__ import division, print_function
import unittest
from contextlib import contextmanager
from PIL import Image, ImageDraw
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
class TestImagingResampleVulnerability(PillowTestCase):
# see https://github.com/python-pillow/Pillow/issues/1710
def test_overflow(self):
im = hopper("L")
xsize = 0x100000008 // 4
ysize = 1000 # unimportant
size_too_large = 0x100000008 // 4
size_normal = 1000 # unimportant
for xsize, ysize in (
(size_too_large, size_normal),
(size_normal, size_too_large),
):
with self.assertRaises(MemoryError):
# any resampling filter will do here
im.im.resize((xsize, ysize), Image.BILINEAR)

View File

@ -148,5 +148,5 @@ class TestImageResize(PillowTestCase):
resize(mode, (188, 214))
# Test unknown resampling filter
im = hopper()
with hopper() as im:
self.assertRaises(ValueError, im.resize, (10, 10), "unknown")

View File

@ -39,12 +39,12 @@ class TestImageThumbnail(PillowTestCase):
def test_no_resize(self):
# Check that draft() can resize the image to the destination size
im = Image.open("Tests/images/hopper.jpg")
with Image.open("Tests/images/hopper.jpg") as im:
im.draft(None, (64, 64))
self.assertEqual(im.size, (64, 64))
# Test thumbnail(), where only draft() is necessary to resize the image
im = Image.open("Tests/images/hopper.jpg")
with Image.open("Tests/images/hopper.jpg") as im:
im.thumbnail((64, 64))
self.assert_image(im, im.mode, (64, 64))

View File

@ -1,14 +1,12 @@
import math
from PIL import Image
from PIL import Image, ImageTransform
from .helper import PillowTestCase, hopper
class TestImageTransform(PillowTestCase):
def test_sanity(self):
from PIL import ImageTransform
im = Image.new("L", (100, 100))
seq = tuple(range(10))
@ -22,6 +20,16 @@ class TestImageTransform(PillowTestCase):
transform = ImageTransform.MeshTransform([(seq[:4], seq[:8])])
im.transform((100, 100), transform)
def test_info(self):
comment = b"File written by Adobe Photoshop\xa8 4.0"
im = Image.open("Tests/images/hopper.gif")
self.assertEqual(im.info["comment"], comment)
transform = ImageTransform.ExtentTransform((0, 0, 0, 0))
new_im = im.transform((100, 100), transform)
self.assertEqual(new_im.info["comment"], comment)
def test_extent(self):
im = hopper("RGB")
(w, h) = im.size
@ -156,11 +164,11 @@ class TestImageTransform(PillowTestCase):
self.test_mesh()
def test_missing_method_data(self):
im = hopper()
with hopper() as im:
self.assertRaises(ValueError, im.transform, (100, 100), None)
def test_unknown_resampling_filter(self):
im = hopper()
with hopper() as im:
(w, h) = im.size
for resample in (Image.BOX, "unknown"):
self.assertRaises(

Some files were not shown because too many files have changed in this diff Show More