From 7a18631b8ffd1d355fcc71a6759337defa3bbf68 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Thu, 25 Feb 2021 16:04:56 +0000 Subject: [PATCH] Improvement to template function raw_field: an optional second argument providing the default if the field is None. --- manual/template_lang.rst | 3 ++- src/calibre/utils/formatter.py | 9 ++++++--- src/calibre/utils/formatter_functions.py | 12 ++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/manual/template_lang.rst b/manual/template_lang.rst index a75503bada..fa84dc8caf 100644 --- a/manual/template_lang.rst +++ b/manual/template_lang.rst @@ -505,7 +505,8 @@ parameters can be statements (sequences of expressions). Note that the definitiv well with test or `first_non_empty`. You can have as many values as you want. * ``print(a, b, ...)`` -- prints the arguments to standard output. Unless you start calibre from the command line (``calibre-debug -g``), the output will go to a black hole. - * ``raw_field(name)`` -- returns the metadata field named by name without applying any formatting. + * ``raw_field(name [, optional_default]))`` -- returns the metadata field named by name without applying any formatting. + It evaluates and returns the optional second argument ``default`` if the field is undefined (``None``). * ``raw_list(name, separator)`` -- returns the metadata list named by name without applying any formatting or sorting and with items separated by separator. * ``re_group(val, pattern, template_for_group_1, for_group_2, ...)`` -- return a string made by applying the regular expression pattern to the val and replacing each matched instance with the string computed by replacing each matched group by the value returned by the corresponding diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py index e97a54715b..83f2a002b3 100644 --- a/src/calibre/utils/formatter.py +++ b/src/calibre/utils/formatter.py @@ -141,10 +141,11 @@ class FieldNode(Node): class RawFieldNode(Node): - def __init__(self, expression): + def __init__(self, expression, default=None): Node.__init__(self) self.node_type = self.NODE_RAW_FIELD self.expression = expression + self.default = default class FirstNonEmptyNode(Node): @@ -460,8 +461,8 @@ class _Parser(object): self.error(_('Missing closing parenthesis')) if id_ == 'field' and len(arguments) == 1: return FieldNode(arguments[0]) - if id_ == 'raw_field' and len(arguments) == 1: - return RawFieldNode(arguments[0]) + if id_ == 'raw_field' and (len(arguments) in (1, 2)): + return RawFieldNode(*arguments) if id_ == 'test' and len(arguments) == 3: return IfNode(arguments[0], (arguments[1],), (arguments[2],)) if id_ == 'first_non_empty' and len(arguments) > 0: @@ -634,6 +635,8 @@ class _Interpreter(object): try: name = self.expr(prog.expression) res = getattr(self.parent_book, name, None) + if res is None and prog.default is not None: + return self.expr(prog.default) if res is not None: if isinstance(res, list): fm = self.parent_book.metadata_for_field(name) diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index f296af3eae..c423bab003 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -455,13 +455,17 @@ class BuiltinField(BuiltinFormatterFunction): class BuiltinRawField(BuiltinFormatterFunction): name = 'raw_field' - arg_count = 1 + arg_count = -1 category = 'Get values from metadata' - __doc__ = doc = _('raw_field(name) -- returns the metadata field named by name ' - 'without applying any formatting.') + __doc__ = doc = _('raw_field(name [, optional_default]) -- returns the ' + 'metadata field named by name without applying any formatting. ' + 'It evaluates and returns the optional second argument ' + "'default' if the field is undefined ('None').") - def evaluate(self, formatter, kwargs, mi, locals, name): + def evaluate(self, formatter, kwargs, mi, locals, name, default=None): res = getattr(mi, name, None) + if res is None and default is not None: + return default if isinstance(res, list): fm = mi.metadata_for_field(name) if fm is None: