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

Skip to content

Commit fef412e

Browse files
committed
Merge pull request #5021 from jkseppan/json-font-cache
Use json for the font cache instead of pickle
2 parents d9bd62b + 3008a7a commit fef412e

File tree

2 files changed

+57
-23
lines changed

2 files changed

+57
-23
lines changed

lib/matplotlib/font_manager.py

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
unicode_literals)
2424

2525
from matplotlib.externals import six
26-
from matplotlib.externals.six.moves import cPickle as pickle
2726

2827
"""
2928
KNOWN ISSUES
@@ -47,6 +46,7 @@
4746
see license/LICENSE_TTFQUERY.
4847
"""
4948

49+
import json
5050
import os, sys, warnings
5151
try:
5252
set
@@ -947,23 +947,43 @@ def ttfdict_to_fnames(d):
947947
fnames.append(fname)
948948
return fnames
949949

950-
def pickle_dump(data, filename):
951-
"""
952-
Equivalent to pickle.dump(data, open(filename, 'w'))
953-
but closes the file to prevent filehandle leakage.
954-
"""
955-
with open(filename, 'wb') as fh:
956-
pickle.dump(data, fh)
950+
class JSONEncoder(json.JSONEncoder):
951+
def default(self, o):
952+
if isinstance(o, FontManager):
953+
return dict(o.__dict__, _class='FontManager')
954+
elif isinstance(o, FontEntry):
955+
return dict(o.__dict__, _class='FontEntry')
956+
else:
957+
return super(JSONEncoder, self).default(o)
958+
959+
def _json_decode(o):
960+
cls = o.pop('_class', None)
961+
if cls is None:
962+
return o
963+
elif cls == 'FontManager':
964+
r = FontManager.__new__(FontManager)
965+
r.__dict__.update(o)
966+
return r
967+
elif cls == 'FontEntry':
968+
r = FontEntry.__new__(FontEntry)
969+
r.__dict__.update(o)
970+
return r
971+
else:
972+
raise ValueError("don't know how to deserialize _class=%s" % cls)
957973

958-
def pickle_load(filename):
959-
"""
960-
Equivalent to pickle.load(open(filename, 'r'))
961-
but closes the file to prevent filehandle leakage.
962-
"""
963-
with open(filename, 'rb') as fh:
964-
data = pickle.load(fh)
965-
return data
974+
def json_dump(data, filename):
975+
"""Dumps a data structure as JSON in the named file.
976+
Handles FontManager and its fields."""
977+
978+
with open(filename, 'w') as fh:
979+
json.dump(data, fh, cls=JSONEncoder, indent=2)
966980

981+
def json_load(filename):
982+
"""Loads a data structure as JSON from the named file.
983+
Handles FontManager and its fields."""
984+
985+
with open(filename, 'r') as fh:
986+
return json.load(fh, object_hook=_json_decode)
967987

968988
class TempCache(object):
969989
"""
@@ -1388,10 +1408,7 @@ def findfont(prop, fontext='ttf'):
13881408
if not 'TRAVIS' in os.environ:
13891409
cachedir = get_cachedir()
13901410
if cachedir is not None:
1391-
if six.PY3:
1392-
_fmcache = os.path.join(cachedir, 'fontList.py3k.cache')
1393-
else:
1394-
_fmcache = os.path.join(cachedir, 'fontList.cache')
1411+
_fmcache = os.path.join(cachedir, 'fontList.json')
13951412

13961413
fontManager = None
13971414

@@ -1404,12 +1421,12 @@ def _rebuild():
14041421
global fontManager
14051422
fontManager = FontManager()
14061423
if _fmcache:
1407-
pickle_dump(fontManager, _fmcache)
1424+
json_dump(fontManager, _fmcache)
14081425
verbose.report("generated new fontManager")
14091426

14101427
if _fmcache:
14111428
try:
1412-
fontManager = pickle_load(_fmcache)
1429+
fontManager = json_load(_fmcache)
14131430
if (not hasattr(fontManager, '_version') or
14141431
fontManager._version != FontManager.__version__):
14151432
_rebuild()

lib/matplotlib/tests/test_font_manager.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
from matplotlib.externals import six
66

77
import os
8+
import tempfile
9+
import warnings
810

9-
from matplotlib.font_manager import findfont, FontProperties
11+
from matplotlib.font_manager import (
12+
findfont, FontProperties, fontManager, json_dump, json_load)
1013
from matplotlib import rc_context
1114

1215

@@ -17,3 +20,17 @@ def test_font_priority():
1720
font = findfont(
1821
FontProperties(family=["sans-serif"]))
1922
assert_equal(os.path.basename(font), 'cmmi10.ttf')
23+
24+
25+
def test_json_serialization():
26+
with tempfile.NamedTemporaryFile() as temp:
27+
json_dump(fontManager, temp.name)
28+
copy = json_load(temp.name)
29+
with warnings.catch_warnings():
30+
warnings.filterwarnings('ignore', 'findfont: Font family.*not found')
31+
for prop in ({'family': 'STIXGeneral'},
32+
{'family': 'Bitstream Vera Sans', 'weight': 700},
33+
{'family': 'no such font family'}):
34+
fp = FontProperties(**prop)
35+
assert_equal(fontManager.findfont(fp, rebuild_if_missing=False),
36+
copy.findfont(fp, rebuild_if_missing=False))

0 commit comments

Comments
 (0)