What is the proper way to change the note type of a card from within an add-on? Is there an example for that?
See how it’s done by Anki here:
Thanks! It pushed me in the right direction!
I still can’t figure it out. This is my current code:
change_notetype_info = mw.col.models.change_notetype_info(
old_notetype_id=old_notetype_id,
new_notetype_id=new_notetype_id,
)
note_ids: Sequence[NoteId] = []
# Fill the list ...
req = ChangeNotetypeRequest()
req.ParseFromString(change_notetype_info.SerializeToString())
req.note_ids.extend(note_ids)
mw.col.models.change_notetype_of_notes(req)
But the last line triggers an error: anki.errors.BackendError: ProtoError { info: “failed to decode Protobuf message: ChangeNotetypeRequest.old_notetype_id: invalid wire type: LengthDelimited (expected Varint)” }
Any ideas?
By the way, the docstring for change_notetype_request() does not mention that you have to serialize the argument to ParseFromString().
Looks like this is my bad. The note_ids I pass look suspicious. I’ll come back, when I’ve found the reason.
The note_ids are okay. The “suspicious” ones were were added by the ParseFromString() call. I have checked both notetype ids. They both belong to existing models/note types. I have checked every note in note_ids. They exist and are using the model with old_notetype_id.
Why does this fail then?
It appears that the example given in the docstring no longer works after some changes to the protobuf structure. This example works for me:
def new_names_to_indices(new_names: list[str], old_names: list[str]) -> list[int]:
indices = []
for name in new_names:
try:
indices.append(old_names.index(name))
except ValueError:
indices.append(-1)
return indices
basic = mw.col.models.by_name("Basic")
basic_reversed = mw.col.models.by_name("Basic (and reversed card)")
info = mw.col.models.change_notetype_info(
old_notetype_id=basic["id"], new_notetype_id=basic_reversed["id"]
)
req = ChangeNotetypeRequest()
req.new_fields.extend(
new_names_to_indices(list(info.new_field_names), list(info.old_field_names))
)
req.new_templates.extend(
new_names_to_indices(
list(info.new_template_names), list(info.old_template_names)
)
)
req.old_notetype_id = basic["id"]
req.new_notetype_id = basic_reversed["id"]
req.current_schema = mw.col.db.scalar("select scm from col")
req.old_notetype_name = basic["name"]
req.is_cloze = basic["type"] == 1 or basic_reversed["type"] == 1
req.note_ids.extend([1720992551032])
mw.col.models.change_notetype_of_notes(req)
I’ll look into sending a PR to fix the docs and maybe add a helper function to do the conversion.
Thank you! That is very much appreciated.
Was that maybe this commit? Merging Notetypes on Import (#2612) · ankitects/anki@14de845 · GitHub
I guess the minimum required version of my add-on will be the release containing the change.
My guess is that it’s this commit: Change Notetype UI Rework (#1499) · ankitects/anki@6809208 · GitHub
It adds an additional field to ChangeNotetypeInfo.
My example above can be simplified a lot:
basic = mw.col.models.by_name("Basic")
basic_reversed = mw.col.models.by_name("Basic (and reversed card)")
info = mw.col.models.change_notetype_info(
old_notetype_id=basic["id"], new_notetype_id=basic_reversed["id"]
)
req = info.input
req.note_ids.extend([1720992551032])
mw.col.models.change_notetype_of_notes(req)
I can confirm that the complicated version works like a charm. But I will try the simplification, too, and then mark one of your replies as the solution. Thanks a lot again!
The simplified version is also slightly better than the long version because it also fills the “Sort Field”.