From b11df5c7330efdd2f604dbf3e9458d7ecd0dc925 Mon Sep 17 00:00:00 2001 From: Erez Volk Date: Thu, 2 Jan 2020 16:01:44 +0200 Subject: [PATCH 1/3] Add an option to add a set of tags to notes updated on import --- anki-qt/aqt/importing.py | 3 + anki-qt/designer/importing.ui | 14 ++++ lib-python/anki/importing/noteimp.py | 16 +++++ lib-python/tests/test_importing.py | 95 ++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+) 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")) From e36f019ec234600e79722ec4a95aea3b81f14603 Mon Sep 17 00:00:00 2001 From: Erez Volk Date: Thu, 2 Jan 2020 21:05:56 +0200 Subject: [PATCH 2/3] Split tags on spaces, not commas --- lib-python/anki/importing/noteimp.py | 2 +- lib-python/tests/test_importing.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib-python/anki/importing/noteimp.py b/lib-python/anki/importing/noteimp.py index e4b95dde0..eb11504cc 100644 --- a/lib-python/anki/importing/noteimp.py +++ b/lib-python/anki/importing/noteimp.py @@ -275,7 +275,7 @@ content in the text file to the correct fields.""" 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.split(tags) + self.tagModified.split() tagList = self.col.tags.canonify(tagList) self.col.tags.register(tagList) tags = self.col.tags.join(tagList) diff --git a/lib-python/tests/test_importing.py b/lib-python/tests/test_importing.py index 9cafe817d..ae7406fc1 100644 --- a/lib-python/tests/test_importing.py +++ b/lib-python/tests/test_importing.py @@ -249,7 +249,7 @@ def test_tsv_tag_multiple_tags(): tf.flush() i = TextImporter(deck, tf.name) i.initMapping() - i.tagModified = "five,six" + i.tagModified = "five six" i.run() n.load() From 46a24812ce13d9b42b015813c55fa2ccf11d628c Mon Sep 17 00:00:00 2001 From: Erez Volk Date: Fri, 3 Jan 2020 08:32:44 +0200 Subject: [PATCH 3/3] Enable Tag Modified iff importMode is Update --- CONTRIBUTORS | 2 +- qt/aqt/importing.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 88cff1adb..f41d0d36f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -18,7 +18,7 @@ support site, it would be great if you could add your name below as well. ******************** -- Sample Name +Erez Volk ******************** diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py index 046176d18..65e649c7f 100644 --- a/qt/aqt/importing.py +++ b/qt/aqt/importing.py @@ -91,6 +91,7 @@ class ImportDialog(QDialog): self.frm.autoDetect.clicked.connect(self.onDelimiter) self.updateDelimiterButtonText() self.frm.allowHTML.setChecked(self.mw.pm.profile.get("allowHTML", True)) + self.frm.importMode.currentIndexChanged.connect(self.importModeChanged) self.frm.importMode.setCurrentIndex(self.mw.pm.profile.get("importMode", 1)) # import button b = QPushButton(_("Import")) @@ -286,6 +287,14 @@ you can enter it here. Use \\t to represent tab.""" def helpRequested(self): openHelp("importing") + def importModeChanged(self, newImportMode): + if newImportMode == 0: + allowTagModified = True + else: + allowTagModified = False + self.frm.tagModifiedCheck.setEnabled(allowTagModified) + self.frm.tagModifiedTag.setEnabled(allowTagModified) + def showUnicodeWarning(): """Shorthand to show a standard warning."""