Skip to content

Commit ead1bb3

Browse files
committed
Revert "Merge pull request #9677 from anntzer/more-lru_cache"
This reverts commit 5730794, reversing changes made to 1ca3d1a. Fixes #10740 by avoiding suspected bugs in backports.lru_cache
1 parent fe001ef commit ead1bb3

File tree

7 files changed

+61
-41
lines changed

7 files changed

+61
-41
lines changed

lib/matplotlib/backends/backend_agg.py

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from matplotlib import cbook, rcParams, __version__
3232
from matplotlib.backend_bases import (
3333
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, cursors)
34+
from matplotlib.cbook import maxdict
35+
from matplotlib.figure import Figure
3436
from matplotlib.font_manager import findfont, get_font
3537
from matplotlib.ft2font import (LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING,
3638
LOAD_DEFAULT, LOAD_NO_AUTOHINT)

lib/matplotlib/backends/backend_svg.py

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from matplotlib.backend_bases import (
2323
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
2424
from matplotlib.backends.backend_mixed import MixedModeRenderer
25+
from matplotlib.cbook import is_writable_file_like, maxdict
2526
from matplotlib.colors import rgb2hex
2627
from matplotlib.font_manager import findfont, get_font
2728
from matplotlib.ft2font import LOAD_NO_HINTING
@@ -259,6 +260,9 @@ def generate_css(attrib={}):
259260

260261
_capstyle_d = {'projecting' : 'square', 'butt' : 'butt', 'round': 'round',}
261262
class RendererSVG(RendererBase):
263+
FONT_SCALE = 100.0
264+
fontd = maxdict(50)
265+
262266
def __init__(self, width, height, svgwriter, basename=None, image_dpi=72):
263267
self.width = width
264268
self.height = height

lib/matplotlib/colors.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ def _is_nth_color(c):
111111

112112
def is_color_like(c):
113113
"""Return whether *c* can be interpreted as an RGB(A) color."""
114-
# Special-case nth color syntax because it cannot be parsed during setup.
114+
# Special-case nth color syntax because it cannot be parsed during
115+
# setup.
115116
if _is_nth_color(c):
116117
return True
117118
try:

lib/matplotlib/font_manager.py

+21-21
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,6 @@ def _normalize_font_family(family):
994994
return family
995995

996996

997-
@cbook.deprecated("2.2")
998997
class TempCache(object):
999998
"""
1000999
A class to store temporary caches that are (a) not saved to disk
@@ -1279,20 +1278,6 @@ def findfont(self, prop, fontext='ttf', directory=None,
12791278
<http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ documentation
12801279
for a description of the font finding algorithm.
12811280
"""
1282-
# Pass the relevant rcParams (and the font manager, as `self`) to
1283-
# _findfont_cached so to prevent using a stale cache entry after an
1284-
# rcParam was changed.
1285-
rc_params = tuple(tuple(rcParams[key]) for key in [
1286-
"font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
1287-
"font.monospace"])
1288-
return self._findfont_cached(
1289-
prop, fontext, directory, fallback_to_default, rebuild_if_missing,
1290-
rc_params)
1291-
1292-
@lru_cache()
1293-
def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
1294-
rebuild_if_missing, rc_params):
1295-
12961281
if not isinstance(prop, FontProperties):
12971282
prop = FontProperties(prop)
12981283
fname = prop.get_file()
@@ -1306,7 +1291,11 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
13061291
else:
13071292
fontlist = self.ttflist
13081293

1309-
if directory is not None:
1294+
if directory is None:
1295+
cached = _lookup_cache[fontext].get(prop)
1296+
if cached is not None:
1297+
return cached
1298+
else:
13101299
directory = os.path.normcase(directory)
13111300

13121301
best_score = 1e64
@@ -1364,20 +1353,26 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
13641353
else:
13651354
raise ValueError("No valid font could be found")
13661355

1356+
if directory is None:
1357+
_lookup_cache[fontext].set(prop, result)
13671358
return result
13681359

1369-
@lru_cache()
1360+
_is_opentype_cff_font_cache = {}
13701361
def is_opentype_cff_font(filename):
13711362
"""
13721363
Returns True if the given font is a Postscript Compact Font Format
13731364
Font embedded in an OpenType wrapper. Used by the PostScript and
13741365
PDF backends that can not subset these fonts.
13751366
"""
13761367
if os.path.splitext(filename)[1].lower() == '.otf':
1377-
with open(filename, 'rb') as fd:
1378-
return fd.read(4) == b"OTTO"
1379-
else:
1380-
return False
1368+
result = _is_opentype_cff_font_cache.get(filename)
1369+
if result is None:
1370+
with open(filename, 'rb') as fd:
1371+
tag = fd.read(4)
1372+
result = (tag == b'OTTO')
1373+
_is_opentype_cff_font_cache[filename] = result
1374+
return result
1375+
return False
13811376

