View Single Post
Old 03-17-2023, 07:21 PM   #1
charlweed
Enthusiast
charlweed began at the beginning.
 
Posts: 27
Karma: 30
Join Date: Jul 2011
Device: none
cache.set_field() Why "Bad binding argument type supplied - argument #1?

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!
charlweed is offline   Reply With Quote