Skip to content

Commit 93d09be

Browse files
committed
Merge pull request #7596 from anntzer/delay-fc-list-warning
Delay fc-list warning by 5s.
1 parent e09a6f7 commit 93d09be

File tree

2 files changed

+52
-47
lines changed

2 files changed

+52
-47
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
`afm.get_fontconfig_fonts` returns a list of paths and does not check for existence
2+
```````````````````````````````````````````````````````````````````````````````````
3+
4+
`afm.get_fontconfig_fonts` used to return a set of paths encoded as a
5+
``{key: 1, ...}`` dict, and checked for the existence of the paths. It now
6+
returns a list and dropped the existence check, as the same check is performed
7+
by the caller (`afm.findSystemFonts`) as well.

lib/matplotlib/font_manager.py

+45-47
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,19 @@
4747
see license/LICENSE_TTFQUERY.
4848
"""
4949

50-
import os, sys, warnings
51-
try:
52-
set
53-
except NameError:
54-
from sets import Set as set
5550
from collections import Iterable
51+
import json
52+
import os
53+
import sys
54+
from threading import Timer
55+
import warnings
56+
5657
import matplotlib
57-
from matplotlib import afm
58-
from matplotlib import ft2font
59-
from matplotlib import rcParams, get_cachedir
58+
from matplotlib import afm, cbook, ft2font, rcParams, get_cachedir
6059
from matplotlib.cbook import is_string_like
61-
import matplotlib.cbook as cbook
6260
from matplotlib.compat import subprocess
63-
from matplotlib.fontconfig_pattern import \
64-
parse_fontconfig_pattern, generate_fontconfig_pattern
61+
from matplotlib.fontconfig_pattern import (
62+
parse_fontconfig_pattern, generate_fontconfig_pattern)
6563

6664
try:
6765
from functools import lru_cache
@@ -265,39 +263,39 @@ def OSXInstalledFonts(directories=None, fontext='ttf'):
265263
files.extend(list_fonts(path, fontext))
266264
return files
267265

268-
def get_fontconfig_fonts(fontext='ttf'):
266+
267+
@lru_cache()
268+
def _call_fc_list():
269+
"""Cache and list the font filenames known to `fc-list`.
269270
"""
270-
Grab a list of all the fonts that are being tracked by fontconfig
271-
by making a system call to ``fc-list``. This is an easy way to
272-
grab all of the fonts the user wants to be made available to
273-
applications, without needing knowing where all of them reside.
271+
# Delay the warning by 5s.
272+
timer = Timer(5, lambda: warnings.warn(
273+
'Matplotlib is building the font cache using fc-list. '
274+
'This may take a moment.'))
275+
timer.start()
276+
try:
277+
out = subprocess.check_output(['fc-list', '--format=%{file}'])
278+
except (OSError, subprocess.CalledProcessError):
279+
return []
280+
finally:
281+
timer.cancel()
282+
fnames = []
283+
for fname in out.split(b'\n'):
284+
try:
285+
fname = six.text_type(fname, sys.getfilesystemencoding())
286+
except UnicodeDecodeError:
287+
continue
288+
fnames.append(fname)
289+
return fnames
290+
291+
292+
def get_fontconfig_fonts(fontext='ttf'):
293+
"""List the font filenames known to `fc-list` having the given extension.
274294
"""
275295
fontext = get_fontext_synonyms(fontext)
296+
return [fname for fname in _call_fc_list()
297+
if os.path.splitext(fname)[1][1:] in fontext]
276298

277-
fontfiles = {}
278-
try:
279-
warnings.warn('Matplotlib is building the font cache using fc-list. This may take a moment.')
280-
pipe = subprocess.Popen(['fc-list', '--format=%{file}\\n'],
281-
stdout=subprocess.PIPE,
282-
stderr=subprocess.PIPE)
283-
output = pipe.communicate()[0]
284-
except (OSError, IOError):
285-
# Calling fc-list did not work, so we'll just return nothing
286-
return fontfiles
287-
288-
if pipe.returncode == 0:
289-
# The line breaks between results are in ascii, but each entry
290-
# is in in sys.filesystemencoding().
291-
for fname in output.split(b'\n'):
292-
try:
293-
fname = six.text_type(fname, sys.getfilesystemencoding())
294-
except UnicodeDecodeError:
295-
continue
296-
if (os.path.splitext(fname)[1][1:] in fontext and
297-
os.path.exists(fname)):
298-
fontfiles[fname] = 1
299-
300-
return fontfiles
301299

302300
def findSystemFonts(fontpaths=None, fontext='ttf'):
303301
"""
@@ -307,7 +305,7 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
307305
available. A list of TrueType fonts are returned by default with
308306
AFM fonts as an option.
309307
"""
310-
fontfiles = {}
308+
fontfiles = set()
311309
fontexts = get_fontext_synonyms(fontext)
312310

313311
if fontpaths is None:
@@ -319,26 +317,26 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
319317
for f in win32InstalledFonts(fontdir):
320318
base, ext = os.path.splitext(f)
321319
if len(ext)>1 and ext[1:].lower() in fontexts:
322-
fontfiles[f] = 1
320+
fontfiles.add(f)
323321
else:
324322
fontpaths = X11FontDirectories
325323
# check for OS X & load its fonts if present
326324
if sys.platform == 'darwin':
327325
for f in OSXInstalledFonts(fontext=fontext):
328-
fontfiles[f] = 1
326+
fontfiles.add(f)
329327

330328
for f in get_fontconfig_fonts(fontext):
331-
fontfiles[f] = 1
329+
fontfiles.add(f)
332330

333331
elif isinstance(fontpaths, six.string_types):
334332
fontpaths = [fontpaths]
335333

336334
for path in fontpaths:
337335
files = list_fonts(path, fontexts)
338336
for fname in files:
339-
fontfiles[os.path.abspath(fname)] = 1
337+
fontfiles.add(os.path.abspath(fname))
340338

341-
return [fname for fname in six.iterkeys(fontfiles) if os.path.exists(fname)]
339+
return [fname for fname in fontfiles if os.path.exists(fname)]
342340

343341
def weight_as_number(weight):
344342
"""
@@ -837,7 +835,7 @@ def set_family(self, family):
837835
family = rcParams['font.family']
838836
if is_string_like(family):
839837
family = [six.text_type(family)]
840-
elif (not is_string_like(family) and isinstance(family, Iterable)):
838+
elif not is_string_like(family) and isinstance(family, Iterable):
841839
family = [six.text_type(f) for f in family]
842840
self._family = family
843841
set_name = set_family

0 commit comments

Comments
 (0)