mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
1) Fix silly regression in template_functions preference that caused all functions to be added to the custom function preference.
2) Change function registration and deregistration to restore function bodies if the name conflict goes away.
This commit is contained in:
parent
e7777df9ae
commit
8a5c71f36a
@ -220,11 +220,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
def commit(self):
|
def commit(self):
|
||||||
# formatter_functions().reset_to_builtins()
|
# formatter_functions().reset_to_builtins()
|
||||||
pref_value = []
|
pref_value = []
|
||||||
for f in self.funcs:
|
for name, cls in self.funcs.iteritems():
|
||||||
func = self.funcs[f]
|
if name not in self.builtins:
|
||||||
pref_value.append((func.name, func.doc, func.arg_count, func.program_text))
|
pref_value.append((cls.name, cls.doc, cls.arg_count, cls.program_text))
|
||||||
self.db.prefs.set('user_template_functions', pref_value)
|
self.db.prefs.set('user_template_functions', pref_value)
|
||||||
formatter_functions().unregister_functions(self.db.library_id)
|
|
||||||
load_user_template_functions(self.db.library_id, pref_value)
|
load_user_template_functions(self.db.library_id, pref_value)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import inspect, re, traceback
|
import inspect, re, traceback
|
||||||
from math import trunc
|
from math import trunc
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
from calibre import human_readable
|
from calibre import human_readable
|
||||||
from calibre.constants import DEBUG
|
from calibre.constants import DEBUG
|
||||||
@ -23,10 +22,16 @@ from calibre.utils.localization import calibre_langcode_to_name, canonicalize_la
|
|||||||
|
|
||||||
class FormatterFunctions(object):
|
class FormatterFunctions(object):
|
||||||
|
|
||||||
|
error_function_body = ('def evaluate(self, formatter, kwargs, mi, locals):\n'
|
||||||
|
'\treturn "' +
|
||||||
|
_('Duplicate user function name {0}. '
|
||||||
|
'Change the name or ensure that the functions are identical')
|
||||||
|
+ '"')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._builtins = {}
|
self._builtins = {}
|
||||||
self._functions = {}
|
self._functions = {}
|
||||||
self._functions_from_library = defaultdict(list)
|
self._functions_from_library = {}
|
||||||
|
|
||||||
def register_builtin(self, func_class):
|
def register_builtin(self, func_class):
|
||||||
if not isinstance(func_class, FormatterFunction):
|
if not isinstance(func_class, FormatterFunction):
|
||||||
@ -40,7 +45,7 @@ class FormatterFunctions(object):
|
|||||||
for a in func_class.aliases:
|
for a in func_class.aliases:
|
||||||
self._functions[a] = func_class
|
self._functions[a] = func_class
|
||||||
|
|
||||||
def register_function(self, library_uuid, func_class, replace=False):
|
def _register_function(self, func_class, replace=False):
|
||||||
if not isinstance(func_class, FormatterFunction):
|
if not isinstance(func_class, FormatterFunction):
|
||||||
raise ValueError('Class %s is not an instance of FormatterFunction'%(
|
raise ValueError('Class %s is not an instance of FormatterFunction'%(
|
||||||
func_class.__class__.__name__))
|
func_class.__class__.__name__))
|
||||||
@ -48,16 +53,36 @@ class FormatterFunctions(object):
|
|||||||
if not replace and name in self._functions:
|
if not replace and name in self._functions:
|
||||||
raise ValueError('Name %s already used'%name)
|
raise ValueError('Name %s already used'%name)
|
||||||
self._functions[name] = func_class
|
self._functions[name] = func_class
|
||||||
self._functions_from_library[library_uuid].append(name)
|
|
||||||
|
|
||||||
def function_exists(self, name):
|
def register_functions(self, library_uuid, funcs):
|
||||||
return self._functions.get(name, None)
|
self._functions_from_library[library_uuid] = funcs
|
||||||
|
self._register_functions()
|
||||||
|
|
||||||
|
def _register_functions(self):
|
||||||
|
for compiled_funcs in self._functions_from_library.itervalues():
|
||||||
|
for cls in compiled_funcs:
|
||||||
|
f = self._functions.get(cls.name, None)
|
||||||
|
replace = False
|
||||||
|
if f is not None:
|
||||||
|
existing_body = f.program_text
|
||||||
|
new_body = cls.program_text
|
||||||
|
if new_body != existing_body:
|
||||||
|
# Change the body of the template function to one that will
|
||||||
|
# return an error message. Also change the arg count to
|
||||||
|
# -1 (variable) to avoid template compilation errors
|
||||||
|
replace = True
|
||||||
|
func = [cls.name, '', -1, self.error_function_body.format(cls.name)]
|
||||||
|
cls = compile_user_function(*func)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
formatter_functions()._register_function(cls, replace=replace)
|
||||||
|
|
||||||
def unregister_functions(self, library_uuid):
|
def unregister_functions(self, library_uuid):
|
||||||
if library_uuid in self._functions_from_library:
|
if library_uuid in self._functions_from_library:
|
||||||
for name in self._functions_from_library[library_uuid]:
|
for cls in self._functions_from_library[library_uuid]:
|
||||||
self._functions.pop(name)
|
self._functions.pop(cls.name, None)
|
||||||
self._functions_from_library.pop(library_uuid)
|
self._functions_from_library.pop(library_uuid)
|
||||||
|
self._register_functions()
|
||||||
|
|
||||||
def get_builtins(self):
|
def get_builtins(self):
|
||||||
return self._builtins
|
return self._builtins
|
||||||
@ -1271,15 +1296,11 @@ class UserFunction(FormatterUserFunction):
|
|||||||
cls = locals_['UserFunction'](name, doc, arg_count, eval_func)
|
cls = locals_['UserFunction'](name, doc, arg_count, eval_func)
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
error_function_body = ('def evaluate(self, formatter, kwargs, mi, locals):\n'
|
|
||||||
'\treturn "' +
|
|
||||||
_('Duplicate user function name {0}. '
|
|
||||||
'Change the name or ensure that the functions are identical')
|
|
||||||
+ '"')
|
|
||||||
|
|
||||||
def load_user_template_functions(library_uuid, funcs):
|
def load_user_template_functions(library_uuid, funcs):
|
||||||
unload_user_template_functions(library_uuid)
|
unload_user_template_functions(library_uuid)
|
||||||
|
|
||||||
|
compiled_funcs = []
|
||||||
for func in funcs:
|
for func in funcs:
|
||||||
try:
|
try:
|
||||||
# Force a name conflict to test the logic
|
# Force a name conflict to test the logic
|
||||||
@ -1290,26 +1311,10 @@ def load_user_template_functions(library_uuid, funcs):
|
|||||||
# source. This helps ensure that if the function already is defined
|
# source. This helps ensure that if the function already is defined
|
||||||
# then white space differences don't cause them to compare differently
|
# then white space differences don't cause them to compare differently
|
||||||
|
|
||||||
cls = compile_user_function(*func)
|
compiled_funcs.append(compile_user_function(*func))
|
||||||
f = formatter_functions().function_exists(cls.name)
|
|
||||||
replace = False
|
|
||||||
if f is not None:
|
|
||||||
existing_body = f.program_text
|
|
||||||
new_body = cls.program_text
|
|
||||||
if new_body != existing_body:
|
|
||||||
# Change the body of the template function to one that will
|
|
||||||
# return an error message. Also change the arg count to
|
|
||||||
# -1 (variable) to avoid template compilation errors
|
|
||||||
replace = True
|
|
||||||
func[3] = error_function_body.format(func[0])
|
|
||||||
func[2] = -1
|
|
||||||
cls = compile_user_function(*func)
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
formatter_functions().register_function(library_uuid, cls, replace=replace)
|
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
formatter_functions().register_functions(library_uuid, compiled_funcs)
|
||||||
|
|
||||||
def unload_user_template_functions(library_uuid):
|
def unload_user_template_functions(library_uuid):
|
||||||
formatter_functions().unregister_functions(library_uuid)
|
formatter_functions().unregister_functions(library_uuid)
|
Loading…
x
Reference in New Issue
Block a user