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

Skip to content

Commit e732310

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 9324b27 commit e732310

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
@@ -44,6 +44,7 @@
4444
from dummy_threading import Timer
4545
import warnings
4646

47+
import matplotlib as mpl
4748
from matplotlib import afm, cbook, ft2font, rcParams, get_cachedir
4849
from matplotlib.fontconfig_pattern import (
4950
parse_fontconfig_pattern, generate_fontconfig_pattern)
@@ -828,15 +829,23 @@ def copy(self):
828829
class JSONEncoder(json.JSONEncoder):
829830
def default(self, o):
830831
if isinstance(o, FontManager):
831-
return dict(o.__dict__, _class='FontManager')
832+
return dict(o.__dict__, __class__='FontManager')
832833
elif isinstance(o, FontEntry):
833-
return dict(o.__dict__, _class='FontEntry')
834+
d = dict(o.__dict__, __class__='FontEntry')
835+
try:
836+
# Cache paths of fonts shipped with mpl relative to the mpl
837+
# data path, which helps in the presence of venvs.
838+
d["fname"] = str(
839+
Path(d["fname"]).relative_to(mpl.get_data_path()))
840+
except ValueError:
841+
pass
842+
return d
834843
else:
835844
return super().default(o)
836845

837846

838847
def _json_decode(o):
839-
cls = o.pop('_class', None)
848+
cls = o.pop('__class__', None)
840849
if cls is None:
841850
return o
842851
elif cls == 'FontManager':
@@ -846,15 +855,21 @@ def _json_decode(o):
846855
elif cls == 'FontEntry':
847856
r = FontEntry.__new__(FontEntry)
848857
r.__dict__.update(o)
858+
if not os.path.isabs(r.fname):
859+
r.fname = os.path.join(mpl.get_data_path(), r.fname)
849860
return r
850861
else:
851-
raise ValueError("don't know how to deserialize _class=%s" % cls)
862+
raise ValueError("don't know how to deserialize __class__=%s" % cls)
852863

853864

854865
def json_dump(data, filename):
855-
"""Dumps a data structure as JSON in the named file.
856-
Handles FontManager and its fields."""
866+
"""
867+
Dumps a data structure as JSON in the named file.
857868
869+
Handles FontManager and its fields. File paths that are children of the
870+
Matplotlib data path (typically, fonts shipped with Matplotlib) are stored
871+
relative to that data path (to remain valid across virtualenvs).
872+
"""
858873
with open(filename, 'w') as fh:
859874
try:
860875
json.dump(data, fh, cls=JSONEncoder, indent=2)
@@ -863,9 +878,13 @@ def json_dump(data, filename):
863878

864879

865880
def json_load(filename):
866-
"""Loads a data structure as JSON from the named file.
867-
Handles FontManager and its fields."""
881+
"""
882+
Loads a data structure as JSON from the named file.
868883
884+
Handles FontManager and its fields. Relative file paths are interpreted
885+
as being relative to the Matplotlib data path, and transformed into
886+
absolute paths.
887+
"""
869888
with open(filename, 'r') as fh:
870889
return json.load(fh, object_hook=_json_decode)
871890

@@ -951,30 +970,32 @@ def __init__(self, size=None, weight='normal'):
951970
_log.debug('font search path %s', str(paths))
952971
# Load TrueType fonts and create font dictionary.
953972

954-
self.ttffiles = findSystemFonts(paths) + findSystemFonts()
955973
self.defaultFamily = {
956974
'ttf': 'DejaVu Sans',
957975
'afm': 'Helvetica'}
958976
self.defaultFont = {}
959977

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

9791000
def get_default_weight(self):
9801001
"""

0 commit comments

Comments
 (0)