Skip to content

Commit bcba233

Browse files
committed
Remove "experimental" fontconfig font_manager backend.
The "experimental" fontconfig backend for font_manager was never publicly accessible: even if one does `matplotlib.font_manager.USE_FONTCONFIG = True`, that didn't change the already existing `findfont`. The only way to access it was to edit the source, or use `reload()`, neither of which really count as public API... Note that our "use" of "fontconfig-like" patterns actually has subtly different semantics from actual fontconfig patterns, so it's not as if that backend was correctly working anyways. We don't need to set `fontManager.default_size` when loading it as we already check that fontManager has the correct `__version__` (and thus must have a correct `default_size`; moreover the only use of `default_size` is in `sizeval1 = self.default_size * font_scalings[size1]` so it's not as if a value of `None` (if it had somehow been missing) was going to be helpful anyways... `get_cachedir()` always returns a real directory (creating a temporary one if necessary), so we can drop the code paths handling `get_cachedir() == None`. Note that we still rely on fontconfig to *list* fonts; the backend only added an (non-publicly-accessible, per above) option to *match* fonts using fontconfig.
1 parent 640ecd9 commit bcba233

File tree

3 files changed

+33
-101
lines changed

3 files changed

+33
-101
lines changed

doc/api/next_api_changes/2018-02-26-AL-removals.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ The following deprecated API elements have been removed:
1414
``cbook.reverse_dict``, ``cbook.restrict_dict``, ``cbook.issubclass_safe``,
1515
``cbook.recursive_remove``, ``cbook.unmasked_index_ranges``,
1616
``cbook.Null``, ``cbook.RingBuffer``, ``cbook.Sorter``, ``cbook.Xlator``,
17-
- ``font_manager.weight_as_number``, ``font_manager.ttfdict_to_fnames``,
17+
- ``font_manager.ttfdict_to_fnames``, ``font_manager.weight_as_number``,
18+
``font_manager.USE_FONTCONFIG``, ``font_manager.cachedir``,
1819
- ``pyplot.colors``, ``pyplot.spectral``,
1920
- ``rcsetup.validate_negative_linestyle``,
2021
``rcsetup.validate_negative_linestyle_legacy``,

lib/matplotlib/__init__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ def _get_home():
576576
return None
577577

578578

579-
def _create_tmp_config_dir():
579+
def _create_tmp_config_or_cache_dir():
580580
"""
581581
If the config directory can not be created, create a temporary
582582
directory.
@@ -624,7 +624,7 @@ def _get_config_or_cache_dir(xdg_base):
624624
configdir = os.path.abspath(configdir)
625625
Path(configdir).mkdir(parents=True, exist_ok=True)
626626
if not _is_writable_dir(configdir):
627-
return _create_tmp_config_dir()
627+
return _create_tmp_config_or_cache_dir()
628628
return configdir
629629

630630
p = None
@@ -648,7 +648,7 @@ def _get_config_or_cache_dir(xdg_base):
648648
else:
649649
return p
650650

651-
return _create_tmp_config_dir()
651+
return _create_tmp_config_or_cache_dir()
652652

653653

654654
def _get_configdir():

lib/matplotlib/font_manager.py

+28-97
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@
1111
The design is based on the `W3C Cascading Style Sheet, Level 1 (CSS1)
1212
font specification <http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_.
1313
Future versions may implement the Level 2 or 2.1 specifications.
14-
15-
Experimental support is included for using `fontconfig` on Unix
16-
variant platforms (Linux, OS X, Solaris). To enable it, set the
17-
constant ``USE_FONTCONFIG`` in this file to ``True``. Fontconfig has
18-
the advantage that it is the standard way to look up fonts on X11
19-
platforms, so if a font is installed, it is much more likely to be
20-
found.
2114
"""
2215

2316
# KNOWN ISSUES
@@ -42,14 +35,13 @@
4235
from threading import Timer
4336
import warnings
4437

45-
from matplotlib import afm, cbook, ft2font, rcParams, get_cachedir
38+
import matplotlib as mpl
39+
from matplotlib import afm, cbook, ft2font, rcParams
4640
from matplotlib.fontconfig_pattern import (
4741
parse_fontconfig_pattern, generate_fontconfig_pattern)
4842

4943
_log = logging.getLogger(__name__)
5044

