Skip to content

Commit 3374e91

Browse files
authored
Merge pull request #7750 from hugovk/type-hints-replace-io.BytesIO
Replace `io.BytesIO` in type hints
2 parents cdecb3d + 29dd025 commit 3374e91

12 files changed

Lines changed: 48 additions & 47 deletions

File tree

.coveragerc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ exclude_also =
1212
except ImportError
1313
if TYPE_CHECKING:
1414
@abc.abstractmethod
15+
# Empty bodies in protocols or abstract methods
16+
^\s*def [a-zA-Z0-9_]+\(.*\)(\s*->.*)?:\s*\.\.\.(\s*#.*)?$
17+
^\s*\.\.\.(\s*#.*)?$
1518

1619
[run]
1720
omit =

Tests/test_image.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,6 @@ def test_stringio(self) -> None:
162162
pass
163163

164164
def test_pathlib(self, tmp_path: Path) -> None:
165-
from PIL.Image import Path
166-
167165
with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im:
168166
assert im.mode == "P"
169167
assert im.size == (10, 10)

Tests/test_util.py

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,16 @@
11
from __future__ import annotations
22

3-
from pathlib import Path
3+
from pathlib import Path, PurePath
44

55
import pytest
66

77
from PIL import _util
88

99

10-
def test_is_path() -> None:
11-
# Arrange
12-
fp = "filename.ext"
13-
14-
# Act
15-
it_is = _util.is_path(fp)
16-
17-
# Assert
18-
assert it_is
19-
20-
21-
def test_path_obj_is_path() -> None:
22-
# Arrange
23-
from pathlib import Path
24-
25-
test_path = Path("filename.ext")
26-
10+
@pytest.mark.parametrize(
11+
"test_path", ["filename.ext", Path("filename.ext"), PurePath("filename.ext")]
12+
)
13+
def test_is_path(test_path) -> None:
2714
# Act
2815
it_is = _util.is_path(test_path)
2916

docs/reference/internal_design.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Internal Reference Docs
2-
=======================
1+
Internal Reference
2+
==================
33

44
.. toctree::
55
:maxdepth: 2

docs/reference/internal_modules.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ Internal Modules
3333
Provides a convenient way to import type hints that are not available
3434
on some Python versions.
3535

36+
.. py:class:: StrOrBytesPath
37+
38+
Typing alias.
39+
40+
.. py:class:: SupportsRead
41+
42+
An object that supports the read method.
43+
3644
.. py:data:: TypeGuard
3745
:value: typing.TypeGuard
3846

docs/reference/open_files.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
File Handling in Pillow
44
=======================
55

6-
When opening a file as an image, Pillow requires a filename, ``pathlib.Path``
6+
When opening a file as an image, Pillow requires a filename, ``os.PathLike``
77
object, or a file-like object. Pillow uses the filename or ``Path`` to open a
88
file, so for the rest of this article, they will all be treated as a file-like
99
object.

src/PIL/GdImageFile.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ class is not registered for use with :py:func:`PIL.Image.open()`. To open a
2727
"""
2828
from __future__ import annotations
2929

30-
from io import BytesIO
30+
from typing import IO
3131

3232
from . import ImageFile, ImagePalette, UnidentifiedImageError
3333
from ._binary import i16be as i16
3434
from ._binary import i32be as i32
35+
from ._typing import StrOrBytesPath
3536

3637

3738
class GdImageFile(ImageFile.ImageFile):
@@ -80,7 +81,7 @@ def _open(self) -> None:
8081
]
8182

8283

83-
def open(fp: BytesIO, mode: str = "r") -> GdImageFile:
84+
def open(fp: StrOrBytesPath | IO[bytes], mode: str = "r") -> GdImageFile:
8485
"""
8586
Load texture from a GD image file.
8687

src/PIL/Image.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import warnings
4141
from collections.abc import Callable, MutableMapping
4242
from enum import IntEnum
43-
from pathlib import Path
4443
from types import ModuleType
4544
from typing import IO, TYPE_CHECKING, Any
4645

@@ -2383,7 +2382,7 @@ def save(self, fp, format=None, **params) -> None:
23832382
implement the ``seek``, ``tell``, and ``write``
23842383
methods, and be opened in binary mode.
23852384
2386-
:param fp: A filename (string), pathlib.Path object or file object.
2385+
:param fp: A filename (string), os.PathLike object or file object.
23872386
:param format: Optional format override. If omitted, the
23882387
format to use is determined from the filename extension.
23892388
If a file object was used instead of a filename, this
@@ -2398,11 +2397,8 @@ def save(self, fp, format=None, **params) -> None:
23982397

23992398
filename: str | bytes = ""
24002399
open_fp = False
2401-
if isinstance(fp, Path):
2402-
filename = str(fp)
2403-
open_fp = True
2404-
elif isinstance(fp, (str, bytes)):
2405-
filename = fp
2400+
if is_path(fp):
2401+
filename = os.path.realpath(os.fspath(fp))
24062402
open_fp = True
24072403
elif fp == sys.stdout:
24082404
try:
@@ -3225,7 +3221,7 @@ def open(fp, mode="r", formats=None) -> Image:
32253221
:py:meth:`~PIL.Image.Image.load` method). See
32263222
:py:func:`~PIL.Image.new`. See :ref:`file-handling`.
32273223
3228-
:param fp: A filename (string), pathlib.Path object or a file object.
3224+
:param fp: A filename (string), os.PathLike object or a file object.
32293225
The file object must implement ``file.read``,
32303226
``file.seek``, and ``file.tell`` methods,
32313227
and be opened in binary mode. The file object will also seek to zero

src/PIL/ImageFont.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@
3333
import warnings
3434
from enum import IntEnum
3535
from io import BytesIO
36-
from pathlib import Path
3736
from typing import BinaryIO
3837

3938
from . import Image
39+
from ._typing import StrOrBytesPath
4040
from ._util import is_directory, is_path
4141

4242

@@ -193,7 +193,7 @@ class FreeTypeFont:
193193

194194
def __init__(
195195
self,
196-
font: bytes | str | Path | BinaryIO | None = None,
196+
font: StrOrBytesPath | BinaryIO | None = None,
197197
size: float = 10,
198198
index: int = 0,
199199
encoding: str = "",
@@ -230,8 +230,7 @@ def load_from_bytes(f):
230230
)
231231

232232
if is_path(font):
233-
if isinstance(font, Path):
234-
font = str(font)
233+
font = os.path.realpath(os.fspath(font))
235234
if sys.platform == "win32":
236235
font_bytes_path = font if isinstance(font, bytes) else font.encode()
237236
try:

src/PIL/MpegImagePlugin.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@
1414
#
1515
from __future__ import annotations
1616

17-
from io import BytesIO
18-
1917
from . import Image, ImageFile
2018
from ._binary import i8
19+
from ._typing import SupportsRead
2120

2221
#
2322
# Bitstream parser
2423

2524

2625
class BitStream:
27-
def __init__(self, fp: BytesIO) -> None:
26+
def __init__(self, fp: SupportsRead[bytes]) -> None:
2827
self.fp = fp
2928
self.bits = 0
3029
self.bitbuffer = 0

0 commit comments

Comments
 (0)