10000 Merge pull request #20126 from anntzer/wfm · matplotlib/matplotlib@9ab4b73 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9ab4b73

Browse files
authored
Merge pull request #20126 from anntzer/wfm
Simplify font_manager font enumeration logic.
2 parents 31d5636 + fa7f42f commit 9ab4b73

File tree

3 files changed

+55
-14
lines changed

3 files changed

+55
-14
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``font_manager`` helpers
2+
~~~~~~~~~~~~~~~~~~~~~~~~
3+
The following functions in `matplotlib.font_manager` have been deprecated:
4+
``win32InstalledFonts``, ``get_fontconfig_fonts``.

lib/matplotlib/font_manager.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ def _win32RegistryFonts(reg_domain, base_dir):
264264
return items
265265

266266

267+
# Also remove _win32RegistryFonts when this is removed.
268+
@_api.deprecated("3.5")
267269
def win32InstalledFonts(directory=None, fontext='ttf'):
268270
"""
269271
Search for fonts in the specified font directory, or use the
@@ -291,9 +293,41 @@ def win32InstalledFonts(directory=None, fontext='ttf'):
291293
return [str(path) for path in items if path.suffix.lower() in fontext]
292294

293295

296+
def _get_win32_installed_fonts():
297+
"""List the font paths known to the Windows registry."""
298+
import winreg
299+
items = set()
300+
# Search and resolve fonts listed in the registry.
301+
for domain, base_dirs in [
302+
(winreg.HKEY_LOCAL_MACHINE, [win32FontDirectory()]), # System.
303+
(winreg.HKEY_CURRENT_USER, MSUserFontDirectories), # User.
304+
]:
305+
for base_dir in base_dirs:
306+
for reg_path in MSFontDirectories:
307+
try:
308+
with winreg.OpenKey(domain, reg_path) as local:
309+
for j in range(winreg.QueryInfoKey(local)[1]):
310+
# value may contain the filename of the font or its
311+
# absolute path.
312+
key, value, tp = winreg.EnumValue(local, j)
313+
if not isinstance(value, str):
314+
continue
315+
try:
316+
# If value contains already an absolute path,
317+
# then it is not changed further.
318+
path = Path(base_dir, value).resolve()
319+
except RuntimeError:
320+
# Don't fail with invalid entries.
321+
continue
322+
items.add(path)
323+
except (OSError, MemoryError):
324+
continue
325+
return items
326+
327+
294328
@lru_cache()
295-
def _call_fc_list():
296-
"""Cache and list the font filenames known to `fc-list`."""
329+
def _get_fontconfig_fonts():
330+
"""Cache and list the font paths known to `fc-list`."""
297331
try:
298332
if b'--format' not in subprocess.check_output(['fc-list', '--help']):
299333
_log.warning( # fontconfig 2.7 implemented --format.
@@ -302,14 +336,15 @@ def _call_fc_list():
302336
out = subprocess.check_output(['fc-list', '--format=%{file}\\n'])
303337
except (OSError, subprocess.CalledProcessError):
304338
return []
305-
return [os.fsdecode(fname) for fname in out.split(b'\n')]
339+
return [Path(os.fsdecode(fname)) for fname in out.split(b'\n')]
306340

307341

342+
@_api.deprecated("3.5")
308343
def get_fontconfig_fonts(fontext='ttf'):
309344
"""List font filenames known to `fc-list` having the given extension."""
310345
fontext = ['.' + ext for ext in get_fontext_synonyms(fontext)]
311-
return [fname for fname in _call_fc_list()
312-
if Path(fname).suffix.lower() in fontext]
346+
return [str(path) for path in _get_fontconfig_fonts()
347+
if path.suffix.lower() in fontext]
313348

314349

315350
def findSystemFonts(fontpaths=None, fontext='ttf'):
@@ -325,14 +360,16 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
325360

326361
if fontpaths is None:
327362
if sys.platform == 'win32':
363+
installed_fonts = _get_win32_installed_fonts()
328364
fontpaths = MSUserFontDirectories + [win32FontDirectory()]
329-
# now get all installed fonts directly...
330-
fontfiles.update(win32InstalledFonts(fontext=fontext))
331365
else:
332-
fontpaths = X11FontDirectories
366+
installed_fonts = _get_fontconfig_fonts()
333367
if sys.platform == 'darwin':
334368
fontpaths = [*X11FontDirectories, *OSXFontDirectories]
335-
fontfiles.update(get_fontconfig_fonts(fontext))
369+
else:
370+
fontpaths = X11FontDirectories
371+
fontfiles.update(str(path) for path in installed_fonts
372+
if path.suffix.lower()[1:] in fontexts)
336373

337374
elif isinstance(fontpaths, str):
338375
fontpaths = [fontpaths]

lib/matplotlib/tests/test_font_manager.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
from matplotlib.font_manager import (
1414
findfont, findSystemFonts, FontProperties, fontManager, json_dump,
15-
json_load, get_font, get_fontconfig_fonts, is_opentype_cff_font,
16-
MSUserFontDirectories, _call_fc_list)
15+
json_load, get_font, is_opentype_cff_font, MSUserFontDirectories,
16+
_get_fontconfig_fonts)
1717
from matplotlib import pyplot as plt, rc_context
1818

1919
has_fclist = shutil.which('fc-list') is not None
@@ -73,7 +73,7 @@ def test_otf():
7373

7474
@pytest.mark.skipif(not has_fclist, reason='no fontconfig installed')
7575
def test_get_fontconfig_fonts():
76-
assert len(get_fontconfig_fonts()) > 1
76+
assert len(_get_fontconfig_fonts()) > 1
7777

7878

7979
@pytest.mark.parametrize('factor', [2, 4, 6, 8])
@@ -154,13 +154,13 @@ def test_user_fonts_linux(tmpdir, monkeypatch):
154154

155155
with monkeypatch.context() as m:
156156
m.setenv('XDG_DATA_HOME', str(tmpdir))
157-
_call_fc_list.cache_clear()
157+
_get_fontconfig_fonts.cache_clear()
158158
# Now, the font should be available
159159
fonts = findSystemFonts()
160160
assert any(font_test_file in font for font in fonts)
161161

162162
# Make sure the temporary directory is no longer cached.
163-
_call_fc_list.cache_clear()
163+
_get_fontconfig_fonts.cache_clear()
164164

165165

166166
@pytest.mark.skipif(sys.platform != 'win32', reason='Windows only')

0 commit comments

Comments
 (0)
0