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.

This commit is contained in:
Charles Haley 2017-05-16 12:29:20 +02:00 committed by Kovid Goyal
parent 66a0b28b93
commit b21abb1147
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 23 additions and 16 deletions

View File

@ -33,7 +33,8 @@ from calibre.utils.filenames import (
from calibre.utils.img import save_cover_data_to from calibre.utils.img import save_cover_data_to
from calibre.utils.formatter_functions import (load_user_template_functions, from calibre.utils.formatter_functions import (load_user_template_functions,
unload_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, from calibre.db.tables import (OneToOneTable, ManyToOneTable, ManyToManyTable,
SizeTable, FormatsTable, AuthorsTable, IdentifiersTable, PathTable, SizeTable, FormatsTable, AuthorsTable, IdentifiersTable, PathTable,
CompositeTable, UUIDTable, RatingTable) CompositeTable, UUIDTable, RatingTable)
@ -413,11 +414,16 @@ class DB(object):
if load_user_formatter_functions: if load_user_formatter_functions:
set_global_state(self) set_global_state(self)
def get_template_functions(self):
return self._template_functions
def get_user_template_functions(self): def get_user_template_functions(self):
return self._user_template_functions return self._user_template_functions
def set_user_template_functions(self, user_formatter_functions): def set_user_template_functions(self, user_formatter_functions):
self._user_template_functions = 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): # {{{ def initialize_prefs(self, default_prefs, restore_all_prefs, progress_callback): # {{{
self.prefs = DBPrefs(self) self.prefs = DBPrefs(self)

View File

@ -356,13 +356,13 @@ class Cache(object):
for field, table in self.backend.tables.iteritems(): for field, table in self.backend.tables.iteritems():
self.fields[field] = create_field(field, table, bools_are_tristate, 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': if table.metadata['datatype'] == 'composite':
self.composites[field] = self.fields[field] self.composites[field] = self.fields[field]
self.fields['ondevice'] = create_field('ondevice', self.fields['ondevice'] = create_field('ondevice',
VirtualTable('ondevice'), bools_are_tristate, VirtualTable('ondevice'), bools_are_tristate,
self.backend.get_user_template_functions) self.backend.get_template_functions)
for name, field in self.fields.iteritems(): for name, field in self.fields.iteritems():
if name[0] == '#' and name.endswith('_index'): if name[0] == '#' and name.endswith('_index'):

View File

@ -41,7 +41,7 @@ class Field(object):
is_many_many = False is_many_many = False
is_composite = 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 self.name, self.table = name, table
dt = self.metadata['datatype'] dt = self.metadata['datatype']
self.has_text_data = dt in {'text', 'comments', 'series', 'enumeration'} 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.category_formatter = calibre_langcode_to_name
self.writer = Writer(self) self.writer = Writer(self)
self.series_field = None self.series_field = None
self.get_user_formatter_functions = get_user_formatter_functions self.get_template_functions = get_template_functions
@property @property
def metadata(self): def metadata(self):
@ -204,8 +204,8 @@ class CompositeField(OneToOneField):
is_composite = True is_composite = True
SIZE_SUFFIX_MAP = {suffix:i for i, suffix in enumerate(('', 'K', 'M', 'G', 'T', 'P', 'E'))} 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): def __init__(self, name, table, bools_are_tristate, get_template_functions):
OneToOneField.__init__(self, name, table, bools_are_tristate, get_user_formatter_functions) OneToOneField.__init__(self, name, table, bools_are_tristate, get_template_functions)
self._render_cache = {} self._render_cache = {}
self._lock = Lock() self._lock = Lock()
@ -266,7 +266,7 @@ class CompositeField(OneToOneField):
ans = formatter.safe_format( ans = formatter.safe_format(
self.metadata['display']['composite_template'], mi, _('TEMPLATE ERROR'), self.metadata['display']['composite_template'], mi, _('TEMPLATE ERROR'),
mi, column_name=self._composite_name, template_cache=template_cache, 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: with self._lock:
self._render_cache[book_id] = ans self._render_cache[book_id] = ans
return ans return ans
@ -349,7 +349,7 @@ class CompositeField(OneToOneField):
class OnDeviceField(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.name = name
self.book_on_device_func = None self.book_on_device_func = None
self.is_multiple = False self.is_multiple = False
@ -735,7 +735,7 @@ class TagsField(ManyToManyField):
return ans 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 = { cls = {
ONE_ONE: OneToOneField, ONE_ONE: OneToOneField,
MANY_ONE: ManyToOneField, MANY_ONE: ManyToOneField,
@ -755,5 +755,5 @@ def create_field(name, table, bools_are_tristate, get_user_formatter_functions):
cls = CompositeField cls = CompositeField
elif table.metadata['datatype'] == 'series': elif table.metadata['datatype'] == 'series':
cls = SeriesField cls = SeriesField
return cls(name, table, bools_are_tristate, get_user_formatter_functions) return cls(name, table, bools_are_tristate, get_template_functions)

View File

@ -359,15 +359,16 @@ class TemplateFormatter(string.Formatter):
def safe_format(self, fmt, kwargs, error_value, book, def safe_format(self, fmt, kwargs, error_value, book,
column_name=None, template_cache=None, column_name=None, template_cache=None,
strip_results=True, user_functions=None): strip_results=True, template_functions=None):
self.strip_results = strip_results self.strip_results = strip_results
self.column_name = column_name self.column_name = column_name
self.template_cache = template_cache self.template_cache = template_cache
self.kwargs = kwargs self.kwargs = kwargs
self.book = book self.book = book
if user_functions: if template_functions:
self.funcs = formatter_functions().get_builtins().copy() self.funcs = template_functions
self.funcs.update(user_functions) else:
self.funcs = formatter_functions().get_functions()
self.composite_values = {} self.composite_values = {}
self.locals = {} self.locals = {}
try: try:

View File

@ -861,7 +861,7 @@ class BuiltinFormatNumber(BuiltinFormatterFunction):
def evaluate(self, formatter, kwargs, mi, locals, val, template): def evaluate(self, formatter, kwargs, mi, locals, val, template):
if val == '' or val == 'None': if val == '' or val == 'None':
return '' return ''
if not '{' in template: if '{' not in template:
template = '{0:' + template + '}' template = '{0:' + template + '}'
try: try:
v1 = float(val) v1 = float(val)