47
47
see license/LICENSE_TTFQUERY.
48
48
"""
49
49
50
- import json
51
- import os , sys , warnings
52
50
from collections import Iterable
51
+ import json
52
+ import os
53
+ import sys
54
+ from threading import Timer
55
+ import warnings
56
+
53
57
import matplotlib
54
- from matplotlib import afm
55
- from matplotlib import ft2font
56
- from matplotlib import rcParams , get_cachedir
58
+ from matplotlib import afm , cbook , ft2font , rcParams , get_cachedir
57
59
from matplotlib .cbook import is_string_like
58
- import matplotlib .cbook as cbook
59
60
from matplotlib .compat import subprocess
60
- from matplotlib .fontconfig_pattern import \
61
- parse_fontconfig_pattern , generate_fontconfig_pattern
61
+ from matplotlib .fontconfig_pattern import (
62
+ parse_fontconfig_pattern , generate_fontconfig_pattern )
62
63
63
64
try :
64
65
from functools import lru_cache
@@ -262,39 +263,39 @@ def OSXInstalledFonts(directories=None, fontext='ttf'):
262
263
files .extend (list_fonts (path , fontext ))
263
264
return files
264
265
265
- 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`.
266
270
"""
267
- Grab a list of all the fonts that are being tracked by fontconfig
268
- by making a system call to ``fc-list``. This is an easy way to
269
- grab all of the fonts the user wants to be made available to
270
- 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.
271
294
"""
272
295
fontext = get_fontext_synonyms (fontext )
296
+ return [fname for fname in _call_fc_list ()
297
+ if os .path .splitext (fname )[1 ][1 :] in fontext ]
273
298
274
- fontfiles = {}
275
- try :
276
- warnings .warn ('Matplotlib is building the font cache using fc-list. This may take a moment.' )
277
- pipe = subprocess .Popen (['fc-list' , '--format=%{file}\\ n' ],
278
- stdout = subprocess .PIPE ,
279
- stderr = subprocess .PIPE )
280
- output = pipe .communicate ()[0 ]
281
- except (OSError , IOError ):
282
- # Calling fc-list did not work, so we'll just return nothing
283
- return fontfiles
284
-
285
- if pipe .returncode == 0 :
286
- # The line breaks between results are in ascii, but each entry
287
- # is in in sys.filesystemencoding().
288
- for fname in output .split (b'\n ' ):
289
- try :
290
- fname = six .text_type (fname , sys .getfilesystemencoding ())
291
- except UnicodeDecodeError :
292
- continue
293
- if (os .path .splitext (fname )[1 ][1 :] in fontext and
294
- os .path .exists (fname )):
295
- fontfiles [fname ] = 1
296
-
297
- return fontfiles
298
299
299
300
def findSystemFonts (fontpaths = None , fontext = 'ttf' ):
300
301
"""
@@ -304,7 +305,7 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
304
305
available. A list of TrueType fonts are returned by default with
305
306
AFM fonts as an option.
306
307
"""
307
- fontfiles = {}
308
+ fontfiles = set ()
308
309
fontexts = get_fontext_synonyms (fontext )
309
310
310
311
if fontpaths is None :
@@ -316,26 +317,26 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
316
317
for f in win32InstalledFonts (fontdir ):
317
318
base , ext = os .path .splitext (f )
318
319
if len (ext )> 1 and ext [1 :].lower () in fontexts :
319
- fontfiles [ f ] = 1
320
+ fontfiles . add ( f )
320
321
else :
321
322
fontpaths = X11FontDirectories
322
323
# check for OS X & load its fonts if present
323
324
if sys .platform == 'darwin' :
324
325
for f in OSXInstalledFonts (fontext = fontext ):
325
- fontfiles [ f ] = 1
326
+ fontfiles . add ( f )
326
327
327
328
for f in get_fontconfig_fonts (fontext ):
328
- fontfiles [ f ] = 1
329
+ fontfiles . add ( f )
329
330
330
331
elif isinstance (fontpaths , six .string_types ):
331
332
fontpaths = [fontpaths ]
332
333
333
334
for path in fontpaths :
334
335
files = list_fonts (path , fontexts )
335
336
for fname in files :
336
- fontfiles [ os .path .abspath (fname )] = 1
337
+ fontfiles . add ( os .path .abspath (fname ))
337
338
338
- 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 )]
339
340
340
341
def weight_as_number (weight ):
341
342
"""
@@ -833,7 +834,7 @@ def set_family(self, family):
833
834
family = rcParams ['font.family' ]
834
835
if is_string_like (family ):
835
836
family = [six .text_type (family )]
836
- elif ( not is_string_like (family ) and isinstance (family , Iterable ) ):
837
+ elif not is_string_like (family ) and isinstance (family , Iterable ):
837
838
family = [six .text_type (f ) for f in family ]
838
839
self ._family = family
839
840
set_name = set_family
0 commit comments