mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Merge branch 'main' of ssh://github.com/python-pillow/Pillow into fix-alpha-for-overlapping-glyphs
This commit is contained in:
commit
11bea8fea6
|
@ -13,7 +13,7 @@ indent_style = space
|
|||
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.yml]
|
||||
[*.{toml,yml}]
|
||||
# Two-space indentation
|
||||
indent_size = 2
|
||||
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
repos:
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.13.0
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.4
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py38-plus]
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.9.1
|
||||
rev: 23.10.1
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--target-version=py38]
|
||||
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.7.5
|
||||
hooks:
|
||||
|
@ -23,32 +18,19 @@ repos:
|
|||
args: [--severity-level=high]
|
||||
files: ^src/
|
||||
|
||||
- repo: https://github.com/asottile/yesqa
|
||||
rev: v1.5.0
|
||||
hooks:
|
||||
- id: yesqa
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.5.4
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 6.1.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
[flake8-2020, flake8-errmsg, flake8-implicit-str-concat, flake8-logging]
|
||||
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.10.0
|
||||
hooks:
|
||||
- id: python-check-blanket-noqa
|
||||
- id: rst-backticks
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
rev: v4.5.0
|
||||
hooks:
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-merge-conflict
|
||||
|
@ -61,17 +43,17 @@ repos:
|
|||
exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/
|
||||
|
||||
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
||||
rev: v0.6.8
|
||||
rev: v0.8.1
|
||||
hooks:
|
||||
- id: sphinx-lint
|
||||
|
||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||
rev: 1.2.0
|
||||
rev: 1.4.1
|
||||
hooks:
|
||||
- id: pyproject-fmt
|
||||
|
||||
- repo: https://github.com/abravalheri/validate-pyproject
|
||||
rev: v0.14
|
||||
rev: v0.15
|
||||
hooks:
|
||||
- id: validate-pyproject
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ include *.md
|
|||
include *.py
|
||||
include *.rst
|
||||
include *.sh
|
||||
include *.toml
|
||||
include *.txt
|
||||
include *.yaml
|
||||
include .flake8
|
||||
|
|
6
Makefile
6
Makefile
|
@ -49,7 +49,7 @@ help:
|
|||
@echo " install make and install"
|
||||
@echo " install-coverage make and install with C coverage"
|
||||
@echo " lint run the lint checks"
|
||||
@echo " lint-fix run Black and isort to (mostly) fix lint issues"
|
||||
@echo " lint-fix run Ruff to (mostly) fix lint issues"
|
||||
@echo " release-test run code and package tests before release"
|
||||
@echo " test run tests on installed Pillow"
|
||||
|
||||
|
@ -118,6 +118,6 @@ lint:
|
|||
.PHONY: lint-fix
|
||||
lint-fix:
|
||||
python3 -c "import black" > /dev/null 2>&1 || python3 -m pip install black
|
||||
python3 -c "import isort" > /dev/null 2>&1 || python3 -m pip install isort
|
||||
python3 -m black --target-version py38 .
|
||||
python3 -m isort .
|
||||
python3 -c "import ruff" > /dev/null 2>&1 || python3 -m pip install ruff
|
||||
python3 -m ruff --fix .
|
||||
|
|
|
@ -45,7 +45,7 @@ def test_direct():
|
|||
|
||||
assert caccess[(0, 0)] == access[(0, 0)]
|
||||
|
||||
print("Size: %sx%s" % im.size)
|
||||
print("Size: %sx%s" % im.size) # noqa: UP031
|
||||
timer(iterate_get, "PyAccess - get", im.size, access)
|
||||
timer(iterate_set, "PyAccess - set", im.size, access)
|
||||
timer(iterate_get, "C-api - get", im.size, caccess)
|
||||
|
|
|
@ -350,7 +350,7 @@ def test_apng_save(tmp_path):
|
|||
im.load()
|
||||
assert not im.is_animated
|
||||
assert im.n_frames == 1
|
||||
assert im.get_format_mimetype() == "image/apng"
|
||||
assert im.get_format_mimetype() == "image/png"
|
||||
assert im.info.get("default_image") is None
|
||||
assert im.getpixel((0, 0)) == (0, 255, 0, 255)
|
||||
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
|
||||
|
@ -450,26 +450,29 @@ def test_apng_save_duration_loop(tmp_path):
|
|||
test_file, save_all=True, append_images=[frame, frame], duration=[500, 100, 150]
|
||||
)
|
||||
with Image.open(test_file) as im:
|
||||
im.load()
|
||||
assert im.n_frames == 1
|
||||
assert im.info.get("duration") == 750
|
||||
assert "duration" not in im.info
|
||||
|
||||
different_frame = Image.new("RGBA", (128, 64))
|
||||
frame.save(
|
||||
test_file,
|
||||
save_all=True,
|
||||
append_images=[frame, different_frame],
|
||||
duration=[500, 100, 150],
|
||||
)
|
||||
with Image.open(test_file) as im:
|
||||
assert im.n_frames == 2
|
||||
assert im.info["duration"] == 600
|
||||
|
||||
im.seek(1)
|
||||
assert im.info["duration"] == 150
|
||||
|
||||
# test info duration
|
||||
frame.info["duration"] = 750
|
||||
frame.save(test_file, save_all=True)
|
||||
frame.info["duration"] = 300
|
||||
frame.save(test_file, save_all=True, append_images=[frame, different_frame])
|
||||
with Image.open(test_file) as im:
|
||||
assert im.info.get("duration") == 750
|
||||
|
||||
|
||||
def test_apng_save_duplicate_duration(tmp_path):
|
||||
test_file = str(tmp_path / "temp.png")
|
||||
frame = Image.new("RGB", (1, 1))
|
||||
|
||||
# Test a single duration is correctly combined across duplicate frames
|
||||
frame.save(test_file, save_all=True, append_images=[frame, frame], duration=500)
|
||||
with Image.open(test_file) as im:
|
||||
assert im.n_frames == 1
|
||||
assert im.info.get("duration") == 1500
|
||||
assert im.n_frames == 2
|
||||
assert im.info["duration"] == 600
|
||||
|
||||
|
||||
def test_apng_save_disposal(tmp_path):
|
||||
|
@ -674,7 +677,8 @@ def test_seek_after_close():
|
|||
|
||||
@pytest.mark.parametrize("mode", ("RGBA", "RGB", "P"))
|
||||
@pytest.mark.parametrize("default_image", (True, False))
|
||||
def test_different_modes_in_later_frames(mode, default_image, tmp_path):
|
||||
@pytest.mark.parametrize("duplicate", (True, False))
|
||||
def test_different_modes_in_later_frames(mode, default_image, duplicate, tmp_path):
|
||||
test_file = str(tmp_path / "temp.png")
|
||||
|
||||
im = Image.new("L", (1, 1))
|
||||
|
@ -682,7 +686,7 @@ def test_different_modes_in_later_frames(mode, default_image, tmp_path):
|
|||
test_file,
|
||||
save_all=True,
|
||||
default_image=default_image,
|
||||
append_images=[Image.new(mode, (1, 1))],
|
||||
append_images=[im.convert(mode) if duplicate else Image.new(mode, (1, 1), 1)],
|
||||
)
|
||||
with Image.open(test_file) as reloaded:
|
||||
assert reloaded.mode == mode
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import sys
|
||||
|
||||
from setuptools.build_meta import * # noqa: F401, F403
|
||||
from setuptools.build_meta import * # noqa: F403
|
||||
from setuptools.build_meta import build_wheel
|
||||
|
||||
backend_class = build_wheel.__self__.__class__
|
||||
|
|
14
docs/conf.py
14
docs/conf.py
|
@ -318,14 +318,14 @@ def setup(app):
|
|||
|
||||
|
||||
linkcheck_allowed_redirects = {
|
||||
r"https://www.bestpractices.dev/projects/6331": r"https://www.bestpractices.dev/en/.*", # noqa: E501
|
||||
r"https://badges.gitter.im/python-pillow/Pillow.svg": r"https://badges.gitter.im/repo.svg", # noqa: E501
|
||||
r"https://gitter.im/python-pillow/Pillow?.*": r"https://app.gitter.im/#/room/#python-pillow_Pillow:gitter.im?.*", # noqa: E501
|
||||
r"https://pillow.readthedocs.io/?badge=latest": r"https://pillow.readthedocs.io/en/stable/?badge=latest", # noqa: E501
|
||||
r"https://www.bestpractices.dev/projects/6331": r"https://www.bestpractices.dev/en/.*",
|
||||
r"https://badges.gitter.im/python-pillow/Pillow.svg": r"https://badges.gitter.im/repo.svg",
|
||||
r"https://gitter.im/python-pillow/Pillow?.*": r"https://app.gitter.im/#/room/#python-pillow_Pillow:gitter.im?.*",
|
||||
r"https://pillow.readthedocs.io/?badge=latest": r"https://pillow.readthedocs.io/en/stable/?badge=latest",
|
||||
r"https://pillow.readthedocs.io": r"https://pillow.readthedocs.io/en/stable/",
|
||||
r"https://tidelift.com/badges/package/pypi/Pillow?.*": r"https://img.shields.io/badge/.*", # noqa: E501
|
||||
r"https://zenodo.org/badge/17549/python-pillow/Pillow.svg": r"https://zenodo.org/badge/doi/[\.0-9]+/zenodo.[0-9]+.svg", # noqa: E501
|
||||
r"https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow": r"https://zenodo.org/record/[0-9]+", # noqa: E501
|
||||
r"https://tidelift.com/badges/package/pypi/Pillow?.*": r"https://img.shields.io/badge/.*",
|
||||
r"https://zenodo.org/badge/17549/python-pillow/Pillow.svg": r"https://zenodo.org/badge/doi/[\.0-9]+/zenodo.[0-9]+.svg",
|
||||
r"https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow": r"https://zenodo.org/record/[0-9]+",
|
||||
}
|
||||
|
||||
# sphinx.ext.extlinks
|
||||
|
|
|
@ -10,7 +10,7 @@ Deprecated features
|
|||
-------------------
|
||||
|
||||
Below are features which are considered deprecated. Where appropriate,
|
||||
a ``DeprecationWarning`` is issued.
|
||||
a :py:exc:`DeprecationWarning` is issued.
|
||||
|
||||
PSFile
|
||||
~~~~~~
|
||||
|
@ -267,7 +267,7 @@ ImageFile.raise_ioerror
|
|||
.. deprecated:: 7.2.0
|
||||
.. versionremoved:: 9.0.0
|
||||
|
||||
``IOError`` was merged into ``OSError`` in Python 3.3.
|
||||
:py:exc:`IOError` was merged into :py:exc:`OSError` in Python 3.3.
|
||||
So, ``ImageFile.raise_ioerror`` has been removed.
|
||||
Use ``ImageFile.raise_oserror`` instead.
|
||||
|
||||
|
@ -293,9 +293,9 @@ im.offset
|
|||
``im.offset()`` has been removed, call :py:func:`.ImageChops.offset()` instead.
|
||||
|
||||
It was documented as deprecated in PIL 1.1.2,
|
||||
raised a ``DeprecationWarning`` since 1.1.5,
|
||||
an ``Exception`` since Pillow 3.0.0
|
||||
and ``NotImplementedError`` since 3.3.0.
|
||||
raised a :py:exc:`DeprecationWarning` since 1.1.5,
|
||||
an :py:exc:`Exception` since Pillow 3.0.0
|
||||
and :py:exc:`NotImplementedError` since 3.3.0.
|
||||
|
||||
Image.fromstring, im.fromstring and im.tostring
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -307,9 +307,9 @@ Image.fromstring, im.fromstring and im.tostring
|
|||
* ``im.fromstring()`` has been removed, call :py:meth:`~PIL.Image.Image.frombytes()` instead.
|
||||
* ``im.tostring()`` has been removed, call :py:meth:`~PIL.Image.Image.tobytes()` instead.
|
||||
|
||||
They issued a ``DeprecationWarning`` since 2.0.0,
|
||||
an ``Exception`` since 3.0.0
|
||||
and ``NotImplementedError`` since 3.3.0.
|
||||
They issued a :py:exc:`DeprecationWarning` since 2.0.0,
|
||||
an :py:exc:`Exception` since 3.0.0
|
||||
and :py:exc:`NotImplementedError` since 3.3.0.
|
||||
|
||||
ImageCms.CmsProfile attributes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -318,7 +318,7 @@ ImageCms.CmsProfile attributes
|
|||
.. versionremoved:: 8.0.0
|
||||
|
||||
Some attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed. From 6.0.0,
|
||||
they issued a ``DeprecationWarning``:
|
||||
they issued a :py:exc:`DeprecationWarning`:
|
||||
|
||||
======================== ===================================================
|
||||
Removed Use instead
|
||||
|
@ -442,7 +442,7 @@ PIL.OleFileIO
|
|||
.. deprecated:: 4.0.0
|
||||
.. versionremoved:: 6.0.0
|
||||
|
||||
PIL.OleFileIO was removed as a vendored file in Pillow 4.0.0 (2017-01) in favour of
|
||||
the upstream :pypi:`olefile` Python package, and replaced with an ``ImportError`` in 5.0.0
|
||||
``PIL.OleFileIO`` was removed as a vendored file in Pillow 4.0.0 (2017-01) in favour of
|
||||
the upstream :pypi:`olefile` Python package, and replaced with an :py:exc:`ImportError` in 5.0.0
|
||||
(2018-01). The deprecated file has now been removed from Pillow. If needed, install from
|
||||
PyPI (eg. ``python3 -m pip install olefile``).
|
||||
|
|
|
@ -20,7 +20,7 @@ the imToolkit package.
|
|||
|
||||
.. warning::
|
||||
To protect against potential DOS attacks when using arbitrary strings as
|
||||
text input, Pillow will raise a ``ValueError`` if the number of characters
|
||||
text input, Pillow will raise a :py:exc:`ValueError` if the number of characters
|
||||
is over a certain limit, :py:data:`MAX_STRING_LENGTH`.
|
||||
|
||||
This threshold can be changed by setting
|
||||
|
@ -89,5 +89,5 @@ Constants
|
|||
.. data:: MAX_STRING_LENGTH
|
||||
|
||||
Set to 1,000,000, to protect against potential DOS attacks. Pillow will
|
||||
raise a ``ValueError`` if the number of characters is over this limit. The
|
||||
raise a :py:exc:`ValueError` if the number of characters is over this limit. The
|
||||
check can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.
|
||||
|
|
|
@ -8,7 +8,7 @@ Setting image mode
|
|||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you attempt to set the mode of an image directly, e.g.
|
||||
``im.mode = "RGBA"``, you will now receive an ``AttributeError``. This is
|
||||
``im.mode = "RGBA"``, you will now receive an :py:exc:`AttributeError`. This is
|
||||
not about removing existing functionality, but instead about raising an
|
||||
explicit error to prevent later consequences. The ``convert`` method is the
|
||||
correct way to change an image's mode.
|
||||
|
|
|
@ -10,7 +10,7 @@ operations. As a result PIL was unable to open them as images, requiring a wrap
|
|||
``cStringIO`` or ``BytesIO``.
|
||||
|
||||
Now new functionality has been added to ``Image.open()`` by way of an ``.seek(0)`` check and
|
||||
catch on exception ``AttributeError`` or ``io.UnsupportedOperation``. If this is caught we
|
||||
catch on exception :py:exc:`AttributeError` or :py:exc:`io.UnsupportedOperation`. If this is caught we
|
||||
attempt to wrap the object using ``io.BytesIO`` (which will only work on buffer-file-like
|
||||
objects).
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Deprecation Warning when Saving JPEGs
|
|||
|
||||
JPEG images cannot contain an alpha channel. Pillow prior to 3.4.0
|
||||
silently drops the alpha channel. With this release Pillow will now
|
||||
issue a ``DeprecationWarning`` when attempting to save a ``RGBA`` mode
|
||||
issue a :py:exc:`DeprecationWarning` when attempting to save a ``RGBA`` mode
|
||||
image as a JPEG. This will become an error in Pillow 4.2.
|
||||
|
||||
New DDS Decoders
|
||||
|
|
|
@ -8,7 +8,7 @@ Image size
|
|||
^^^^^^^^^^
|
||||
|
||||
If you attempt to set the size of an image directly, e.g.
|
||||
``im.size = (100, 100)``, you will now receive an ``AttributeError``. This is
|
||||
``im.size = (100, 100)``, you will now receive an :py:exc:`AttributeError`. This is
|
||||
not about removing existing functionality, but instead about raising an
|
||||
explicit error to prevent later consequences. The ``resize`` method is the
|
||||
correct way to change an image's size.
|
||||
|
@ -16,7 +16,8 @@ correct way to change an image's size.
|
|||
The exceptions to this are:
|
||||
|
||||
* The ICO and ICNS image formats, which use ``im.size = (100, 100)`` to select a subimage.
|
||||
* The TIFF image format, which now has a ``DeprecationWarning`` for this action, as direct image size setting was previously necessary to work around an issue with tile extents.
|
||||
* The TIFF image format, which now has a :py:exc:`DeprecationWarning` for this action,
|
||||
as direct image size setting was previously necessary to work around an issue with tile extents.
|
||||
|
||||
|
||||
API Additions
|
||||
|
|
|
@ -15,7 +15,7 @@ PNG: Handle IDAT chunks after image end
|
|||
|
||||
Some PNG images have multiple IDAT chunks. In some cases, Pillow will stop
|
||||
reading image data before the IDAT chunks finish. A regression caused an
|
||||
``EOFError`` exception when previously there was none. This is now fixed, and
|
||||
:py:exc:`EOFError` exception when previously there was none. This is now fixed, and
|
||||
file reading continues in case there are subsequent text chunks.
|
||||
|
||||
PNG: MIME type
|
||||
|
@ -30,7 +30,7 @@ File closing
|
|||
^^^^^^^^^^^^
|
||||
|
||||
A regression caused an unsupported image file to report a
|
||||
``ValueError: seek of closed file`` exception instead of an ``OSError``. This
|
||||
``ValueError: seek of closed file`` exception instead of an :py:exc:`OSError`. This
|
||||
has been fixed by ensuring that image plugins only close their internal ``__fp``
|
||||
if they are not the same as ``ImageFile``'s ``fp``, allowing each to manage their own
|
||||
file pointers.
|
||||
|
|
|
@ -103,7 +103,7 @@ ImageCms.CmsProfile attributes
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Some attributes in ``ImageCms.CmsProfile`` have been deprecated since Pillow 3.2.0. From
|
||||
6.0.0, they issue a ``DeprecationWarning``:
|
||||
6.0.0, they issue a :py:exc:`DeprecationWarning`:
|
||||
|
||||
======================== ===============================
|
||||
Deprecated Use instead
|
||||
|
|
|
@ -58,7 +58,7 @@ file. ``ImageFont.FreeTypeFont`` has four new methods,
|
|||
:py:meth:`PIL.ImageFont.FreeTypeFont.set_variation_by_name` for using named styles, and
|
||||
:py:meth:`PIL.ImageFont.FreeTypeFont.get_variation_axes` and
|
||||
:py:meth:`PIL.ImageFont.FreeTypeFont.set_variation_by_axes` for using font axes
|
||||
instead. An ``IOError`` will be raised if the font is not a variation font. FreeType
|
||||
instead. An :py:exc:`IOError` will be raised if the font is not a variation font. FreeType
|
||||
2.9.1 or greater is required.
|
||||
|
||||
Other Changes
|
||||
|
|
|
@ -85,7 +85,7 @@ Custom unidentified image error
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Pillow will now throw a custom ``UnidentifiedImageError`` when an image cannot be
|
||||
identified. For backwards compatibility, this will inherit from ``OSError``.
|
||||
identified. For backwards compatibility, this will inherit from :py:exc:`OSError`.
|
||||
|
||||
New argument ``reducing_gap`` for Image.resize() and Image.thumbnail() methods
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -7,7 +7,7 @@ Fix another regression seeking PNG files
|
|||
This fixes a regression introduced in 7.1.0 when adding support for APNG files.
|
||||
|
||||
When calling ``seek(n)`` on a regular PNG where ``n > 0``, it failed to raise an
|
||||
``EOFError`` as it should have done, resulting in:
|
||||
:py:exc:`EOFError` as it should have done, resulting in:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
|
|
|
@ -53,6 +53,6 @@ a custom :py:class:`~PIL.ImageShow.Viewer` class.
|
|||
ImageFile.raise_ioerror
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror``
|
||||
:py:exc:`IOError` was merged into :py:exc:`OSError` in Python 3.3. So, ``ImageFile.raise_ioerror``
|
||||
is now deprecated and will be removed in a future release. Use
|
||||
``ImageFile.raise_oserror`` instead.
|
||||
|
|
|
@ -168,7 +168,7 @@ offset.
|
|||
Error for large BMP files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Previously, if a BMP file was too large, an ``OSError`` would be raised. Now,
|
||||
Previously, if a BMP file was too large, an :py:exc:`OSError` would be raised. Now,
|
||||
``DecompressionBombError`` is used instead, as Pillow already uses for other formats.
|
||||
|
||||
Dark theme for docs
|
||||
|
|
|
@ -22,9 +22,10 @@ Catch OSError when checking if destination is sys.stdout
|
|||
========================================================
|
||||
|
||||
In 8.3.0, a check to see if the destination was ``sys.stdout`` when saving an image was
|
||||
updated. This lead to an OSError being raised if the environment restricted access.
|
||||
updated. This lead to an :py:exc:`OSError` being raised if the environment restricted
|
||||
access.
|
||||
|
||||
The OSError is now silently caught.
|
||||
The :py:exc:`OSError` is now silently caught.
|
||||
|
||||
Fixed removing orientation in ImageOps.exif_transpose
|
||||
=====================================================
|
||||
|
@ -34,7 +35,7 @@ original image EXIF data was not modified, and the orientation was only removed
|
|||
the modified copy.
|
||||
|
||||
However, for certain images the orientation was already missing from the modified
|
||||
image, leading to a KeyError.
|
||||
image, leading to a :py:exc:`KeyError`.
|
||||
|
||||
This error has been resolved, and the copying of metadata to the modified image
|
||||
improved.
|
||||
|
|
|
@ -63,7 +63,7 @@ a custom :py:class:`~PIL.ImageShow.Viewer` class.
|
|||
ImageFile.raise_ioerror
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror``
|
||||
:py:exc:`IOError` was merged into :py:exc:`OSError` in Python 3.3. So, ``ImageFile.raise_ioerror``
|
||||
has been removed. Use ``ImageFile.raise_oserror`` instead.
|
||||
|
||||
|
||||
|
|
|
@ -8,14 +8,14 @@ Raise an error when performing a negative crop
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Performing a negative crop on an image previously just returned a ``(0, 0)`` image. Now
|
||||
it will raise a ``ValueError``, to help reduce confusion if a user has unintentionally
|
||||
it will raise a :py:exc:`ValueError`, to help reduce confusion if a user has unintentionally
|
||||
provided the wrong arguments.
|
||||
|
||||
Added specific error if path coordinate type is incorrect
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Rather than returning a ``SystemError``, passing the incorrect types of coordinates into
|
||||
a path will now raise a more specific ``ValueError``, with the message "incorrect
|
||||
Rather than returning a :py:exc:`SystemError`, passing the incorrect types of coordinates into
|
||||
a path will now raise a more specific :py:exc:`ValueError`, with the message "incorrect
|
||||
coordinate type".
|
||||
|
||||
Replace requirements.txt with extras
|
||||
|
|
|
@ -77,8 +77,34 @@ package-dir = {"" = "src"}
|
|||
[tool.setuptools.dynamic]
|
||||
version = {attr = "PIL.__version__"}
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
[tool.ruff]
|
||||
target-version = "py38"
|
||||
line-length = 88
|
||||
select = [
|
||||
"E", # pycodestyle errors
|
||||
"EM", # flake8-errmsg
|
||||
"F", # pyflakes errors
|
||||
"I", # isort
|
||||
"ISC", # flake8-implicit-str-concat
|
||||
"PGH", # pygrep-hooks
|
||||
"RUF100", # unused noqa (yesqa)
|
||||
"UP", # pyupgrade
|
||||
"W", # pycodestyle warnings
|
||||
"YTT", # flake8-2020
|
||||
# "LOG", # TODO: enable flake8-logging when it's not in preview anymore
|
||||
]
|
||||
extend-ignore = [
|
||||
"E203", # Whitespace before ':'
|
||||
"E221", # Multiple spaces before operator
|
||||
"E226", # Missing whitespace around arithmetic operator
|
||||
"E241", # Multiple spaces after ','
|
||||
]
|
||||
|
||||
[tool.ruff.per-file-ignores]
|
||||
"Tests/*.py" = ["I001"]
|
||||
|
||||
[tool.ruff.isort]
|
||||
known-first-party = ["PIL"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = "-ra --color=yes"
|
||||
|
|
|
@ -122,7 +122,7 @@ def Ghostscript(tile, size, fp, scale=1, transparency=False):
|
|||
gs_binary,
|
||||
"-q", # quiet mode
|
||||
"-g%dx%d" % size, # set output geometry (pixels)
|
||||
"-r%fx%f" % res, # set input DPI (dots per inch)
|
||||
"-r%fx%f" % res, # set input DPI (dots per inch) # noqa: UP031
|
||||
"-dBATCH", # exit after processing
|
||||
"-dNOPAUSE", # don't pause between pages
|
||||
"-dSAFER", # safe mode
|
||||
|
|
|
@ -392,7 +392,7 @@ if __name__ == "__main__":
|
|||
imf = IcnsImageFile(fp)
|
||||
for size in imf.info["sizes"]:
|
||||
imf.size = size
|
||||
imf.save("out-%s-%s-%s.png" % size)
|
||||
imf.save("out-%s-%s-%s.png" % size) # noqa: UP031
|
||||
with Image.open(sys.argv[1]) as im:
|
||||
im.save("out.png")
|
||||
if sys.platform == "windows":
|
||||
|
|
|
@ -3100,7 +3100,7 @@ def fromarray(obj, mode=None):
|
|||
try:
|
||||
mode, rawmode = _fromarray_typemap[typekey]
|
||||
except KeyError as e:
|
||||
msg = "Cannot handle this data type: %s, %s" % typekey
|
||||
msg = "Cannot handle this data type: %s, %s" % typekey # noqa: UP031
|
||||
raise TypeError(msg) from e
|
||||
else:
|
||||
rawmode = mode
|
||||
|
|
|
@ -222,7 +222,7 @@ class UnsharpMask(MultibandFilter):
|
|||
|
||||
.. _digital unsharp masking: https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking
|
||||
|
||||
""" # noqa: E501
|
||||
"""
|
||||
|
||||
name = "UnsharpMask"
|
||||
|
||||
|
|
|
@ -18,10 +18,9 @@ import os
|
|||
import tempfile
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i8
|
||||
from ._binary import i8, o8
|
||||
from ._binary import i16be as i16
|
||||
from ._binary import i32be as i32
|
||||
from ._binary import o8
|
||||
|
||||
COMPRESSION = {1: "raw", 5: "jpeg"}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class IndirectReference(
|
|||
collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"])
|
||||
):
|
||||
def __str__(self):
|
||||
return "%s %s R" % self
|
||||
return "%s %s R" % self # noqa: UP031
|
||||
|
||||
def __bytes__(self):
|
||||
return self.__str__().encode("us-ascii")
|
||||
|
@ -103,7 +103,7 @@ class IndirectReference(
|
|||
|
||||
class IndirectObjectDef(IndirectReference):
|
||||
def __str__(self):
|
||||
return "%s %s obj" % self
|
||||
return "%s %s obj" % self # noqa: UP031
|
||||
|
||||
|
||||
class XrefTable:
|
||||
|
|
|
@ -1156,6 +1156,9 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
|
|||
encoderinfo["duration"] = duration
|
||||
im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo})
|
||||
|
||||
if len(im_frames) == 1 and not default_image:
|
||||
return im_frames[0]["im"]
|
||||
|
||||
# animation control
|
||||
chunk(
|
||||
fp,
|
||||
|
@ -1391,8 +1394,10 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
|
|||
chunk(fp, b"eXIf", exif)
|
||||
|
||||
if save_all:
|
||||
_write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
|
||||
else:
|
||||
im = _write_multiple_frames(
|
||||
im, fp, chunk, rawmode, default_image, append_images
|
||||
)
|
||||
if im:
|
||||
ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
|
||||
|
||||
if info:
|
||||
|
|
|
@ -244,7 +244,7 @@ class _PyAccessI16_L(PyAccess):
|
|||
except TypeError:
|
||||
color = min(color[0], 65535)
|
||||
|
||||
pixel.l = color & 0xFF # noqa: E741
|
||||
pixel.l = color & 0xFF
|
||||
pixel.r = color >> 8
|
||||
|
||||
|
||||
|
@ -265,7 +265,7 @@ class _PyAccessI16_B(PyAccess):
|
|||
except Exception:
|
||||
color = min(color[0], 65535)
|
||||
|
||||
pixel.l = color >> 8 # noqa: E741
|
||||
pixel.l = color >> 8
|
||||
pixel.r = color & 0xFF
|
||||
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ DEPS = {
|
|||
"libs": ["*.lib"],
|
||||
},
|
||||
"freetype": {
|
||||
"url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz", # noqa: E501
|
||||
"url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz",
|
||||
"filename": "freetype-2.13.2.tar.gz",
|
||||
"dir": "freetype-2.13.2",
|
||||
"license": ["LICENSE.TXT", r"docs\FTL.TXT", r"docs\GPLv2.TXT"],
|
||||
|
@ -321,7 +321,7 @@ DEPS = {
|
|||
},
|
||||
"libimagequant": {
|
||||
# commit: Merge branch 'master' into msvc (matches 2.17.0 tag)
|
||||
"url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip", # noqa: E501
|
||||
"url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip",
|
||||
"filename": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab.zip",
|
||||
"dir": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab",
|
||||
"license": "COPYRIGHT",
|
||||
|
|
Loading…
Reference in New Issue
Block a user