From b21abb1147b03f565dbec3cf739c374afa20c334 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Tue, 16 May 2017 12:29:20 +0200 Subject: [PATCH] Improve performance of the recent changes to support per-library user template functions. The original implementation created a copy of the template functions dict every time a template was evaluated. The new implementation creates that dict when the library is opened and passes it to the formatter. --- src/calibre/db/backend.py | 8 +++++++- src/calibre/db/cache.py | 4 ++-- src/calibre/db/fields.py | 16 ++++++++-------- src/calibre/utils/formatter.py | 9 +++++---- src/calibre/utils/formatter_functions.py | 2 +- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index de67437cf9..68e5570123 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -33,7 +33,8 @@ from calibre.utils.filenames import ( from calibre.utils.img import save_cover_data_to from calibre.utils.formatter_functions import (load_user_template_functions, unload_user_template_functions, - compile_user_template_functions) + compile_user_template_functions, + formatter_functions) from calibre.db.tables import (OneToOneTable, ManyToOneTable, ManyToManyTable, SizeTable, FormatsTable, AuthorsTable, IdentifiersTable, PathTable, CompositeTable, UUIDTable, RatingTable) @@ -413,11 +414,16 @@ class DB(object): if load_user_formatter_functions: set_global_state(self) + def get_template_functions(self): + return self._template_functions + def get_user_template_functions(self): return self._user_template_functions def set_user_template_functions(self, user_formatter_functions): self._user_template_functions = user_formatter_functions + self._template_functions = formatter_functions().get_builtins() + self._template_functions.update(user_formatter_functions) def initialize_prefs(self, default_prefs, restore_all_prefs, progress_callback): # {{{ self.prefs = DBPrefs(self) diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 17450cbae0..6f3713527a 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -356,13 +356,13 @@ class Cache(object): for field, table in self.backend.tables.iteritems(): self.fields[field] = create_field(field, table, bools_are_tristate, - self.backend.get_user_template_functions) + self.backend.get_template_functions) if table.metadata['datatype'] == 'composite': self.composites[field] = self.fields[field] self.fields['ondevice'] = create_field('ondevice', VirtualTable('ondevice'), bools_are_tristate, - self.backend.get_user_template_functions) + self.backend.get_template_functions) for name, field in self.fields.iteritems(): if name[0] == '#' and name.endswith('_index'): diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 21611d4258..e00307187b 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -41,7 +41,7 @@ class Field(object): is_many_many = False is_composite = False - def __init__(self, name, table, bools_are_tristate, get_user_formatter_functions): + def __init__(self, name, table, bools_are_tristate, get_template_functions): self.name, self.table = name, table dt = self.metadata['datatype'] self.has_text_data = dt in {'text', 'comments', 'series', 'enumeration'} @@ -88,7 +88,7 @@ class Field(object): self.category_formatter = calibre_langcode_to_name self.writer = Writer(self) self.series_field = None - self.get_user_formatter_functions = get_user_formatter_functions + self.get_template_functions = get_template_functions @property def metadata(self): @@ -204,8 +204,8 @@ class CompositeField(OneToOneField): is_composite = True SIZE_SUFFIX_MAP = {suffix:i for i, suffix in enumerate(('', 'K', 'M', 'G', 'T', 'P', 'E'))} - def __init__(self, name, table, bools_are_tristate, get_user_formatter_functions): - OneToOneField.__init__(self, name, table, bools_are_tristate, get_user_formatter_functions) + def __init__(self, name, table, bools_are_tristate, get_template_functions): + OneToOneField.__init__(self, name, table, bools_are_tristate, get_template_functions) self._render_cache = {} self._lock = Lock() @@ -266,7 +266,7 @@ class CompositeField(OneToOneField): ans = formatter.safe_format( self.metadata['display']['composite_template'], mi, _('TEMPLATE ERROR'), mi, column_name=self._composite_name, template_cache=template_cache, - user_functions=self.get_user_formatter_functions()).strip() + template_functions=self.get_template_functions()).strip() with self._lock: self._render_cache[book_id] = ans return ans @@ -349,7 +349,7 @@ class CompositeField(OneToOneField): class OnDeviceField(OneToOneField): - def __init__(self, name, table, bools_are_tristate, get_user_formatter_functions): + def __init__(self, name, table, bools_are_tristate, get_template_functions): self.name = name self.book_on_device_func = None self.is_multiple = False @@ -735,7 +735,7 @@ class TagsField(ManyToManyField): return ans -def create_field(name, table, bools_are_tristate, get_user_formatter_functions): +def create_field(name, table, bools_are_tristate, get_template_functions): cls = { ONE_ONE: OneToOneField, MANY_ONE: ManyToOneField, @@ -755,5 +755,5 @@ def create_field(name, table, bools_are_tristate, get_user_formatter_functions): cls = CompositeField elif table.metadata['datatype'] == 'series': cls = SeriesField - return cls(name, table, bools_are_tristate, get_user_formatter_functions) + return cls(name, table, bools_are_tristate, get_template_functions) diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py index 3c93663360..9e9e3130a5 100644 --- a/src/calibre/utils/formatter.py +++ b/src/calibre/utils/formatter.py @@ -359,15 +359,16 @@ class TemplateFormatter(string.Formatter): def safe_format(self, fmt, kwargs, error_value, book, column_name=None, template_cache=None, - strip_results=True, user_functions=None): + strip_results=True, template_functions=None): self.strip_results = strip_results self.column_name = column_name self.template_cache = template_cache self.kwargs = kwargs self.book = book - if user_functions: - self.funcs = formatter_functions().get_builtins().copy() - self.funcs.update(user_functions) + if template_functions: + self.funcs = template_functions + else: + self.funcs = formatter_functions().get_functions() self.composite_values = {} self.locals = {} try: diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index 3d25c0b04b..47976b323a 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -861,7 +861,7 @@ class BuiltinFormatNumber(BuiltinFormatterFunction): def evaluate(self, formatter, kwargs, mi, locals, val, template): if val == '' or val == 'None': return '' - if not '{' in template: + if '{' not in template: template = '{0:' + template + '}' try: v1 = float(val)