Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add os.PathLike support to FT2Font constructor, and FontManager#30573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tacaswell merged 1 commit intomatplotlib:text-overhaulfromQuLogic:font-pathlike
Sep 25, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletionslib/matplotlib/font_manager.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1611,10 +1611,10 @@ def get_font(font_filepaths, hinting_factor=None):

Parameters
----------
font_filepaths : Iterable[str,Path, bytes], str,Path, bytes
font_filepaths : Iterable[str,bytes, os.PathLike], str,bytes, os.PathLike
Relative or absolute paths to the font files to be used.

If a single string, bytes, or `pathlib.Path`, then it will be treated
If a single string, bytes, or `os.PathLike`, then it will be treated
as a list with that entry only.

If more than one filepath is passed, then the returned FT2Font object
Expand All@@ -1626,7 +1626,7 @@ def get_font(font_filepaths, hinting_factor=None):
`.ft2font.FT2Font`

"""
if isinstance(font_filepaths, (str,Path, bytes)):
if isinstance(font_filepaths, (str,bytes, os.PathLike)):
paths = (_cached_realpath(font_filepaths),)
else:
paths = tuple(_cached_realpath(fname) for fname in font_filepaths)
Expand Down
14 changes: 7 additions & 7 deletionslib/matplotlib/font_manager.pyi
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,7 +24,7 @@ def list_fonts(directory: str, extensions: Iterable[str]) -> list[str]: ...
def win32FontDirectory() -> str: ...
def _get_fontconfig_fonts() -> list[Path]: ...
def findSystemFonts(
fontpaths: Iterable[str | os.PathLike | Path] | None = ..., fontext: str = ...
fontpaths: Iterable[str | os.PathLike] | None = ..., fontext: str = ...
) -> list[str]: ...
@dataclass
class FontEntry:
Expand All@@ -50,7 +50,7 @@ class FontProperties:
weight: int | str | None = ...,
stretch: int | str | None = ...,
size: float | str | None = ...,
fname: str | os.PathLike |Path |None = ...,
fname: str | os.PathLike | None = ...,
math_fontfamily: str | None = ...,
) -> None: ...
def __hash__(self) -> int: ...
Expand All@@ -72,7 +72,7 @@ class FontProperties:
def set_weight(self, weight: int | str | None) -> None: ...
def set_stretch(self, stretch: int | str | None) -> None: ...
def set_size(self, size: float | str | None) -> None: ...
def set_file(self, file: str | os.PathLike |Path |None) -> None: ...
def set_file(self, file: str | os.PathLike | None) -> None: ...
def set_fontconfig_pattern(self, pattern: str) -> None: ...
def get_math_fontfamily(self) -> str: ...
def set_math_fontfamily(self, fontfamily: str | None) -> None: ...
Expand All@@ -83,8 +83,8 @@ class FontProperties:
set_slant = set_style
get_size_in_points = get_size

def json_dump(data: FontManager, filename: str |Path |os.PathLike) -> None: ...
def json_load(filename: str |Path |os.PathLike) -> FontManager: ...
def json_dump(data: FontManager, filename: str | os.PathLike) -> None: ...
def json_load(filename: str | os.PathLike) -> FontManager: ...

class FontManager:
__version__: str
Expand All@@ -93,7 +93,7 @@ class FontManager:
afmlist: list[FontEntry]
ttflist: list[FontEntry]
def __init__(self, size: float | None = ..., weight: str = ...) -> None: ...
def addfont(self, path: str |Path |os.PathLike) -> None: ...
def addfont(self, path: str | os.PathLike) -> None: ...
@property
def defaultFont(self) -> dict[str, str]: ...
def get_default_weight(self) -> str: ...
Expand All@@ -120,7 +120,7 @@ class FontManager:

def is_opentype_cff_font(filename: str) -> bool: ...
def get_font(
font_filepaths: Iterable[str |Path |bytes] | str |Path |bytes,
font_filepaths: Iterable[str |bytes |os.PathLike] | str |bytes |os.PathLike,
hinting_factor: int | None = ...,
) -> ft2font.FT2Font: ...

Expand Down
5 changes: 3 additions & 2 deletionslib/matplotlib/ft2font.pyi
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
from enum import Enum, Flag
from os import PathLike
import sys
from typing import BinaryIO, Literal, NewType, TypeAlias, TypedDict, cast, final, overload
from typing_extensions import Buffer # < Py 3.12
Expand DownExpand Up@@ -194,7 +195,7 @@ class _SfntPcltDict(TypedDict):
class FT2Font(Buffer):
def __init__(
self,
filename: str | BinaryIO,
filename: str |bytes | PathLike |BinaryIO,
hinting_factor: int = ...,
*,
_fallback_list: list[FT2Font] | None = ...,
Expand DownExpand Up@@ -256,7 +257,7 @@ class FT2Font(Buffer):
@property
def family_name(self) -> str: ...
@property
def fname(self) -> str: ...
def fname(self) -> str | bytes: ...
@property
def height(self) -> int: ...
@property
Expand Down
33 changes: 27 additions & 6 deletionslib/matplotlib/tests/test_font_manager.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
from io import BytesIO, StringIO
from io import BytesIO
import gc
import multiprocessing
import os
Expand DownExpand Up@@ -137,6 +137,32 @@ def test_find_noto():
fig.savefig(BytesIO(), format=fmt)


def test_find_valid():
class PathLikeClass:
def __init__(self, filename):
self.filename = filename

def __fspath__(self):
return self.filename

file_str = findfont('DejaVu Sans')
file_bytes = os.fsencode(file_str)

font = get_font(file_str)
assert font.fname == file_str
font = get_font(file_bytes)
assert font.fname == file_bytes
font = get_font(PathLikeClass(file_str))
assert font.fname == file_str
font = get_font(PathLikeClass(file_bytes))
assert font.fname == file_bytes

# Note, fallbacks are not currently accessible.
font = get_font([file_str, file_bytes,
PathLikeClass(file_str), PathLikeClass(file_bytes)])
assert font.fname == file_str


def test_find_invalid(tmp_path):

with pytest.raises(FileNotFoundError):
Expand All@@ -148,11 +174,6 @@ def test_find_invalid(tmp_path):
with pytest.raises(FileNotFoundError):
get_font(bytes(tmp_path / 'non-existent-font-name.ttf'))

# Not really public, but get_font doesn't expose non-filename constructor.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

note to future reviewers, this was removed as redundent with other test

from matplotlib.ft2font import FT2Font
with pytest.raises(TypeError, match='font file or a binary-mode file'):
FT2Font(StringIO()) # type: ignore[arg-type]


@pytest.mark.skipif(sys.platform != 'linux' or not has_fclist,
reason='only Linux with fontconfig installed')
Expand Down
22 changes: 22 additions & 0 deletionslib/matplotlib/tests/test_ft2font.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
import itertools
import io
import os
from pathlib import Path
from typing import cast

Expand DownExpand Up@@ -134,6 +135,27 @@ def test_ft2font_stix_bold_attrs():
assert font.bbox == (4, -355, 1185, 2095)


def test_ft2font_valid_args():
class PathLikeClass:
def __init__(self, filename):
self.filename = filename

def __fspath__(self):
return self.filename

file_str = fm.findfont('DejaVu Sans')
file_bytes = os.fsencode(file_str)

font = ft2font.FT2Font(file_str)
assert font.fname == file_str
font = ft2font.FT2Font(file_bytes)
assert font.fname == file_bytes
font = ft2font.FT2Font(PathLikeClass(file_str))
assert font.fname == file_str
font = ft2font.FT2Font(PathLikeClass(file_bytes))
assert font.fname == file_bytes


def test_ft2font_invalid_args(tmp_path):
# filename argument.
with pytest.raises(TypeError, match='to a font file or a binary-mode file object'):
Expand Down
13 changes: 8 additions & 5 deletionssrc/ft2font_wrapper.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -424,7 +424,7 @@ close_file_callback(FT_Stream stream)
const char *PyFT2Font_init__doc__ = R"""(
Parameters
----------
filename : strorfile-like
filename : str, bytes, os.PathLike,orio.BinaryIO
The source of the font data in a format (ttf or ttc) that FreeType can read.

hinting_factor : int, optional
Expand DownExpand Up@@ -488,7 +488,10 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8,
open_args.flags = FT_OPEN_STREAM;
open_args.stream = &self->stream;

if (py::isinstance<py::bytes>(filename) || py::isinstance<py::str>(filename)) {
auto PathLike = py::module_::import("os").attr("PathLike");
if (py::isinstance<py::bytes>(filename) || py::isinstance<py::str>(filename) ||
py::isinstance(filename, PathLike))
{
self->py_file = py::module_::import("io").attr("open")(filename, "rb");
self->stream.close = &close_file_callback;
} else {
Expand All@@ -511,13 +514,13 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8,
return self;
}

static py::str
static py::object
PyFT2Font_fname(PyFT2Font *self)
{
if (self->stream.close) { //Called passed a filename to the constructor.
if (self->stream.close) { //User passed a filename to the constructor.
return self->py_file.attr("name");
} else {
returnpy::cast<py::str>(self->py_file);
return self->py_file;
}
}

Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp