47
47
see license/LICENSE_TTFQUERY.
48
48
"""
49
49
50
- import os , sys , warnings
51
- try :
52
- set
53
- except NameError :
54
- from sets import Set as set
55
50
from collections import Iterable
51
+ import json
52
+ import os
53
+ import sys
54
+ from threading import Timer
55
+ import warnings
56
+
56
57
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
60
59
from matplotlib .cbook import is_string_like
61
- import matplotlib .cbook as cbook
62
60
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 )
65
63
66
64
try :
67
65
from functools import lru_cache
@@ -265,39 +263,39 @@ def OSXInstalledFonts(directories=None, fontext='ttf'):
265
263
files .extend (list_fonts (path , fontext ))
266
264
return files
267
265
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`.
269
270
"""
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.
274
294
"""
275
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 ]
276
298
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
301
299
302
300
def findSystemFonts (fontpaths = None , fontext = 'ttf' ):
303
301
"""
@@ -307,7 +305,7 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
307
305
available. A list of TrueType fonts are returned by default with
308
306
AFM fonts as an option.
309
307
"""
310
- fontfiles = {}
308
+ fontfiles = set ()
311
309
fontexts = get_fontext_synonyms (fontext )
312
310
313
311
if fontpaths is None :
@@ -319,26 +317,26 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
319
317
for f in win32InstalledFonts (fontdir ):
320
318
base , ext = os .path .splitext (f )
321
319
if len (ext )> 1 and ext [1 :].lower () in fontexts :
322
- fontfiles [ f ] = 1
320
+ fontfiles . add ( f )
323
321
else :
324
322
fontpaths = X11FontDirectories
325
323
# check for OS X & load its fonts if present
326
324
if sys .platform == 'darwin' :
327
325
for f in OSXInstalledFonts (fontext = fontext ):
328
- fontfiles [ f ] = 1
326
+ fontfiles . add ( f )
329
327
330
328
for f in get_fontconfig_fonts (fontext ):
331
- fontfiles [ f ] = 1
329
+ fontfiles . add ( f )
332
330
333
331
elif isinstance (fontpaths , six .string_types ):
334
332
fontpaths = [fontpaths ]
335
333
336
334
for path in fontpaths :
337
335
files = list_fonts (path , fontexts )
338
336
for fname in files :
339
- fontfiles [ os .path .abspath (fname )] = 1
337
+ fontfiles . add ( os .path .abspath (fname ))
340
338
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 )]
342
340
343
341
def weight_as_number (weight ):
344
342
"""
@@ -837,7 +835,7 @@ def set_family(self, family):
837
835
family = rcParams ['font.family' ]
838
836
if is_string_like (family ):
839
837
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 ):
841
839
family = [six .text_type (f ) for f in family ]
842
840
self ._family = family
843
841
set_name = set_family
0 commit comments