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
5550from collections import Iterable
51+ import json
52+ import os
53+ import sys
54+ from threading import Timer
55+ import warnings
56+
5657import 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
6059from matplotlib .cbook import is_string_like
61- import matplotlib .cbook as cbook
6260from 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
6664try :
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
302300def 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
343341def 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