10-08-2022, 10:49 AM | #16 | ||
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Quote:
Quote:
|
||
10-08-2022, 11:38 AM | #17 | ||||
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
I think what you are looking for is future proofing and simplifying git forking. How about we make the protoype be Code:
def evaluate(**arguments): # This could be **kwargs if that is better for some reason Code:
evaluate(book=book, db=db) Code:
book = arguments['book'] db = arguments['db'] In the future, more named arguments could be added without breaking existing python templates. Quote:
Quote:
Quote:
Adding on to the above suggestion about **arguments, how about adding a line to the context menu of the template editor that inserts Code:
python: def evaluate(**arguments): book = arguments['book'] db = arguments['db'] |
||||
Advert | |
|
10-08-2022, 11:58 AM | #18 | ||
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Quote:
Quote:
|
||
10-08-2022, 12:54 PM | #19 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Can we still access the globals dict with this mode?
|
10-08-2022, 01:00 PM | #20 |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
I have wondered about that and haven't been able to find a use case that class instances (e.g., self.my_data) doesn't cover. Do you have one in mind, taking into consideration of the lifetime of of globals and the class instance? Is there something in action chains that would use it?
If you need it, adding it would trivial as a third argument. |
Advert | |
|
10-08-2022, 01:09 PM | #21 | |
Chalut o/
Posts: 410
Karma: 145324
Join Date: Dec 2017
Device: Kobo
|
Quote:
But maybe it would still be great to put an *args. We have **arguments (which we rename **data) which contains the basic data related to this book, or anything else we want to provide turnkey to the users. And on the other side we have *args, which allows to pass arguments to the function during its use, to give it a little more versatility and less "single use". For *args, it's up to the user to program the analysis and the use of the arguments he passed to the function. Code:
python_template('authors', 'title', 'tags') python_template('#original_title', '#translator') Maybe. Yep. That would be great. |
|
10-08-2022, 01:21 PM | #22 | |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Quote:
While at it, is there a way to pass the chain instance itself? |
|
10-08-2022, 01:24 PM | #23 | |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
Said another way, a python template is like a GPM template used in an advanced icon rule. It doesn't have a name and is not callable from anywhere else. |
|
10-08-2022, 01:28 PM | #24 | ||
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
Quote:
|
||
10-08-2022, 01:43 PM | #25 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
I was just not sure it is OK to add non string values to the globals dict. Otherwise, I'm fine with using the globals dict for this purpose. This would make my newly added "Run Python Code" action obsolete, and I can phase it out.
|
10-08-2022, 01:55 PM | #26 | |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
This template works: Code:
python: def evaluate(self, **kwargs): mi = kwargs['book'] db = kwargs['db'] g = kwargs['globals'] v = g.get('_mything', dict()) v['someting'] = {1,2,3,4} g['_mything'] = v print(g) print(mi.authors) print('aaa', db.path(mi.id, index_is_id=True)) s = self.get_default_if_none(mi, 'series', '**no series**') return s + ':::' + str(self.get_default_if_none(mi, '#myint', 999)) def get_default_if_none(self, mi, field, default): v = mi.get(field, None) return default if v is None else v Code:
{'_mything': {'someting': {1, 2, 3, 4}}} ['The 10 Angry Men'] aaa The 10 Angry Men\_Unknown_ (1444) |
|
10-09-2022, 10:30 AM | #27 |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Resolution ...
Thank you @capink & @un_pogaz for your comments. I think I have something that will satisfy you both.
What is in this implemention:
Python templates have the following header that you can insert using a context menu line in the template editor. Code:
python: def evaluate(book, db, globals, arguments, **kwargs): # book is a calibre metadata object # db is a calibre legacy database object # globals is the template global variable dictionary # arguments is a list of arguments if the template is called by a GPM template, otherwise None # kwargs is a dictionary provided for future use # Python code goes here return 'a string' One sample template: Code:
python: def evaluate(book, db, globals, arguments, **kwargs): print(book.authors) print('aaa', db.path(book.id, index_is_id=True)) s = get_default_if_none(book, 'series', '**no series**') return s + ':::' + str(get_default_if_none(book, '#myint', 999)) def get_default_if_none(book, field, default): v = book.get(field, None) return default if v is None else v Code:
python: def evaluate(book, db, globals, arguments, **kwargs): if arguments: if len(arguments != 2): return 'incorrect number of arguments' return arguments[0] + ':::' + arguments[1] return 'no arguments provided' The sample calling GPM template: Code:
program: a_python_template_2_args(1, 'aaaa') @capink: you use the FormatterFunction class in Action Chains and set is_python=True. This works with the new code to distinguish between python template functions and stored templates. However, if you need to distinguish between stored GPM templates and stored python templates then you must use the object_type attribute. If you want to store python templates then you must use the FormatterUserFunction class instead of the FormatterFunction class. The current code is attached. There are 5 .py files. If either of you have time and energy to try it before I submit the changes to Kovid that would be great. EDIT: I removed this zip file. It had the files in the wrong place. A new file is in this post. Last edited by chaley; 10-09-2022 at 12:59 PM. Reason: Wrong zip file |
10-09-2022, 11:49 AM | #28 | |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
@chaley: thanks a lot for your efforts and patience. I am more than satisfied with your final implementation. I will test and report back.
Quote:
|
|
10-09-2022, 12:09 PM | #29 |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Another example python template, this time a bit more complicated and more useful. It produces a list of all the authors for a series. The list is stored in a composite column (#comp2) that shows in the book details "on separate lines", which requires the list be a comma-separated. To make that work the template converts commas in author names to semicolons then builds the comma-separated list. The authors are then sorted, which is why the template uses author_sort.
The template: Code:
python: def evaluate(book, db, globals, arguments, **kwargs): if book.series is None: return '' ans = set() for id_ in db.search_getting_ids(f'series:"={book.series}"', ''): ans.update([v.strip() for v in db.new_api.field_for('author_sort', id_).split('&')]) return ', '.join(v.replace(',', ';') for v in sorted(ans)) Last edited by chaley; 10-09-2022 at 12:14 PM. Reason: Corrected the template |
10-09-2022, 12:09 PM | #30 |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Python functions in database and calibre 5 | Terisa de morgan | Calibre | 7 | 09-27-2020 02:52 AM |
A little help with template functions in a composite column, please! | mopkin | Library Management | 2 | 11-05-2019 11:07 PM |
Using built-in template functions in a custom template function | ilovejedd | Library Management | 4 | 01-28-2018 12:20 PM |
Rules, templates, and functions for column coloring and composed icons | readin | Library Management | 7 | 08-11-2016 04:41 PM |
template: if one of the tag is something... maybe contains or in_list functions | fxp33 | Calibre | 4 | 07-19-2014 05:18 AM |