Merge pull request #7750 from hugovk/type-hints-replace-io.BytesIO

Replace `io.BytesIO` in type hints
This commit is contained in:
Andrew Murray 2024-02-13 21:29:52 +11:00 committed by GitHub
commit 3374e91d5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 48 additions and 47 deletions

View File

@ -12,6 +12,9 @@ exclude_also =
except ImportError
if TYPE_CHECKING:
@abc.abstractmethod
# Empty bodies in protocols or abstract methods
^\s*def [a-zA-Z0-9_]+\(.*\)(\s*->.*)?:\s*\.\.\.(\s*#.*)?$
^\s*\.\.\.(\s*#.*)?$
[run]
omit =

View File

@ -162,8 +162,6 @@ class TestImage:
pass
def test_pathlib(self, tmp_path: Path) -> None:
from PIL.Image import Path
with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im:
assert im.mode == "P"
assert im.size == (10, 10)

View File

@ -1,29 +1,16 @@
from __future__ import annotations
from pathlib import Path
from pathlib import Path, PurePath
import pytest
from PIL import _util
def test_is_path() -> None:
# Arrange
fp = "filename.ext"
# Act
it_is = _util.is_path(fp)
# Assert
assert it_is
def test_path_obj_is_path() -> None:
# Arrange
from pathlib import Path
test_path = Path("filename.ext")
@pytest.mark.parametrize(
"test_path", ["filename.ext", Path("filename.ext"), PurePath("filename.ext")]
)
def test_is_path(test_path) -> None:
# Act
it_is = _util.is_path(test_path)

View File

@ -1,5 +1,5 @@
Internal Reference Docs
=======================
Internal Reference
==================
.. toctree::
:maxdepth: 2

View File

@ -33,6 +33,14 @@ Internal Modules
Provides a convenient way to import type hints that are not available
on some Python versions.
.. py:class:: StrOrBytesPath
Typing alias.
.. py:class:: SupportsRead
An object that supports the read method.
.. py:data:: TypeGuard
:value: typing.TypeGuard

View File

@ -3,7 +3,7 @@
File Handling in Pillow
=======================
When opening a file as an image, Pillow requires a filename, ``pathlib.Path``
When opening a file as an image, Pillow requires a filename, ``os.PathLike``
object, or a file-like object. Pillow uses the filename or ``Path`` to open a
file, so for the rest of this article, they will all be treated as a file-like
object.

View File

@ -27,11 +27,12 @@
"""
from __future__ import annotations
from io import BytesIO
from typing import IO
from . import ImageFile, ImagePalette, UnidentifiedImageError
from ._binary import i16be as i16
from ._binary import i32be as i32
from ._typing import StrOrBytesPath
class GdImageFile(ImageFile.ImageFile):
@ -80,7 +81,7 @@ class GdImageFile(ImageFile.ImageFile):
]
def open(fp: BytesIO, mode: str = "r") -> GdImageFile:
def open(fp: StrOrBytesPath | IO[bytes], mode: str = "r") -> GdImageFile:
"""
Load texture from a GD image file.

View File

@ -40,7 +40,6 @@ import tempfile
import warnings
from collections.abc import Callable, MutableMapping
from enum import IntEnum
from pathlib import Path
from types import ModuleType
from typing import IO, TYPE_CHECKING, Any
@ -2383,7 +2382,7 @@ class Image:
implement the ``seek``, ``tell``, and ``write``
methods, and be opened in binary mode.
:param fp: A filename (string), pathlib.Path object or file object.
:param fp: A filename (string), os.PathLike object or file object.
:param format: Optional format override. If omitted, the
format to use is determined from the filename extension.
If a file object was used instead of a filename, this
@ -2398,11 +2397,8 @@ class Image:
filename: str | bytes = ""
open_fp = False
if isinstance(fp, Path):
filename = str(fp)
open_fp = True
elif isinstance(fp, (str, bytes)):
filename = fp
if is_path(fp):
filename = os.path.realpath(os.fspath(fp))
open_fp = True
elif fp == sys.stdout:
try:
@ -3225,7 +3221,7 @@ def open(fp, mode="r", formats=None) -> Image:
:py:meth:`~PIL.Image.Image.load` method). See
:py:func:`~PIL.Image.new`. See :ref:`file-handling`.
:param fp: A filename (string), pathlib.Path object or a file object.
:param fp: A filename (string), os.PathLike object or a file object.
The file object must implement ``file.read``,
``file.seek``, and ``file.tell`` methods,
and be opened in binary mode. The file object will also seek to zero

View File

@ -33,10 +33,10 @@ import sys
import warnings
from enum import IntEnum
from io import BytesIO
from pathlib import Path
from typing import BinaryIO
from . import Image
from ._typing import StrOrBytesPath
from ._util import is_directory, is_path
@ -193,7 +193,7 @@ class FreeTypeFont:
def __init__(
self,
font: bytes | str | Path | BinaryIO | None = None,
font: StrOrBytesPath | BinaryIO | None = None,
size: float = 10,
index: int = 0,
encoding: str = "",
@ -230,8 +230,7 @@ class FreeTypeFont:
)
if is_path(font):
if isinstance(font, Path):
font = str(font)
font = os.path.realpath(os.fspath(font))
if sys.platform == "win32":
font_bytes_path = font if isinstance(font, bytes) else font.encode()
try:

View File

@ -14,17 +14,16 @@
#
from __future__ import annotations
from io import BytesIO
from . import Image, ImageFile
from ._binary import i8
from ._typing import SupportsRead
#
# Bitstream parser
class BitStream:
def __init__(self, fp: BytesIO) -> None:
def __init__(self, fp: SupportsRead[bytes]) -> None:
self.fp = fp
self.bits = 0
self.bitbuffer = 0

View File

@ -1,7 +1,8 @@
from __future__ import annotations
import os
import sys
from typing import Sequence, Union
from typing import Protocol, Sequence, TypeVar, Union
if sys.version_info >= (3, 10):
from typing import TypeGuard
@ -19,4 +20,14 @@ else:
Coords = Union[Sequence[float], Sequence[Sequence[float]]]
__all__ = ["TypeGuard"]
_T_co = TypeVar("_T_co", covariant=True)
class SupportsRead(Protocol[_T_co]):
def read(self, __length: int = ...) -> _T_co: ...
StrOrBytesPath = Union[str, bytes, "os.PathLike[str]", "os.PathLike[bytes]"]
__all__ = ["TypeGuard", "StrOrBytesPath", "SupportsRead"]

View File

@ -1,17 +1,16 @@
from __future__ import annotations
import os
from pathlib import Path
from typing import Any, NoReturn
from ._typing import TypeGuard
from ._typing import StrOrBytesPath, TypeGuard
def is_path(f: Any) -> TypeGuard[bytes | str | Path]:
return isinstance(f, (bytes, str, Path))
def is_path(f: Any) -> TypeGuard[StrOrBytesPath]:
return isinstance(f, (bytes, str, os.PathLike))
def is_directory(f: Any) -> TypeGuard[bytes | str | Path]:
def is_directory(f: Any) -> TypeGuard[StrOrBytesPath]:
"""Checks if an object is a string, and that it points to a directory."""
return is_path(f) and os.path.isdir(f)