13821377
fontManager = None
13831378
_fmcache = None
@@ -1444,6 +1439,11 @@ def findfont(prop, fontext='ttf'):
14441439

14451440
fontManager = None
14461441

1442+
_lookup_cache = {
1443+
'ttf': TempCache(),
1444+
'afm': TempCache()
1445+
}
1446+
14471447
def _rebuild():
14481448
global fontManager
14491449

lib/matplotlib/mathtext.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@
2525
import unicodedata
2626
from warnings import warn
2727

28-
try:
29-
from functools import lru_cache
30-
except ImportError: # Py2
31-
from backports.functools_lru_cache import lru_cache
32-
28+
from numpy import inf, isinf
3329
import numpy as np
3430

3531
from pyparsing import (
@@ -3251,8 +3247,8 @@ def __init__(self, output):
32513247
Create a MathTextParser for the given backend *output*.
32523248
"""
32533249
self._output = output.lower()
3250+
self._cache = maxdict(50)
32543251

3255-
@lru_cache(50)
32563252
def parse(self, s, dpi = 72, prop = None):
32573253
"""
32583254
Parse the given math expression *s* at the given *dpi*. If
@@ -3264,10 +3260,16 @@ def parse(self, s, dpi = 72, prop = None):
32643260
The results are cached, so multiple calls to :meth:`parse`
32653261
with the same expression should be fast.
32663262
"""
3267-
3263+
# There is a bug in Python 3.x where it leaks frame references,
3264+
# and therefore can't handle this caching
32683265
if prop is None:
32693266
prop = FontProperties()
32703267

3268+
cacheKey = (s, dpi, hash(prop))
3269+
result = self._cache.get(cacheKey)
3270+
if result is not None:
3271+
return result
3272+
32713273
if self._output == 'ps' and rcParams['ps.useafm']:
32723274
font_output = StandardPsFonts(prop)
32733275
else:
@@ -3290,7 +3292,9 @@ def parse(self, s, dpi = 72, prop = None):
32903292

32913293
box = self._parser.parse(s, font_output, fontsize, dpi)
32923294
font_output.set_canvas_size(box.width, box.height, box.depth)
3293-
return font_output.get_results(box)
3295+
result = font_output.get_results(box)
3296+
self._cache[cacheKey] = result
3297+
return result
32943298

32953299
def to_mask(self, texstr, dpi=120, fontsize=14):
32963300
"""

lib/matplotlib/path.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616

1717
from weakref import WeakValueDictionary
1818

19-
try:
20-
from functools import lru_cache
21-
except ImportError: # Py2
22-
from backports.functools_lru_cache import lru_cache
23-
2419
import numpy as np
2520

2621
from . import _path, rcParams
@@ -940,17 +935,27 @@ def wedge(cls, theta1, theta2, n=None):
940935
"""
941936
return cls.arc(theta1, theta2, n, True)
942937

943-
@staticmethod
944-
@lru_cache(8)
945-
def hatch(hatchpattern, density=6):
938+
_hatch_dict = maxdict(8)
939+
940+
@classmethod
941+
def hatch(cls, hatchpattern, density=6):
946942
"""
947943
Given a hatch specifier, *hatchpattern*, generates a Path that
948944
can be used in a repeated hatching pattern. *density* is the
949945
number of lines per unit square.
950946
"""
951947
from matplotlib.hatch import get_path
952-
return (get_path(hatchpattern, density)
953-
if hatchpattern is not None else None)
948+
949+
if hatchpattern is None:
950+
return None
951+
952+
hatch_path = cls._hatch_dict.get((hatchpattern, density))
953+
if hatch_path is not None:
954+
return hatch_path
955+
956+
hatch_path = get_path(hatchpattern, density)
957+
cls._hatch_dict[(hatchpattern, density)] = hatch_path
958+
return hatch_path
954959

955960
def clip_to_bbox(self, bbox, inside=True):
956961
"""

lib/matplotlib/textpath.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class TextToPath(object):
3333
DPI = 72
3434

3535
def __init__(self):
36+
"""
37+
Initialization
38+
"""
3639
self.mathtext_parser = MathTextParser('path')
3740
self.tex_font_map = None
3841

@@ -489,7 +492,8 @@ def _revalidate_path(self):
489492
necessary.
490493
491494
"""
492-
if self._invalid or self._cached_vertices is None:
495+
if (self._invalid or
496+
(self._cached_vertices is None)):
493497
tr = Affine2D().scale(
494498
self._size / text_to_path.FONT_SCALE,
495499
self._size / text_to_path.FONT_SCALE).translate(*self._xy)

0 commit comments

Comments
 (0)