I am writing a plugin to assist users in fixing libraries where many books have the fields values scrambled.
I have a method that works when run as a test directly from my plugin gui:
Code:
class SomeGUI:
...
def button_pressed_demo(self):
field_name = 'authors'
value = "Neil Gaiman"
db_cache_api = self.gui_db.new_api
rows = self.gui.library_view.selectionModel().selectedRows()
ids = list(map(self.gui.library_view.model().id, rows))
first_selected = ids[0]
BookDemangler.write_publication_field(db_cache_api, first_selected, field_name, value) # This works
class BookDemangler:
...
@staticmethod
def write_publication_field(db_cache_api, book_id, field_name, value):
if field_name == 'author_sort':
field_name = 'authors'
value = Workshop.flip_author_sorts(value)
print("Book \"%s\"->Setting field \"%s\" to value \"%s\"" % (str(book_id), field_name, value))
bitvm = {book_id: value}
changed = db_cache_api.set_field(name=field_name,
book_id_to_val_map=bitvm,
allow_case_change=True)
The above simple case works as expected. However, when I try to run it with real data, the call to db_cache_api.set_field() fails with the error `TypeError: Bad binding argument type supplied - argument #1: type Metadata` . The biggest difference between the test-calland live code are
- live code iterates over the book_ids from all selected rows of books
- the same db_cache_api is reused, because it is passed as an argument
- field names and values are derived, not hard coded
Code:
class SomeGUI:
...
def process_authorship(self):
from calibre.ebooks.metadata.meta import set_metadata
from calibre.gui2 import error_dialog, info_dialog
# Get currently selected books
rows = self.gui.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
return error_dialog(self.gui, 'Cannot demangle books', 'No books selected', show=True)
# Map the rows to book ids
ids = list(map(self.gui.library_view.model().id, rows))
db_cache_api = self.gui_db.new_api
if db_cache_api:
for book_id in ids:
BookDemangler.demangle(db_cache_api, book_id) # Fails
else:
raise RuntimeError("Failed to obtain database_api cache object.")
info_dialog(self, 'Accessed books', 'Ran processor on %d book(s)' % len(ids), show=True)
BookDemangler.demangle() attempts to guess the correct author, title, and series values from mangled metadata. When I review the arguments I pass to set_field(), I am pretty confident in field name and values being correct. That leads me to suspect
- I can't iterate over books and change them.
- I somehow now have an an invalid book_id, see above.
- something is wrong/stale/broken with reusing db_cache_api.
- something completely different

What might be going wrong here?
Thanks for any help!