Merge branch 'master' into gha-cache

This commit is contained in:
Andrew Murray 2019-11-29 19:44:56 +11:00 committed by GitHub
commit 9f972cdf4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
206 changed files with 809 additions and 1820 deletions

View File

@ -40,11 +40,6 @@ install:
- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\ - xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images - xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
- cd c:\pillow\winbuild\ - cd c:\pillow\winbuild\
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy2")
{
c:\pillow\winbuild\appveyor_install_pypy2.cmd
}
- ps: | - ps: |
if ($env:PYTHON -eq "c:/vp/pypy3") if ($env:PYTHON -eq "c:/vp/pypy3")
{ {
@ -61,6 +56,9 @@ install:
c:\pillow\winbuild\build_deps.cmd c:\pillow\winbuild\build_deps.cmd
$host.SetShouldExit(0) $host.SetShouldExit(0)
} }
- curl -fsSL -o gs950.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs950/gs950w32.exe
- gs950.exe /S
- path %path%;C:\Program Files (x86)\gs\gs9.50\bin
build_script: build_script:
- ps: | - ps: |

View File

@ -9,14 +9,14 @@ Please send a pull request to the master branch. Please include [documentation](
- Fork the Pillow repository. - Fork the Pillow repository.
- Create a branch from master. - Create a branch from master.
- Develop bug fixes, features, tests, etc. - 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. - Create a pull request to pull the changes from your branch to the Pillow master.
### Guidelines ### Guidelines
- Separate code commits from reformatting commits. - Separate code commits from reformatting commits.
- Provide tests for any newly added code. - 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. - When committing only documentation changes please include [ci skip] in the commit message to avoid running tests on Travis-CI and AppVeyor.
## Reporting Issues ## Reporting Issues

View File

@ -9,7 +9,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.5", "3.6", "3.7"] python-version: ["3.5", "3.6", "3.7", "3.8", "pypy3.6"]
architecture: ["x86", "x64"] architecture: ["x86", "x64"]
include: include:
- architecture: "x86" - architecture: "x86"
@ -31,6 +31,11 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions/checkout@v1
with:
repository: python-pillow/pillow-depends
ref: master
- name: Cache - name: Cache
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
@ -73,24 +78,18 @@ jobs:
- name: Fetch dependencies - name: Fetch dependencies
run: | 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 ..\pillow-depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\"
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"
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 ..\pillow-depends\gs950w32.exe /S
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"
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 $env:PYTHON=$env:pythonLocation
curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/master.zip xcopy ..\pillow-depends\*.zip $env:GITHUB_WORKSPACE\winbuild\
7z x pillow-depends.zip -oc:\ xcopy ..\pillow-depends\*.tar.gz $env:GITHUB_WORKSPACE\winbuild\
mv c:\pillow-depends-master c:\pillow-depends xcopy /s ..\pillow-depends\test_images\* $env:GITHUB_WORKSPACE\tests\images\
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/ cd $env:GITHUB_WORKSPACE/winbuild/
python.exe $env:GITHUB_WORKSPACE\winbuild\build_dep.py python.exe $env:GITHUB_WORKSPACE\winbuild\build_dep.py
env: env:
@ -263,7 +262,6 @@ jobs:
# for Raqm # for Raqm
- name: Build dependencies / HarfBuzz - name: Build dependencies / HarfBuzz
if: "!contains(matrix.python-version, 'pypy')"
run: | run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32 set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
@ -284,7 +282,6 @@ jobs:
# for Raqm # for Raqm
- name: Build dependencies / FriBidi - name: Build dependencies / FriBidi
if: "!contains(matrix.python-version, 'pypy')"
run: | run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32 set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
@ -302,9 +299,7 @@ jobs:
copy /Y /B *.lib %INCLIB% copy /Y /B *.lib %INCLIB%
shell: cmd shell: cmd
# failing with PyPy3
- name: Build dependencies / Raqm - name: Build dependencies / Raqm
if: "!contains(matrix.python-version, 'pypy')"
run: | run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32 set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
@ -334,6 +329,7 @@ jobs:
set LIB=%INCLIB%;%PYTHON%\tcl set LIB=%INCLIB%;%PYTHON%\tcl
set INCLUDE=%INCLIB%;%GITHUB_WORKSPACE%\depends\tcl86\include;%INCLUDE% 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 }} 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 DISTUTILS_USE_SDK=1
set py_vcruntime_redist=true set py_vcruntime_redist=true
%PYTHON%\python.exe setup.py build_ext install %PYTHON%\python.exe setup.py build_ext install

View File

