Cleanup previous PR

This commit is contained in:
Kovid Goyal 2022-10-17 20:11:16 +05:30
parent 8b270da20f
commit dd8d3bfeef
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 30 additions and 33 deletions

View File

@ -661,7 +661,7 @@ A PTM template begins with:
# db: a calibre legacy database object # db: a calibre legacy database object
# globals: the template global variable dictionary # globals: the template global variable dictionary
# arguments: is a list of arguments if the template is called by a GPM template, otherwise None # arguments: is a list of arguments if the template is called by a GPM template, otherwise None
# funcs: allows to use the Builtin/User functions and Stored GPM/Python templates # funcs: allows using the Builtin/User functions and Stored GPM/Python templates
# your Python code goes here # your Python code goes here
return 'a string' return 'a string'
@ -670,7 +670,7 @@ You can add the above text to your template using the context menu, usually acce
The context object supports ``str(context)`` that returns a string of the context's contents, and ``context.attributes`` that returns a list of the attribute names in the context. The context object supports ``str(context)`` that returns a string of the context's contents, and ``context.attributes`` that returns a list of the attribute names in the context.
The ``context.funcs`` attribute allows to use the Builtin and User functions, and also the Stored GPM/Python templates so that you can exectute them directly in your code. The functions can be retrieve by they name and they name plus a '_' at the end in case of conflict with Python language keywords. The ``context.funcs`` attribute allows using the Builtin and User functions, and also the Stored GPM/Python templates, so that you can execute them directly in your code. The functions can be retrieve by their names. If the name conflicts with a Python keyword, add an underscore to the end of the name.
Here is an example of a PTM template that produces a list of all the authors for a series. The list is stored in a `Column built from other columns, behaves like tags`. It shows in :guilabel:`Book details` and has the :guilabel:`on separate lines` checked (in :guilabel:`Preferences->Look & feel->Book details`). That option requires the list to be comma-separated. To satisfy that requirement the template converts commas in author names to semicolons then builds a comma-separated list of authors. The authors are then sorted, which is why the template uses author_sort. Here is an example of a PTM template that produces a list of all the authors for a series. The list is stored in a `Column built from other columns, behaves like tags`. It shows in :guilabel:`Book details` and has the :guilabel:`on separate lines` checked (in :guilabel:`Preferences->Look & feel->Book details`). That option requires the list to be comma-separated. To satisfy that requirement the template converts commas in author names to semicolons then builds a comma-separated list of authors. The authors are then sorted, which is why the template uses author_sort.

View File

@ -866,60 +866,57 @@ class PythonTemplateContext(object):
return '\n'.join(f'{k}:{v}' for k,v in ans.items()) return '\n'.join(f'{k}:{v}' for k,v in ans.items())
class FormatterFuncsCaller(): class FormatterFuncsCaller:
''' '''
Provides a convenient solution for call the funcs loaded in a TemplateFormatter Provides a convenient solution to call the functions loaded in a TemplateFormatter.
The funcs can be called by their name as attribut of this class, plus a _ 'underscore' a the end (Python keyword conflicts) The funcs can be called by their name as attributes of this class, with a underscore at the end if the name conflicts with a Python keyword.
If the name contain a illegal character for a attribut (like .:-), use getattr() If the name contain a illegal character for a attribute (like .:-), use getattr()
''' '''
def __init__(self, formatter): def __init__(self, formatter):
object.__init__(self)
if not isinstance(formatter, TemplateFormatter): if not isinstance(formatter, TemplateFormatter):
raise ValueError('Class {} is not an instance of TemplateFormatter' raise TypeError(f'{formatter} is not an instance of TemplateFormatter')
.format(formatter.__class__.__name__))
self.__formatter__ = formatter self.__formatter__ = formatter
def __getattribute__(self, name): def __getattribute__(self, name):
if name.startswith('__') and name.endswith('__'): # return internal special attribut if name.startswith('__') and name.endswith('__'): # return internal special attribute
try: try:
return object.__getattribute__(self, name) return object.__getattribute__(self, name)
except: except Exception:
pass pass
formatter = self.__formatter__ formatter = self.__formatter__
func_name = None func_name = ''
if name.endswith('_') and name[:-1] in formatter.funcs: #given the priority to the backup name if name.endswith('_') and name[:-1] in formatter.funcs: # give the priority to the backup name
func_name = name[:-1] func_name = name[:-1]
elif name in formatter.funcs: elif name in formatter.funcs:
func_name = name func_name = name
if func_name: if func_name:
def call(*args, **kargs): def call(*args, **kargs):
def n(d): def n(d):
return str('' if d is None else d) return '' if d is None else str(d)
args = [n(a) for a in args] args = tuple(n(a) for a in args)
try: try:
def raise_error(msg):
raise ValueError(msg)
if kargs: if kargs:
raise_error(_('Got an unsupported keyword argument')) raise ValueError(_('Keyword arguments are not allowed'))
# special function # special function
if func_name == 'arguments': if func_name == 'arguments':
raise_error(_('Get the arguments from context.arguments instead of calling arguments()')) raise ValueError(_('Get the arguments from context.arguments instead of calling arguments()'))
elif func_name == 'globals': if func_name == 'globals':
raise_error(_('Get the globals from context.globals instead of calling globals()')) raise ValueError(_('Get the globals from context.globals instead of calling globals()'))
elif func_name == 'set_globals': if func_name == 'set_globals':
raise_error(_("Set globals using context.globals['name'] = val instead of calling set_globals()")) raise ValueError(_("Set globals using context.globals['name'] = val instead of calling set_globals()"))
elif func_name == 'character': if func_name == 'character':
if _Parser.inlined_function_nodes['character'][0](args): if _Parser.inlined_function_nodes['character'][0](args):
rslt = _Interpreter.characters.get(args[0], None) rslt = _Interpreter.characters.get(args[0])
if rslt is None: if rslt is None:
raise_error(_("Invalid character name '{0}'").format(args[0])) raise ValueError(_("Invalid character name '{0}'").format(args[0]))
else: else:
raise_error(_('Incorrect number of arguments')) raise ValueError(_('Incorrect number of arguments'))
else: else:
# builtin/user function and Stored GPM/Python template # builtin/user function and Stored GPM/Python template
func = formatter.funcs[func_name] func = formatter.funcs[func_name]
@ -939,7 +936,7 @@ class FormatterFuncsCaller():
return call return call
e = AttributeError(_("no function '{}' exists").format(name)) e = AttributeError(_("no function named {!r} exists").format(name))
e.is_internal = True e.is_internal = True
raise e raise e