diff --git a/beets/dbcore/db.py b/beets/dbcore/db.py index 97a4a7ce31..3195b52c9d 100755 --- a/beets/dbcore/db.py +++ b/beets/dbcore/db.py @@ -25,7 +25,7 @@ import contextlib import beets -from beets.util.functemplate import Template +from beets.util import functemplate from beets.util import py3_path from beets.dbcore import types from .query import MatchQuery, NullSort, TrueQuery @@ -597,7 +597,7 @@ def evaluate_template(self, template, for_path=False): """ # Perform substitution. if isinstance(template, six.string_types): - template = Template(template) + template = functemplate.template(template) return template.substitute(self.formatted(for_path), self._template_funcs()) diff --git a/beets/library.py b/beets/library.py index d49d672271..5786ce9d97 100644 --- a/beets/library.py +++ b/beets/library.py @@ -31,7 +31,7 @@ from beets import util from beets.util import bytestring_path, syspath, normpath, samefile, \ MoveOperation -from beets.util.functemplate import Template +from beets.util.functemplate import template, Template from beets import dbcore from beets.dbcore import types import beets @@ -855,7 +855,7 @@ def destination(self, fragment=False, basedir=None, platform=None, if isinstance(path_format, Template): subpath_tmpl = path_format else: - subpath_tmpl = Template(path_format) + subpath_tmpl = template(path_format) # Evaluate the selected template. subpath = self.evaluate_template(subpath_tmpl, True) @@ -1134,7 +1134,7 @@ def art_destination(self, image, item_dir=None): image = bytestring_path(image) item_dir = item_dir or self.item_dir() - filename_tmpl = Template( + filename_tmpl = template( beets.config['art_filename'].as_str()) subpath = self.evaluate_template(filename_tmpl, True) if beets.config['asciify_paths']: diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 327db6b044..622a1e7f01 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -36,7 +36,7 @@ from beets import library from beets import plugins from beets import util -from beets.util.functemplate import Template +from beets.util.functemplate import template from beets import config from beets.util import confit, as_string from beets.autotag import mb @@ -616,7 +616,7 @@ def get_path_formats(subview=None): subview = subview or config['paths'] for query, view in subview.items(): query = PF_KEY_QUERIES.get(query, query) # Expand common queries. - path_formats.append((query, Template(view.as_str()))) + path_formats.append((query, template(view.as_str()))) return path_formats diff --git a/beets/util/functemplate.py b/beets/util/functemplate.py index 6a34a3bb38..9c625b7f98 100644 --- a/beets/util/functemplate.py +++ b/beets/util/functemplate.py @@ -35,6 +35,7 @@ import types import sys import six +import functools SYMBOL_DELIM = u'$' FUNC_DELIM = u'%' @@ -553,8 +554,20 @@ def _parse(template): return Expression(parts) -# External interface. +# Decorator that enables lru_cache on py3, and no caching on py2. +def cached(func): + if six.PY2: + # Sorry python2 users, no caching for you :( + return func + return functools.lru_cache(maxsize=128)(func) + +@cached +def template(fmt): + return Template(fmt) + + +# External interface. class Template(object): """A string template, including text, Symbols, and Calls. """ diff --git a/docs/changelog.rst b/docs/changelog.rst index d88bf0b12b..085345353a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -117,6 +117,9 @@ Some improvements have been focused on improving beets' performance: to be displayed. Thanks to :user:`pprkut`. :bug:`3089` +* Querying the library was further improved by reusing compiled teamplates + instead of compiling them over and over again. + Thanks to :user:`SimonPersson`. * :doc:`/plugins/absubmit`, :doc:`/plugins/badfiles`: Analysis now works in parallel (on Python 3 only). Thanks to :user:`bemeurer`.