@ -91,5 +91,6 @@ jobs:
run: | run: |
.travis/after_success.sh .travis/after_success.sh
env: env:
MATRIX_OS: ${{ matrix.os }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

View File

@ -6,8 +6,8 @@ notifications:
irc: "chat.freenode.net#pil" irc: "chat.freenode.net#pil"
# Run fast lint first to get fast feedback. # Run fast lint first to get fast feedback.
# Run slow PyPy* next, to give them a headstart and reduce waiting time. # Run slow PyPy next, to give it a headstart and reduce waiting time.
# Run latest 3.x and 2.x next, to get quick compatibility results. # Run latest 3.x next, to get quick compatibility results.
# Then run the remainder, with fastest Docker jobs last. # Then run the remainder, with fastest Docker jobs last.
matrix: matrix:

View File

@ -1,7 +1,12 @@
#!/bin/bash #!/bin/bash
# gather the coverage data # gather the coverage data
sudo apt-get -qq install lcov if [[ "$MATRIX_OS" == "macOS-latest" ]]; then
brew install lcov
else
sudo apt-get -qq install lcov
fi
lcov --capture --directory . -b . --output-file coverage.info lcov --capture --directory . -b . --output-file coverage.info
# filter to remove system headers # filter to remove system headers
lcov --remove coverage.info '/usr/*' -o coverage.filtered.info lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
@ -11,16 +16,12 @@ coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
coverage report coverage report
pip install codecov pip install codecov
if [[ $TRAVIS_PYTHON_VERSION != "2.7_with_system_site_packages" ]]; then pip install coveralls-merge
# Not working here. Just skip it, it's being removed soon. coveralls-merge coverage.c.json
pip install coveralls-merge
coveralls-merge coverage.c.json
fi
codecov 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. # 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-install.sh
depends/diffcover-run.sh depends/diffcover-run.sh
fi fi

View File

@ -20,8 +20,8 @@ if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
pip install pyqt5 pip install pyqt5
fi fi
# docs only on Python 2.7 # docs only on Python 3.7
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then pip install -r requirements.txt ; fi
# webp # webp
pushd depends && ./install_webp.sh && popd pushd depends && ./install_webp.sh && popd

View File

@ -5,4 +5,4 @@ set -e
python -m pytest -v -x --cov PIL --cov-report term Tests python -m pytest -v -x --cov PIL --cov-report term Tests
# Docs # Docs
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make doccheck; fi if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then make doccheck; fi

View File

@ -5,6 +5,15 @@ Changelog (Pillow)
7.0.0 (unreleased) 7.0.0 (unreleased)
------------------ ------------------
- Drop support for EOL Python 2.7 #4109
[hugovk, radarhere, jdufresne]
- Added UnidentifiedImageError #4182
[radarhere, hugovk]
- Remove deprecated __version__ from plugins #4197
[hugovk, radarhere]
- Fixed freeing unallocated pointer when resizing with height too large #4116 - Fixed freeing unallocated pointer when resizing with height too large #4116
[radarhere] [radarhere]
@ -14,7 +23,7 @@ Changelog (Pillow)
- Corrected DdsImagePlugin setting info gamma #4171 - Corrected DdsImagePlugin setting info gamma #4171
[radarhere] [radarhere]
- Depends: Update libtiff to 4.1.0 #4195 - Depends: Update libtiff to 4.1.0 #4195, Tk Tcl to 8.6.10 #4229
[radarhere] [radarhere]
- Improve handling of file resources #3577 - Improve handling of file resources #3577

View File

@ -3,7 +3,7 @@
.DEFAULT_GOAL := release-test .DEFAULT_GOAL := release-test
clean: clean:
python setup.py clean python3 setup.py clean
rm src/PIL/*.so || true rm src/PIL/*.so || true
rm -r build || true rm -r build || true
find . -name __pycache__ | xargs rm -r || true find . -name __pycache__ | xargs rm -r || true
@ -15,8 +15,8 @@ co:
done done
coverage: coverage:
python selftest.py python3 selftest.py
python setup.py test python3 setup.py test
rm -r htmlcov || true rm -r htmlcov || true
coverage report coverage report
@ -30,7 +30,7 @@ doccheck:
$(MAKE) -C docs linkcheck || true $(MAKE) -C docs linkcheck || true
docserve: docserve:
cd docs/_build/html && python -mSimpleHTTPServer 2> /dev/null& cd docs/_build/html && python3 -mSimpleHTTPServer 2> /dev/null&
help: help:
@echo "Welcome to Pillow development. Please use \`make <target>\` where <target> is one of" @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" @echo " upload-test build and upload sdists to test.pythonpackages.com"
inplace: clean inplace: clean
python setup.py develop build_ext --inplace python3 setup.py develop build_ext --inplace
install: install:
python setup.py install python3 setup.py install
python selftest.py python3 selftest.py
install-coverage: install-coverage:
CFLAGS="-coverage" python setup.py build_ext install CFLAGS="-coverage" python3 setup.py build_ext install
python selftest.py python3 selftest.py
debug: debug:
# make a debug version if we don't have a -dbg python. Leaves in symbols # 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 # for our stuff, kills optimization, and redirects to dev null so we
# see any build failures. # see any build failures.
make clean > /dev/null 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: install-req:
pip install -r requirements.txt pip install -r requirements.txt
@ -76,17 +76,17 @@ install-venv:
release-test: release-test:
$(MAKE) install-req $(MAKE) install-req
python setup.py develop python3 setup.py develop
python selftest.py python3 selftest.py
python -m pytest Tests python3 -m pytest Tests
python setup.py install python3 setup.py install
python -m pytest -qq python3 -m pytest -qq
check-manifest check-manifest
pyroma . pyroma .
viewdoc viewdoc
sdist: sdist:
python setup.py sdist --format=gztar python3 setup.py sdist --format=gztar
test: test:
pytest -qq pytest -qq
@ -97,10 +97,10 @@ upload-test:
# username: # username:
# password: # password:
# repository = http://test.pythonpackages.com # repository = http://test.pythonpackages.com
python setup.py sdist --format=gztar upload -r test python3 setup.py sdist --format=gztar upload -r test
upload: upload:
python setup.py sdist --format=gztar upload python3 setup.py sdist --format=gztar upload
readme: readme:
viewdoc viewdoc

View File

@ -1,8 +1,9 @@
import time import time
import unittest
from PIL import PyAccess 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. # Not running this test by default. No DOS against Travis CI.

View File

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

View File

@ -1,10 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
import unittest
from __future__ import division
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_win32, unittest from .helper import PillowTestCase, is_win32
min_iterations = 100 min_iterations = 100
max_iterations = 10000 max_iterations = 10000

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO from io import BytesIO
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_win32, unittest from .helper import PillowTestCase, is_win32
# Limits for testing the leak # Limits for testing the leak
mem_limit = 1024 * 1048576 mem_limit = 1024 * 1048576

View File

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

View File

@ -1,6 +1,7 @@
import unittest
from io import BytesIO from io import BytesIO
from .helper import PillowTestCase, hopper, is_win32, unittest from .helper import PillowTestCase, hopper, is_win32
iterations = 5000 iterations = 5000

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
""" """
Helper functions. Helper functions.
""" """
from __future__ import print_function
import logging import logging
import os import os
@ -12,7 +11,6 @@ import unittest
from io import BytesIO from io import BytesIO
from PIL import Image, ImageMath from PIL import Image, ImageMath
from PIL._util import py3
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -76,10 +74,13 @@ class PillowTestCase(unittest.TestCase):
def assert_deep_equal(self, a, b, msg=None): def assert_deep_equal(self, a, b, msg=None):
try: try:
self.assertEqual( 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( 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: except Exception:
self.assertEqual(a, b, msg) self.assertEqual(a, b, msg)
@ -87,20 +88,24 @@ class PillowTestCase(unittest.TestCase):
def assert_image(self, im, mode, size, msg=None): def assert_image(self, im, mode, size, msg=None):
if mode is not None: if mode is not None:
self.assertEqual( 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: if size is not None:
self.assertEqual( 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): def assert_image_equal(self, a, b, msg=None):
self.assertEqual( 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( 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 a.tobytes() != b.tobytes():
if HAS_UPLOADER: if HAS_UPLOADER:
@ -121,10 +126,10 @@ class PillowTestCase(unittest.TestCase):
def assert_image_similar(self, a, b, epsilon, msg=None): def assert_image_similar(self, a, b, epsilon, msg=None):
epsilon = float(epsilon) epsilon = float(epsilon)
self.assertEqual( 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( 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) a, b = convert_to_comparable(a, b)
@ -216,12 +221,12 @@ class PillowTestCase(unittest.TestCase):
def open_withImagemagick(self, f): def open_withImagemagick(self, f):
if not imagemagick_available(): if not imagemagick_available():
raise IOError() raise OSError()
outfile = self.tempfile("temp.png") outfile = self.tempfile("temp.png")
if command_succeeds([IMCONVERT, f, outfile]): if command_succeeds([IMCONVERT, f, outfile]):
return Image.open(outfile) return Image.open(outfile)
raise IOError() raise OSError()
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS") @unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@ -264,11 +269,6 @@ class PillowLeakTestCase(PillowTestCase):
# helpers # helpers
if not py3:
# Remove DeprecationWarning in Python 3
PillowTestCase.assertRaisesRegex = PillowTestCase.assertRaisesRegexp
PillowTestCase.assertRegex = PillowTestCase.assertRegexpMatches
def fromstring(data): def fromstring(data):
return Image.open(BytesIO(data)) return Image.open(BytesIO(data))
@ -306,11 +306,10 @@ def command_succeeds(cmd):
Runs the command, which must be a list of strings. Returns True if the 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. command succeeds, or False if an OSError was raised by subprocess.Popen.
""" """
with open(os.devnull, "wb") as f: try:
try: subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT) except OSError:
except OSError: return False
return False
return True return True
@ -373,7 +372,7 @@ def distro():
return line.strip().split("=")[1] return line.strip().split("=")[1]
class cached_property(object): class cached_property:
def __init__(self, func): def __init__(self, func):
self.func = func self.func = func

View File

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

View File

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

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import os import os
from PIL import Image from PIL import Image
@ -109,4 +107,4 @@ class TestBmpReference(PillowTestCase):
os.path.join(base, "g", "pal4rle.bmp"), os.path.join(base, "g", "pal4rle.bmp"),
) )
if f not in unsupported: 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 array import array
from PIL import Image, ImageFilter from PIL import Image, ImageFilter
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
try: try:
import numpy import numpy

View File

@ -1,10 +1,9 @@
from __future__ import division, print_function
import sys import sys
import unittest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_pypy, unittest from .helper import PillowTestCase, is_pypy
class TestCoreStats(PillowTestCase): class TestCoreStats(PillowTestCase):

View File

@ -1,10 +1,9 @@
from __future__ import unicode_literals
import io import io
import unittest
from PIL import features from PIL import features
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
try: try:
from PIL import _webp from PIL import _webp

View File

@ -1,8 +1,9 @@
import io import io
import unittest
from PIL import EpsImagePlugin, Image from PIL import EpsImagePlugin, Image
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript() HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
@ -91,7 +92,7 @@ class TestFileEps(PillowTestCase):
def test_iobase_object(self): def test_iobase_object(self):
# issue 479 # issue 479
with Image.open(file1) as image1: with Image.open(file1) as image1:
with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh: with open(self.tempfile("temp_iobase.eps"), "wb") as fh:
image1.save(fh, "EPS") image1.save(fh, "EPS")
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available") @unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")

View File

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

View File

@ -1,4 +1,4 @@
from PIL import GdImageFile from PIL import GdImageFile, UnidentifiedImageError
from .helper import PillowTestCase from .helper import PillowTestCase
@ -17,4 +17,4 @@ class TestFileGd(PillowTestCase):
def test_invalid_file(self): def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg" 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 io import BytesIO
from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette
from .helper import PillowTestCase, hopper, is_pypy, netpbm_available, unittest from .helper import PillowTestCase, hopper, is_pypy, netpbm_available
try: try:
from PIL import _webp from PIL import _webp
@ -87,9 +88,7 @@ class TestFileGif(PillowTestCase):
def check(colors, size, expected_palette_length): def check(colors, size, expected_palette_length):
# make an image with empty colors in the start of the palette range # make an image with empty colors in the start of the palette range
im = Image.frombytes( im = Image.frombytes(
"P", "P", (colors, colors), bytes(range(256 - colors, 256)) * colors
(colors, colors),
bytes(bytearray(range(256 - colors, 256)) * colors),
) )
im = im.resize((size, size)) im = im.resize((size, size))
outfile = BytesIO() outfile = BytesIO()
@ -119,7 +118,7 @@ class TestFileGif(PillowTestCase):
check(256, 511, 256) check(256, 511, 256)
def test_optimize_full_l(self): 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() test_file = BytesIO()
im.save(test_file, "GIF", optimize=True) im.save(test_file, "GIF", optimize=True)
self.assertEqual(im.mode, "L") self.assertEqual(im.mode, "L")
@ -632,8 +631,7 @@ class TestFileGif(PillowTestCase):
# Tests appending using a generator # Tests appending using a generator
def imGenerator(ims): def imGenerator(ims):
for im in ims: yield from ims
yield im
im.save(out, save_all=True, append_images=imGenerator(ims)) im.save(out, save_all=True, append_images=imGenerator(ims))
@ -655,7 +653,7 @@ class TestFileGif(PillowTestCase):
# that's > 128 items where the transparent color is actually # that's > 128 items where the transparent color is actually
# the top palette entry to trigger the bug. # 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) palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
im = Image.new("L", (253, 1)) im = Image.new("L", (253, 1))
@ -703,7 +701,7 @@ class TestFileGif(PillowTestCase):
im = hopper("P") im = hopper("P")
im_l = Image.frombytes("L", im.size, im.tobytes()) im_l = Image.frombytes("L", im.size, im.tobytes())
palette = bytes(bytearray(im.getpalette())) palette = bytes(im.getpalette())
out = self.tempfile("temp.gif") out = self.tempfile("temp.gif")
im_l.save(out, palette=palette) im_l.save(out, palette=palette)
@ -718,7 +716,7 @@ class TestFileGif(PillowTestCase):
# Forcing a non-straight grayscale palette. # Forcing a non-straight grayscale palette.
im = hopper("P") 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") out = self.tempfile("temp.gif")
im.save(out, palette=palette) im.save(out, palette=palette)
@ -759,7 +757,7 @@ class TestFileGif(PillowTestCase):
im.putpalette(ImagePalette.ImagePalette("RGB")) im.putpalette(ImagePalette.ImagePalette("RGB"))
im.info = {"background": 0} 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 GifImagePlugin._FORCE_OPTIMIZE = True
try: try:

View File

@ -1,9 +1,10 @@
import io import io
import sys import sys
import unittest
from PIL import IcnsImagePlugin, Image from PIL import IcnsImagePlugin, Image
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
# sample icon file # sample icon file
TEST_FILE = "Tests/images/pillow.icns" TEST_FILE = "Tests/images/pillow.icns"

View File

@ -1,3 +1,6 @@
import sys
from io import StringIO
from PIL import Image, IptcImagePlugin from PIL import Image, IptcImagePlugin
from .helper import PillowTestCase, hopper from .helper import PillowTestCase, hopper
@ -52,12 +55,6 @@ class TestFileIptc(PillowTestCase):
# Arrange # Arrange
c = b"abc" c = b"abc"
# Temporarily redirect stdout # Temporarily redirect stdout
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import sys
old_stdout = sys.stdout old_stdout = sys.stdout
sys.stdout = mystdout = StringIO() sys.stdout = mystdout = StringIO()

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import base64 import base64
import distutils.version import distutils.version
import io import io
@ -10,7 +8,6 @@ from collections import namedtuple
from ctypes import c_float from ctypes import c_float
from PIL import Image, TiffImagePlugin, TiffTags, features from PIL import Image, TiffImagePlugin, TiffTags, features
from PIL._util import py3
from .helper import PillowTestCase, hopper from .helper import PillowTestCase, hopper
@ -263,7 +260,6 @@ class TestFileLibTiff(LibTiffTestCase):
tc(4.25, TiffTags.FLOAT, True), tc(4.25, TiffTags.FLOAT, True),
tc(4.25, TiffTags.DOUBLE, True), tc(4.25, TiffTags.DOUBLE, True),
tc("custom tag value", TiffTags.ASCII, 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(b"custom tag value", TiffTags.BYTE, True),
tc((4, 5, 6), TiffTags.SHORT, True), tc((4, 5, 6), TiffTags.SHORT, True),
tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True), tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
@ -361,12 +357,8 @@ class TestFileLibTiff(LibTiffTestCase):
b = im.tobytes() b = im.tobytes()
# Bytes are in image native order (little endian) # Bytes are in image native order (little endian)
if py3: self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[0], ord(b"\xe0")) self.assertEqual(b[1], ord(b"\x01"))
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 = self.tempfile("temp.tif")
# out = "temp.le.tif" # out = "temp.le.tif"
@ -387,12 +379,8 @@ class TestFileLibTiff(LibTiffTestCase):
b = im.tobytes() b = im.tobytes()
# Bytes are in image native order (big endian) # Bytes are in image native order (big endian)
if py3: self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[0], ord(b"\x01")) self.assertEqual(b[1], ord(b"\xe0"))
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") out = self.tempfile("temp.tif")
im.save(out) im.save(out)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImagePalette, features from PIL import Image, ImagePalette, features
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
try: try:
from PIL import MicImagePlugin from PIL import MicImagePlugin

View File

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

View File

@ -99,8 +99,7 @@ class TestFilePdf(PillowTestCase):
# Test appending using a generator # Test appending using a generator
def imGenerator(ims): def imGenerator(ims):
for im in ims: yield from ims
yield im
im.save(outfile, save_all=True, append_images=imGenerator(ims)) im.save(outfile, save_all=True, append_images=imGenerator(ims))
@ -163,13 +162,10 @@ class TestFilePdf(PillowTestCase):
def test_pdf_append_fails_on_nonexistent_file(self): def test_pdf_append_fails_on_nonexistent_file(self):
im = hopper("RGB") im = hopper("RGB")
temp_dir = tempfile.mkdtemp() with tempfile.TemporaryDirectory() as temp_dir:
try:
self.assertRaises( self.assertRaises(
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
) )
finally:
os.rmdir(temp_dir)
def check_pdf_pages_consistency(self, pdf): def check_pdf_pages_consistency(self, pdf):
pages_info = pdf.read_indirect(pdf.pages_ref) pages_info = pdf.read_indirect(pdf.pages_ref)
@ -207,7 +203,7 @@ class TestFilePdf(PillowTestCase):
# append some info # append some info
pdf.info.Title = "abc" pdf.info.Title = "abc"
pdf.info.Author = "def" pdf.info.Author = "def"
pdf.info.Subject = u"ghi\uABCD" pdf.info.Subject = "ghi\uABCD"
pdf.info.Keywords = "qw)e\\r(ty" pdf.info.Keywords = "qw)e\\r(ty"
pdf.info.Creator = "hopper()" pdf.info.Creator = "hopper()"
pdf.start_writing() pdf.start_writing()
@ -235,7 +231,7 @@ class TestFilePdf(PillowTestCase):
self.assertEqual(pdf.info.Title, "abc") self.assertEqual(pdf.info.Title, "abc")
self.assertEqual(pdf.info.Producer, "PdfParser") self.assertEqual(pdf.info.Producer, "PdfParser")
self.assertEqual(pdf.info.Keywords, "qw)e\\r(ty") 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"CreationDate", pdf.info)
self.assertIn(b"ModDate", pdf.info) self.assertIn(b"ModDate", pdf.info)
self.check_pdf_pages_consistency(pdf) self.check_pdf_pages_consistency(pdf)

View File

@ -1,10 +1,10 @@
import unittest
import zlib import zlib
from io import BytesIO from io import BytesIO
from PIL import Image, ImageFile, PngImagePlugin from PIL import Image, ImageFile, PngImagePlugin
from PIL._util import py3
from .helper import PillowLeakTestCase, PillowTestCase, hopper, is_win32, unittest from .helper import PillowLeakTestCase, PillowTestCase, hopper, is_win32
try: try:
from PIL import _webp from PIL import _webp
@ -448,9 +448,7 @@ class TestFilePng(PillowTestCase):
self.assertIsInstance(im.info["Text"], str) self.assertIsInstance(im.info["Text"], str)
def test_unicode_text(self): def test_unicode_text(self):
# Check preservation of non-ASCII characters on Python 3 # Check preservation of non-ASCII characters
# This cannot really be meaningfully tested on Python 2,
# since it didn't preserve charsets to begin with.
def rt_text(value): def rt_text(value):
im = Image.new("RGB", (32, 32)) im = Image.new("RGB", (32, 32))
@ -459,17 +457,11 @@ class TestFilePng(PillowTestCase):
im = roundtrip(im, pnginfo=info) im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"Text": value}) self.assertEqual(im.info, {"Text": value})
if py3: rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1 rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic # CJK:
rt_text( rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
chr(0x4E00) rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
+ chr(0x66F0)
+ chr(0x9FBA) # CJK
+ chr(0x3042)
+ chr(0xAC00)
)
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
def test_scary(self): def test_scary(self):
# Check reading of evil PNG file. For information, see: # Check reading of evil PNG file. For information, see:

View File

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

View File

@ -1,13 +1,13 @@
import logging import logging
import os import os
import unittest
from io import BytesIO from io import BytesIO
import pytest import pytest
from PIL import Image, TiffImagePlugin from PIL import Image, TiffImagePlugin
from PIL._util import py3
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
from .helper import PillowTestCase, hopper, is_pypy, is_win32, unittest from .helper import PillowTestCase, hopper, is_pypy, is_win32
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -198,12 +198,8 @@ class TestFileTiff(PillowTestCase):
b = im.tobytes() b = im.tobytes()
# Bytes are in image native order (little endian) # Bytes are in image native order (little endian)
if py3: self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[0], ord(b"\xe0")) self.assertEqual(b[1], ord(b"\x01"))
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): def test_big_endian(self):
im = Image.open("Tests/images/16bit.MM.cropped.tif") im = Image.open("Tests/images/16bit.MM.cropped.tif")
@ -213,12 +209,8 @@ class TestFileTiff(PillowTestCase):
b = im.tobytes() b = im.tobytes()
# Bytes are in image native order (big endian) # Bytes are in image native order (big endian)
if py3: self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[0], ord(b"\x01")) self.assertEqual(b[1], ord(b"\xe0"))
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): def test_16bit_s(self):
im = Image.open("Tests/images/16bit.s.tif") im = Image.open("Tests/images/16bit.s.tif")
@ -545,8 +537,7 @@ class TestFileTiff(PillowTestCase):
# Test appending using a generator # Test appending using a generator
def imGenerator(ims): def imGenerator(ims):
for im in ims: yield from ims
yield im
mp = BytesIO() mp = BytesIO()
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims)) im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))

View File

@ -161,13 +161,13 @@ class TestFileTiffMetadata(PillowTestCase):
self.assert_deep_equal( self.assert_deep_equal(
original[tag], original[tag],
value, value,
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value), "{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
) )
else: else:
self.assertEqual( self.assertEqual(
original[tag], original[tag],
value, 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(): for tag, value in original.items():

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, WebPImagePlugin from PIL import Image, WebPImagePlugin
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
try: try:
from PIL import _webp from PIL import _webp

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
try: try:
from PIL import _webp from PIL import _webp

View File

@ -91,8 +91,7 @@ class TestFileWebpAnimation(PillowTestCase):
# Tests appending using a generator # Tests appending using a generator
def imGenerator(ims): def imGenerator(ims):
for im in ims: yield from ims
yield im
temp_file2 = self.tempfile("temp_generator.webp") temp_file2 = self.tempfile("temp_generator.webp")
frame1.copy().save( frame1.copy().save(

View File

@ -110,9 +110,9 @@ class TestFileWebpMetadata(PillowTestCase):
if not _webp.HAVE_WEBPANIM: if not _webp.HAVE_WEBPANIM:
self.skipTest("WebP animation support not available") self.skipTest("WebP animation support not available")
iccp_data = "<iccp_data>".encode("utf-8") iccp_data = b"<iccp_data>"
exif_data = "<exif_data>".encode("utf-8") exif_data = b"<exif_data>"
xmp_data = "<xmp_data>".encode("utf-8") xmp_data = b"<xmp_data>"
temp_file = self.tempfile("temp.webp") temp_file = self.tempfile("temp.webp")
frame1 = Image.open("Tests/images/anim_frame1.webp") frame1 = Image.open("Tests/images/anim_frame1.webp")

View File

@ -1,8 +1,8 @@
from __future__ import division import unittest
from PIL import Image, ImageDraw, ImageFont, features from PIL import Image, ImageDraw, ImageFont, features
from .helper import PillowLeakTestCase, is_win32, unittest from .helper import PillowLeakTestCase, is_win32
@unittest.skipIf(is_win32(), "requires Unix or macOS") @unittest.skipIf(is_win32(), "requires Unix or macOS")

View File

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

View File

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

View File

@ -1,11 +1,11 @@
import os import os
import shutil import shutil
import tempfile import tempfile
import unittest
from PIL import Image from PIL import Image, UnidentifiedImageError
from PIL._util import py3
from .helper import PillowTestCase, hopper, is_win32, unittest from .helper import PillowTestCase, hopper, is_win32
class TestImage(PillowTestCase): class TestImage(PillowTestCase):
@ -48,6 +48,9 @@ class TestImage(PillowTestCase):
Image.new(mode, (1, 1)) Image.new(mode, (1, 1))
self.assertEqual(str(e.exception), "unrecognized image mode") self.assertEqual(str(e.exception), "unrecognized image mode")
def test_exception_inheritance(self):
self.assertTrue(issubclass(UnidentifiedImageError, IOError))
def test_sanity(self): def test_sanity(self):
im = Image.new("L", (100, 100)) im = Image.new("L", (100, 100))
@ -80,20 +83,14 @@ class TestImage(PillowTestCase):
im.size = (3, 4) im.size = (3, 4)
def test_invalid_image(self): def test_invalid_image(self):
if py3: import io
import io
im = io.BytesIO(b"") im = io.BytesIO(b"")
else: self.assertRaises(UnidentifiedImageError, Image.open, im)
import StringIO
im = StringIO.StringIO("")
self.assertRaises(IOError, Image.open, im)
def test_bad_mode(self): def test_bad_mode(self):
self.assertRaises(ValueError, Image.open, "filename", "bad mode") self.assertRaises(ValueError, Image.open, "filename", "bad mode")
@unittest.skipUnless(Image.HAS_PATHLIB, "requires pathlib/pathlib2")
def test_pathlib(self): def test_pathlib(self):
from PIL.Image import Path from PIL.Image import Path
@ -113,7 +110,7 @@ class TestImage(PillowTestCase):
def test_fp_name(self): def test_fp_name(self):
temp_file = self.tempfile("temp.jpg") temp_file = self.tempfile("temp.jpg")
class FP(object): class FP:
def write(a, b): def write(a, b):
pass pass
@ -592,11 +589,11 @@ class TestImage(PillowTestCase):
try: try:
im.load() im.load()
self.assertFail() self.assertFail()
except IOError as e: except OSError as e:
self.assertEqual(str(e), "buffer overrun when reading image file") self.assertEqual(str(e), "buffer overrun when reading image file")
class MockEncoder(object): class MockEncoder:
pass pass

View File

@ -2,11 +2,12 @@ import ctypes
import os import os
import subprocess import subprocess
import sys import sys
import unittest
from distutils import ccompiler, sysconfig from distutils import ccompiler, sysconfig
from PIL import Image from PIL import Image
from .helper import PillowTestCase, hopper, is_win32, on_ci, unittest from .helper import PillowTestCase, hopper, is_win32, on_ci
# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2 # CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670 # https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
@ -125,7 +126,7 @@ class TestImageGetPixel(AccessTest):
self.assertEqual( self.assertEqual(
im.getpixel((0, 0)), im.getpixel((0, 0)),
c, 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 # check putpixel negative index
@ -154,7 +155,7 @@ class TestImageGetPixel(AccessTest):
self.assertEqual( self.assertEqual(
im.getpixel((0, 0)), im.getpixel((0, 0)),
c, 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 # check initial color negative index
self.assertEqual( self.assertEqual(
@ -348,12 +349,8 @@ class TestEmbeddable(unittest.TestCase):
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
char *home = "%s"; char *home = "%s";
#if PY_MAJOR_VERSION >= 3
wchar_t *whome = Py_DecodeLocale(home, NULL); wchar_t *whome = Py_DecodeLocale(home, NULL);
Py_SetPythonHome(whome); Py_SetPythonHome(whome);
#else
Py_SetPythonHome(home);
#endif
Py_InitializeEx(0); Py_InitializeEx(0);
Py_DECREF(PyImport_ImportModule("PIL.Image")); Py_DECREF(PyImport_ImportModule("PIL.Image"));
@ -363,9 +360,7 @@ int main(int argc, char* argv[])
Py_DECREF(PyImport_ImportModule("PIL.Image")); Py_DECREF(PyImport_ImportModule("PIL.Image"));
Py_Finalize(); Py_Finalize();
#if PY_MAJOR_VERSION >= 3
PyMem_RawFree(whome); PyMem_RawFree(whome);
#endif
return 0; return 0;
} }

View File

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

View File

@ -6,7 +6,7 @@ from .test_imageqt import PillowQtTestCase
class TestFromQImage(PillowQtTestCase, PillowTestCase): class TestFromQImage(PillowQtTestCase, PillowTestCase):
def setUp(self): def setUp(self):
super(TestFromQImage, self).setUp() super().setUp()
self.files_to_test = [ self.files_to_test = [
hopper(), hopper(),
Image.open("Tests/images/transparent.png"), Image.open("Tests/images/transparent.png"),

View File

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

View File

@ -1,10 +1,9 @@
from __future__ import division, print_function import unittest
from contextlib import contextmanager from contextlib import contextmanager
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
class TestImagingResampleVulnerability(PillowTestCase): class TestImagingResampleVulnerability(PillowTestCase):

View File

@ -1,8 +1,9 @@
import os.path import os.path
import unittest
from PIL import Image, ImageColor, ImageDraw, ImageFont, features from PIL import Image, ImageColor, ImageDraw, ImageFont, features
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
BLACK = (0, 0, 0) BLACK = (0, 0, 0)
WHITE = (255, 255, 255) WHITE = (255, 255, 255)

View File

@ -1,8 +1,9 @@
import os.path import os.path
import unittest
from PIL import Image, ImageDraw2, features from PIL import Image, ImageDraw2, features
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
BLACK = (0, 0, 0) BLACK = (0, 0, 0)
WHITE = (255, 255, 255) WHITE = (255, 255, 255)

View File

@ -35,7 +35,7 @@ class TestImageEnhance(PillowTestCase):
self.assert_image_equal( self.assert_image_equal(
im.getchannel("A"), im.getchannel("A"),
original.getchannel("A"), original.getchannel("A"),
"Diff on %s: %s" % (op, amount), "Diff on {}: {}".format(op, amount),
) )
def test_alpha(self): def test_alpha(self):

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO from io import BytesIO
from PIL import EpsImagePlugin, Image, ImageFile from PIL import EpsImagePlugin, Image, ImageFile
from .helper import PillowTestCase, fromstring, hopper, tostring, unittest from .helper import PillowTestCase, fromstring, hopper, tostring
try: try:
from PIL import _webp from PIL import _webp

View File

@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
import copy import copy
import distutils.version import distutils.version
import os import os
import re import re
import shutil import shutil
import sys import sys
import unittest
from io import BytesIO from io import BytesIO
from PIL import Image, ImageDraw, ImageFont, features from PIL import Image, ImageDraw, ImageFont, features
from .helper import PillowTestCase, is_pypy, is_win32, unittest from .helper import PillowTestCase, is_pypy, is_win32
FONT_PATH = "Tests/fonts/FreeMono.ttf" FONT_PATH = "Tests/fonts/FreeMono.ttf"
FONT_SIZE = 20 FONT_SIZE = 20
@ -20,7 +20,7 @@ HAS_FREETYPE = features.check("freetype2")
HAS_RAQM = features.check("raqm") HAS_RAQM = features.check("raqm")
class SimplePatcher(object): class SimplePatcher:
def __init__(self, parent_obj, attr_name, value): def __init__(self, parent_obj, attr_name, value):
self._parent_obj = parent_obj self._parent_obj = parent_obj
self._attr_name = attr_name self._attr_name = attr_name
@ -462,12 +462,12 @@ class TestImageFont(PillowTestCase):
# issue #2826 # issue #2826
font = ImageFont.load_default() font = ImageFont.load_default()
with self.assertRaises(UnicodeEncodeError): with self.assertRaises(UnicodeEncodeError):
font.getsize(u"") font.getsize("")
@unittest.skipIf(sys.version.startswith("2") or is_pypy(), "requires CPython 3.3+") @unittest.skipIf(is_pypy(), "failing on PyPy")
def test_unicode_extended(self): def test_unicode_extended(self):
# issue #3777 # issue #3777
text = u"A\u278A\U0001F12B" text = "A\u278A\U0001F12B"
target = "Tests/images/unicode_extended.png" target = "Tests/images/unicode_extended.png"
ttf = ImageFont.truetype( ttf = ImageFont.truetype(

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
image_font_installed = True image_font_installed = True
try: try:

View File

@ -1,7 +1,8 @@
# -*- coding: utf-8 -*- import unittest
from PIL import Image, ImageDraw, ImageFont, features from PIL import Image, ImageDraw, ImageFont, features
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
FONT_SIZE = 20 FONT_SIZE = 20
FONT_PATH = "Tests/fonts/DejaVuSans.ttf" FONT_PATH = "Tests/fonts/DejaVuSans.ttf"

View File

@ -1,5 +1,3 @@
from __future__ import print_function
from PIL import Image, ImageMath from PIL import Image, ImageMath
from .helper import PillowTestCase from .helper import PillowTestCase
@ -7,7 +5,7 @@ from .helper import PillowTestCase
def pixel(im): def pixel(im):
if hasattr(im, "im"): if hasattr(im, "im"):
return "%s %r" % (im.mode, im.getpixel((0, 0))) return "{} {!r}".format(im.mode, im.getpixel((0, 0)))
else: else:
if isinstance(im, int): if isinstance(im, int):
return int(im) # hack to deal with booleans return int(im) # hack to deal with booleans

View File

@ -11,7 +11,7 @@ except ImportError:
class TestImageOps(PillowTestCase): class TestImageOps(PillowTestCase):
class Deformer(object): class Deformer:
def getmesh(self, im): def getmesh(self, im):
x, y = im.size x, y = im.size
return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))] return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))]

View File

@ -5,7 +5,7 @@ from .helper import PillowTestCase
class TestImageOpsUsm(PillowTestCase): class TestImageOpsUsm(PillowTestCase):
def setUp(self): def setUp(self):
super(TestImageOpsUsm, self).setUp() super().setUp()
self.im = Image.open("Tests/images/hopper.ppm") self.im = Image.open("Tests/images/hopper.ppm")
self.addCleanup(self.im.close) self.addCleanup(self.im.close)
self.snakes = Image.open("Tests/images/color_snakes.png") self.snakes = Image.open("Tests/images/color_snakes.png")

View File

@ -2,7 +2,6 @@ import array
import struct import struct
from PIL import Image, ImagePath from PIL import Image, ImagePath
from PIL._util import py3
from .helper import PillowTestCase from .helper import PillowTestCase
@ -75,10 +74,7 @@ class TestImagePath(PillowTestCase):
# This fails due to the invalid malloc above, # This fails due to the invalid malloc above,
# and segfaults # and segfaults
for i in range(200000): for i in range(200000):
if py3: x[i] = b"0" * 16
x[i] = b"0" * 16
else:
x[i] = "0" * 16
class evil: class evil:

View File

@ -15,7 +15,7 @@ else:
test_case.skipTest("Qt bindings are not installed") test_case.skipTest("Qt bindings are not installed")
class PillowQtTestCase(object): class PillowQtTestCase:
def setUp(self): def setUp(self):
skip_if_qt_is_not_installed(self) skip_if_qt_is_not_installed(self)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImageShow from PIL import Image, ImageShow
from .helper import PillowTestCase, hopper, is_win32, on_ci, on_github_actions, unittest from .helper import PillowTestCase, hopper, is_win32, on_ci, on_github_actions
class TestImageShow(PillowTestCase): class TestImageShow(PillowTestCase):

View File

@ -1,15 +1,14 @@
from PIL import Image import unittest
from PIL._util import py3
from .helper import PillowTestCase, hopper, unittest from PIL import Image
from .helper import PillowTestCase, hopper
try: try:
from PIL import ImageTk from PIL import ImageTk
if py3: import tkinter as tk
import tkinter as tk
else:
import Tkinter as tk
dir(ImageTk) dir(ImageTk)
HAS_TK = True HAS_TK = True
except (OSError, ImportError): except (OSError, ImportError):

View File

@ -1,6 +1,8 @@
import unittest
from PIL import ImageWin from PIL import ImageWin
from .helper import PillowTestCase, hopper, is_win32, unittest from .helper import PillowTestCase, hopper, is_win32
class TestImageWin(PillowTestCase): class TestImageWin(PillowTestCase):

View File

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

View File

@ -18,7 +18,7 @@ class TestLibPack(PillowTestCase):
if isinstance(data, int): if isinstance(data, int):
data_len = data * len(pixels) data_len = data * len(pixels)
data = bytes(bytearray(range(1, data_len + 1))) data = bytes(range(1, data_len + 1))
self.assertEqual(data, im.tobytes("raw", rawmode)) self.assertEqual(data, im.tobytes("raw", rawmode))
@ -226,7 +226,7 @@ class TestLibUnpack(PillowTestCase):
""" """
if isinstance(data, int): if isinstance(data, int):
data_len = data * len(pixels) data_len = data * len(pixels)
data = bytes(bytearray(range(1, data_len + 1))) data = bytes(range(1, data_len + 1))
im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1) im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1)

View File

@ -1,10 +1,9 @@
from __future__ import print_function
import locale import locale
import unittest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
# ref https://github.com/python-pillow/Pillow/issues/272 # ref https://github.com/python-pillow/Pillow/issues/272
# on windows, in polish locale: # on windows, in polish locale:

View File

@ -1,11 +1,10 @@
from __future__ import unicode_literals
import os import os
import subprocess import subprocess
import sys import sys
import unittest
from unittest import TestCase from unittest import TestCase
from .helper import is_pypy, is_win32, on_github_actions, unittest from .helper import is_pypy, is_win32, on_github_actions
class TestMain(TestCase): class TestMain(TestCase):

View File

@ -1,8 +1,9 @@
import sys import sys
import unittest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, is_win32, unittest from .helper import PillowTestCase, is_win32
try: try:
import numpy import numpy

View File

@ -20,7 +20,11 @@ class TestModeI16(PillowTestCase):
self.assertEqual( self.assertEqual(
p1, p1,
p2, p2,
("got %r from mode %s at %s, expected %r" % (p1, im1.mode, xy, p2)), (
"got {!r} from mode {} at {}, expected {!r}".format(
p1, im1.mode, xy, p2
)
),
) )
def test_basic(self): def test_basic(self):

View File

@ -1,8 +1,8 @@
from __future__ import print_function import unittest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, hopper, unittest from .helper import PillowTestCase, hopper
try: try:
import numpy import numpy

View File

@ -22,7 +22,7 @@ class TestPdfParser(PillowTestCase):
self.assertEqual(encode_text("abc"), b"\xFE\xFF\x00a\x00b\x00c") self.assertEqual(encode_text("abc"), b"\xFE\xFF\x00a\x00b\x00c")
self.assertEqual(decode_text(b"\xFE\xFF\x00a\x00b\x00c"), "abc") self.assertEqual(decode_text(b"\xFE\xFF\x00a\x00b\x00c"), "abc")
self.assertEqual(decode_text(b"abc"), "abc") self.assertEqual(decode_text(b"abc"), "abc")
self.assertEqual(decode_text(b"\x1B a \x1C"), u"\u02D9 a \u02DD") self.assertEqual(decode_text(b"\x1B a \x1C"), "\u02D9 a \u02DD")
def test_indirect_refs(self): def test_indirect_refs(self):
self.assertEqual(IndirectReference(1, 2), IndirectReference(1, 2)) self.assertEqual(IndirectReference(1, 2), IndirectReference(1, 2))

View File

@ -1,5 +1,6 @@
import os import os
import sys import sys
from io import StringIO
from PIL import Image, PSDraw from PIL import Image, PSDraw
@ -47,10 +48,6 @@ class TestPsDraw(PillowTestCase):
def test_stdout(self): def test_stdout(self):
# Temporarily redirect stdout # Temporarily redirect stdout
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
old_stdout = sys.stdout old_stdout = sys.stdout
sys.stdout = mystdout = StringIO() sys.stdout = mystdout = StringIO()

View File

@ -1,6 +1,8 @@
import unittest
from PIL import __version__ from PIL import __version__
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
try: try:
import pyroma import pyroma

View File

@ -57,7 +57,7 @@ if ImageQt.qt_is_installed:
class Example(QWidget): class Example(QWidget):
def __init__(self): def __init__(self):
super(Example, self).__init__() super().__init__()
img = hopper().resize((1000, 1000)) img = hopper().resize((1000, 1000))

View File

@ -1,29 +1,11 @@
import unittest
from PIL import _util from PIL import _util
from .helper import PillowTestCase, unittest from .helper import PillowTestCase
class TestUtil(PillowTestCase): class TestUtil(PillowTestCase):
def test_is_string_type(self):
# Arrange
color = "red"
# Act
it_is = _util.isStringType(color)
# Assert
self.assertTrue(it_is)
def test_is_not_string_type(self):
# Arrange
color = (255, 0, 0)
# Act
it_is_not = _util.isStringType(color)
# Assert
self.assertFalse(it_is_not)
def test_is_path(self): def test_is_path(self):
# Arrange # Arrange
fp = "filename.ext" fp = "filename.ext"

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO from io import BytesIO
from PIL import Image, features from PIL import Image, features
from .helper import PillowLeakTestCase, unittest from .helper import PillowLeakTestCase
test_file = "Tests/images/hopper.webp" test_file = "Tests/images/hopper.webp"

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import io import io
import queue import queue
import sys import sys

View File

@ -1,5 +1,3 @@
from __future__ import print_function
from PIL import Image from PIL import Image

View File

@ -1,43 +0,0 @@
# This is a sample Dockerfile to build Pillow on Alpine Linux
# with all/most of the dependencies working.
#
# Tcl/Tk isn't detecting
# Freetype has different metrics so tests are failing.
# sudo and bash are required for the webp build script.
FROM alpine
USER root
RUN apk --no-cache add python \
build-base \
python-dev \
py-pip \
# Pillow dependencies
jpeg-dev \
zlib-dev \
freetype-dev \
lcms2-dev \
openjpeg-dev \
tiff-dev \
tk-dev \
tcl-dev
# install from pip, without webp
#RUN LIBRARY_PATH=/lib:/usr/lib /bin/sh -c "pip install Pillow"
# install from git, run tests, including webp
RUN apk --no-cache add git \
bash \
sudo
RUN git clone https://github.com/python-pillow/Pillow.git /Pillow
RUN pip install virtualenv && virtualenv /vpy && source /vpy/bin/activate && pip install nose
RUN echo "#!/bin/bash" >> /test && \
echo "source /vpy/bin/activate && cd /Pillow " >> test && \
echo "pushd depends && ./install_webp.sh && ./install_imagequant.sh && popd" >> test && \
echo "LIBRARY_PATH=/lib:/usr/lib make install && make test" >> test
RUN chmod +x /test
CMD ["/test"]

View File

@ -1,18 +0,0 @@
#!/bin/sh
#
# Installs all of the dependencies for Pillow for Debian 8.2
# for both system Pythons 2.7 and 3.4
#
# Also works for Raspbian Jessie
#
sudo apt-get -y install python-dev python-setuptools \
python3-dev python-virtualenv cmake
sudo apt-get -y install libtiff5-dev libjpeg62-turbo-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev \
python-tk python3-tk libharfbuzz-dev libfribidi-dev
./install_openjpeg.sh
./install_imagequant.sh
./install_raqm.sh

View File

@ -1,18 +0,0 @@
#!/bin/sh
#
# Installs all of the dependencies for Pillow for Fedora 23
# for both system Pythons 2.7 and 3.4
#
# note that Fedora does ship packages for Pillow as python-pillow
# this is a workaround for
# "gcc: error: /usr/lib/rpm/redhat/redhat-hardened-cc1: No such file or directory"
# errors when compiling.
sudo dnf install redhat-rpm-config
sudo dnf install python-devel python3-devel python-virtualenv make gcc
sudo dnf install libtiff-devel libjpeg-devel zlib-devel freetype-devel \
lcms2-devel libwebp-devel openjpeg2-devel tkinter python3-tkinter \
tcl-devel tk-devel harfbuzz-devel fribidi-devel libraqm-devel

View File

@ -1,13 +0,0 @@
#!/bin/sh
#
# Installs all of the dependencies for Pillow for Freebsd 10.x
# for both system Pythons 2.7 and 3.4
#
sudo pkg install python2 python3 py27-pip py27-virtualenv wget cmake
# Openjpeg fails badly using the openjpeg package.
# I can't find a python3.4 version of tkinter
sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 harfbuzz fribidi py27-tkinter
./install_raqm_cmake.sh

View File

@ -1,17 +0,0 @@
#!/bin/sh
#
# Installs all of the dependencies for Pillow for Ubuntu 12.04
# for both system Pythons 2.7 and 3.2
#
sudo apt-get -y install python-dev python-setuptools \
python3-dev python-virtualenv cmake
sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev tcl8.5-dev \
tk8.5-dev python-tk python3-tk
./install_openjpeg.sh
./install_webp.sh
./install_imagequant.sh

View File

@ -1,16 +0,0 @@
#!/bin/sh
#
# Installs all of the dependencies for Pillow for Ubuntu 14.04
# for both system Pythons 2.7 and 3.4
#
sudo apt-get update
sudo apt-get -y install python-dev python-setuptools \
python3-dev python-virtualenv cmake
sudo apt-get -y install libtiff5-dev libjpeg8-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev \
python-tk python3-tk libharfbuzz-dev libfribidi-dev
./install_openjpeg.sh
./install_imagequant.sh
./install_raqm.sh

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# #
# Pillow (PIL Fork) documentation build configuration file, created by # Pillow (PIL Fork) documentation build configuration file, created by
# sphinx-quickstart on Sat Apr 4 07:54:11 2015. # sphinx-quickstart on Sat Apr 4 07:54:11 2015.
@ -42,9 +41,9 @@ source_suffix = ".rst"
master_doc = "index" master_doc = "index"
# General information about the project. # General information about the project.
project = u"Pillow (PIL Fork)" project = "Pillow (PIL Fork)"
copyright = u"1995-2011 Fredrik Lundh, 2010-2019 Alex Clark and Contributors" copyright = "1995-2011 Fredrik Lundh, 2010-2019 Alex Clark and Contributors"
author = u"Fredrik Lundh, Alex Clark and Contributors" author = "Fredrik Lundh, Alex Clark and Contributors"
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
@ -220,8 +219,8 @@ latex_documents = [
( (
master_doc, master_doc,
"PillowPILFork.tex", "PillowPILFork.tex",
u"Pillow (PIL Fork) Documentation", "Pillow (PIL Fork) Documentation",
u"Alex Clark", "Alex Clark",
"manual", "manual",
) )
] ]
@ -252,7 +251,7 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
(master_doc, "pillowpilfork", u"Pillow (PIL Fork) Documentation", [author], 1) (master_doc, "pillowpilfork", "Pillow (PIL Fork) Documentation", [author], 1)
] ]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
@ -268,7 +267,7 @@ texinfo_documents = [
( (
master_doc, master_doc,
"PillowPILFork", "PillowPILFork",
u"Pillow (PIL Fork) Documentation", "Pillow (PIL Fork) Documentation",
author, author,
"PillowPILFork", "PillowPILFork",
"Pillow is the friendly PIL fork by Alex Clark and Contributors.", "Pillow is the friendly PIL fork by Alex Clark and Contributors.",

View File

@ -22,31 +22,6 @@ Python 2.7 reaches end-of-life on 2020-01-01.
Pillow 7.0.0 will be released on 2020-01-01 and will drop support for Python 2.7, making Pillow 7.0.0 will be released on 2020-01-01 and will drop support for Python 2.7, making
Pillow 6.x the last series to support Python 2. Pillow 6.x the last series to support Python 2.
PIL.*ImagePlugin.__version__ attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 6.0.0
The version constants of individual plugins have been deprecated and will be removed in
a future version. Use ``PIL.__version__`` instead.
=============================== ================================= ==================================
Deprecated Deprecated Deprecated
=============================== ================================= ==================================
``BmpImagePlugin.__version__`` ``Jpeg2KImagePlugin.__version__`` ``PngImagePlugin.__version__``
``CurImagePlugin.__version__`` ``JpegImagePlugin.__version__`` ``PpmImagePlugin.__version__``
``DcxImagePlugin.__version__`` ``McIdasImagePlugin.__version__`` ``PsdImagePlugin.__version__``
``EpsImagePlugin.__version__`` ``MicImagePlugin.__version__`` ``SgiImagePlugin.__version__``
``FliImagePlugin.__version__`` ``MpegImagePlugin.__version__`` ``SunImagePlugin.__version__``
``FpxImagePlugin.__version__`` ``MpoImagePlugin.__version__`` ``TgaImagePlugin.__version__``
``GdImageFile.__version__`` ``MspImagePlugin.__version__`` ``TiffImagePlugin.__version__``
``GifImagePlugin.__version__`` ``PalmImagePlugin.__version__`` ``WmfImagePlugin.__version__``
``IcoImagePlugin.__version__`` ``PcdImagePlugin.__version__`` ``XbmImagePlugin.__version__``
``ImImagePlugin.__version__`` ``PcxImagePlugin.__version__`` ``XpmImagePlugin.__version__``
``ImtImagePlugin.__version__`` ``PdfImagePlugin.__version__`` ``XVThumbImagePlugin.__version__``
``IptcImagePlugin.__version__`` ``PixarImagePlugin.__version__``
=============================== ================================= ==================================
ImageCms.CmsProfile attributes ImageCms.CmsProfile attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -103,6 +78,31 @@ PILLOW_VERSION constant
``PILLOW_VERSION`` has been removed. Use ``__version__`` instead. ``PILLOW_VERSION`` has been removed. Use ``__version__`` instead.
PIL.*ImagePlugin.__version__ attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 7.0.0.*
The version constants of individual plugins have been removed. Use ``PIL.__version__``
instead.
=============================== ================================= ==================================
Removed Removed Removed
=============================== ================================= ==================================
``BmpImagePlugin.__version__`` ``Jpeg2KImagePlugin.__version__`` ``PngImagePlugin.__version__``
``CurImagePlugin.__version__`` ``JpegImagePlugin.__version__`` ``PpmImagePlugin.__version__``
``DcxImagePlugin.__version__`` ``McIdasImagePlugin.__version__`` ``PsdImagePlugin.__version__``
``EpsImagePlugin.__version__`` ``MicImagePlugin.__version__`` ``SgiImagePlugin.__version__``
``FliImagePlugin.__version__`` ``MpegImagePlugin.__version__`` ``SunImagePlugin.__version__``
``FpxImagePlugin.__version__`` ``MpoImagePlugin.__version__`` ``TgaImagePlugin.__version__``
``GdImageFile.__version__`` ``MspImagePlugin.__version__`` ``TiffImagePlugin.__version__``
``GifImagePlugin.__version__`` ``PalmImagePlugin.__version__`` ``WmfImagePlugin.__version__``
``IcoImagePlugin.__version__`` ``PcdImagePlugin.__version__`` ``XbmImagePlugin.__version__``
``ImImagePlugin.__version__`` ``PcxImagePlugin.__version__`` ``XpmImagePlugin.__version__``
``ImtImagePlugin.__version__`` ``PdfImagePlugin.__version__`` ``XVThumbImagePlugin.__version__``
``IptcImagePlugin.__version__`` ``PixarImagePlugin.__version__``
=============================== ================================= ==================================
PyQt4 and PySide PyQt4 and PySide
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

View File

@ -212,10 +212,10 @@ class DdsImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
magic, header_size = struct.unpack("<II", self.fp.read(8)) magic, header_size = struct.unpack("<II", self.fp.read(8))
if header_size != 124: if header_size != 124:
raise IOError("Unsupported header size %r" % (header_size)) raise OSError("Unsupported header size %r" % (header_size))
header_bytes = self.fp.read(header_size - 4) header_bytes = self.fp.read(header_size - 4)
if len(header_bytes) != 120: if len(header_bytes) != 120:
raise IOError("Incomplete header: %s bytes" % len(header_bytes)) raise OSError("Incomplete header: %s bytes" % len(header_bytes))
header = BytesIO(header_bytes) header = BytesIO(header_bytes)
flags, height, width = struct.unpack("<3I", header.read(12)) flags, height, width = struct.unpack("<3I", header.read(12))
@ -250,7 +250,7 @@ class DXT1Decoder(ImageFile.PyDecoder):
try: try:
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize)) self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
except struct.error: except struct.error:
raise IOError("Truncated DDS file") raise OSError("Truncated DDS file")
return 0, 0 return 0, 0
@ -261,7 +261,7 @@ class DXT5Decoder(ImageFile.PyDecoder):
try: try:
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize)) self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
except struct.error: except struct.error:
raise IOError("Truncated DDS file") raise OSError("Truncated DDS file")
return 0, 0 return 0, 0

View File

@ -18,7 +18,6 @@ in the :py:mod:`~PIL.Image` module::
If successful, this function returns an :py:class:`~PIL.Image.Image` object. If successful, this function returns an :py:class:`~PIL.Image.Image` object.
You can now use instance attributes to examine the file contents:: You can now use instance attributes to examine the file contents::
>>> from __future__ import print_function
>>> print(im.format, im.size, im.mode) >>> print(im.format, im.size, im.mode)
PPM (512, 512) RGB PPM (512, 512) RGB
@ -67,7 +66,6 @@ Convert files to JPEG
:: ::
from __future__ import print_function
import os, sys import os, sys
from PIL import Image from PIL import Image
@ -89,7 +87,6 @@ Create JPEG thumbnails
:: ::
from __future__ import print_function
import os, sys import os, sys
from PIL import Image from PIL import Image
@ -120,7 +117,6 @@ Identify Image Files
:: ::
from __future__ import print_function
import sys import sys
from PIL import Image from PIL import Image

View File

@ -125,10 +125,9 @@ External Libraries
.. note:: .. note::
There are scripts to install the dependencies for some operating There are Dockerfiles in our `Docker images repo
systems included in the ``depends`` directory. Also see the <https://github.com/python-pillow/docker-images>`_ to install the
Dockerfiles in our `docker images repo dependencies for some operating systems.
<https://github.com/python-pillow/docker-images>`_.
Many of Pillow's features require external libraries: Many of Pillow's features require external libraries:

View File

@ -9,6 +9,29 @@ PILLOW_VERSION constant
``PILLOW_VERSION`` has been removed. Use ``__version__`` instead. ``PILLOW_VERSION`` has been removed. Use ``__version__`` instead.
PIL.*ImagePlugin.__version__ attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The version constants of individual plugins have been removed. Use ``PIL.__version__``
instead.
=============================== ================================= ==================================
Removed Removed Removed
=============================== ================================= ==================================
``BmpImagePlugin.__version__`` ``Jpeg2KImagePlugin.__version__`` ``PngImagePlugin.__version__``
``CurImagePlugin.__version__`` ``JpegImagePlugin.__version__`` ``PpmImagePlugin.__version__``
``DcxImagePlugin.__version__`` ``McIdasImagePlugin.__version__`` ``PsdImagePlugin.__version__``
``EpsImagePlugin.__version__`` ``MicImagePlugin.__version__`` ``SgiImagePlugin.__version__``
``FliImagePlugin.__version__`` ``MpegImagePlugin.__version__`` ``SunImagePlugin.__version__``
``FpxImagePlugin.__version__`` ``MpoImagePlugin.__version__`` ``TgaImagePlugin.__version__``
``GdImageFile.__version__`` ``MspImagePlugin.__version__`` ``TiffImagePlugin.__version__``
``GifImagePlugin.__version__`` ``PalmImagePlugin.__version__`` ``WmfImagePlugin.__version__``
``IcoImagePlugin.__version__`` ``PcdImagePlugin.__version__`` ``XbmImagePlugin.__version__``
``ImImagePlugin.__version__`` ``PcxImagePlugin.__version__`` ``XpmImagePlugin.__version__``
``ImtImagePlugin.__version__`` ``PdfImagePlugin.__version__`` ``XVThumbImagePlugin.__version__``
``IptcImagePlugin.__version__`` ``PixarImagePlugin.__version__``
=============================== ================================= ==================================
PyQt4 and PySide PyQt4 and PySide
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
@ -40,11 +63,11 @@ TODO
API Additions API Additions
============= =============
TODO Custom unidentified image error
^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TODO
Pillow will now throw a custom ``UnidentifiedImageError`` when an image cannot be
identified. For backwards compatibility, this will inherit from ``IOError``.
Other Changes Other Changes
============= =============

View File

@ -1,93 +0,0 @@
# A monkey patch of the base distutils.ccompiler to use parallel builds
# Tested on 2.7, looks to be identical to 3.3.
# Only applied on Python 2.7 because otherwise, it conflicts with Python's
# own newly-added support for parallel builds.
from __future__ import print_function
import os
import sys
from distutils.ccompiler import CCompiler
from multiprocessing import Pool, cpu_count
try:
MAX_PROCS = int(os.environ.get("MAX_CONCURRENCY", min(4, cpu_count())))
except NotImplementedError:
MAX_PROCS = None
# hideous monkeypatching. but. but. but.
def _mp_compile_one(tp):
(self, obj, build, cc_args, extra_postargs, pp_opts) = tp
try:
src, ext = build[obj]
except KeyError:
return
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
return
def _mp_compile(
self,
sources,
output_dir=None,
macros=None,
include_dirs=None,
debug=0,
extra_preargs=None,
extra_postargs=None,
depends=None,
):
"""Compile one or more source files.
see distutils.ccompiler.CCompiler.compile for comments.
"""
# A concrete compiler class can either override this method
# entirely or implement _compile().
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
output_dir, macros, include_dirs, sources, depends, extra_postargs
)
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
pool = Pool(MAX_PROCS)
try:
print("Building using %d processes" % pool._processes)
except Exception:
pass
arr = [(self, obj, build, cc_args, extra_postargs, pp_opts) for obj in objects]
pool.map_async(_mp_compile_one, arr)
pool.close()
pool.join()
# Return *all* object filenames, not just the ones we just built.
return objects
def install():
fl_win = sys.platform.startswith("win")
fl_cygwin = sys.platform.startswith("cygwin")
if fl_win or fl_cygwin:
# Windows barfs on multiprocessing installs
print("Single threaded build for Windows")
return
if MAX_PROCS != 1:
# explicitly don't enable if environment says 1 processor
try:
# bug, only enable if we can make a Pool. see issue #790 and
# https://stackoverflow.com/questions/6033599/oserror-38-errno-38-with-multiprocessing
Pool(2)
CCompiler.compile = _mp_compile
except Exception as msg:
print("Exception installing mp_compile, proceeding without: %s" % msg)
else:
print(
"Single threaded build, not installing mp_compile: %s processes" % MAX_PROCS
)
# We monkeypatch Python 2.7
if sys.version_info.major < 3:
install()

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# minimal sanity check # minimal sanity check
from __future__ import print_function
import sys import sys

View File

@ -7,7 +7,6 @@
# Final rating: 10/10 # Final rating: 10/10
# Your cheese is so fresh most people think it's a cream: Mascarpone # Your cheese is so fresh most people think it's a cream: Mascarpone
# ------------------------------ # ------------------------------
from __future__ import print_function
import os import os
import re import re
@ -20,10 +19,6 @@ from distutils.command.build_ext import build_ext
from setuptools import Extension, setup from setuptools import Extension, setup
# monkey patch import hook. Even though flake8 says it's not used, it is.
# comment this out to disable multi threaded builds.
import mp_compile
def get_version(): def get_version():
version_file = "src/PIL/_version.py" version_file = "src/PIL/_version.py"
@ -189,10 +184,10 @@ def _find_library_dirs_ldconfig():
expr = r".* => (.*)" expr = r".* => (.*)"
env = {} env = {}
null = open(os.devnull, "wb")
try: try:
with null: p = subprocess.Popen(
p = subprocess.Popen(args, stderr=null, stdout=subprocess.PIPE, env=env) args, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE, env=env
)
except OSError: # E.g. command not found except OSError: # E.g. command not found
return [] return []
[data, _] = p.communicate() [data, _] = p.communicate()
@ -305,8 +300,7 @@ class pil_build_ext(build_ext):
return getattr(self, feat) is None return getattr(self, feat) is None
def __iter__(self): def __iter__(self):
for x in self.features: yield from self.features
yield x
feature = feature() feature = feature()
@ -334,12 +328,15 @@ class pil_build_ext(build_ext):
if self.debug: if self.debug:
global DEBUG global DEBUG
DEBUG = True DEBUG = True
if sys.version_info.major >= 3 and not self.parallel: if not self.parallel:
# For Python 2.7, we monkeypatch distutils to have parallel # If --parallel (or -j) wasn't specified, we want to reproduce the same
# builds. If --parallel (or -j) wasn't specified, we want to # behavior as before, that is, auto-detect the number of jobs.
# reproduce the same behavior as before, that is, auto-detect the try:
# number of jobs. self.parallel = int(
self.parallel = mp_compile.MAX_PROCS os.environ.get("MAX_CONCURRENCY", min(4, os.cpu_count()))
)
except TypeError:
self.parallel = None
for x in self.feature: for x in self.feature:
if getattr(self, "disable_%s" % x): if getattr(self, "disable_%s" % x):
setattr(self.feature, x, False) setattr(self.feature, x, False)
@ -347,7 +344,7 @@ class pil_build_ext(build_ext):
_dbg("Disabling %s", x) _dbg("Disabling %s", x)
if getattr(self, "enable_%s" % x): if getattr(self, "enable_%s" % x):
raise ValueError( raise ValueError(
"Conflicting options: --enable-%s and --disable-%s" % (x, x) "Conflicting options: --enable-{} and --disable-{}".format(x, x)
) )
if getattr(self, "enable_%s" % x): if getattr(self, "enable_%s" % x):
_dbg("Requiring %s", x) _dbg("Requiring %s", x)
@ -719,7 +716,7 @@ class pil_build_ext(build_ext):
defs.append(("HAVE_LIBTIFF", None)) defs.append(("HAVE_LIBTIFF", None))
if sys.platform == "win32": if sys.platform == "win32":
libs.extend(["kernel32", "user32", "gdi32"]) libs.extend(["kernel32", "user32", "gdi32"])
if struct.unpack("h", "\0\1".encode("ascii"))[0] == 1: if struct.unpack("h", b"\0\1")[0] == 1:
defs.append(("WORDS_BIGENDIAN", None)) defs.append(("WORDS_BIGENDIAN", None))
if sys.platform == "win32" and not (PLATFORM_PYPY or PLATFORM_MINGW): if sys.platform == "win32" and not (PLATFORM_PYPY or PLATFORM_MINGW):
@ -800,7 +797,7 @@ class pil_build_ext(build_ext):
print("-" * 68) print("-" * 68)
print("version Pillow %s" % PILLOW_VERSION) print("version Pillow %s" % PILLOW_VERSION)
v = sys.version.split("[") v = sys.version.split("[")
print("platform %s %s" % (sys.platform, v[0].strip())) print("platform {} {}".format(sys.platform, v[0].strip()))
for v in v[1:]: for v in v[1:]:
print(" [%s" % v.strip()) print(" [%s" % v.strip())
print("-" * 68) print("-" * 68)
@ -823,7 +820,7 @@ class pil_build_ext(build_ext):
version = "" version = ""
if len(option) >= 3 and option[2]: if len(option) >= 3 and option[2]:
version = " (%s)" % option[2] version = " (%s)" % option[2]
print("--- %s support available%s" % (option[1], version)) print("--- {} support available{}".format(option[1], version))
else: else:
print("*** %s support not available" % option[1]) print("*** %s support not available" % option[1])
all = 0 all = 0
@ -868,13 +865,12 @@ try:
classifiers=[ classifiers=[
"Development Status :: 6 - Mature", "Development Status :: 6 - Mature",
"License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)", # noqa: E501 "License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)", # noqa: E501
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Multimedia :: Graphics", "Topic :: Multimedia :: Graphics",
@ -883,7 +879,7 @@ try:
"Topic :: Multimedia :: Graphics :: Graphics Conversion", "Topic :: Multimedia :: Graphics :: Graphics Conversion",
"Topic :: Multimedia :: Graphics :: Viewers", "Topic :: Multimedia :: Graphics :: Viewers",
], ],
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", python_requires=">=3.5",
cmdclass={"build_ext": pil_build_ext}, cmdclass={"build_ext": pil_build_ext},
ext_modules=[Extension("PIL._imaging", ["_imaging.c"])], ext_modules=[Extension("PIL._imaging", ["_imaging.c"])],
include_package_data=True, include_package_data=True,

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