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

Skip to content

Commit 60e3180

Browse files
authored
Merge pull request #10245 from anntzer/fontmanager-relpath
Cache paths of fonts shipped with mpl relative to the mpl data path.
2 parents 6c1105b + 9f821d1 commit 60e3180

File tree

2 files changed

+50
-28
lines changed

2 files changed

+50
-28
lines changed

.flake8

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ per-file-ignores =
4242
matplotlib/backends/qt_editor/formlayout.py: E301, E501
4343
matplotlib/backends/tkagg.py: E231, E302, E701
4444
matplotlib/backends/windowing.py: E301, E302
45-
matplotlib/font_manager.py: E203, E221, E225, E251, E261, E262, E302, E501
45+
matplotlib/font_manager.py: E203, E221, E251, E261, E262, E302, E501
4646
matplotlib/fontconfig_pattern.py: E201, E203, E221, E222, E225, E302
4747
matplotlib/legend_handler.py: E201, E501
4848
matplotlib/mathtext.py: E201, E202, E203, E211, E221, E222, E225, E231, E251, E261, E301, E302, E303, E402, E501

lib/matplotlib/font_manager.py

Lines changed: 49 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

@@ -926,7 +945,7 @@ class FontManager(object):
926945
# Increment this version number whenever the font cache data
927946
# format or behavior has changed and requires a existing font
928947
# cache files to be rebuilt.
929-
__version__ = 201
948+
__version__ = 300
930949

931950
def __init__(self, size=None, weight='normal'):
932951
self._version = self.__version__
@@ -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]
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)
968984

969-
self.ttflist = createFontList(self.ttffiles)
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
970989

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
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
"""
@@ -1312,7 +1333,8 @@ def findfont(prop, fontext='ttf'):
13121333

13131334
cachedir = get_cachedir()
13141335
if cachedir is not None:
1315-
_fmcache = os.path.join(cachedir, 'fontList.json')
1336+
_fmcache = os.path.join(
1337+
cachedir, 'fontlist-v{}.json'.format(FontManager.__version__))
13161338

13171339
fontManager = None
13181340

0 commit comments

Comments
 (0)