Skip to content

Commit

Permalink
Merge branch 'main' into harfbuzz
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed May 21, 2024
2 parents e9b15f8 + d879f39 commit 676a0dd
Show file tree
Hide file tree
Showing 65 changed files with 742 additions and 639 deletions.
2 changes: 1 addition & 1 deletion .ci/requirements-cibw.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cibuildwheel==2.18.0
cibuildwheel==2.18.1
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ BinPackParameters: false
BreakBeforeBraces: Attach
ColumnLimit: 88
DerivePointerAlignment: false
IndentGotoLabels: false
IndentWidth: 4
Language: Cpp
PointerAlignment: Right
Expand Down
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ repos:
- id: remove-tabs
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.4
hooks:
- id: clang-format
types: [c]
exclude: ^src/thirdparty/

- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
Expand Down
27 changes: 0 additions & 27 deletions Tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,6 @@
uploader = "github_actions"


modes = (
"1",
"L",
"LA",
"La",
"P",
"PA",
"F",
"I",
"I;16",
"I;16L",
"I;16B",
"I;16N",
"RGB",
"RGBA",
"RGBa",
"RGBX",
"BGR;15",
"BGR;16",
"BGR;24",
"CMYK",
"YCbCr",
"HSV",
"LAB",
)


def upload(a: Image.Image, b: Image.Image) -> str | None:
if uploader == "show":
# local img.show for errors.
Expand Down
9 changes: 4 additions & 5 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
is_big_endian,
is_win32,
mark_if_feature_version,
modes,
skip_unless_feature,
)

Expand All @@ -46,7 +45,7 @@ def helper_image_new(mode: str, size: tuple[int, int]) -> Image.Image:


class TestImage:
@pytest.mark.parametrize("mode", modes)
@pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"])
def test_image_modes_success(self, mode: str) -> None:
helper_image_new(mode, (1, 1))

Expand Down Expand Up @@ -1027,7 +1026,7 @@ def test_close_graceful(self, caplog: pytest.LogCaptureFixture) -> None:


class TestImageBytes:
@pytest.mark.parametrize("mode", modes)
@pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"])
def test_roundtrip_bytes_constructor(self, mode: str) -> None:
im = hopper(mode)
source_bytes = im.tobytes()
Expand All @@ -1039,7 +1038,7 @@ def test_roundtrip_bytes_constructor(self, mode: str) -> None:
reloaded = Image.frombytes(mode, im.size, source_bytes)
assert reloaded.tobytes() == source_bytes

@pytest.mark.parametrize("mode", modes)
@pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"])
def test_roundtrip_bytes_method(self, mode: str) -> None:
im = hopper(mode)
source_bytes = im.tobytes()
Expand All @@ -1048,7 +1047,7 @@ def test_roundtrip_bytes_method(self, mode: str) -> None:
reloaded.frombytes(source_bytes)
assert reloaded.tobytes() == source_bytes

@pytest.mark.parametrize("mode", modes)
@pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"])
def test_getdata_putdata(self, mode: str) -> None:
if is_big_endian() and mode == "BGR;15":
pytest.xfail("Known failure of BGR;15 on big-endian")
Expand Down
13 changes: 7 additions & 6 deletions Tests/test_image_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from PIL import Image

from .helper import assert_image_equal, hopper, is_win32, modes
from .helper import assert_image_equal, hopper, is_win32

# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
Expand Down Expand Up @@ -205,12 +205,13 @@ def check(self, mode: str, expected_color_int: int | None = None) -> None:
with pytest.raises(error):
im.getpixel((-1, -1))

@pytest.mark.parametrize("mode", modes)
@pytest.mark.parametrize("mode", Image.MODES)
def test_basic(self, mode: str) -> None:
if mode.startswith("BGR;"):
with pytest.warns(DeprecationWarning):
self.check(mode)
else:
self.check(mode)

@pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24"))
def test_deprecated(self, mode: str) -> None:
with pytest.warns(DeprecationWarning):
self.check(mode)

def test_list(self) -> None:
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
def get_version():
version_file = "src/PIL/_version.py"
with open(version_file, encoding="utf-8") as f:
exec(compile(f.read(), version_file, "exec"))
return locals()["__version__"]
return f.read().split('"')[1]


configuration = {}
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def _open(self) -> None:
else:
self.tile = [ImageFile._Tile("raw", extents, 0, rawmode or self.mode)]

def load_seek(self, pos):
def load_seek(self, pos: int) -> None:
pass


Expand Down
4 changes: 2 additions & 2 deletions src/PIL/EpsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
gs_windows_binary = None


def has_ghostscript():
def has_ghostscript() -> bool:
global gs_binary, gs_windows_binary
if gs_binary is None:
if sys.platform.startswith("win"):
Expand Down Expand Up @@ -404,7 +404,7 @@ def load(self, scale=1, transparency=False):
self.tile = []
return Image.Image.load(self)

def load_seek(self, pos):
def load_seek(self, pos: int) -> None:
# we can't incrementally load, so force ImageFile.parser to
# use our custom load method by defining this method.
pass
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FliImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def seek(self, frame: int) -> None:
for f in range(self.__frame + 1, frame + 1):
self._seek(f)

def _seek(self, frame):
def _seek(self, frame: int) -> None:
if frame == 0:
self.__frame = -1
self._fp.seek(self.__rewind)
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FtexImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _open(self) -> None:
self.fp.close()
self.fp = BytesIO(data)

def load_seek(self, pos):
def load_seek(self, pos: int) -> None:
pass


Expand Down
10 changes: 5 additions & 5 deletions src/PIL/GifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def data(self) -> bytes | None:
return self.fp.read(s[0])
return None

