diff --git a/anki-qt/aqt/importing.py b/anki-qt/aqt/importing.py index 756b0db91..046176d18 100644 --- a/anki-qt/aqt/importing.py +++ b/anki-qt/aqt/importing.py @@ -179,6 +179,9 @@ you can enter it here. Use \\t to represent tab.""" self.mw.pm.profile["importMode"] = self.importer.importMode self.importer.allowHTML = self.frm.allowHTML.isChecked() self.mw.pm.profile["allowHTML"] = self.importer.allowHTML + if self.frm.tagModifiedCheck.isChecked(): + self.importer.tagModified = self.frm.tagModifiedTag.toPlainText() + self.mw.pm.profile["tagModified"] = self.importer.tagModified did = self.deck.selectedId() if did != self.importer.model["did"]: self.importer.model["did"] = did diff --git a/anki-qt/designer/importing.ui b/anki-qt/designer/importing.ui index ce14706bc..07dd178be 100644 --- a/anki-qt/designer/importing.ui +++ b/anki-qt/designer/importing.ui @@ -77,6 +77,20 @@ + + + + + + Tag modified notes: + + + + + + + + diff --git a/lib-python/anki/importing/noteimp.py b/lib-python/anki/importing/noteimp.py index 8b190a61b..e4b95dde0 100644 --- a/lib-python/anki/importing/noteimp.py +++ b/lib-python/anki/importing/noteimp.py @@ -64,11 +64,13 @@ class NoteImporter(Importer): allowHTML = False importMode = 0 mapping: Optional[List[str]] + tagModified: Optional[str] def __init__(self, col: _Collection, file: str) -> None: Importer.__init__(self, col, file) self.model = col.models.current() self.mapping = None + self.tagModified = None self._tagsMapped = False def run(self) -> None: @@ -271,6 +273,13 @@ content in the text file to the correct fields.""" self.col.tags.register(n.tags) tags = self.col.tags.join(n.tags) return [intTime(), self.col.usn(), n.fieldsStr, tags, id, n.fieldsStr, tags] + elif self.tagModified: + tags = self.col.db.scalar("select tags from notes where id = ?", id) + tagList = self.col.tags.split(tags) + self.tagModified.split(",") + tagList = self.col.tags.canonify(tagList) + self.col.tags.register(tagList) + tags = self.col.tags.join(tagList) + return [intTime(), self.col.usn(), n.fieldsStr, tags, id, n.fieldsStr] else: return [intTime(), self.col.usn(), n.fieldsStr, id, n.fieldsStr] @@ -283,6 +292,13 @@ update notes set mod = ?, usn = ?, flds = ?, tags = ? where id = ? and (flds != ? or tags != ?)""", rows, ) + elif self.tagModified: + self.col.db.executemany( + """ +update notes set mod = ?, usn = ?, flds = ?, tags = ? +where id = ? and flds != ?""", + rows, + ) else: self.col.db.executemany( """ diff --git a/lib-python/tests/test_importing.py b/lib-python/tests/test_importing.py index 78c1edb2e..9cafe817d 100644 --- a/lib-python/tests/test_importing.py +++ b/lib-python/tests/test_importing.py @@ -1,6 +1,7 @@ # coding: utf-8 import os +from tempfile import NamedTemporaryFile from anki.importing import ( Anki2Importer, @@ -194,6 +195,100 @@ def test_csv2(): deck.close() +def test_tsv_tag_modified(): + deck = getEmptyCol() + mm = deck.models + m = mm.current() + f = mm.newField("Top") + mm.addField(m, f) + mm.save(m) + n = deck.newNote() + n["Front"] = "1" + n["Back"] = "2" + n["Top"] = "3" + n.addTag("four") + deck.addNote(n) + + with NamedTemporaryFile(mode="w") as tf: + tf.write("1\tb\tc\n") + tf.flush() + i = TextImporter(deck, tf.name) + i.initMapping() + i.tagModified = "boom" + i.run() + + n.load() + assert n["Front"] == "1" + assert n["Back"] == "b" + assert n["Top"] == "c" + assert "four" in n.tags + assert "boom" in n.tags + assert len(n.tags) == 2 + assert i.updateCount == 1 + + deck.close() + + +def test_tsv_tag_multiple_tags(): + deck = getEmptyCol() + mm = deck.models + m = mm.current() + f = mm.newField("Top") + mm.addField(m, f) + mm.save(m) + n = deck.newNote() + n["Front"] = "1" + n["Back"] = "2" + n["Top"] = "3" + n.addTag("four") + n.addTag("five") + deck.addNote(n) + + with NamedTemporaryFile(mode="w") as tf: + tf.write("1\tb\tc\n") + tf.flush() + i = TextImporter(deck, tf.name) + i.initMapping() + i.tagModified = "five,six" + i.run() + + n.load() + assert n["Front"] == "1" + assert n["Back"] == "b" + assert n["Top"] == "c" + assert list(sorted(n.tags)) == list(sorted(["four", "five", "six"])) + + deck.close() + + +def test_csv_tag_only_if_modified(): + deck = getEmptyCol() + mm = deck.models + m = mm.current() + f = mm.newField("Left") + mm.addField(m, f) + mm.save(m) + n = deck.newNote() + n["Front"] = "1" + n["Back"] = "2" + n["Left"] = "3" + deck.addNote(n) + + with NamedTemporaryFile(mode="w") as tf: + tf.write("1,2,3\n") + tf.flush() + i = TextImporter(deck, tf.name) + i.initMapping() + i.tagModified = "right" + i.run() + + n.load() + assert n.tags == [] + assert i.updateCount == 0 + + deck.close() + + def test_supermemo_xml_01_unicode(): deck = getEmptyCol() file = str(os.path.join(testDir, "support/supermemo1.xml"))