51-
USE_FONTCONFIG = False
52-
5345
font_scalings = {
5446
'xx-small' : 0.579,
5547
'x-small' : 0.694,
@@ -102,12 +94,10 @@
10294
MSFolders = \
10395
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
10496

105-
10697
MSFontDirectories = [
10798
r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts',
10899
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts']
109100

110-
111101
X11FontDirectories = [
112102
# an old standard installation point
113103
"/usr/X11R6/lib/X11/fonts/TTF/",
@@ -118,21 +108,20 @@
118108
"/usr/local/share/fonts/",
119109
# common application, not really useful
120110
"/usr/lib/openoffice/share/fonts/truetype/",
121-
]
111+
# user fonts
112+
str(Path.home() / ".fonts"),
113+
]
122114

123115
OSXFontDirectories = [
124116
"/Library/Fonts/",
125117
"/Network/Library/Fonts/",
126118
"/System/Library/Fonts/",
127119
# fonts installed via MacPorts
128-
"/opt/local/share/fonts"
129-
""
120+
"/opt/local/share/fonts",
121+
# user fonts
122+
str(Path.home() / "Library/Fonts"),
130123
]
131124

132-
if not USE_FONTCONFIG and sys.platform != 'win32':
133-
OSXFontDirectories.append(str(Path.home() / "Library/Fonts"))
134-
X11FontDirectories.append(str(Path.home() / ".fonts"))
135-
136125

137126
def get_fontext_synonyms(fontext):
138127
"""
@@ -1136,7 +1125,7 @@ def score_size(self, size1, size2):
11361125
sizeval2 = float(size2)
11371126
except ValueError:
11381127
return 1.0
1139-
return abs(sizeval1 - sizeval2) / 72.0
1128+
return abs(sizeval1 - sizeval2) / 72
11401129

11411130
def findfont(self, prop, fontext='ttf', directory=None,
11421131
fallback_to_default=True, rebuild_if_missing=True):
@@ -1245,6 +1234,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
12451234

12461235
return result
12471236

1237+
12481238
@lru_cache()
12491239
def is_opentype_cff_font(filename):
12501240
"""
@@ -1258,94 +1248,35 @@ def is_opentype_cff_font(filename):
12581248
else:
12591249
return False
12601250

1261-
fontManager = None
1262-
_fmcache = None
1263-
12641251

12651252
_get_font = lru_cache(64)(ft2font.FT2Font)
1253+
_fmcache = os.path.join(mpl.get_cachedir(), 'fontList.json')
1254+
fontManager = None
1255+
12661256

12671257
def get_font(filename, hinting_factor=None):
12681258
if hinting_factor is None:
12691259
hinting_factor = rcParams['text.hinting_factor']
12701260
return _get_font(filename, hinting_factor)
12711261

12721262

1273-
# The experimental fontconfig-based backend.
1274-
if USE_FONTCONFIG and sys.platform != 'win32':
1263+
def _rebuild():
1264+
global fontManager
1265+
fontManager = FontManager()
1266+
with cbook._lock_path(_fmcache):
1267+
json_dump(fontManager, _fmcache)
1268+
_log.info("generated new fontManager")
12751269

1276-
def fc_match(pattern, fontext):
1277-
fontexts = get_fontext_synonyms(fontext)
1278-
ext = "." + fontext
1279-
try:
1280-
pipe = subprocess.Popen(
1281-
['fc-match', '-s', '--format=%{file}\\n', pattern],
1282-
stdout=subprocess.PIPE,
1283-
stderr=subprocess.PIPE)
1284-
output = pipe.communicate()[0]
1285-
except OSError:
1286-
return None
1287-
1288-
# The bulk of the output from fc-list is ascii, so we keep the
1289-
# result in bytes and parse it as bytes, until we extract the
1290-
# filename, which is in sys.filesystemencoding().
1291-
if pipe.returncode == 0:
1292-
for fname in map(os.fsdecode, output.split(b'\n')):
1293-
if os.path.splitext(fname)[1][1:] in fontexts:
1294-
return fname
1295-
return None
1296-
1297-
_fc_match_cache = {}
1298-
1299-
def findfont(prop, fontext='ttf'):
1300-
if not isinstance(prop, str):
1301-
prop = prop.get_fontconfig_pattern()
1302-
cached = _fc_match_cache.get(prop)
1303-
if cached is not None:
1304-
return cached
1305-
1306-
result = fc_match(prop, fontext)
1307-
if result is None:
1308-
result = fc_match(':', fontext)
1309-
1310-
_fc_match_cache[prop] = result
1311-
return result
13121270

1271+
try:
1272+
fontManager = json_load(_fmcache)
1273+
except Exception:
1274+
_rebuild()
13131275
else:
1314-
_fmcache = None
1315-
1316-
cachedir = get_cachedir()
1317-
if cachedir is not None:
1318-
_fmcache = os.path.join(cachedir, 'fontList.json')
1319-
1320-
fontManager = None
1321-
1322-
def _rebuild():
1323-
global fontManager
1324-
1325-
fontManager = FontManager()
1326-
1327-
if _fmcache:
1328-
with cbook._lock_path(_fmcache):
1329-
json_dump(fontManager, _fmcache)
1330-
_log.info("generated new fontManager")
1331-
1332-
if _fmcache:
1333-
try:
1334-
fontManager = json_load(_fmcache)
1335-
if (not hasattr(fontManager, '_version') or
1336-
fontManager._version != FontManager.__version__):
1337-
_rebuild()
1338-
else:
1339-
fontManager.default_size = None
1340-
_log.debug("Using fontManager instance from %s", _fmcache)
1341-
except TimeoutError:
1342-
raise
1343-
except Exception:
1344-
_rebuild()
1345-
else:
1276+
if getattr(fontManager, '_version', object()) != FontManager.__version__:
13461277
_rebuild()
1278+
else:
1279+
_log.debug("Using fontManager instance from %s", _fmcache)
1280+
13471281

1348-
def findfont(prop, **kw):
1349-
global fontManager
1350-
font = fontManager.findfont(prop, **kw)
1351-
return font
1282+
findfont = fontManager.findfont

0 commit comments

Comments
 (0)