View Single Post
Old 10-07-2022, 08:36 AM   #1
chaley
Grand Sorcerer
chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.
 
Posts: 12,495
Karma: 8065348
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
python templates (was possible template functions)

EDIT: This thread started as a proposition for some new template functions but has morphed into a discussion of python templates. Most of what is said in this first post is no longer being considered.
------

Several times over the last years I have wanted to have 'real' python-like dictionaries in the template language. By that I mean a variable that holds "key:value" pairs, where both key and value are arbitrary strings. I am thinking about adding this support. Before I spend the time, I am asking "Would anyone else use this?"

The problem: how to do it that makes sense in the context of the template language. What I am considering: a set of "dict_...()" functions as follows. In all cases the parameters are strings. The function explanation code uses python syntax.
  • dict_set(dict_name, dict_key, dict_value): Set the key to the value in dict.
    Code:
    dict_name.set(dict_key, dict_value)
  • dict_get(dict_name, dict_key[, default]): return the value from the dict. If default is not provided then the funtion returns the empty string if the key doesn't exist in the dict.
    Code:
    dict_name.get(dict_key, default)
  • dict_keys(dict_name, sep): return a list of keys separated by sep.
    Code:
    sep.join(dict_name.keys())
  • dict_values(dict_name, sep): return a list of values separated by sep.
    Code:
    sep.join(dict_name.values())
  • dict_to_string(dict_name): return the dict JSON encoded. This lets you put the dict into template variables, for example globals or arguments.
    Code:
    json.dumps(dict_name)
  • dict_from_string(dict_name, string_form_of_dict): convert a JSON encoded dict into a template dict.
    Code:
    dict_name = json.loads(string_form_of_var)
Example: a template search for series with more than one author. The template (that won't work because the dict_() functions don't exist):
Code:
program:
# Get the already-computed dict if it exists
	d = globals(series_authors);
	if d then
		dict_from_string('series_authors', d)
	else
# Compute the dict the first time through and save it as a global
		series = book_values('series', 'series:True', ':::', 0);
		for s in series separator ':::':
			authors = book_values('authors', 'series:"""=' & a & '"""', '&', 0);
			for a in authors separator '&':
				dict_set('series_authors', s, list_union(dict_get('series_authors'), a, '&'))
			rof
		rof;
		set_globals(series_authors=dict_to_string('series_authors)
	fi;
# At this point we have a dict keyed by series containing a list of authors of that series.
# Check if the current book has a series, and if so does it have more than one author.
# Return the series name if it does, '' if it doesn't.
	authors = dict_get('series_authors', $series)
	if list_count(authors, '&') ># 1 then
		return $series
	else
		return ''
	fi
Here is a template search that would use the template. It would select books with a series that has more than one author. The authors can be co-authors or single authors of separate books in the same series.

You might ask "How does this differ from using select() on identfier-like strings? Some of the differences:
  • Both keys and values are arbitrary strings. There is no assumption about format or content. This avoids the problem that keys and values in identifiers are always separated by a colon.
  • The value in a dict can itself be a (json encoded) dict, allowing nesting.
  • Performance is much better because the template processer will use real python dicts without converting to/from strings.
Attached Thumbnails
Click image for larger version

Name:	Clipboard02.jpg
Views:	1476
Size:	65.4 KB
ID:	197034  

Last edited by chaley; 10-08-2022 at 08:56 AM.
chaley is offline   Reply With Quote