mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-17 18:54:46 +03:00
Merge 5bd776a621
into 489d6f32f1
This commit is contained in:
commit
c45b029717
|
@ -1,5 +1,6 @@
|
|||
import io
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
@ -21,6 +22,22 @@ from .helper import (
|
|||
)
|
||||
|
||||
|
||||
class MyStrPathLike:
|
||||
def __init__(self, path_str):
|
||||
self.path_str = path_str
|
||||
|
||||
def __fspath__(self):
|
||||
return self.path_str
|
||||
|
||||
|
||||
class MyBytesPathLike:
|
||||
def __init__(self, path_str):
|
||||
self.path_bytes = os.fsencode(path_str)
|
||||
|
||||
def __fspath__(self):
|
||||
return self.path_bytes
|
||||
|
||||
|
||||
class TestImage:
|
||||
def test_image_modes_success(self):
|
||||
for mode in [
|
||||
|
@ -149,22 +166,30 @@ class TestImage:
|
|||
with Image.open(io.StringIO()):
|
||||
pass
|
||||
|
||||
def test_pathlib(self, tmp_path):
|
||||
from PIL.Image import Path
|
||||
|
||||
with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im:
|
||||
@pytest.mark.parametrize(
|
||||
"PathCls",
|
||||
(
|
||||
pathlib.Path,
|
||||
MyStrPathLike, # Returns `str` on `os.fspath`
|
||||
MyBytesPathLike, # Returns `bytes` on `os.fspath`
|
||||
str,
|
||||
os.fsencode, # Converts path to `bytes`
|
||||
),
|
||||
)
|
||||
def test_path_like(self, tmp_path, PathCls):
|
||||
with Image.open(PathCls("Tests/images/multipage-mmap.tiff")) as im:
|
||||
assert im.mode == "P"
|
||||
assert im.size == (10, 10)
|
||||
|
||||
with Image.open(Path("Tests/images/hopper.jpg")) as im:
|
||||
with Image.open(PathCls("Tests/images/hopper.jpg")) as im:
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
|
||||
for ext in (".jpg", ".jp2"):
|
||||
temp_file = str(tmp_path / ("temp." + ext))
|
||||
temp_file = str((tmp_path / "temp").with_suffix(ext))
|
||||
if os.path.exists(temp_file):
|
||||
os.remove(temp_file)
|
||||
im.save(Path(temp_file))
|
||||
im.save(PathCls(temp_file))
|
||||
|
||||
def test_fp_name(self, tmp_path):
|
||||
temp_file = str(tmp_path / "temp.jpg")
|
||||
|
|
|
@ -4,6 +4,7 @@ import re
|
|||
import shutil
|
||||
import sys
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from packaging.version import parse as parse_version
|
||||
|
@ -87,6 +88,7 @@ class TestImageFont:
|
|||
pytest.skip("Non-ASCII path could not be created")
|
||||
|
||||
ImageFont.truetype(tempfile, FONT_SIZE)
|
||||
ImageFont.truetype(Path(tempfile), FONT_SIZE)
|
||||
|
||||
def _render(self, font):
|
||||
txt = "Hello World!"
|
||||
|
|
|
@ -27,6 +27,21 @@ def test_path_obj_is_path():
|
|||
assert it_is
|
||||
|
||||
|
||||
def test_path_like_is_path():
|
||||
# Arrange
|
||||
class PathThingy:
|
||||
def __fspath__(self):
|
||||
return "UNIMPORTANT" # pragma: no cover
|
||||
|
||||
test_path = PathThingy()
|
||||
|
||||
# Act
|
||||
it_is = _util.is_path(test_path)
|
||||
|
||||
# Assert
|
||||
assert it_is
|
||||
|
||||
|
||||
def test_is_not_path(tmp_path):
|
||||
# Arrange
|
||||
with (tmp_path / "temp.ext").open("w") as fp:
|
||||
|
@ -39,6 +54,22 @@ def test_is_not_path(tmp_path):
|
|||
assert not it_is_not
|
||||
|
||||
|
||||
def test_path_like_file_is_not_path(tmp_path):
|
||||
# Arrange
|
||||
import io
|
||||
|
||||
class PathAndFileThingy(io.TextIOWrapper):
|
||||
def __fspath__(self):
|
||||
return "UNIMPORTANT" # pragma: no cover
|
||||
|
||||
with PathAndFileThingy(open(tmp_path / "temp.ext", "wb")) as test_obj:
|
||||
# Act
|
||||
it_is_not = _util.is_path(test_obj)
|
||||
|
||||
# Assert
|
||||
assert not it_is_not
|
||||
|
||||
|
||||
def test_is_directory():
|
||||
# Arrange
|
||||
directory = "Tests"
|
||||
|
|
|
@ -2182,9 +2182,9 @@ class Image:
|
|||
|
||||
def save(self, fp, format=None, **params):
|
||||
"""
|
||||
Saves this image under the given filename. If no format is
|
||||
specified, the format to use is determined from the filename
|
||||
extension, if possible.
|
||||
Saves this image under the given file path. If no format is
|
||||
specified, the format to use is determined from the path's
|
||||
file extension, if possible.
|
||||
|
||||
Keyword options can be used to provide additional instructions
|
||||
to the writer. If a writer doesn't recognise an option, it is
|
||||
|
@ -2192,12 +2192,12 @@ class Image:
|
|||
:doc:`image format documentation
|
||||
<../handbook/image-file-formats>` for each writer.
|
||||
|
||||
You can use a file object instead of a filename. In this case,
|
||||
You can use a file object instead of a file path. In this case,
|
||||
you must always specify the format. The file object must
|
||||
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 file path (str or bytes), path-like 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
|
||||
|
@ -2216,7 +2216,7 @@ class Image:
|
|||
filename = str(fp)
|
||||
open_fp = True
|
||||
elif is_path(fp):
|
||||
filename = fp
|
||||
filename = os.fsdecode(fp)
|
||||
open_fp = True
|
||||
elif fp == sys.stdout:
|
||||
try:
|
||||
|
@ -2992,7 +2992,7 @@ def open(fp, mode="r", formats=None):
|
|||
: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 file path (str or bytes), path-like object or a file object.
|
||||
The file object must implement ``file.read``,
|
||||
``file.seek``, and ``file.tell`` methods,
|
||||
and be opened in binary mode.
|
||||
|
|
|
@ -202,6 +202,7 @@ class FreeTypeFont:
|
|||
)
|
||||
|
||||
if is_path(font):
|
||||
font = os.fspath(font)
|
||||
if sys.platform == "win32":
|
||||
font_bytes_path = font if isinstance(font, bytes) else font.encode()
|
||||
try:
|
||||
|
@ -818,10 +819,10 @@ def load(filename):
|
|||
|
||||
|
||||
def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
||||
"""
|
||||
Load a TrueType or OpenType font from a file or file-like object,
|
||||
r"""
|
||||
Load a TrueType or OpenType font from a file path or file-like object,
|
||||
and create a font object.
|
||||
This function loads a font object from the given file or file-like
|
||||
This function loads a font object from the given file path or file-like
|
||||
object, and creates a font object for a font of the given size.
|
||||
|
||||
Pillow uses FreeType to open font files. If you are opening many fonts
|
||||
|
@ -831,12 +832,12 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
|||
|
||||
This function requires the _imagingft service.
|
||||
|
||||
:param font: A filename or file-like object containing a TrueType font.
|
||||
If the file is not found in this filename, the loader may also
|
||||
search in other directories, such as the :file:`fonts/`
|
||||
:param font: A file path or file-like object containing a TrueType font.
|
||||
If the file is not found at this path, the loader may also
|
||||
search in other directories, such as the :file:`%WINDIR%\fonts\`
|
||||
directory on Windows or :file:`/Library/Fonts/`,
|
||||
:file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/` on
|
||||
macOS.
|
||||
:file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/`
|
||||
on macOS.
|
||||
|
||||
:param size: The requested size, in pixels.
|
||||
:param index: Which font face to load (default is first available face).
|
||||
|
@ -878,7 +879,7 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
|||
except OSError:
|
||||
if not is_path(font):
|
||||
raise
|
||||
ttf_filename = os.path.basename(font)
|
||||
ttf_filename = os.fsdecode(os.path.basename(font))
|
||||
|
||||
dirs = []
|
||||
if sys.platform == "win32":
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def is_path(f):
|
||||
return isinstance(f, (bytes, str, Path))
|
||||
"""
|
||||
Checks whether the given object is a string or path-like object that
|
||||
isn't also a file-like object
|
||||
"""
|
||||
return isinstance(f, (bytes, str, os.PathLike)) and not hasattr(f, "read")
|
||||
|
||||
|
||||
def is_directory(f):
|
||||
|
|
Loading…
Reference in New Issue
Block a user