8000 Rely more on lru_cache rather than custom caching. by anntzer · Pull Request #9677 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Rely more on lru_cache rather than custom caching. #9677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/api/api_changes/removed-attributes.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Removed attributes
``````````````````
The unused `FONT_SCALE` and `fontd` attributes of the `RendererSVG` class have
been removed.
1 change: 0 additions & 1 deletion lib/matplotlib/backends/backend_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
from matplotlib import verbose, rcParams, __version__
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, cursors)
from matplotlib.cbook import maxdict
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont, get_font
from matplotlib.ft2font import (LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING,
Expand Down
5 changes: 1 addition & 4 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
RendererBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.cbook import is_writable_file_like, maxdict
from matplotlib.cbook import is_writable_file_like
from matplotlib.colors import rgb2hex
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont, FontProperties, get_font
Expand Down Expand Up @@ -258,9 +258,6 @@ def generate_css(attrib={}):

_capstyle_d = {'projecting' : 'square', 'butt' : 'butt', 'round': 'round',}
class RendererSVG(RendererBase):
FONT_SCALE = 100.0
fontd = maxdict(50)

def __init__(self, width, height, svgwriter, basename=None, image_dpi=72):
self.width = width
self.height = height
Expand Down
3 changes: 1 addition & 2 deletions lib/matplotlib/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ def _is_nth_color(c):

def is_color_like(c):
"""Return whether *c* can be interpreted as an RGB(A) color."""
# Special-case nth color syntax because it cannot be parsed during
# setup.
# Special-case nth color syntax because it cannot be parsed during setup.
if _is_nth_color(c):
return True
try:
Expand Down
42 changes: 21 additions & 21 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ def _normalize_font_family(family):
return family


@cbook.deprecated("2.2")
class TempCache(object):
"""
A class to store temporary caches that are (a) not saved to disk
Expand Down Expand Up @@ -1268,6 +1269,20 @@ def findfont(self, prop, fontext='ttf', directory=None,
<http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ documentation
for a description of the font finding algorithm.
"""
# Pass the relevant rcParams (and the font manager, as `self`) to
# _findfont_cached so to prevent using a stale cache entry after an
# rcParam was changed.
rc_params = tuple(tuple(rcParams[key]) for key in [
"font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
"font.monospace"])
return self._findfont_cached(
prop, fontext, directory, fallback_to_default, rebuild_if_missing,
rc_params)

@lru_cache()
def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
rebuild_if_missing, rc_params):

if not isinstance(prop, FontProperties):
prop = FontProperties(prop)
fname = prop.get_file()
Expand All @@ -1280,11 +1295,7 @@ def findfont(self, prop, fontext='ttf', directory=None,
else:
fontlist = self.ttflist

if directory is None:
cached = _lookup_cache[fontext].get(prop)
if cached is not None:
return cached
else:
if directory is not None:
directory = os.path.normcase(directory)

best_score = 1e64
Expand Down Expand Up @@ -1342,26 +1353,20 @@ def findfont(self, prop, fontext='ttf', directory=None,
else:
raise ValueError("No valid font could be found")

if directory is None:
_lookup_cache[fontext].set(prop, result)
return result

_is_opentype_cff_font_cache = {}
@lru_cache()
def is_opentype_cff_font(filename):
"""
Returns True if the given font is a Postscript Compact Font Format
Font embedded in an OpenType wrapper. Used by the PostScript and
PDF backends that can not subset these fonts.
"""
if os.path.splitext(filename)[1].lower() == '.otf':
result = _is_opentype_cff_font_cache.get(filename)
if result is None:
with open(filename, 'rb') as fd:
tag = fd.read(4)
result = (tag == b'OTTO')
_is_opentype_cff_font_cache[filename] = result
return result
return False
with open(filename, 'rb') as fd:
return fd.read(4) == b"OTTO"
else:
return False

fontManager = None
_fmcache = None
Expand Down Expand Up @@ -1424,11 +1429,6 @@ def findfont(prop, fontext='ttf'):

fontManager = None

_lookup_cache = {
'ttf': TempCache(),
'afm': TempCache()
}

def _rebuild():
global fontManager

Expand Down
19 changes: 8 additions & 11 deletions lib/matplotlib/mathtext.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
import unicodedata
from warnings import warn

try:
from functools import lru_cache
except ImportError: # Py2
from backports.functools_lru_cache import lru_cache

from numpy import inf, isinf
import numpy as np

Expand Down Expand Up @@ -3257,8 +3262,8 @@ def __init__(self, output):
Create a MathTextParser for the given backend *output*.
"""
self._output = output.lower()
self._cache = maxdict(50)

@lru_cache(50)
def parse(self, s, dpi = 72, prop = None):
"""
Parse the given math expression *s* at the given *dpi*. If
Expand All @@ -3270,16 +3275,10 @@ def parse(self, s, dpi = 72, prop = None):
The results are cached, so multiple calls to :meth:`parse`
with the same expression should be fast.
"""
# There is a bug in Python 3.x where it leaks frame references,
# and therefore can't handle this caching

if prop is None:
prop = FontProperties()

cacheKey = (s, dpi, hash(prop))
result = self._cache.get(cacheKey)
if result is not None:
return result

if self._output == 'ps' and rcParams['ps.useafm']:
font_output = StandardPsFonts(prop)
else:
Expand All @@ -3302,9 +3301,7 @@ def parse(self, s, dpi = 72, prop = None):

box = self._parser.parse(s, font_output, fontsize, dpi)
font_output.set_canvas_size(box.width, box.height, box.depth)
result = font_output.get_results(box)
self._cache[cacheKey] = result
return result
return font_output.get_results(box)

def to_mask(self, texstr, dpi=120, fontsize=14):
"""
Expand Down
25 changes: 10 additions & 15 deletions lib/matplotlib/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
import math
from weakref import WeakValueDictionary

try:
from functools import lru_cache
except ImportError: # Py2
from backports.functools_lru_cache import lru_cache

import numpy as np

from . import _path, rcParams
Expand Down Expand Up @@ -942,27 +947,17 @@ def wedge(cls, theta1, theta2, n=None):
"""
return cls.arc(theta1, theta2, n, True)

_hatch_dict = maxdict(8)

@classmethod
def hatch(cls, hatchpattern, density=6):
@staticmethod
@lru_cache(8)
def hatch(hatchpattern, density=6):
"""
Given a hatch specifier, *hatchpattern*, generates a Path that
can be used in a repeated hatching pattern. *density* is the
number of lines per unit square.
"""
from matplotlib.hatch import get_path

if hatchpattern is None:
return None

hatch_path = cls._hatch_dict.get((hatchpattern, density))
if hatch_path is not None:
return hatch_path

hatch_path = get_path(hatchpattern, density)
cls._hatch_dict[(hatchpattern, density)] = hatch_path
return hatch_path
return (get_path(hatchpattern, density)
if hatchpattern is not None else None)

def clip_to_bbox(self, bbox, inside=True):
"""
Expand Down
6 changes: 1 addition & 5 deletions lib/matplotlib/textpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ class TextToPath(object):
DPI = 72

def __init__(self):
"""
Initialization
"""
self.mathtext_parser = MathTextParser('path')
self.tex_font_map = None

Expand Down Expand Up @@ -492,8 +489,7 @@ def _revalidate_path(self):
necessary.

"""
if (self._invalid or
(self._cached_vertices is None)):
if self._invalid or self._cached_vertices is None:
tr = Affine2D().scale(
self._size / text_to_path.FONT_SCALE,
self._size / text_to_path.FONT_SCALE).translate(*self._xy)
Expand Down
0