mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
New formatter function 'field_list_count('lookup_name')': returns the length of the multi-valued field 'lookup_name' without first converting it to a string. This is much faster than the existing function list_count()
This commit is contained in:
parent
f52b5f8835
commit
4f46ae4707
@ -495,10 +495,11 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
* ``eval(string)`` -- evaluates the string as a program, passing the local variables. This permits using the template processor to construct complex results from local variables. In :ref:`Template Program Mode <template_mode>`, because the `{` and `}` characters are interpreted before the template is evaluated you must use `[[` for the `{` character and `]]` for the ``}`` character. They are converted automatically. Note also that prefixes and suffixes (the `|prefix|suffix` syntax) cannot be used in the argument to this function when using :ref:`Template Program Mode <template_mode>`.
|
||||
* ``extra_file_size(file_name)`` -- returns the size in bytes of the extra file ``file_name`` in the book's ``data/`` folder if it exists, otherwise ``-1``. See also the functions ``has_extra_files()``, ``extra_file_names()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``extra_file_modtime(file_name, format_string)`` -- returns the modification time of the extra file ``file_name`` in the book's ``data/`` folder if it exists, otherwise ``-1``. The modtime is formatted according to ``format_string`` (see ``format_date()`` for details). If ``format_string`` is the empty string, returns the modtime as the floating point number of seconds since the epoch. See also the functions ``has_extra_files()``, ``extra_file_names()`` and ``extra_file_size()``. The epoch is OS dependent. This function can be used only in the GUI.
|
||||
* ``extra_file_names(sep [, pattern])`` returns a ``sep``-separated list of extra files in the book's ``data/`` folder. If the optional parameter ``pattern``, a regular expression, is supplied then the list is filtered to files that match ``pattern``. The pattern match is case insensitive. See also the functions ``has_extra_files()``, ``extra_file_modtime()`` and ``extra_file_size()``. This function can be used only in the GUI.
|
||||
* ``extra_file_names(sep [, pattern])`` -- returns a ``sep``-separated list of extra files in the book's ``data/`` folder. If the optional parameter ``pattern``, a regular expression, is supplied then the list is filtered to files that match ``pattern``. The pattern match is case insensitive. See also the functions ``has_extra_files()``, ``extra_file_modtime()`` and ``extra_file_size()``. This function can be used only in the GUI.
|
||||
* ``field(lookup_name)`` -- returns the value of the metadata field with lookup name ``lookup_name``.
|
||||
* ``field_exists(field_name)`` -- checks if a field (column) with the lookup name ``field_name`` exists, returning ``'1'`` if so and the empty string if not.
|
||||
* ``finish_formatting(val, fmt, prefix, suffix)`` -- apply the format, prefix, and suffix to a value in the same way as done in a template like ``{series_index:05.2f| - |- }``. This function is provided to ease conversion of complex single-function- or template-program-mode templates to `GPM` Templates. For example, the following program produces the same output as the above template::
|
||||
* ``field_exists(lookup_name)`` -- checks if a field (column) with the lookup name ``lookup_name`` exists, returning ``'1'`` if so and the empty string if not.
|
||||
* ``field_list_count(lookup_name)``-- returns the count of items in the field with the lookup name `lookup_name`. The field must be multi-valued such as ``authors`` or ``tags``, otherwise the function raises an error. This function is much faster than ``list_count()`` because it operates directly on calibre data without converting it to a string first. Example: ``field_list_count('tags')``
|
||||
* ``finish_formatting(val, fmt, prefix, suffix)`` -- apply the format, prefix, and uffix to a value in the same way as done in a template like ``{series_index:05.2f| - |- }``. This function is provided to ease conversion of complex single-function- or template-program-mode templates to `GPM` Templates. For example, the following program produces the same output as the above template::
|
||||
|
||||
program: finish_formatting(field("series_index"), "05.2f", " - ", " - ")
|
||||
|
||||
|
@ -59,6 +59,7 @@ class Node:
|
||||
NODE_RANGE = 30
|
||||
NODE_SWITCH = 31
|
||||
NODE_SWITCH_IF = 32
|
||||
NODE_FIELD_LIST_COUNT = 33
|
||||
|
||||
def __init__(self, line_number, name):
|
||||
self.my_line_number = line_number
|
||||
@ -331,6 +332,13 @@ class StrcatNode(Node):
|
||||
self.expression_list = expression_list
|
||||
|
||||
|
||||
class FieldListCountNode(Node):
|
||||
def __init__(self, line_number, expression):
|
||||
Node.__init__(self, line_number, 'field_list_count()')
|
||||
self.node_type = self.NODE_FIELD_LIST_COUNT
|
||||
self.expression = expression
|
||||
|
||||
|
||||
class _Parser:
|
||||
LEX_OP = 1
|
||||
LEX_ID = 2
|
||||
@ -709,7 +717,9 @@ class _Parser:
|
||||
'print': (lambda _: True,
|
||||
lambda ln, args: PrintNode(ln, args)),
|
||||
'strcat': (lambda _: True,
|
||||
lambda ln, args: StrcatNode(ln, args))
|
||||
lambda ln, args: StrcatNode(ln, args)),
|
||||
'field_list_count': (lambda args: len(args) == 1,
|
||||
lambda ln, args: FieldListCountNode(ln, args[0]))
|
||||
}
|
||||
|
||||
def expr(self):
|
||||
@ -1337,6 +1347,18 @@ class _Interpreter:
|
||||
self.break_reporter(prog.node_name, res, prog.line_number)
|
||||
return res
|
||||
|
||||
def do_node_field_list_count(self, prog):
|
||||
name = field_metadata.search_term_to_field_key(self.expr(prog.expression))
|
||||
if not self.parent_book.has_key(name):
|
||||
self.error(_("'{0}' is not a field").format(name), prog.line_number)
|
||||
res = getattr(self.parent_book, name, None)
|
||||
if not isinstance(res, (list, tuple, set, dict)):
|
||||
self.error(_("Field '{0}' is not a list").format(name), prog.line_number)
|
||||
ans = str(len(res))
|
||||
if self.break_reporter:
|
||||
self.break_reporter(prog.node_name, ans, prog.line_number)
|
||||
return ans
|
||||
|
||||
def do_node_break(self, prog):
|
||||
if (self.break_reporter):
|
||||
self.break_reporter(prog.node_name, '', prog.line_number)
|
||||
@ -1566,6 +1588,7 @@ class _Interpreter:
|
||||
Node.NODE_BINARY_STRINGOP: do_node_stringops,
|
||||
Node.NODE_LOCAL_FUNCTION_DEFINE: do_node_local_function_define,
|
||||
Node.NODE_LOCAL_FUNCTION_CALL: do_node_local_function_call,
|
||||
Node.NODE_FIELD_LIST_COUNT: do_node_field_list_count,
|
||||
}
|
||||
|
||||
def expr(self, prog):
|
||||
|
@ -2662,6 +2662,23 @@ class BuiltinIsDarkMode(BuiltinFormatterFunction):
|
||||
only_in_gui_error('is_dark_mode')
|
||||
|
||||
|
||||
class BuiltinFieldListCount(BuiltinFormatterFunction):
|
||||
name = 'field_list_count'
|
||||
arg_count = 0
|
||||
category = 'List manipulation'
|
||||
__doc__ = doc = _("field_list_count(field_name) -- returns the count of items "
|
||||
"in the field with the lookup name 'field_name'. The field "
|
||||
"must be multi-valued such as authors or tags, otherwise "
|
||||
"the function raises an error. This function is much faster "
|
||||
"than list_count() because it operates directly on calibre "
|
||||
"data without converting it to a string first. "
|
||||
"Example: {}").format("field_list_count('tags')")
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||
# The globals function is implemented in-line in the formatter
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
_formatter_builtins = [
|
||||
BuiltinAdd(), BuiltinAnd(), BuiltinApproximateFormats(), BuiltinArguments(),
|
||||
BuiltinAssign(),
|
||||
@ -2673,7 +2690,7 @@ _formatter_builtins = [
|
||||
BuiltinCurrentVirtualLibraryName(), BuiltinDateArithmetic(),
|
||||
BuiltinDaysBetween(), BuiltinDivide(), BuiltinEval(),
|
||||
BuiltinExtraFileNames(), BuiltinExtraFileSize(), BuiltinExtraFileModtime(),
|
||||
BuiltinFirstNonEmpty(), BuiltinField(), BuiltinFieldExists(),
|
||||
BuiltinFieldListCount(), BuiltinFirstNonEmpty(), BuiltinField(), BuiltinFieldExists(),
|
||||
BuiltinFinishFormatting(), BuiltinFirstMatchingCmp(), BuiltinFloor(),
|
||||
BuiltinFormatDate(), BuiltinFormatDateField(), BuiltinFormatNumber(), BuiltinFormatsModtimes(),
|
||||
BuiltinFormatsPaths(), BuiltinFormatsSizes(), BuiltinFractionalPart(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user