Merge remote-tracking branch 'upstream/master' into formats

This commit is contained in:
nulano 2020-09-04 21:07:34 +02:00
commit a340dc5fd3
221 changed files with 1507 additions and 923 deletions

View File

@ -30,7 +30,10 @@ pip install -U pytest-cov
pip install pyroma
pip install test-image-results
pip install numpy
if [ "$TRAVIS_PYTHON_VERSION" == "3.9-dev" ]; then pip install setuptools==47.3.1 ; fi
# TODO Remove when 3.9-dev includes setuptools 49.3.2+:
if [ "$GHA_PYTHON_VERSION" == "3.9-dev" ]; then pip install -U "setuptools>=49.3.2" ; fi
if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
# arm64, ppc64le, s390x CPUs:
# "ERROR: Could not find a version that satisfies the requirement pyqt5"

View File

@ -2,7 +2,7 @@
set -e
python -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests
python -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests
# Docs
if [ "$TRAVIS_PYTHON_VERSION" == "3.8" ] && [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then

View File

@ -15,5 +15,8 @@ pip install test-image-results
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
pip install numpy
# TODO Remove when 3.9-dev includes setuptools 49.3.2+:
if [ "$GHA_PYTHON_VERSION" == "3.9-dev" ]; then pip install -U "setuptools>=49.3.2" ; fi
# extra test images
pushd depends && ./install_extra_test_images.sh && popd

View File

@ -63,7 +63,12 @@ jobs:
- name: pip install wheel pytest pytest-cov
run: python -m pip install wheel pytest pytest-cov
- name: Prepare dependencies
# TODO Remove when 3.9-dev includes setuptools 49.3.2+:
- name: Upgrade setuptools
if: "contains(matrix.python-version, '3.9-dev')"
run: python -m pip install -U "setuptools>=49.3.2"
- name: Install dependencies
run: |
7z x winbuild\depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\"
Write-Host "::add-path::$env:RUNNER_WORKSPACE\nasm-2.14.02"
@ -72,41 +77,71 @@ jobs:
Write-Host "::add-path::C:\Program Files (x86)\gs\gs9.50\bin"
xcopy /s winbuild\depends\test_images\* Tests\images\
shell: pwsh
& python.exe winbuild\build_prepare.py -v --python=$env:pythonLocation
- name: Cache build
id: build-cache
uses: actions/cache@v2
with:
path: winbuild\build
key:
${{ hashFiles('winbuild\build_prepare.py') }}-${{ hashFiles('.github\workflows\test-windows.yml') }}-${{ env.pythonLocation }}
- name: Prepare build
if: steps.build-cache.outputs.cache-hit != 'true'
run: |
& python.exe winbuild\build_prepare.py -v --python=$env:pythonLocation --srcdir
shell: pwsh
- name: Build dependencies / libjpeg-turbo
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libjpeg.cmd"
- name: Build dependencies / zlib
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_zlib.cmd"
- name: Build dependencies / LibTiff
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libtiff.cmd"
- name: Build dependencies / WebP
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libwebp.cmd"
- name: Build dependencies / FreeType
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_freetype.cmd"
- name: Build dependencies / LCMS2
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_lcms2.cmd"
- name: Build dependencies / OpenJPEG
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_openjpeg.cmd"
# GPL licensed; skip if building wheels
# GPL licensed
- name: Build dependencies / libimagequant
if: "github.event_name != 'push'"
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libimagequant.cmd"
# Raqm dependencies
- name: Build dependencies / HarfBuzz
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_harfbuzz.cmd"
- name: Build dependencies / FriBidi
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_fribidi.cmd"
- name: Build dependencies / Raqm
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libraqm.cmd"
# trim ~150MB x 9
- name: Optimize build cache
if: steps.build-cache.outputs.cache-hit != 'true'
run: rmdir /S /Q winbuild\build\src
shell: cmd
- name: Build Pillow
run: |
& winbuild\build\build_pillow.cmd install
$FLAGS=""
if ('${{ github.event_name }}' -eq 'push') { $FLAGS="--disable-imagequant" }
& winbuild\build\build_pillow.cmd $FLAGS install
& $env:pythonLocation\python.exe selftest.py --installed
shell: pwsh
@ -151,7 +186,7 @@ jobs:
if: "github.event_name == 'push'"
run: |
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ::set-output name=dist::dist-%%a
winbuild\\build\\build_pillow.cmd bdist_wheel"
winbuild\\build\\build_pillow.cmd --disable-imagequant bdist_wheel
shell: cmd
- uses: actions/upload-artifact@v2
@ -169,8 +204,10 @@ jobs:
mingw: ["MINGW32", "MINGW64"]
include:
- mingw: "MINGW32"
name: "MSYS2 MinGW 32-bit"
package: "mingw-w64-i686"
- mingw: "MINGW64"
name: "MSYS2 MinGW 64-bit"
package: "mingw-w64-x86_64"
defaults:
@ -181,7 +218,7 @@ jobs:
CHERE_INVOKING: 1
timeout-minutes: 30
name: MSYS2 ${{ matrix.mingw }}
name: ${{ matrix.name }}
steps:
- uses: actions/checkout@v2
@ -193,23 +230,23 @@ jobs:
- name: Install Dependencies
run: |
pacman -S --noconfirm \
${{ matrix.package }}-python3-cffi \
${{ matrix.package }}-python3-numpy \
${{ matrix.package }}-python3-olefile \
${{ matrix.package }}-python3-pip \
${{ matrix.package }}-python3-setuptools \
${{ matrix.package }}-python3-pyqt5 \
${{ matrix.package }}-python3-pytest \
${{ matrix.package }}-python3-pytest-cov \
${{ matrix.package }}-python3-cffi \
${{ matrix.package }}-python3-olefile \
${{ matrix.package }}-python3-numpy \
${{ matrix.package }}-python3-pyqt5 \
${{ matrix.package }}-python3-numpy \
${{ matrix.package }}-python3-setuptools \
${{ matrix.package }}-freetype \
${{ matrix.package }}-lcms2 \
${{ matrix.package }}-libwebp \
${{ matrix.package }}-libjpeg-turbo \
${{ matrix.package }}-openjpeg2 \
${{ matrix.package }}-libimagequant \
${{ matrix.package }}-libraqm \
${{ matrix.package }}-ghostscript \
${{ matrix.package }}-lcms2 \
${{ matrix.package }}-libimagequant \
${{ matrix.package }}-libjpeg-turbo \
${{ matrix.package }}-libraqm \
${{ matrix.package }}-libtiff \
${{ matrix.package }}-libwebp \
${{ matrix.package }}-openjpeg2 \
subversion
python3 -m pip install pyroma
@ -217,9 +254,7 @@ jobs:
pushd depends && ./install_extra_test_images.sh && popd
- name: Build Pillow
run: |
# libtiff is unable to open files
CFLAGS="-coverage" python3 setup.py build_ext --disable-tiff install
run: CFLAGS="-coverage" python3 setup.py build_ext install
- name: Test Pillow
run: |
@ -231,4 +266,4 @@ jobs:
python3 -m pip install codecov
bash <(curl -s https://codecov.io/bash) -F GHA_Windows
env:
CODECOV_NAME: MSYS2 ${{ matrix.mingw }}
CODECOV_NAME: ${{ matrix.name }}

View File

@ -62,11 +62,15 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')
run: |
.ci/install.sh
env:
GHA_PYTHON_VERSION: ${{ matrix.python-version }}
- name: Install macOS dependencies
if: startsWith(matrix.os, 'macOS')
run: |
.github/workflows/macos-install.sh
env:
GHA_PYTHON_VERSION: ${{ matrix.python-version }}
- name: Build
run: |

View File

@ -1,43 +1,43 @@
repos:
- repo: https://github.com/psf/black
rev: 6bedb5c58a7d8c25aa9509f8217bc24e9797e90d # frozen: 19.10b0
rev: e66be67b9b6811913470f70c28b4d50f94d05b22 # frozen: 20.8b1
hooks:
- id: black
args: ["--target-version", "py35"]
args: ["--target-version", "py36"]
# Only .py files, until https://github.com/psf/black/issues/402 resolved
files: \.py$
types: []
- repo: https://github.com/timothycrosley/isort
rev: 7c29dd9d55161704cfc45998c6f5c2c43d39264b # frozen: 4.3.21
rev: 377d260ffa6f746693f97b46d95025afc4bd8275 # frozen: 5.4.2
hooks:
- id: isort
- repo: https://github.com/asottile/yesqa
rev: b13a51aa54142c59219c764e9f9362c049b439ed # frozen: v1.2.0
rev: 7a009f3ee493c796827ee334f9058b110a0e0db8 # frozen: v1.2.1
hooks:
- id: yesqa
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: ffbd448645bad2e7ca13f96fca5830058d27ccd5 # frozen: v1.1.7
rev: f30f4974a08a6b2f6a1eeaf30a4d501cf909163a # frozen: v1.1.9
hooks:
- id: remove-tabs
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.opt$)
- repo: https://gitlab.com/pycqa/flake8
rev: 735cfe7e1c57a8e05f660ba75de72313005af54a # frozen: 3.8.2
rev: 05f6544aef321e2fee03a1277ce2eef8880fb927 # frozen: 3.8.3
hooks:
- id: flake8
additional_dependencies: [flake8-2020, flake8-implicit-str-concat]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: 0d7d077d6ed5624854f93ac601739c1804ebeb98 # frozen: v1.5.1
rev: eae6397e4c259ed3d057511f6dd5330b92867e62 # frozen: v1.6.0
hooks:
- id: python-check-blanket-noqa
- id: rst-backticks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: ebc15addedad713c86ef18ae9632c88e187dd0af # frozen: v3.1.0
rev: e1668fe86af3810fbca72b8653fe478e66a0afdc # frozen: v3.2.0
hooks:
- id: check-merge-conflict
- id: check-yaml

View File

@ -5,13 +5,43 @@ Changelog (Pillow)
8.0.0 (unreleased)
------------------
- Raise proper TypeError in putpixel #4882
[nulano, hugovk]
- Added writing of subIFDs #4862
[radarhere]
- Fix IFDRational __eq__ bug #4888
[luphord, radarhere]
- Fixed duplicate variable name #4885
[liZe, radarhere]
- Added homebrew zlib include directory #4842
[radarhere]
- Corrected inverted PDF CMYK colors #4866
[radarhere]
- Do not try to close file pointer if file pointer is empty #4823
[radarhere]
- ImageOps.autocontrast: add mask parameter #4843
[navneeth, hugovk]
- Read EXIF data tEXt chunk into info as bytes instead of string #4828
[radarhere]
- Remove long-deprecated Image.py functions #4798
[hugovk, nulano, radarhere]
- Replaced distutils with setuptools #4797, #4809, #4814, #4817, #4829, #4890
[hugovk, radarhere]
- Add MIME type to PsdImagePlugin #4788
[samamorgan]
- Drop support for EOL Python 3.5 #4746
- Drop support for EOL Python 3.5 #4746, #4794
[hugovk, radarhere, nulano]
- Remove ImageCms.CmsProfile attributes deprecated since 3.2.0 #4768

96
README.md Normal file
View File

@ -0,0 +1,96 @@
<p align="center">
<img width="248" height="250" src="https://raw.githubusercontent.com/python-pillow/pillow-logo/master/pillow-logo-248x250.png" alt="Pillow logo">
</p>
# Pillow
## Python Imaging Library (Fork)
Pillow is the friendly PIL fork by [Alex Clark and
Contributors](https://github.com/python-pillow/Pillow/graphs/contributors).
PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
As of 2019, Pillow development is
[supported by Tidelift](https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise).
<table>
<tr>
<th>docs</th>
<td>
<a href="https://pillow.readthedocs.io/?badge=latest"><img
alt="Documentation Status"
src="https://readthedocs.org/projects/pillow/badge/?version=latest"></a>
</td>
</tr>
<tr>
<th>tests</th>
<td>
<a href="https://travis-ci.org/python-pillow/Pillow"><img
alt="Travis CI build status (Linux)"
src="https://img.shields.io/travis/python-pillow/Pillow/master.svg?label=Linux%20build"></a>
<a href="https://travis-ci.org/python-pillow/pillow-wheels"><img
alt="Travis CI build status (macOS)"
src="https://img.shields.io/travis/python-pillow/pillow-wheels/master.svg?label=macOS%20build"></a>
<a href="https://ci.appveyor.com/project/python-pillow/Pillow"><img
alt="AppVeyor CI build status (Windows)"
src="https://img.shields.io/appveyor/build/python-pillow/Pillow/master.svg?label=Windows%20build"></a>
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3ALint"><img
alt="GitHub Actions build status (Lint)"
src="https://github.com/python-pillow/Pillow/workflows/Lint/badge.svg"></a>
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3ATest"><img
alt="GitHub Actions build status (Test Linux and macOS)"
src="https://github.com/python-pillow/Pillow/workflows/Test/badge.svg"></a>
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3A%22Test+Windows%22"><img
alt="GitHub Actions build status (Test Windows)"
src="https://github.com/python-pillow/Pillow/workflows/Test%20Windows/badge.svg"></a>
<a href="https://github.com/python-pillow/Pillow/actions?query=workflow%3A%22Test+Docker%22"><img
alt="GitHub Actions build status (Test Docker)"
src="https://github.com/python-pillow/Pillow/workflows/Test%20Docker/badge.svg"></a>
<a href="https://codecov.io/gh/python-pillow/Pillow"><img
alt="Code coverage"
src="https://codecov.io/gh/python-pillow/Pillow/branch/master/graph/badge.svg"></a>
</td>
</tr>
<tr>
<th>package</th>
<td>
<a href="https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow"><img
alt="Zenodo"
src="https://zenodo.org/badge/17549/python-pillow/Pillow.svg"></a>
<a href="https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=badge"><img
alt="Tidelift"
src="https://tidelift.com/badges/package/pypi/Pillow?style=flat"></a>
<a href="https://pypi.org/project/Pillow/"><img
alt="Newest PyPI version"
src="https://img.shields.io/pypi/v/pillow.svg"></a>
<a href="https://pypi.org/project/Pillow/"><img
alt="Number of PyPI downloads"
src="https://img.shields.io/pypi/dm/pillow.svg"></a>
</td>
</tr>
<tr>
<th>social</th>
<td>
<a href="https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img
alt="Join the chat at https://gitter.im/python-pillow/Pillow"
src="https://badges.gitter.im/python-pillow/Pillow.svg"></a>
<a href="https://twitter.com/PythonPillow"><img
alt="Follow on https://twitter.com/PythonPillow"
src="https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg"></a>
</td>
</tr>
</table>
## More Information
- [Documentation](https://pillow.readthedocs.io/)
- [Installation](https://pillow.readthedocs.io/en/latest/installation.html)
- [Handbook](https://pillow.readthedocs.io/en/latest/handbook/index.html)
- [Contribute](https://github.com/python-pillow/Pillow/blob/master/.github/CONTRIBUTING.md)
- [Issues](https://github.com/python-pillow/Pillow/issues)
- [Pull requests](https://github.com/python-pillow/Pillow/pulls)
- [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst)
- [Pre-fork](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#pre-fork)
## Report a Vulnerability
To report a security vulnerability, please follow the procedure described in the [Tidelift security policy](https://tidelift.com/docs/security).

View File

@ -1,103 +0,0 @@
Pillow
======
Python Imaging Library (Fork)
-----------------------------
Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. As of 2019, Pillow development is `supported by Tidelift <https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise>`_.
.. start-badges
.. list-table::
:stub-columns: 1
* - docs
- |docs|
* - tests
- |linux| |macos| |windows| |gha_lint| |gha| |gha_windows| |gha_docker| |coverage|
* - package
- |zenodo| |tidelift| |version| |downloads|
* - social
- |gitter| |twitter|
.. end-badges
More Information
----------------
- `Documentation <https://pillow.readthedocs.io/>`_
- `Installation <https://pillow.readthedocs.io/en/latest/installation.html>`_
- `Handbook <https://pillow.readthedocs.io/en/latest/handbook/index.html>`_
- `Contribute <https://github.com/python-pillow/Pillow/blob/master/.github/CONTRIBUTING.md>`_
- `Issues <https://github.com/python-pillow/Pillow/issues>`_
- `Pull requests <https://github.com/python-pillow/Pillow/pulls>`_
- `Changelog <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst>`_
- `Pre-fork <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#pre-fork>`_
Report a Vulnerability
----------------------
To report a security vulnerability, please follow the procedure described in the `Tidelift security policy <https://tidelift.com/docs/security>`_.
.. |docs| image:: https://readthedocs.org/projects/pillow/badge/?version=latest
:target: https://pillow.readthedocs.io/?badge=latest
:alt: Documentation Status
.. |linux| image:: https://img.shields.io/travis/python-pillow/Pillow/master.svg?label=Linux%20build
:target: https://travis-ci.org/python-pillow/Pillow
:alt: Travis CI build status (Linux)
.. |macos| image:: https://img.shields.io/travis/python-pillow/pillow-wheels/master.svg?label=macOS%20build
:target: https://travis-ci.org/python-pillow/pillow-wheels
:alt: Travis CI build status (macOS)
.. |windows| image:: https://img.shields.io/appveyor/build/python-pillow/Pillow/master.svg?label=Windows%20build
:target: https://ci.appveyor.com/project/python-pillow/Pillow
:alt: AppVeyor CI build status (Windows)
.. |gha_lint| image:: https://github.com/python-pillow/Pillow/workflows/Lint/badge.svg
:target: https://github.com/python-pillow/Pillow/actions?query=workflow%3ALint
:alt: GitHub Actions build status (Lint)
.. |gha_docker| image:: https://github.com/python-pillow/Pillow/workflows/Test%20Docker/badge.svg
:target: https://github.com/python-pillow/Pillow/actions?query=workflow%3A%22Test+Docker%22
:alt: GitHub Actions build status (Test Docker)
.. |gha| image:: https://github.com/python-pillow/Pillow/workflows/Test/badge.svg
:target: https://github.com/python-pillow/Pillow/actions?query=workflow%3ATest
:alt: GitHub Actions build status (Test Linux and macOS)
.. |gha_windows| image:: https://github.com/python-pillow/Pillow/workflows/Test%20Windows/badge.svg
:target: https://github.com/python-pillow/Pillow/actions?query=workflow%3A%22Test+Windows%22
:alt: GitHub Actions build status (Test Windows)
.. |coverage| image:: https://codecov.io/gh/python-pillow/Pillow/branch/master/graph/badge.svg
:target: https://codecov.io/gh/python-pillow/Pillow
:alt: Code coverage
.. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg
:target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow
.. |tidelift| image:: https://tidelift.com/badges/package/pypi/Pillow?style=flat
:target: https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=badge
.. |version| image:: https://img.shields.io/pypi/v/pillow.svg
:target: https://pypi.org/project/Pillow/
:alt: Latest PyPI version
.. |downloads| image:: https://img.shields.io/pypi/dm/pillow.svg
:target: https://pypi.org/project/Pillow/
:alt: Number of PyPI downloads
.. |gitter| image:: https://badges.gitter.im/python-pillow/Pillow.svg
:target: https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
:alt: Join the chat at https://gitter.im/python-pillow/Pillow
.. |twitter| image:: https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg
:target: https://twitter.com/PythonPillow
:alt: Follow on https://twitter.com/PythonPillow

View File

@ -101,11 +101,7 @@ Released as needed privately to individual vendors for critical security-related
cd pillow-wheels
./update-pillow-tag.sh [[release tag]]
```
* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).
```bash
wget -m -A 'Pillow-<VERSION>-*' \
http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
```
* [ ] Download wheels from the [Pillow Wheel Builder release](https://github.com/python-pillow/pillow-wheels/releases).
## Publicize Release

View File

@ -28,15 +28,17 @@ def timer(func, label, *args):
func(*args)
if time.time() - starttime > 10:
print(
"%s: breaking at %s iterations, %.6f per iteration"
% (label, x + 1, (time.time() - starttime) / (x + 1.0))
"{}: breaking at {} iterations, {:.6f} per iteration".format(
label, x + 1, (time.time() - starttime) / (x + 1.0)
)
)
break
if x == iterations - 1:
endtime = time.time()
print(
"%s: %.4f s %.6f per iteration"
% (label, endtime - starttime, (endtime - starttime) / (x + 1.0))
"{}: {:.4f} s {:.6f} per iteration".format(
label, endtime - starttime, (endtime - starttime) / (x + 1.0)
)
)

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
import pytest
from PIL import Image
from .helper import is_win32
@ -11,7 +12,7 @@ pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
def _get_mem_usage():
from resource import getpagesize, getrusage, RUSAGE_SELF
from resource import RUSAGE_SELF, getpagesize, getrusage
mem = getrusage(RUSAGE_SELF).ru_maxrss
return mem * getpagesize() / 1024 / 1024
@ -25,7 +26,7 @@ def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs):
if i < min_iterations:
mem_limit = mem + 1
continue
msg = "memory usage limit exceeded after %d iterations" % (i + 1)
msg = f"memory usage limit exceeded after {i + 1} iterations"
assert mem <= mem_limit, msg

View File

@ -1,6 +1,7 @@
from io import BytesIO
import pytest
from PIL import Image
from .helper import is_win32, skip_unless_feature
@ -18,7 +19,7 @@ pytestmark = [
def test_leak_load():
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))
@ -28,7 +29,7 @@ def test_leak_load():
def test_leak_save():
from resource import setrlimit, RLIMIT_AS, RLIMIT_STACK
from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit
setrlimit(RLIMIT_STACK, (stack_size, stack_size))
setrlimit(RLIMIT_AS, (mem_limit, mem_limit))

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image

View File

@ -119,10 +119,10 @@ def test_qtables_leak():
def test_exif_leak():
"""
pre patch:
pre patch:
MB
177.1^ #
177.1^ #
| @@@#
| :@@@@@@#
| ::::@@@@@@#
@ -146,10 +146,10 @@ pre patch:
0 11.37
post patch:
post patch:
MB
21.06^ ::::::::::::::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
21.06^ ::::::::::::::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
| ##::: ::::: : ::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
| # ::: ::::: : ::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
| # ::: ::::: : ::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
@ -171,8 +171,7 @@ post patch:
| @ @@@# ::: ::::: : ::::::::::@::::@::::@::::@::::@::::@:::::::::@::::::
0 +----------------------------------------------------------------------->Gi
0 11.33
"""
"""
im = hopper("RGB")
exif = b"12345678" * 4096
@ -183,9 +182,9 @@ post patch:
def test_base_save():
"""
base case:
base case:
MB
20.99^ ::::: :::::::::::::::::::::::::::::::::::::::::::@:::
20.99^ ::::: :::::::::::::::::::::::::::::::::::::::::::@:::
| ##: : ::::::@::::::: :::: :::: : : : : : : :::::::::::: :::@:::
| # : : :: :: @:: :::: :::: :::: : : : : : : :::::::::::: :::@:::
| # : : :: :: @:: :::: :::: :::: : : : : : : :::::::::::: :::@:::
@ -206,8 +205,7 @@ base case:
| :@ @@ @ # : : :: :: @:: :::: :::: :::: : : : : : : :::::::::::: :::@:::
| :@ @@ @ # : : :: :: @:: :::: :::: :::: : : : : : : :::::::::::: :::@:::
0 +----------------------------------------------------------------------->Gi
0 7.882
"""
0 7.882"""
im = hopper("RGB")
for _ in range(iterations):

View File

@ -1,6 +1,7 @@
import sys
import pytest
from PIL import Image
# This test is not run automatically.

View File

@ -1,6 +1,7 @@
import sys
import pytest
from PIL import Image
# This test is not run automatically.

View File

@ -1,11 +1,12 @@
import pytest
from PIL import Image
TEST_FILE = "Tests/images/libtiff_segfault.tif"
def test_libtiff_segfault():
""" This test should not segfault. It will on Pillow <= 3.1.0 and
"""This test should not segfault. It will on Pillow <= 3.1.0 and
libtiff >= 4.0.0
"""

View File

@ -42,8 +42,8 @@ def test_dos_total_memory():
info = PngImagePlugin.PngInfo()
for x in range(64):
info.add_text("t%s" % x, compressed_data, zip=True)
info.add_itxt("i%s" % x, compressed_data, zip=True)
info.add_text(f"t{x}", compressed_data, zip=True)
info.add_itxt(f"i{x}", compressed_data, zip=True)
b = BytesIO()
im.save(b, "PNG", pnginfo=info)

View File

@ -9,4 +9,4 @@ def pytest_report_header(config):
features.pilinfo(out=out, supported_formats=False)
return out.getvalue()
except Exception as e:
return "pytest_report_header failed: %s" % e
return f"pytest_report_header failed: {e}"

View File

@ -6,7 +6,7 @@ if __name__ == "__main__":
# create font data chunk for embedding
font = "Tests/images/courB08"
print(" f._load_pilfont_data(")
print(" # %s" % os.path.basename(font))
print(f" # {os.path.basename(font)}")
print(" BytesIO(base64.decodestring(b'''")
with open(font + ".pil", "rb") as fp:
print(base64.b64encode(fp.read()).decode())

View File

@ -11,6 +11,7 @@ import tempfile
from io import BytesIO
import pytest
from PIL import Image, ImageMath, features
logger = logging.getLogger(__name__)
@ -67,37 +68,31 @@ def convert_to_comparable(a, b):
def assert_deep_equal(a, b, msg=None):
try:
assert len(a) == len(b), msg or "got length {}, expected {}".format(
len(a), len(b)
)
assert len(a) == len(b), msg or f"got length {len(a)}, expected {len(b)}"
except Exception:
assert a == b, msg
def assert_image(im, mode, size, msg=None):
if mode is not None:
assert im.mode == mode, msg or "got mode {!r}, expected {!r}".format(
im.mode, mode
assert im.mode == mode, (
msg or f"got mode {repr(im.mode)}, expected {repr(mode)}"
)
if size is not None:
assert im.size == size, msg or "got size {!r}, expected {!r}".format(
im.size, size
assert im.size == size, (
msg or f"got size {repr(im.size)}, expected {repr(size)}"
)
def assert_image_equal(a, b, msg=None):
assert a.mode == b.mode, msg or "got mode {!r}, expected {!r}".format(
a.mode, b.mode
)
assert a.size == b.size, msg or "got size {!r}, expected {!r}".format(
a.size, b.size
)
assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}"
if a.tobytes() != b.tobytes():
if HAS_UPLOADER:
try:
url = test_image_results.upload(a, b)
logger.error("Url for test images: %s" % url)
logger.error(f"Url for test images: {url}")
except Exception:
pass
@ -112,12 +107,8 @@ def assert_image_equal_tofile(a, filename, msg=None, mode=None):
def assert_image_similar(a, b, epsilon, msg=None):
assert a.mode == b.mode, msg or "got mode {!r}, expected {!r}".format(
a.mode, b.mode
)
assert a.size == b.size, msg or "got size {!r}, expected {!r}".format(
a.size, b.size
)
assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}"
a, b = convert_to_comparable(a, b)
@ -129,13 +120,14 @@ def assert_image_similar(a, b, epsilon, msg=None):
ave_diff = diff / (a.size[0] * a.size[1])
try:
assert epsilon >= ave_diff, (
msg or ""
) + " average pixel value difference %.4f > epsilon %.4f" % (ave_diff, epsilon)
(msg or "")
+ f" average pixel value difference {ave_diff:.4f} > epsilon {epsilon:.4f}"
)
except Exception as e:
if HAS_UPLOADER:
try:
url = test_image_results.upload(a, b)
logger.error("Url for test images: %s" % url)
logger.error(f"Url for test images: {url}")
except Exception:
pass
raise e
@ -166,7 +158,7 @@ def assert_tuple_approx_equal(actuals, targets, threshold, msg):
def skip_unless_feature(feature):
reason = "%s not available" % feature
reason = f"{feature} not available"
return pytest.mark.skipif(not features.check(feature), reason=reason)
@ -184,7 +176,7 @@ class PillowLeakTestCase:
:returns: memory usage in kilobytes
"""
from resource import getrusage, RUSAGE_SELF
from resource import RUSAGE_SELF, getrusage
mem = getrusage(RUSAGE_SELF).ru_maxrss
if sys.platform == "darwin":
@ -204,7 +196,7 @@ class PillowLeakTestCase:
for cycle in range(self.iterations):
core()
mem = self._get_mem_usage() - start_mem
msg = "memory usage limit exceeded in iteration %d" % cycle
msg = f"memory usage limit exceeded in iteration {cycle}"
assert mem < self.mem_limit, msg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Tests/images/exif_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

View File

@ -1,6 +1,7 @@
import os
import pytest
from PIL import Image
from .helper import assert_image_similar
@ -15,8 +16,8 @@ def get_files(d, ext=".bmp"):
def test_bad():
""" These shouldn't crash/dos, but they shouldn't return anything
either """
"""These shouldn't crash/dos, but they shouldn't return anything
either"""
for f in get_files("b"):
def open(f):
@ -31,8 +32,8 @@ def test_bad():
def test_questionable():
""" These shouldn't crash/dos, but it's not well defined that these
are in spec """
"""These shouldn't crash/dos, but it's not well defined that these
are in spec"""
supported = [
"pal8os2v2.bmp",
"rgb24prof.bmp",
@ -49,15 +50,15 @@ def test_questionable():
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)
print(f"Please add {f} to the partially supported bmp specs.")
except Exception: # as msg:
if os.path.basename(f) in supported:
raise
def test_good():
""" These should all work. There's a set of target files in the
html directory that we can compare against. """
"""These should all work. There's a set of target files in the
html directory that we can compare against."""
# Target files, if they're not just replacing the extension
file_map = {
@ -84,7 +85,7 @@ def test_good():
if name in file_map:
return os.path.join(base, "html", file_map[name])
name = os.path.splitext(name)[0]
return os.path.join(base, "html", "%s.png" % name)
return os.path.join(base, "html", f"{name}.png")
for f in get_files("g"):
try:
@ -107,4 +108,4 @@ def test_good():
os.path.join(base, "g", "pal8rle.bmp"),
os.path.join(base, "g", "pal4rle.bmp"),
)
assert f in unsupported, "Unsupported Image {}: {}".format(f, msg)
assert f in unsupported, f"Unsupported Image {f}: {msg}"

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImageFilter
sample = Image.new("L", (7, 5))

View File

@ -1,6 +1,7 @@
from array import array
import pytest
from PIL import Image, ImageFilter
from .helper import assert_image_equal

View File

@ -1,6 +1,7 @@
import sys
import pytest
from PIL import Image
from .helper import is_pypy

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import hopper

View File

@ -2,6 +2,7 @@ import io
import re
import pytest
from PIL import features
from .helper import skip_unless_feature

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImageSequence, PngImagePlugin
@ -311,7 +312,7 @@ def test_apng_sequence_errors():
]
for f in test_files:
with pytest.raises(SyntaxError):
with Image.open("Tests/images/apng/{0}".format(f)) as im:
with Image.open(f"Tests/images/apng/{f}") as im:
im.seek(im.n_frames - 1)
im.load()
@ -358,7 +359,10 @@ def test_apng_save_split_fdat(tmp_path):
with Image.open("Tests/images/old-style-jpeg-compression.png") as im:
frames = [im.copy(), Image.new("RGBA", im.size, (255, 0, 0, 255))]
im.save(
test_file, save_all=True, default_image=True, append_images=frames,
test_file,
save_all=True,
default_image=True,
append_images=frames,
)
with Image.open(test_file) as im:
exception = None

View File

@ -1,6 +1,7 @@
import io
import pytest
from PIL import BmpImagePlugin, Image
from .helper import assert_image_equal, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import BufrStubImagePlugin, Image
from .helper import hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import CurImagePlugin, Image
TEST_FILE = "Tests/images/deerstalker.cur"

View File

@ -1,4 +1,5 @@
import pytest
from PIL import DcxImagePlugin, Image
from .helper import assert_image_equal, hopper, is_pypy

View File

@ -2,6 +2,7 @@
from io import BytesIO
import pytest
from PIL import DdsImagePlugin, Image
from .helper import assert_image_equal

View File

@ -1,6 +1,7 @@
import io
import pytest
from PIL import EpsImagePlugin, Image, features
from .helper import assert_image_similar, hopper, skip_unless_feature

View File

@ -1,4 +1,5 @@
import pytest
from PIL import FitsStubImagePlugin, Image
TEST_FILE = "Tests/images/hopper.fits"

View File

@ -1,4 +1,5 @@
import pytest
from PIL import FliImagePlugin, Image
from .helper import assert_image_equal, is_pypy

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
FpxImagePlugin = pytest.importorskip(

View File

@ -1,4 +1,5 @@
import pytest
from PIL import GbrImagePlugin, Image
from .helper import assert_image_equal

View File

@ -1,4 +1,5 @@
import pytest
from PIL import GdImageFile, UnidentifiedImageError
TEST_GD_FILE = "Tests/images/hopper.gd"

View File

@ -1,6 +1,7 @@
from io import BytesIO
import pytest
from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, features
from .helper import (

View File

@ -1,4 +1,5 @@
import pytest
from PIL.GimpPaletteFile import GimpPaletteFile

View File

@ -1,4 +1,5 @@
import pytest
from PIL import GribStubImagePlugin, Image
from .helper import hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Hdf5StubImagePlugin, Image
TEST_FILE = "Tests/images/hdf5.h5"

View File

@ -2,6 +2,7 @@ import io
import sys
import pytest
from PIL import IcnsImagePlugin, Image, features
from .helper import assert_image_equal, assert_image_similar

View File

@ -1,6 +1,7 @@
import io
import pytest
from PIL import IcoImagePlugin, Image, ImageDraw
from .helper import assert_image_equal, hopper

View File

@ -1,6 +1,7 @@
import filecmp
import pytest
from PIL import Image, ImImagePlugin
from .helper import assert_image_equal, hopper, is_pypy

View File

@ -3,10 +3,12 @@ import re
from io import BytesIO
import pytest
from PIL import (
ExifTags,
Image,
ImageFile,
ImageOps,
JpegImagePlugin,
UnidentifiedImageError,
features,
@ -38,7 +40,7 @@ class TestFileJpeg:
return im
def gen_random_image(self, size, mode="RGB"):
""" Generates a very hard to compress file
"""Generates a very hard to compress file
:param size: tuple
:param mode: optional image mode
@ -98,7 +100,8 @@ class TestFileJpeg:
assert k > 0.9
@pytest.mark.parametrize(
"test_image_path", [TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
"test_image_path",
[TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
)
def test_dpi(self, test_image_path):
def test(xdpi, ydpi=None):
@ -223,10 +226,7 @@ class TestFileJpeg:
# Should not raise a TypeError
im._getexif()
def test_exif_gps(self):
# Arrange
with Image.open("Tests/images/exif_gps.jpg") as im:
gps_index = 34853
def test_exif_gps(self, tmp_path):
expected_exif_gps = {
0: b"\x00\x00\x00\x01",
2: 4294967295,
@ -234,13 +234,51 @@ class TestFileJpeg:
30: 65535,
29: "1999:99:99 99:99:99",
}
gps_index = 34853
# Act
# Reading
with Image.open("Tests/images/exif_gps.jpg") as im:
exif = im._getexif()
# Assert
assert exif[gps_index] == expected_exif_gps
# Writing
f = str(tmp_path / "temp.jpg")
exif = Image.Exif()
exif[gps_index] = expected_exif_gps
hopper().save(f, exif=exif)
with Image.open(f) as reloaded:
exif = reloaded._getexif()
assert exif[gps_index] == expected_exif_gps
def test_empty_exif_gps(self):
with Image.open("Tests/images/empty_gps_ifd.jpg") as im:
exif = im.getexif()
del exif[0x8769]
# Assert that it needs to be transposed
assert exif[0x0112] == Image.TRANSVERSE
# Assert that the GPS IFD is present and empty
assert exif[0x8825] == {}
transposed = ImageOps.exif_transpose(im)
exif = transposed.getexif()
assert exif[0x8825] == {}
# Assert that it was transposed
assert 0x0112 not in exif
def test_exif_equality(self):
# In 7.2.0, Exif rationals were changed to be read as
# TiffImagePlugin.IFDRational. This class had a bug in __eq__,
# breaking the self-equality of Exif data
exifs = []
for i in range(2):
with Image.open("Tests/images/exif-200dpcm.jpg") as im:
exifs.append(im._getexif())
assert exifs[0] == exifs[1]
def test_exif_rollback(self):
# rolling back exif support in 3.1 to pre-3.0 formatting.
# expected from 2.9, with b/u qualifiers switched for 3.2 compatibility

View File

@ -2,6 +2,7 @@ import re
from io import BytesIO
import pytest
from PIL import Image, ImageFile, Jpeg2KImagePlugin, features
from .helper import (

View File

@ -7,6 +7,7 @@ from collections import namedtuple
from ctypes import c_float
import pytest
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features
from .helper import (
@ -170,18 +171,18 @@ class TestFileLibTiff(LibTiffTestCase):
assert (
c_float(val[0][0] / val[0][1]).value
== c_float(value[0][0] / value[0][1]).value
), ("%s didn't roundtrip" % tag)
), f"{tag} didn't roundtrip"
else:
assert c_float(val).value == c_float(value).value, (
"%s didn't roundtrip" % tag
)
assert (
c_float(val).value == c_float(value).value
), f"{tag} didn't roundtrip"
else:
assert val == value, "%s didn't roundtrip" % tag
assert val == value, f"{tag} didn't roundtrip"
# https://github.com/python-pillow/Pillow/issues/1561
requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"]
for field in requested_fields:
assert field in reloaded, "%s not in metadata" % field
assert field in reloaded, f"{field} not in metadata"
def test_additional_metadata(self, tmp_path):
# these should not crash. Seriously dummy data, most of it doesn't make
@ -401,8 +402,8 @@ class TestFileLibTiff(LibTiffTestCase):
assert "temp.tif" == reread.tag[269][0]
def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
"""Are we generating the same interpretation
of the image as Imagemagick is?"""
TiffImagePlugin.READ_LIBTIFF = True
with Image.open("Tests/images/12bit.cropped.tif") as im:
im.load()
@ -502,7 +503,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert len(reloaded.tag_v2[320]) == 768
def xtest_bw_compression_w_rgb(self, tmp_path):
""" This test passes, but when running all tests causes a failure due
"""This test passes, but when running all tests causes a failure due
to output on stderr from the error thrown by libtiff. We need to
capture that but not now"""
@ -767,7 +768,7 @@ class TestFileLibTiff(LibTiffTestCase):
assert im.mode == "RGBA"
assert im.size == (100, 40)
assert im.tile, [
("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236),)
("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236))
]
im.load()

View File

@ -7,13 +7,13 @@ from .test_file_libtiff import LibTiffTestCase
class TestFileLibTiffSmall(LibTiffTestCase):
""" The small lena image was failing on open in the libtiff
"""The small lena image was failing on open in the libtiff
decoder because the file pointer was set to the wrong place
by a spurious seek. It wasn't failing with the byteio method.
It was fixed by forcing an lseek to the beginning of the
file just before reading in libtiff. These tests remain
to ensure that it stays fixed. """
to ensure that it stays fixed."""
def test_g4_hopper_file(self, tmp_path):
"""Testing the open file load path"""

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, McIdasImagePlugin
from .helper import assert_image_equal

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImagePalette
from .helper import assert_image_similar, hopper, skip_unless_feature

View File

@ -1,6 +1,7 @@
from io import BytesIO
import pytest
from PIL import Image
from .helper import assert_image_similar, is_pypy, skip_unless_feature

View File

@ -1,6 +1,7 @@
import os
import pytest
from PIL import Image, MspImagePlugin
from .helper import assert_image_equal, hopper

View File

@ -2,6 +2,7 @@ import os.path
import subprocess
import pytest
from PIL import Image
from .helper import IMCONVERT, assert_image_equal, hopper, imagemagick_available

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImageFile, PcxImagePlugin
from .helper import assert_image_equal, hopper

View File

@ -5,6 +5,7 @@ import tempfile
import time
import pytest
from PIL import Image, PdfParser
from .helper import hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, PixarImagePlugin
from .helper import assert_image_similar, hopper

View File

@ -3,6 +3,7 @@ import zlib
from io import BytesIO
import pytest
from PIL import Image, ImageFile, PngImagePlugin, features
from .helper import (
@ -606,6 +607,11 @@ class TestFilePng:
exif = im.copy().getexif()
assert exif[274] == 1
# With a tEXt chunk
with Image.open("Tests/images/exif_text.png") as im:
exif = im._getexif()
assert exif[274] == 1
# With XMP tags
with Image.open("Tests/images/xmp_tags_orientation.png") as im:
exif = im.getexif()

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import assert_image_equal, assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, PsdImagePlugin
from .helper import assert_image_similar, hopper, is_pypy

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, SgiImagePlugin
from .helper import assert_image_equal, assert_image_similar, hopper

View File

@ -2,6 +2,7 @@ import tempfile
from io import BytesIO
import pytest
from PIL import Image, ImageSequence, SpiderImagePlugin
from .helper import assert_image_equal, hopper, is_pypy

View File

@ -1,6 +1,7 @@
import os
import pytest
from PIL import Image, SunImagePlugin
from .helper import assert_image_equal, assert_image_similar, hopper
@ -45,7 +46,7 @@ def test_others():
with Image.open(path) as im:
im.load()
assert isinstance(im, SunImagePlugin.SunImageFile)
target_path = "%s.png" % os.path.splitext(path)[0]
target_path = f"{os.path.splitext(path)[0]}.png"
# im.save(target_file)
with Image.open(target_path) as target:
assert_image_equal(im, target)

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, TarIO, features
from .helper import is_pypy

View File

@ -3,6 +3,7 @@ from glob import glob
from itertools import product
import pytest
from PIL import Image
from .helper import assert_image_equal, hopper
@ -35,9 +36,7 @@ def test_sanity(tmp_path):
assert_image_equal(saved_im, original_im)
png_paths = glob(
os.path.join(_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower()))
)
png_paths = glob(os.path.join(_TGA_DIR_COMMON, f"*x*_{mode.lower()}.png"))
for png_path in png_paths:
with Image.open(png_path) as reference_im:

View File

@ -2,6 +2,7 @@ import os
from io import BytesIO
import pytest
from PIL import Image, TiffImagePlugin
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
@ -224,8 +225,8 @@ class TestFileTiff:
assert im.getpixel((0, 1)) == 0
def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
"""Are we generating the same interpretation
of the image as Imagemagick is?"""
with Image.open("Tests/images/12bit.cropped.tif") as im:
# to make the target --

View File

@ -2,6 +2,7 @@ import io
import struct
import pytest
from PIL import Image, TiffImagePlugin, TiffTags
from PIL.TiffImagePlugin import IFDRational
@ -11,7 +12,7 @@ TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
def test_rt_metadata(tmp_path):
""" Test writing arbitrary metadata into the tiff image directory
"""Test writing arbitrary metadata into the tiff image directory
Use case is ImageJ private tags, one numeric, one arbitrary
data. https://github.com/python-pillow/Pillow/issues/291
"""
@ -144,16 +145,16 @@ def test_write_metadata(tmp_path):
assert_deep_equal(
original[tag],
value,
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
f"{tag} didn't roundtrip, {original[tag]}, {value}",
)
else:
assert original[tag] == value, "{} didn't roundtrip, {}, {}".format(
tag, original[tag], value
)
assert (
original[tag] == value
), f"{tag} didn't roundtrip, {original[tag]}, {value}"
for tag, value in original.items():
if tag not in ignored:
assert value == reloaded[tag], "%s didn't roundtrip" % tag
assert value == reloaded[tag], f"{tag} didn't roundtrip"
def test_change_stripbytecounts_tag_type(tmp_path):

View File

@ -2,6 +2,7 @@ import io
import re
import pytest
from PIL import Image, WebPImagePlugin, features
from .helper import (

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import assert_image_equal, assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import (

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import assert_image_equal, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, WmfImagePlugin
from .helper import assert_image_similar, hopper

View File

@ -1,6 +1,7 @@
from io import BytesIO
import pytest
from PIL import Image
from .helper import hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, XpmImagePlugin
from .helper import assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, XVThumbImagePlugin
from .helper import assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import BdfFontFile, FontFile
filename = "Tests/images/courB08.bdf"

View File

@ -1,6 +1,7 @@
import os
import pytest
from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile
from .helper import assert_image_equal, assert_image_similar, skip_unless_feature

View File

@ -47,11 +47,11 @@ def save_font(request, tmp_path, encoding):
font.save(tempname)
with Image.open(tempname.replace(".pil", ".pbm")) as loaded:
with Image.open("Tests/fonts/ter-x20b-%s.pbm" % encoding) as target:
with Image.open(f"Tests/fonts/ter-x20b-{encoding}.pbm") as target:
assert_image_equal(loaded, target)
with open(tempname, "rb") as f_loaded:
with open("Tests/fonts/ter-x20b-%s.pil" % encoding, "rb") as f_target:
with open(f"Tests/fonts/ter-x20b-{encoding}.pil", "rb") as f_target:
assert f_loaded.read() == f_target.read()
return tempname

View File

@ -85,7 +85,10 @@ def test_wedge():
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
im.getchannel(1), comparable.getchannel(1), 1, "Saturation conversion is wrong",
im.getchannel(1),
comparable.getchannel(1),
1,
"Saturation conversion is wrong",
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
@ -113,7 +116,10 @@ def test_convert():
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
im.getchannel(1), comparable.getchannel(1), 1, "Saturation conversion is wrong",
im.getchannel(1),
comparable.getchannel(1),
1,
"Saturation conversion is wrong",
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
@ -126,11 +132,20 @@ def test_hsv_to_rgb():
comparable = to_rgb_colorsys(comparable)
assert_image_similar(
converted.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong",
converted.getchannel(0),
comparable.getchannel(0),
3,
"R conversion is wrong",
)
assert_image_similar(
converted.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong",
converted.getchannel(1),
comparable.getchannel(1),
3,
"G conversion is wrong",
)
assert_image_similar(
converted.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong",
converted.getchannel(2),
comparable.getchannel(2),
3,
"B conversion is wrong",
)

View File

@ -3,8 +3,9 @@ import os
import shutil
import tempfile
import PIL
import pytest
import PIL
from PIL import Image, ImageDraw, ImagePalette, ImageShow, UnidentifiedImageError
from .helper import (
@ -726,7 +727,8 @@ class TestImage:
}
@pytest.mark.parametrize(
"test_module", [PIL, Image],
"test_module",
[PIL, Image],
)
def test_pillow_version(self, test_module):
with pytest.warns(DeprecationWarning):
@ -754,7 +756,7 @@ class TestImage:
assert test_module.PILLOW_VERSION > "7.0.0"
def test_overrun(self):
""" For overrun completeness, test as:
"""For overrun completeness, test as:
valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c
"""
for file in [

View File

@ -4,9 +4,9 @@ import subprocess
import sys
import sysconfig
import pytest
from setuptools.command.build_ext import new_compiler
import pytest
from PIL import Image
from .helper import assert_image_equal, hopper, is_win32, on_ci
@ -17,8 +17,9 @@ if os.environ.get("PYTHONOPTIMIZE") == "2":
cffi = None
else:
try:
from PIL import PyAccess
import cffi
from PIL import PyAccess
except ImportError:
cffi = None
@ -127,14 +128,13 @@ class TestImageGetPixel(AccessTest):
im.putpixel((0, 0), c)
assert (
im.getpixel((0, 0)) == c
), "put/getpixel roundtrip failed for mode {}, color {}".format(mode, c)
), f"put/getpixel roundtrip failed for mode {mode}, color {c}"
# check putpixel negative index
im.putpixel((-1, -1), c)
assert im.getpixel((-1, -1)) == c, (
"put/getpixel roundtrip negative index failed for mode %s, color %s"
% (mode, c)
)
assert (
im.getpixel((-1, -1)) == c
), f"put/getpixel roundtrip negative index failed for mode {mode}, color {c}"
# Check 0
im = Image.new(mode, (0, 0), None)
@ -152,11 +152,11 @@ class TestImageGetPixel(AccessTest):
im = Image.new(mode, (1, 1), c)
assert (
im.getpixel((0, 0)) == c
), "initial color failed for mode {}, color {} ".format(mode, c)
), f"initial color failed for mode {mode}, color {c} "
# check initial color negative index
assert (
im.getpixel((-1, -1)) == c
), "initial color failed with negative index for mode %s, color %s " % (mode, c)
), f"initial color failed with negative index for mode {mode}, color {c} "
# Check 0
im = Image.new(mode, (0, 0), c)
@ -327,6 +327,38 @@ class TestCffi(AccessTest):
assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
class TestImagePutPixelError(AccessTest):
IMAGE_MODES1 = ["L", "LA", "RGB", "RGBA"]
IMAGE_MODES2 = ["I", "I;16", "BGR;15"]
INVALID_TYPES1 = ["foo", 1.0, None]
INVALID_TYPES2 = [*INVALID_TYPES1, (10,)]
@pytest.mark.parametrize("mode", IMAGE_MODES1)
def test_putpixel_type_error1(self, mode):
im = hopper(mode)
for v in self.INVALID_TYPES1:
with pytest.raises(TypeError, match="color must be int or tuple"):
im.putpixel((0, 0), v)
@pytest.mark.parametrize("mode", IMAGE_MODES2)
def test_putpixel_type_error2(self, mode):
im = hopper(mode)
for v in self.INVALID_TYPES2:
with pytest.raises(TypeError, match="color must be int"):
im.putpixel((0, 0), v)
@pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2)
def test_putpixel_overflow_error(self, mode):
im = hopper(mode)
with pytest.raises(OverflowError):
im.putpixel((0, 0), 2 ** 80)
def test_putpixel_unrecognized_mode(self):
im = hopper("BGR;15")
with pytest.raises(ValueError, match="unrecognized image mode"):
im.putpixel((0, 0), 0)
class TestEmbeddable:
@pytest.mark.skipif(
not is_win32() or on_ci(),

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import assert_image, assert_image_equal, assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import assert_image_equal, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImageFilter
from .helper import assert_image_equal, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImageQt
from .helper import assert_image_equal, hopper

View File

@ -1,6 +1,8 @@
import logging
import os
import pytest
from PIL import Image
from .helper import hopper
@ -22,6 +24,14 @@ def test_close():
im.getpixel((0, 0))
def test_close_after_load(caplog):
im = Image.open("Tests/images/hopper.gif")
im.load()
with caplog.at_level(logging.DEBUG):
im.close()
assert len(caplog.records) == 0
def test_contextmanager():
fn = None
with Image.open("Tests/images/hopper.gif") as im:

View File

@ -24,7 +24,7 @@ def test_sanity():
def test_16bit_lut():
""" Tests for 16 bit -> 8 bit lut for converting I->L images
"""Tests for 16 bit -> 8 bit lut for converting I->L images
see https://github.com/python-pillow/Pillow/issues/440
"""
im = hopper("I")

View File

@ -1,4 +1,5 @@
import pytest
from PIL import ImagePalette
from .helper import hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import assert_image, assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image, ImageMath, ImageMode
from .helper import convert_to_comparable, skip_unless_feature
@ -161,8 +162,8 @@ def compare_reduce_with_reference(im, factor, average_diff=0.4, max_diff=1):
def assert_compare_images(a, b, max_average_diff, max_diff=255):
assert a.mode == b.mode, "got mode %r, expected %r" % (a.mode, b.mode)
assert a.size == b.size, "got size %r, expected %r" % (a.size, b.size)
assert a.mode == b.mode, f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
assert a.size == b.size, f"got size {repr(a.size)}, expected {repr(b.size)}"
a, b = convert_to_comparable(a, b)
@ -175,16 +176,15 @@ def assert_compare_images(a, b, max_average_diff, max_diff=255):
a.size[0] * a.size[1]
)
msg = (
"average pixel value difference {:.4f} > expected {:.4f} "
"for '{}' band".format(average_diff, max_average_diff, band)
f"average pixel value difference {average_diff:.4f} > "
f"expected {max_average_diff:.4f} for '{band}' band"
)
assert max_average_diff >= average_diff, msg
last_diff = [i for i, num in enumerate(ch_hist) if num > 0][-1]
assert (
max_diff >= last_diff
), "max pixel value difference {} > expected {} for '{}' band".format(
last_diff, max_diff, band
assert max_diff >= last_diff, (
f"max pixel value difference {last_diff} > expected {max_diff} "
f"for '{band}' band"
)

View File

@ -1,6 +1,7 @@
from contextlib import contextmanager
import pytest
from PIL import Image, ImageDraw
from .helper import assert_image_equal, assert_image_similar, hopper
@ -81,15 +82,16 @@ class TestImagingCoreResampleAccuracy:
for y in range(case.size[1]):
for x in range(case.size[0]):
if c_px[x, y] != s_px[x, y]:
message = "\nHave: \n{}\n\nExpected: \n{}".format(
self.serialize_image(case), self.serialize_image(sample)
message = (
f"\nHave: \n{self.serialize_image(case)}\n"
f"\nExpected: \n{self.serialize_image(sample)}"
)
assert s_px[x, y] == c_px[x, y], message
def serialize_image(self, image):
s_px = image.load()
return "\n".join(
" ".join("{:02x}".format(s_px[x, y]) for x in range(image.size[0]))
" ".join(f"{s_px[x, y]:02x}" for x in range(image.size[0]))
for y in range(image.size[1])
)
@ -229,7 +231,7 @@ class TestCoreResampleConsistency:
for x in range(channel.size[0]):
for y in range(channel.size[1]):
if px[x, y] != color:
message = "{} != {} for pixel {}".format(px[x, y], color, (x, y))
message = f"{px[x, y]} != {color} for pixel {(x, y)}"
assert px[x, y] == color, message
def test_8u(self):
@ -268,10 +270,9 @@ class TestCoreResampleAlphaCorrect:
px = i.load()
for y in range(i.size[1]):
used_colors = {px[x, y][0] for x in range(i.size[0])}
assert 256 == len(
used_colors
), "All colors should present in resized image. Only {} on {} line.".format(
len(used_colors), y
assert 256 == len(used_colors), (
"All colors should be present in resized image. "
f"Only {len(used_colors)} on {y} line."
)
@pytest.mark.xfail(reason="Current implementation isn't precise enough")
@ -307,8 +308,9 @@ class TestCoreResampleAlphaCorrect:
for y in range(i.size[1]):
for x in range(i.size[0]):
if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel:
message = "pixel at ({}, {}) is differ:\n{}\n{}".format(
x, y, px[x, y], clean_pixel
message = (
f"pixel at ({x}, {y}) is different:\n"
f"{px[x, y]}\n{clean_pixel}"
)
assert px[x, y][:3] == clean_pixel, message
@ -503,7 +505,7 @@ class TestCoreResampleBox:
]:
res = im.resize(size, Image.LANCZOS, box)
assert res.size == size
assert_image_equal(res, im.crop(box), ">>> {} {}".format(size, box))
assert_image_equal(res, im.crop(box), f">>> {size} {box}")
def test_no_passthrough(self):
# When resize is required
@ -519,9 +521,7 @@ class TestCoreResampleBox:
assert res.size == size
with pytest.raises(AssertionError, match=r"difference \d"):
# check that the difference at least that much
assert_image_similar(
res, im.crop(box), 20, ">>> {} {}".format(size, box)
)
assert_image_similar(res, im.crop(box), 20, f">>> {size} {box}")
def test_skip_horizontal(self):
# Can skip resize for one dimension
@ -541,7 +541,7 @@ class TestCoreResampleBox:
res,
im.crop(box).resize(size, flt),
0.4,
">>> {} {} {}".format(size, box, flt),
f">>> {size} {box} {flt}",
)
def test_skip_vertical(self):
@ -562,5 +562,5 @@ class TestCoreResampleBox:
res,
im.crop(box).resize(size, flt),
0.4,
">>> {} {} {}".format(size, box, flt),
f">>> {size} {box} {flt}",
)

View File

@ -4,6 +4,7 @@ Tests for resize functionality.
from itertools import permutations
import pytest
from PIL import Image
from .helper import assert_image_equal, assert_image_similar, hopper

View File

@ -1,4 +1,5 @@
import pytest
from PIL import Image
from .helper import (

View File

@ -1,6 +1,7 @@
import math
import pytest
from PIL import Image, ImageTransform
from .helper import assert_image_equal, assert_image_similar, hopper

View File

@ -4,6 +4,7 @@ import re
from io import BytesIO
import pytest
from PIL import Image, ImageMode, features
from .helper import assert_image, assert_image_equal, assert_image_similar, hopper
@ -436,7 +437,7 @@ def test_extended_information():
def test_profile_typesafety():
""" Profile init type safety
"""Profile init type safety
prepatch, these would segfault, postpatch they should emit a typeerror
"""

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