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