def _is_palette_needed(self, p):
def _is_palette_needed(self, p: bytes) -> bool:
for i in range(0, len(p), 3):
if not (i // 3 == p[i] == p[i + 1] == p[i + 2]):
return True
Expand Down Expand Up @@ -474,7 +474,7 @@ def tell(self) -> int:
RAWMODE = {"1": "L", "L": "L", "P": "P"}


def _normalize_mode(im):
def _normalize_mode(im: Image.Image) -> Image.Image:
"""
Takes an image (or frame), returns an image in a mode that is appropriate
for saving in a Gif.
Expand Down Expand Up @@ -887,7 +887,7 @@ def _get_optimize(im, info):
return used_palette_colors


def _get_color_table_size(palette_bytes):
def _get_color_table_size(palette_bytes: bytes) -> int:
# calculate the palette size for the header
if not palette_bytes:
return 0
Expand All @@ -897,7 +897,7 @@ def _get_color_table_size(palette_bytes):
return math.ceil(math.log(len(palette_bytes) // 3, 2)) - 1


def _get_header_palette(palette_bytes):
def _get_header_palette(palette_bytes: bytes) -> bytes:
"""
Returns the palette, null padded to the next power of 2 (*3) bytes
suitable for direct inclusion in the GIF header
Expand All @@ -915,7 +915,7 @@ def _get_header_palette(palette_bytes):
return palette_bytes


def _get_palette_bytes(im):
def _get_palette_bytes(im: Image.Image) -> bytes:
"""
Gets the palette for inclusion in the gif header
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GimpPaletteFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ def __init__(self, fp):

self.palette = b"".join(self.palette)

def getpalette(self):
def getpalette(self) -> tuple[bytes, str]:
return self.palette, self.rawmode
2 changes: 1 addition & 1 deletion src/PIL/IcoImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def load(self):

self.size = im.size

def load_seek(self, pos):
def load_seek(self, pos: int) -> None:
# Flag the ImageFile.Parser so that it
# just does all the decode at the end.
pass
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/ImImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,11 @@ def _open(self) -> None:
self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))]

@property
def n_frames(self):
def n_frames(self) -> int:
return self.info[FRAMES]

@property
def is_animated(self):
def is_animated(self) -> bool:
return self.info[FRAMES] > 1

def seek(self, frame: int) -> None:
Expand Down
7 changes: 5 additions & 2 deletions src/PIL/ImageDraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import math
import numbers
import struct
from typing import Sequence, cast
from typing import TYPE_CHECKING, Sequence, cast

from . import Image, ImageColor
from ._typing import Coords
Expand Down Expand Up @@ -92,7 +92,10 @@ def __init__(self, im: Image.Image, mode: str | None = None) -> None:
self.fontmode = "L" # aliasing is okay for other modes
self.fill = False

def getfont(self):
if TYPE_CHECKING:
from . import ImageFont

def getfont(self) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
"""
Get the current default font.
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,11 @@ def load_end(self) -> None:
pass

# may be defined for contained formats
# def load_seek(self, pos):
# def load_seek(self, pos: int) -> None:
# pass

# may be defined for blocked formats (e.g. PNG)
# def load_read(self, read_bytes):
# def load_read(self, read_bytes: int) -> bytes:
# pass

def _seek_check(self, frame):
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/ImageFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ def transform(self, callback, with_normals=False, channels=None, target_mode=Non
_copy_table=False,
)

def __repr__(self):
def __repr__(self) -> str:
r = [
f"{self.__class__.__name__} from {self.table.__class__.__name__}",
"size={:d}x{:d}x{:d}".format(*self.size),
Expand Down
6 changes: 3 additions & 3 deletions src/PIL/ImagePalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def colors(self):
def colors(self, colors):
self._colors = colors

def copy(self):
def copy(self) -> ImagePalette:
new = ImagePalette()

new.mode = self.mode
Expand All @@ -77,7 +77,7 @@ def copy(self):

return new

def getdata(self):
def getdata(self) -> tuple[str, bytes]:
"""
Get palette contents in format suitable for the low-level
``im.putpalette`` primitive.
Expand All @@ -88,7 +88,7 @@ def getdata(self):
return self.rawmode, self.palette
return self.mode, self.tobytes()

def tobytes(self):
def tobytes(self) -> bytes:
"""Convert palette to bytes.
.. warning:: This method is experimental.
Expand Down
12 changes: 6 additions & 6 deletions src/PIL/ImageTk.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def __del__(self) -> None:
except Exception:
pass # ignore internal errors

def __str__(self):
def __str__(self) -> str:
"""
Get the Tkinter photo image identifier. This method is automatically
called by Tkinter whenever a PhotoImage object is passed to a Tkinter
Expand All @@ -146,15 +146,15 @@ def __str__(self):
"""
return str(self.__photo)

def width(self):
def width(self) -> int:
"""
Get the width of the image.
:return: The width, in pixels.
"""
return self.__size[0]

def height(self):
def height(self) -> int:
"""
Get the height of the image.
Expand Down Expand Up @@ -227,23 +227,23 @@ def __del__(self) -> None:
except Exception:
pass # ignore internal errors

def width(self):
def width(self) -> int:
"""
Get the width of the image.
:return: The width, in pixels.
"""
return self.__size[0]

def height(self):
def height(self) -> int:
"""
Get the height of the image.
:return: The height, in pixels.
"""
return self.__size[1]

def __str__(self):
def __str__(self) -> str:
"""
Get the Tkinter bitmap image identifier. This method is automatically
called by Tkinter whenever a BitmapImage object is passed to a Tkinter
Expand Down

0 comments on commit 676a0dd

Please sign in to comment.