Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cd87892

Browse files
committed
Cache paths of fonts shipped with mpl relative to the mpl data path.
This lets the font cache stay valid across multiple virtualenvs (as long as the list of fonts shipped by mpl does not change).
1 parent 634640f commit cd87892

File tree

1 file changed

+48
-27
lines changed

1 file changed

+48
-27
lines changed

lib/matplotlib/font_manager.py

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from threading import Timer
4343
import warnings
4444

45+
import matplotlib as mpl
4546
from matplotlib import afm, cbook, ft2font, rcParams, get_cachedir
4647
from matplotlib.fontconfig_pattern import (
4748
parse_fontconfig_pattern, generate_fontconfig_pattern)
@@ -831,15 +832,23 @@ def copy(self):
831832
class JSONEncoder(json.JSONEncoder):
832833
def default(self, o):
833834
if isinstance(o, FontManager):
834-
return dict(o.__dict__, _class='FontManager')
835+
return dict(o.__dict__, __class__='FontManager')
835836
elif isinstance(o, FontEntry):
836-
return dict(o.__dict__, _class='FontEntry')
837+
d = dict(o.__dict__, __class__='FontEntry')
838+
try:
839+
# Cache paths of fonts shipped with mpl relative to the mpl
840+
# data path, which helps in the presence of venvs.
841+
d["fname"] = str(
842+
Path(d["fname"]).relative_to(mpl.get_data_path()))
843+
except ValueError:
844+
pass
845+
return d
837846
else:
838847
return super().default(o)
839848

840849

841850
def _json_decode(o):
842-
cls = o.pop('_class', None)
851+
cls = o.pop('__class__', None)
843852
if cls is None:
844853
return o
845854
elif cls == 'FontManager':
@@ -849,15 +858,21 @@ def _json_decode(o):
849858
elif cls == 'FontEntry':
850859
r = FontEntry.__new__(FontEntry)
851860
r.__dict__.update(o)
861+
if not os.path.isabs(r.fname):
862+
r.fname = os.path.join(mpl.get_data_path(), r.fname)
852863
return r
853864
else:
854-
raise ValueError("don't know how to deserialize _class=%s" % cls)
865+
raise ValueError("don't know how to deserialize __class__=%s" % cls)
855866

856867

857868
def json_dump(data, filename):
858-
"""Dumps a data structure as JSON in the named file.
859-
Handles FontManager and its fields."""
869+
"""
870+
Dumps a data structure as JSON in the named file.
860871
872+
Handles FontManager and its fields. File paths that are children of the
873+
Matplotlib data path (typically, fonts shipped with Matplotlib) are stored
874+
relative to that data path (to remain valid across virtualenvs).
875+
"""
861876
with open(filename, 'w') as fh:
862877
try:
863878
json.dump(data, fh, cls=JSONEncoder, indent=2)
@@ -866,9 +881,13 @@ def json_dump(data, filename):
866881

867882

868883
def json_load(filename):
869-
"""Loads a data structure as JSON from the named file.
870-
Handles FontManager and its fields."""
884+
"""
885+
Loads a data structure as JSON from the named file.
871886
887+
Handles FontManager and its fields. Relative file paths are interpreted
888+
as being relative to the Matplotlib data path, and transformed into
889+
absolute paths.
890+
"""
872891
with open(filename, 'r') as fh:
873892
return json.load(fh, object_hook=_json_decode)
874893

@@ -954,30 +973,32 @@ def __init__(self, size=None, weight='normal'):
954973
_log.info('font search path %s', str(paths))
955974
# Load TrueType fonts and create font dictionary.
956975

957-
self.ttffiles = findSystemFonts(paths) + findSystemFonts()
958976
self.defaultFamily = {
959977
'ttf': 'DejaVu Sans',
960978
'afm': 'Helvetica'}
961979
self.defaultFont = {}
962980

963-
for fname in self.ttffiles:
964-
_log.debug('trying fontname %s', fname)
965-
if fname.lower().find('DejaVuSans.ttf')>=0:
966-
self.defaultFont['ttf'] = fname
967-
break
968-
else:
969-
# use anything
970-
self.defaultFont['ttf'] = self.ttffiles[0]
971-
972-
self.ttflist = createFontList(self.ttffiles)
973-
974-
self.afmfiles = (findSystemFonts(paths, fontext='afm')
975-
+ findSystemFonts(fontext='afm'))
976-
self.afmlist = createFontList(self.afmfiles, fontext='afm')
977-
if len(self.afmfiles):
978-
self.defaultFont['afm'] = self.afmfiles[0]
979-
else:
980-
self.defaultFont['afm'] = None
981+
ttffiles = findSystemFonts(paths) + findSystemFonts()
982+
self.defaultFont['ttf'] = next(
983+
(fname for fname in ttffiles
984+
if fname.lower().endswith("dejavusans.ttf")),
985+
ttffiles[0])
986+
self.ttflist = createFontList(ttffiles)
987+
988+
afmfiles = (findSystemFonts(paths, fontext='afm')
989+
+ findSystemFonts(fontext='afm'))
990+
self.afmlist = createFontList(afmfiles, fontext='afm')
991+
self.defaultFont['afm'] = afmfiles[0] if afmfiles else None
992+
993+
@property
994+
@cbook.deprecated("3.0")
995+
def ttffiles(self):
996+
return [font.fname for font in self.ttflist]
997+
998+
@property
999+
@cbook.deprecated("3.0")
1000+
def afmfiles(self):
1001+
return [font.fname for font in self.afmlist]
9811002

9821003
def get_default_weight(self):
9831004
"""

0 commit comments

Comments
 (0)