From 4762a481695947508937e11cb7470779889acfb2 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 11:51:05 +0100 Subject: [PATCH 1/7] fix: anki subdecks are not used From 7a3334e530724ccc99a89346ad232883bd99d94b Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 11:51:05 +0100 Subject: [PATCH 2/7] Fixes #396 From dd043fd67356920ee06f3a53a37f3f0663978460 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 12:00:44 +0100 Subject: [PATCH 3/7] tests: ensure ankiconnect gets correct subdecks --- .../anki_connect/test_ankiconnect_destination.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py index 35f1751a..f151b696 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py @@ -63,7 +63,7 @@ def test_ankiconnect_push_prompts(): QAWithoutDoc( question="FakeQuestion", answer="FakeAnswer", - add_tags=["FakeTag"], + add_tags=["#anki/deck/FakeSubdeck"], ), ClozeWithoutDoc( text="FakeText", add_tags=["FakeTag"] @@ -74,6 +74,16 @@ def test_ankiconnect_push_prompts(): ) expected_commands = [(ImportPackage, 1), (UpdateModel, 2)] + import_package_command = next( + c + for c in gateway.executed_commands + if isinstance(c, ImportPackage) + ) + assert ( + import_package_command.package.decks[0].name # type: ignore + == "FakeDeck::FakeSubdeck" + ) + for command in expected_commands: assert ( len( From 9ab65fa34217c6c99cbdcc9844f9c359c0a5d9f8 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 12:09:42 +0100 Subject: [PATCH 4/7] fix: extract all tags from markdown documents --- .../prompt_source/document_ingesters/document.py | 2 +- .../test_markdown_document_ingester.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py index e5a51165..fe1c2a95 100644 --- a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py +++ b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py @@ -11,7 +11,7 @@ class Document: @property def tags(self) -> Sequence[str]: - return list(re.findall(r"#anki\/tag\/\S+", self.content)) + return list(re.findall(r"#[\w\/]+", self.content)) @property def title(self) -> str: diff --git a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py index 22b964bb..251759e0 100644 --- a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py +++ b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py @@ -7,10 +7,18 @@ def test_markdown_document_ingester(tmpdir: Path): ingester = MarkdownDocumentIngester(directory=Path(tmpdir)) with (Path(tmpdir) / "test.md").open("w") as f: - f.write("# Hello World\n#anki/tag/test_tag") + f.write( + """# Hello World\n +#anki/tag/test_tag #anki/tag/test_tag2 +""" + ) documents = ingester.get_documents() assert len(documents) == 1 document = documents[0] assert document.title == "test" - assert document.tags == ["#anki/tag/test_tag"] + assert document.tags == [ + "#anki/tag/test_tag", + "#anki/tag/test_tag2", + "#comment_tag", + ] From 5a220ff2543ed582c30f90418f67915b005ac4a7 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 12:10:52 +0100 Subject: [PATCH 5/7] fix: tag strings should not contain "#" --- .../domain/prompt_source/document_ingesters/document.py | 7 ++++++- .../document_ingesters/test_markdown_document_ingester.py | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py index fe1c2a95..aa7c55a0 100644 --- a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py +++ b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/document.py @@ -11,7 +11,12 @@ class Document: @property def tags(self) -> Sequence[str]: - return list(re.findall(r"#[\w\/]+", self.content)) + tag_strings: list[str] = list( + re.findall(r"#[\w\/]+", self.content) + ) + return [ + tag_string.replace("#", "") for tag_string in tag_strings + ] @property def title(self) -> str: diff --git a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py index 251759e0..6dcc9160 100644 --- a/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py +++ b/personal_mnemonic_medium/domain/prompt_source/document_ingesters/test_markdown_document_ingester.py @@ -18,7 +18,7 @@ def test_markdown_document_ingester(tmpdir: Path): document = documents[0] assert document.title == "test" assert document.tags == [ - "#anki/tag/test_tag", - "#anki/tag/test_tag2", - "#comment_tag", + "anki/tag/test_tag", + "anki/tag/test_tag2", + "comment_tag", ] From dda73bd8e9b670a274e43b3d86ccefd75e71089b Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 12:27:45 +0100 Subject: [PATCH 6/7] fix: import all decks --- .../anki_connect/ankiconnect_destination.py | 17 +++++++++-------- .../prompts/base_anki_prompt.py | 2 +- .../prompt_converter/prompts/test_ankiqa.py | 2 +- .../test_ankiconnect_destination.py | 3 ++- .../test_cloze_prompt_extractor.py | 2 +- .../test_qa_prompt_extractor.py | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/ankiconnect_destination.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/ankiconnect_destination.py index ed9a8523..fd49cc30 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/ankiconnect_destination.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/ankiconnect_destination.py @@ -79,14 +79,14 @@ def _delete_prompts( self.gateway.delete_notes(list(prompt_ids)) def _grouped_cards_to_deck( - self, cards: Mapping[str, Sequence[AnkiCard]] + self, grouped_cards: Mapping[str, Sequence[AnkiCard]] ) -> genanki.Deck: - deck_name = next(iter(cards.keys())) + deck_name = next(iter(grouped_cards.keys())) deck = genanki.Deck( name=deck_name, deck_id=hash_cleaned_str(deck_name) ) - for card in cards[deck_name]: + for card in grouped_cards[deck_name]: deck.add_note(card.to_genanki_note()) # type: ignore return deck @@ -97,11 +97,12 @@ def _create_package( cards_grouped_by_deck = Seq(cards).groupby( lambda card: card.deck ) - decks = ( - Seq([cards_grouped_by_deck]) - .map(self._grouped_cards_to_deck) - .to_list() - ) + decks = [ + self._grouped_cards_to_deck( + {group: cards_grouped_by_deck[group]} + ) + for group in cards_grouped_by_deck + ] return genanki.Package(deck_or_decks=decks) diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py index 97dde3e0..ebc7d6dd 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py @@ -26,7 +26,7 @@ def to_genanki_note(self) -> genanki.Note: @property def deck(self) -> str: - deck_prefix = "#anki/deck/" + deck_prefix = "anki/deck/" deck_in_tags = ( tag.replace(deck_prefix, "") for tag in self.tags diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/test_ankiqa.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/test_ankiqa.py index bc656403..2fcd67a9 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/test_ankiqa.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/test_ankiqa.py @@ -18,5 +18,5 @@ class FakeAnkiQA(AnkiQA): def test_ankiqa_deck_inference(): - card = FakeAnkiQA(tags=["#anki/deck/Subdeck"]) + card = FakeAnkiQA(tags=["anki/deck/Subdeck"]) assert card.deck == "FakeBaseDeck::Subdeck" diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py index f151b696..02c805c3 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py @@ -63,7 +63,7 @@ def test_ankiconnect_push_prompts(): QAWithoutDoc( question="FakeQuestion", answer="FakeAnswer", - add_tags=["#anki/deck/FakeSubdeck"], + add_tags=["anki/deck/FakeSubdeck"], ), ClozeWithoutDoc( text="FakeText", add_tags=["FakeTag"] @@ -83,6 +83,7 @@ def test_ankiconnect_push_prompts(): import_package_command.package.decks[0].name # type: ignore == "FakeDeck::FakeSubdeck" ) + assert len(import_package_command.package.decks) == 2 # type: ignore for command in expected_commands: assert ( diff --git a/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_cloze_prompt_extractor.py b/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_cloze_prompt_extractor.py index e7661b44..e06adfd4 100644 --- a/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_cloze_prompt_extractor.py +++ b/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_cloze_prompt_extractor.py @@ -26,4 +26,4 @@ def test_cloze_prompt_extractor(tmpdir: Path): extractor[0].text == r"What is the meaning of life? {{c734::42}}" ) - assert extractor[0].tags == ["#anki/tag/test_tag"] + assert extractor[0].tags == ["anki/tag/test_tag"] diff --git a/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_qa_prompt_extractor.py b/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_qa_prompt_extractor.py index 7ea1f75e..df0ccf91 100644 --- a/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_qa_prompt_extractor.py +++ b/personal_mnemonic_medium/domain/prompt_source/prompt_extractors/test_qa_prompt_extractor.py @@ -25,5 +25,5 @@ def test_qa_prompt_extractor(tmpdir: Path): prompt = extractor[0] assert prompt.question == "What is the meaning of life?" assert prompt.answer == "42" - assert prompt.tags == ["#anki/tag/test_tag"] + assert prompt.tags == ["anki/tag/test_tag"] assert prompt.uid == 9385242780 From 3ba0c9092fa06a61fbacbb50b7d6fccad438f499 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Fri, 22 Dec 2023 12:30:23 +0100 Subject: [PATCH 7/7] feat: support arbitrary subdeck nesting --- .../prompt_converter/prompts/base_anki_prompt.py | 2 +- .../anki_connect/test_ankiconnect_destination.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py index ebc7d6dd..8dffdb3b 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/prompt_converter/prompts/base_anki_prompt.py @@ -28,7 +28,7 @@ def to_genanki_note(self) -> genanki.Note: def deck(self) -> str: deck_prefix = "anki/deck/" deck_in_tags = ( - tag.replace(deck_prefix, "") + tag.replace(deck_prefix, "").replace("/", "::") for tag in self.tags if tag.startswith(deck_prefix) ) diff --git a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py index 02c805c3..46526056 100644 --- a/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py +++ b/personal_mnemonic_medium/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py @@ -63,7 +63,9 @@ def test_ankiconnect_push_prompts(): QAWithoutDoc( question="FakeQuestion", answer="FakeAnswer", - add_tags=["anki/deck/FakeSubdeck"], + add_tags=[ + "anki/deck/FakeSubdeck/FakeSubSubdeck" + ], ), ClozeWithoutDoc( text="FakeText", add_tags=["FakeTag"] @@ -81,7 +83,7 @@ def test_ankiconnect_push_prompts(): ) assert ( import_package_command.package.decks[0].name # type: ignore - == "FakeDeck::FakeSubdeck" + == "FakeDeck::FakeSubdeck::FakeSubSubdeck" ) assert len(import_package_command.package.decks) == 2 # type: ignore