View Single Post
Old 12-24-2022, 06:20 PM   #1
DaltonST
Deviser
DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.DaltonST ought to be getting tired of karma fortunes by now.
 
DaltonST's Avatar
 
Posts: 2,265
Karma: 2090983
Join Date: Aug 2013
Location: Texas
Device: none
Running PTM/PythonTemplateContexts in Job, not GUI

I saved this PTM template in Preferences > Template Functions:

Spoiler:

daltonst1
python:
def evaluate(book,context):
text = context.globals['val']
text = text + "xxxxxxxxxxxx"
return text


The globals dict was of course empty since it gets filled at runtime, so an error message about the key, 'val', missing was spurious. I still was able to save & apply the PTM template.

I then ran the above PTM template in a plugin's Job using this code:

Code:
 

        funcobject = user_template_functions['daltonst1']
        func_name = funcobject.name
        formatter = TemplateFormatter()
        formatter.funcs.update(formatter_functions()._functions_from_library)
        ptc = PythonTemplateContext()
        ptc.funcs = formatter_functions()._functions_from_library
        if func_name in ptc.funcs:
            func = ptc.funcs[func_name]
        elif func_name in formatter.funcs:
            func = formatter.funcs[func_name]
        else:
            func = funcobject 
        ptc.func = func
        ptc.func_name = func_name
        ptc.name = func_name
        ptc.globals = {}
        ptc.globals['val'] = "ABCDEFGHIJK9999999999MNOPQRSTUVWXYZ"
        ptc.arguments = ""
        ptc.db = guidb
        mi = guidb.new_api.get_metadata(current_book)
        ptc.book = mi
        ptc.formatter = formatter
        formatter.python_context_object = ptc
        formatter.func = func
        formatter.func_name = func_name
        formatter.name = func_name
        formatter.db = guidb
        formatter.mi = mi
        formatter.book = mi
        formatter.kwargs = None
        ffc = FormatterFuncsCaller(formatter)
        call = ffc.__getattribute__(func_name)
        output_text = call(formatter.python_context_object)
The debug log for the above Job shows:

Spoiler:
daltonst1 (<StoredObjectType.StoredPythonTemplate: 3>, <calibre.utils.formatter_functions.FormatterUserFu nction object at 0x0000022E5FCF07C0>)

ERROR in call(formatter.python_context_object): Error in function daltonst1 :: Error in function evaluate on line 3 : KeyError - 'val'



I went back into where I saved this PTM template in Preferences > Template Functions to work on the same PTM template, but the GUI raised the error shown below, and would not let me back into Preferences > Template Functions to work on the PTM template to fix the error (Catch-22):
Spoiler:


calibre, version 6.10.0
ERROR: Unhandled exception: <b>AttributeError</b>:'list' object has no attribute 'object_type'

calibre 6.10 embedded-python: True
Windows-10-10.0.22621-SP0 Windows ('64bit', 'WindowsPE')
('Windows', '10', '10.0.22621')
Python 3.10.1
Windows: ('10', '10.0.22621', 'SP0', 'Multiprocessor Free')
Interface language: None
Successfully initialized third party plugins: Audit Log (1, 0, 18) && Author Book Count (2, 2, 2) && Author Book Count Hierarchy (1, 2, 3) && CalibreSpy (1, 0, 90) && Consolidate All Library Metadata (2, 0, 43) && Drop Search Results (1, 0, 13) && English Noun Frequency (1, 0, 15) && Entities Manager (1, 0, 18) && Extract People Other Metadata (1, 0, 0) && Extract RIS Citations (1, 0, 5) && Favourites Menu (1, 3, 0) && Job Spy (1, 0, 197) && Library Codes (1, 0, 53) && Library Splitter (1, 0, 6) && Media File Importer (1, 0, 26) && MultiColumnSearch (1, 0, 95) && QuarantineAndScrub (3, 6, 119) && Save Composite Custom Columns (1, 1, 1) && View Manager (1, 10, 2) && Zotero Metadata Importer (1, 0, 77)
Traceback (most recent call last):
File "calibre\gui2\preferences\main.py", line 308, in show_plugin
File "calibre\customize\__init__.py", line 675, in create_widget
File "calibre\gui2\preferences\__init__.py", line 267, in __init__
File "calibre\gui2\preferences\template_functions_ui.py ", line 31, in setupUi
File "calibre\gui2\dialogs\template_dialog.py", line 1090, in __init__
File "calibre\gui2\dialogs\template_dialog.py", line 453, in __init__
File "calibre\gui2\dialogs\template_dialog.py", line 858, in function_type_string
AttributeError: 'list' object has no attribute 'object_type'



Since I could not use Preferences > Template Functions any more, at all, I went into metadata.db, table Preferences, key 'user_template_functions', and carved out the entry for my PTM template from the JSON:

Spoiler:
[
"daltonst1",
"",
0,
"python:\ndef evaluate(book,context):\n\ttext = context.globals['val']\n\ttext = text + \"xxxxxxxxxxxx\"\n\treturn text"
],


I then ran Calibre, and could finally enter into Preferences > Template Functions since the PTM template in question no longer existed.

----------------------------------------------------------------------------------------------

Question: Can the PTM template cache get poisoned when the PTM template is run "in batch" via a Job? If so, is there a way to clear it so the template_dialog for Preferences > Template Functions can always be successfully executed?

Question: How do I create a PTM template using a dict with keys that only exist at runtime?

Question: Is this syntax supported: text = context.globals['val'] ? If not, what is the proper way to accomplish passing a single string value to a PTM template at runtime?


Thank you.

Happy/Merry Christmas.


DaltonST
DaltonST is offline   Reply With Quote