From 2393bad1c131858ef777ac1beda328ba75a1c8ba Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 16:58:40 +0000 Subject: [PATCH 1/7] tests: AnkiConnect create -> get all -> delete -> get all sequence Fixes #314 --- .vscode/settings.json | 16 ++----------- .../v2/data_access/test_ankiconnect.py | 23 ++++++++++--------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5b3af19e..338d5e86 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,20 +9,8 @@ "python.analysis.diagnosticMode": "workspace", "githubIssues.queries": [ { - "label": "🔥", - "query": "repo:${owner}/${repository} is:open is:issue milestone:acute-🔥 sort:updated-asc" - }, - { - "label": "🌿", - "query": "repo:${owner}/${repository} is:open is:issue milestone:important-🌿 sort:updated-asc" - }, - { - "label": "No milestone", - "query": "repo:${owner}/${repository} is:open is:issue no:milestone sort:updated-asc" - }, - { - "label": "🌲", - "query": "repo:${owner}/${repository} is:open is:issue milestone:investment-🌲 sort:updated-asc" + "label": "Assigned to me", + "query": "repo:${owner}/${repository} project:martinbernstorff/2 assignee:MartinBernstorff is:open" }, ], } \ No newline at end of file diff --git a/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py b/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py index 33159fd1..2a604f90 100644 --- a/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py +++ b/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py @@ -36,10 +36,10 @@ class TestAnkiConnectGateway: ankiconnect_url=ANKICONNECT_URL, deck_name="Test deck" ) - def test_import_package(self): + def test_full_sequence(self): + # Setup output_path = Path("/output") - # Delete all .apkg in the output directory for f in output_path.glob("*.apkg"): f.unlink() @@ -66,6 +66,8 @@ def test_import_package(self): ) package = genanki.Package(deck_or_decks=deck) + + # Phase 1: Importing self.gateway.import_package( package=package, tmp_write_dir=Path("/output"), @@ -73,13 +75,12 @@ def test_import_package(self): ) assert len(list(Path("/output").glob("*.apkg"))) == 0 - def test_delete_notes(self): - self.gateway.delete_notes(note_ids=[1, 2, 3]) - - def test_get_note_infos(self): - note_infos = self.gateway.get_all_note_infos() + # Phase 2: Getting + all_notes = self.gateway.get_all_note_infos() + assert len(all_notes) == 1 - assert [ - isinstance(note_info, NoteInfo) - for note_info in note_infos - ] + # Phase 3: Deleting + self.gateway.delete_notes( + note_ids=[n.noteId for n in all_notes] + ) + assert len(self.gateway.get_all_note_infos()) == 0 From 93116a4b5cb6384b6e31601ee1c2258f02195575 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 17:05:54 +0000 Subject: [PATCH 2/7] refactor: get rid of tmp_read_dir and tmp_write_dir Fixes #308 --- .../v2/data_access/ankiconnect_gateway.py | 38 +++++++------------ .../v2/data_access/test_ankiconnect.py | 16 ++++---- .../anki_connect/ankiconnect_destination.py | 6 +-- .../v2/presentation/cli.py | 21 ++++++++-- 4 files changed, 39 insertions(+), 42 deletions(-) diff --git a/personal_mnemonic_medium/v2/data_access/ankiconnect_gateway.py b/personal_mnemonic_medium/v2/data_access/ankiconnect_gateway.py index 92d3eff4..3b86ac19 100644 --- a/personal_mnemonic_medium/v2/data_access/ankiconnect_gateway.py +++ b/personal_mnemonic_medium/v2/data_access/ankiconnect_gateway.py @@ -37,9 +37,17 @@ class AnkiConnectCommand(Enum): class AnkiConnectGateway: - def __init__(self, ankiconnect_url: str, deck_name: str) -> None: + def __init__( + self, + ankiconnect_url: str, + deck_name: str, + tmp_read_dir: Path, + tmp_write_dir: Path, + ) -> None: self.ankiconnect_url = ankiconnect_url self.deck_name = deck_name + self.tmp_read_dir = tmp_read_dir + self.tmp_write_dir = tmp_write_dir def update_model(self, model: genanki.Model) -> None: self._invoke( @@ -57,17 +65,12 @@ def update_model(self, model: genanki.Model) -> None: model={"name": model.name, "css": model.css}, # type: ignore ) - def import_package( - self, - package: genanki.Package, - tmp_write_dir: Path, - tmp_read_dir: Path, - ) -> None: + def import_package(self, package: genanki.Package) -> None: apkg_name = f"{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.apkg" - write_path = tmp_write_dir / apkg_name + write_path = self.tmp_write_dir / apkg_name package.write_to_file(write_path) # type: ignore - read_path = tmp_read_dir / apkg_name + read_path = self.tmp_read_dir / apkg_name try: self._invoke( AnkiConnectCommand.IMPORT_PACKAGE, path=str(read_path) @@ -140,8 +143,6 @@ class FakeAnkiCommand: @dataclass(frozen=True) class ImportPackage(FakeAnkiCommand): package: genanki.Package - tmp_write_dir: Path - tmp_read_dir: Path @dataclass(frozen=True) @@ -161,16 +162,5 @@ def get_all_note_infos(self) -> Sequence[NoteInfo]: def update_model(self, model: genanki.Model) -> None: self.executed_commands.append(UpdateModel(model=model)) - def import_package( - self, - package: genanki.Package, - tmp_write_dir: Path, - tmp_read_dir: Path, - ) -> None: - self.executed_commands.append( - ImportPackage( - package=package, - tmp_write_dir=tmp_write_dir, - tmp_read_dir=tmp_read_dir, - ) - ) + def import_package(self, package: genanki.Package) -> None: + self.executed_commands.append(ImportPackage(package=package)) diff --git a/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py b/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py index 33159fd1..08efffcc 100644 --- a/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py +++ b/personal_mnemonic_medium/v2/data_access/test_ankiconnect.py @@ -32,15 +32,17 @@ class MockNoteInfo(NoteInfo): reason="Tests require a running AnkiConnect server", ) class TestAnkiConnectGateway: + output_path = Path("/output") gateway = AnkiConnectGateway( - ankiconnect_url=ANKICONNECT_URL, deck_name="Test deck" + ankiconnect_url=ANKICONNECT_URL, + deck_name="Test deck", + tmp_read_dir=Path("/Users/Leisure/ankidecks"), + tmp_write_dir=output_path, ) def test_import_package(self): - output_path = Path("/output") - # Delete all .apkg in the output directory - for f in output_path.glob("*.apkg"): + for f in self.output_path.glob("*.apkg"): f.unlink() deck = genanki.Deck(deck_id=1, name="Test deck") @@ -66,11 +68,7 @@ def test_import_package(self): ) package = genanki.Package(deck_or_decks=deck) - self.gateway.import_package( - package=package, - tmp_write_dir=Path("/output"), - tmp_read_dir=Path("/Users/Leisure/ankidecks"), - ) + self.gateway.import_package(package=package) assert len(list(Path("/output").glob("*.apkg"))) == 0 def test_delete_notes(self): diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py index c1eb43fd..163f574f 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py @@ -102,11 +102,7 @@ def _push_prompts(self, command: PushPrompts) -> None: package = self._create_package(cards) - self.gateway.import_package( - package, - tmp_write_dir=command.tmp_write_dir, - tmp_read_dir=command.tmp_read_dir, - ) + self.gateway.import_package(package) def update( self, commands: Sequence[PromptDestinationCommand] diff --git a/personal_mnemonic_medium/v2/presentation/cli.py b/personal_mnemonic_medium/v2/presentation/cli.py index 386002c3..883c6f34 100644 --- a/personal_mnemonic_medium/v2/presentation/cli.py +++ b/personal_mnemonic_medium/v2/presentation/cli.py @@ -28,13 +28,18 @@ msg = Printer(timestamp=True) -def _sync_deck(deck_name: str): +def _sync_deck( + deck_name: str, input_dir: Path, apkg_output_filepath: Path +): # TODO: https://github.com/MartinBernstorff/personal-mnemonic-medium/issues/309 feat: use markdown promptsource source_prompts = FakePromptSource().get_prompts() destination = AnkiConnectDestination( gateway=AnkiConnectGateway( - ankiconnect_url=ANKICONNECT_URL, deck_name=deck_name + ankiconnect_url=ANKICONNECT_URL, + deck_name=deck_name, + tmp_read_dir=input_dir, + tmp_write_dir=apkg_output_filepath, ), prompt_converter=AnkiPromptConverter( base_deck=deck_name, card_css=CARD_MODEL_CSS @@ -81,14 +86,22 @@ def main( environment=get_env(default="None"), ) - _sync_deck(deck_name) + _sync_deck( + deck_name=deck_name, + input_dir=input_dir, + apkg_output_filepath=apkg_output_filepath, + ) if watch: sleep_seconds = 60 msg.good( f"Sync complete, sleeping for {sleep_seconds} seconds" ) - _sync_deck(deck_name) + _sync_deck( + deck_name=deck_name, + input_dir=input_dir, + apkg_output_filepath=apkg_output_filepath, + ) if __name__ == "__main__": From 3c47d7ee4cdff588a4f654d15c62bb2580ea74b2 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 17:20:10 +0000 Subject: [PATCH 3/7] feat: add remoteid and use for prompt deletion Fixes #321 --- .../anki_connect/ankiconnect_destination.py | 8 ++++---- .../prompt_converter/anki_prompt_converter.py | 4 ++-- .../prompt_converter/test_anki_prompt_converter.py | 8 ++++---- .../anki_connect/test_ankiconnect_destination.py | 8 ++++---- .../v2/domain/prompts/base_prompt.py | 9 +++++++++ .../v2/domain/prompts/cloze_prompt.py | 2 +- personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py | 2 +- 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py index 163f574f..ef3df0fa 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py @@ -14,8 +14,8 @@ NoteInfo, ) from ...prompts.base_prompt import BasePrompt -from ...prompts.cloze_prompt import RemoteClozePrompt -from ...prompts.qa_prompt import RemoteQAPrompt +from ...prompts.cloze_prompt import ClozeWithoutDoc +from ...prompts.qa_prompt import QAWithoutDoc from ..base_prompt_destination import PromptDestination from .prompt_converter.anki_prompt_converter import ( AnkiPromptConverter, @@ -37,7 +37,7 @@ def _note_info_to_prompt(self, note_info: NoteInfo) -> BasePrompt: "Question" in note_info.fields and "Answer" in note_info.fields ): - return RemoteQAPrompt( + return QAWithoutDoc( question=note_info.fields["Question"].value, answer=note_info.fields["Answer"].value, add_tags=note_info.tags, @@ -45,7 +45,7 @@ def _note_info_to_prompt(self, note_info: NoteInfo) -> BasePrompt: ) if "Text" in note_info.fields: - return RemoteClozePrompt( + return ClozeWithoutDoc( text=note_info.fields["Text"].value, add_tags=note_info.tags, remote_id=str(note_info.noteId), diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/anki_prompt_converter.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/anki_prompt_converter.py index caad4ece..be9cbf16 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/anki_prompt_converter.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/anki_prompt_converter.py @@ -13,7 +13,7 @@ ) from ....prompts.base_prompt import BasePrompt -from ....prompts.cloze_prompt import RemoteClozePrompt +from ....prompts.cloze_prompt import ClozeWithoutDoc from ....prompts.qa_prompt import QAPrompt @@ -45,7 +45,7 @@ def _prompt_to_card(self, prompt: BasePrompt) -> AnkiCard: tags=prompt.tags, css=self.card_css, ) - case RemoteClozePrompt(): + case ClozeWithoutDoc(): card = AnkiCloze( text=prompt.text, deck=deck, diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py index 42cbf181..fdb0fd6d 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py @@ -1,8 +1,8 @@ import pytest from ....prompts.base_prompt import BasePrompt -from ....prompts.cloze_prompt import RemoteClozePrompt -from ....prompts.qa_prompt import RemoteQAPrompt +from ....prompts.cloze_prompt import ClozeWithoutDoc +from ....prompts.qa_prompt import QAWithoutDoc from .anki_prompt_converter import AnkiPromptConverter from .prompts.anki_cloze import AnkiCloze from .prompts.anki_qa import AnkiQA @@ -25,7 +25,7 @@ ("input_prompt", "expected_card"), [ ( - RemoteQAPrompt( + QAWithoutDoc( question="FakeQuestion", answer="FakeAnswer", add_tags=["FakeTag"], @@ -34,7 +34,7 @@ fake_anki_qa, ), ( - RemoteClozePrompt( + ClozeWithoutDoc( text="FakeText", add_tags=["FakeTag"], remote_id="1" ), fake_anki_cloze, diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py index 9af0b492..b0a4694e 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py @@ -10,8 +10,8 @@ UpdateModel, ) from ....data_access.test_ankiconnect import MockNoteInfo -from ...prompts.cloze_prompt import RemoteClozePrompt -from ...prompts.qa_prompt import RemoteQAPrompt +from ...prompts.cloze_prompt import ClozeWithoutDoc +from ...prompts.qa_prompt import QAWithoutDoc from ..destination_commands import PushPrompts from .ankiconnect_destination import AnkiConnectDestination from .prompt_converter.anki_prompt_converter import ( @@ -61,13 +61,13 @@ def test_ankiconnect_push_prompts(tmpdir: Path): [ PushPrompts( prompts=[ - RemoteQAPrompt( + QAWithoutDoc( question="FakeQuestion", answer="FakeAnswer", add_tags=["FakeTag"], remote_id="1", ), - RemoteClozePrompt( + ClozeWithoutDoc( text="FakeText", add_tags=["FakeTag"], remote_id="1", diff --git a/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py index 99017ebe..16bed19f 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py @@ -10,3 +10,12 @@ def uid(self) -> int: @property def tags(self) -> Sequence[str]: ... + + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class RemotePrompt: + prompt: BasePrompt + remote_id: str diff --git a/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py index 3570795a..b28184ca 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py @@ -22,7 +22,7 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) -class RemoteClozePrompt(ClozePrompt): +class ClozeWithoutDoc(ClozePrompt): remote_id: str add_tags: Sequence[str] diff --git a/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py index a493416c..743cd553 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py @@ -25,7 +25,7 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) -class RemoteQAPrompt(QAPrompt): +class QAWithoutDoc(QAPrompt): remote_id: str add_tags: Sequence[str] From 003b5236ef126cb3732cfdf72908a54d24f06547 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 17:20:27 +0000 Subject: [PATCH 4/7] refactor: renames --- .../prompt_extractors/cloze_prompt_extractor.py | 6 +++--- .../prompt_source/prompt_extractors/qa_prompt_extractor.py | 4 ++-- personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py | 2 +- personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/cloze_prompt_extractor.py b/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/cloze_prompt_extractor.py index 767daeaf..3b9ffa3e 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/cloze_prompt_extractor.py +++ b/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/cloze_prompt_extractor.py @@ -3,7 +3,7 @@ import re from collections.abc import Sequence -from ...prompts.cloze_prompt import ClozePrompt, ClozePromptFromDoc +from ...prompts.cloze_prompt import ClozeFromDoc, ClozePrompt from ..document_ingesters.document import Document from .base_prompt_extractor import BasePromptExtractor @@ -68,7 +68,7 @@ def _replace_cloze_id_with_unique( def extract_prompts( self, document: Document ) -> Sequence[ClozePrompt]: - prompts: list[ClozePromptFromDoc] = [] + prompts: list[ClozeFromDoc] = [] blocks = self._break_string_by_two_or_more_newlines( document.content @@ -90,7 +90,7 @@ def extract_prompts( ) prompts.append( - ClozePromptFromDoc( + ClozeFromDoc( text=prompt_content, source_doc=document ) ) diff --git a/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/qa_prompt_extractor.py b/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/qa_prompt_extractor.py index e16f69c6..5bb4b621 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/qa_prompt_extractor.py +++ b/personal_mnemonic_medium/v2/domain/prompt_source/prompt_extractors/qa_prompt_extractor.py @@ -2,7 +2,7 @@ import re from collections.abc import Sequence -from ...prompts.qa_prompt import QAPrompt, QAPromptFromDoc +from ...prompts.qa_prompt import QAFromDoc, QAPrompt from ..document_ingesters.document import Document from .base_prompt_extractor import BasePromptExtractor @@ -79,7 +79,7 @@ def extract_prompts( continue prompts.append( - QAPromptFromDoc( + QAFromDoc( question=question, answer=answer, parent_doc=document, diff --git a/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py index b28184ca..f5d2d669 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py @@ -32,7 +32,7 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) -class ClozePromptFromDoc(ClozePrompt): +class ClozeFromDoc(ClozePrompt): text: str source_doc: Document diff --git a/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py index 743cd553..da030364 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py @@ -35,7 +35,7 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) -class QAPromptFromDoc(QAPrompt): +class QAFromDoc(QAPrompt): parent_doc: Document line_nr: int From 4ac31f6834e9a41ec6d01cecb5971fcde1433f89 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 17:22:44 +0000 Subject: [PATCH 5/7] misc. --- .../anki_connect/ankiconnect_destination.py | 34 ++++++++++++------- .../base_prompt_destination.py | 6 ++-- .../destination_commands.py | 4 +-- .../v2/domain/prompts/cloze_prompt.py | 1 - .../v2/domain/prompts/qa_prompt.py | 1 - 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py index ef3df0fa..29b960d3 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py @@ -13,7 +13,7 @@ AnkiConnectGateway, NoteInfo, ) -from ...prompts.base_prompt import BasePrompt +from ...prompts.base_prompt import RemotePrompt from ...prompts.cloze_prompt import ClozeWithoutDoc from ...prompts.qa_prompt import QAWithoutDoc from ..base_prompt_destination import PromptDestination @@ -32,22 +32,28 @@ def __init__( self.gateway = gateway self.prompt_converter = prompt_converter - def _note_info_to_prompt(self, note_info: NoteInfo) -> BasePrompt: + def _note_info_to_prompt( + self, note_info: NoteInfo + ) -> RemotePrompt: if ( "Question" in note_info.fields and "Answer" in note_info.fields ): - return QAWithoutDoc( - question=note_info.fields["Question"].value, - answer=note_info.fields["Answer"].value, - add_tags=note_info.tags, + return RemotePrompt( + QAWithoutDoc( + question=note_info.fields["Question"].value, + answer=note_info.fields["Answer"].value, + add_tags=note_info.tags, + ), remote_id=str(note_info.noteId), ) if "Text" in note_info.fields: - return ClozeWithoutDoc( - text=note_info.fields["Text"].value, - add_tags=note_info.tags, + return RemotePrompt( + ClozeWithoutDoc( + text=note_info.fields["Text"].value, + add_tags=note_info.tags, + ), remote_id=str(note_info.noteId), ) @@ -55,15 +61,19 @@ def _note_info_to_prompt(self, note_info: NoteInfo) -> BasePrompt: f"NoteInfo {note_info} has neither Question nor Text field" ) - def get_all_prompts(self) -> Sequence[BasePrompt]: + def get_all_prompts(self) -> Sequence[RemotePrompt]: return ( Seq(self.gateway.get_all_note_infos()) .map(self._note_info_to_prompt) .to_list() ) - def _delete_prompts(self, prompts: Sequence[BasePrompt]) -> None: - prompt_ids = {int(prompt.uid) for prompt in prompts} + def _delete_prompts( + self, prompts: Sequence[RemotePrompt] + ) -> None: + prompt_ids = { + int(remote_prompt.prompt.uid) for remote_prompt in prompts + } self.gateway.delete_notes(list(prompt_ids)) def _grouped_cards_to_deck( diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py index 04a74c34..fc11c590 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py @@ -1,12 +1,12 @@ from collections.abc import Sequence from typing import Protocol -from ..prompts.base_prompt import BasePrompt +from ..prompts.base_prompt import RemotePrompt from .destination_commands import PromptDestinationCommand class PromptDestination(Protocol): - def get_all_prompts(self) -> Sequence[BasePrompt]: + def get_all_prompts(self) -> Sequence[RemotePrompt]: ... def update( @@ -16,7 +16,7 @@ def update( class FakePromptDestination(PromptDestination): - def get_all_prompts(self) -> Sequence[BasePrompt]: + def get_all_prompts(self) -> Sequence[RemotePrompt]: ... def update( diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py b/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py index 45a3bddc..d41ac843 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py @@ -2,12 +2,12 @@ from dataclasses import dataclass from pathlib import Path -from ..prompts.base_prompt import BasePrompt +from ..prompts.base_prompt import BasePrompt, RemotePrompt @dataclass(frozen=True) class DeletePrompts: - prompts: Sequence[BasePrompt] + prompts: Sequence[RemotePrompt] @dataclass(frozen=True) diff --git a/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py index f5d2d669..d4cb5208 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/cloze_prompt.py @@ -23,7 +23,6 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) class ClozeWithoutDoc(ClozePrompt): - remote_id: str add_tags: Sequence[str] @property diff --git a/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py index da030364..d5a6a7e7 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/qa_prompt.py @@ -26,7 +26,6 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) class QAWithoutDoc(QAPrompt): - remote_id: str add_tags: Sequence[str] @property From 1c8e3b450bb57ff8089f311b8a03c0f2f6c4ac0a Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 17:23:44 +0000 Subject: [PATCH 6/7] misc: renames --- .../diff_determiner/base_diff_determiner.py | 4 ++-- .../anki_connect/ankiconnect_destination.py | 16 ++++++++-------- .../base_prompt_destination.py | 6 +++--- .../prompt_destination/destination_commands.py | 4 ++-- .../v2/domain/prompts/base_prompt.py | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py b/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py index 62ff37fe..538ffbda 100644 --- a/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py +++ b/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py @@ -10,7 +10,7 @@ DeletePrompts, PushPrompts, ) -from ..prompts.base_prompt import BasePrompt +from ..prompts.base_prompt import BasePrompt, DestinationPrompt K = TypeVar("K") T = TypeVar("T") @@ -60,7 +60,7 @@ def __init__(self, tmp_read_dir: Path, tmp_write_dir: Path): def sync( self, source_prompts: Sequence[BasePrompt], - destination_prompts: Sequence[BasePrompt], + destination_prompts: Sequence[DestinationPrompt], ) -> Sequence[PromptDestinationCommand]: syncer = GeneralSyncer( source={prompt.uid: prompt for prompt in source_prompts}, diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py index 29b960d3..374dda77 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/ankiconnect_destination.py @@ -13,7 +13,7 @@ AnkiConnectGateway, NoteInfo, ) -from ...prompts.base_prompt import RemotePrompt +from ...prompts.base_prompt import DestinationPrompt from ...prompts.cloze_prompt import ClozeWithoutDoc from ...prompts.qa_prompt import QAWithoutDoc from ..base_prompt_destination import PromptDestination @@ -34,34 +34,34 @@ def __init__( def _note_info_to_prompt( self, note_info: NoteInfo - ) -> RemotePrompt: + ) -> DestinationPrompt: if ( "Question" in note_info.fields and "Answer" in note_info.fields ): - return RemotePrompt( + return DestinationPrompt( QAWithoutDoc( question=note_info.fields["Question"].value, answer=note_info.fields["Answer"].value, add_tags=note_info.tags, ), - remote_id=str(note_info.noteId), + destination_id=str(note_info.noteId), ) if "Text" in note_info.fields: - return RemotePrompt( + return DestinationPrompt( ClozeWithoutDoc( text=note_info.fields["Text"].value, add_tags=note_info.tags, ), - remote_id=str(note_info.noteId), + destination_id=str(note_info.noteId), ) raise ValueError( f"NoteInfo {note_info} has neither Question nor Text field" ) - def get_all_prompts(self) -> Sequence[RemotePrompt]: + def get_all_prompts(self) -> Sequence[DestinationPrompt]: return ( Seq(self.gateway.get_all_note_infos()) .map(self._note_info_to_prompt) @@ -69,7 +69,7 @@ def get_all_prompts(self) -> Sequence[RemotePrompt]: ) def _delete_prompts( - self, prompts: Sequence[RemotePrompt] + self, prompts: Sequence[DestinationPrompt] ) -> None: prompt_ids = { int(remote_prompt.prompt.uid) for remote_prompt in prompts diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py index fc11c590..7b0c0dbe 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/base_prompt_destination.py @@ -1,12 +1,12 @@ from collections.abc import Sequence from typing import Protocol -from ..prompts.base_prompt import RemotePrompt +from ..prompts.base_prompt import DestinationPrompt from .destination_commands import PromptDestinationCommand class PromptDestination(Protocol): - def get_all_prompts(self) -> Sequence[RemotePrompt]: + def get_all_prompts(self) -> Sequence[DestinationPrompt]: ... def update( @@ -16,7 +16,7 @@ def update( class FakePromptDestination(PromptDestination): - def get_all_prompts(self) -> Sequence[RemotePrompt]: + def get_all_prompts(self) -> Sequence[DestinationPrompt]: ... def update( diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py b/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py index d41ac843..7fe38764 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/destination_commands.py @@ -2,12 +2,12 @@ from dataclasses import dataclass from pathlib import Path -from ..prompts.base_prompt import BasePrompt, RemotePrompt +from ..prompts.base_prompt import BasePrompt, DestinationPrompt @dataclass(frozen=True) class DeletePrompts: - prompts: Sequence[RemotePrompt] + prompts: Sequence[DestinationPrompt] @dataclass(frozen=True) diff --git a/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py b/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py index 16bed19f..ea3e85c8 100644 --- a/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py +++ b/personal_mnemonic_medium/v2/domain/prompts/base_prompt.py @@ -16,6 +16,6 @@ def tags(self) -> Sequence[str]: @dataclass(frozen=True) -class RemotePrompt: +class DestinationPrompt: prompt: BasePrompt - remote_id: str + destination_id: str From 01ad40522cdecca133cd31b7c63851503c11f5a9 Mon Sep 17 00:00:00 2001 From: Martin Bernstorff Date: Wed, 13 Dec 2023 17:27:03 +0000 Subject: [PATCH 7/7] misc. --- .../diff_determiner/base_diff_determiner.py | 14 +++----------- .../diff_determiner/test_diff_determiner.py | 18 +++++++++++++++--- personal_mnemonic_medium/v2/domain/main.py | 17 ----------------- .../test_anki_prompt_converter.py | 5 +---- .../test_ankiconnect_destination.py | 5 +---- 5 files changed, 20 insertions(+), 39 deletions(-) delete mode 100644 personal_mnemonic_medium/v2/domain/main.py diff --git a/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py b/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py index 538ffbda..4fcfd7b2 100644 --- a/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py +++ b/personal_mnemonic_medium/v2/domain/diff_determiner/base_diff_determiner.py @@ -21,7 +21,7 @@ class BaseDiffDeterminer(Protocol): def sync( self, source_prompts: Sequence[BasePrompt], - destination_prompts: Sequence[BasePrompt], + destination_prompts: Sequence[DestinationPrompt], ) -> Sequence[PromptDestinationCommand]: ... @@ -65,7 +65,8 @@ def sync( syncer = GeneralSyncer( source={prompt.uid: prompt for prompt in source_prompts}, destination={ - prompt.uid: prompt for prompt in destination_prompts + dest_prompt.prompt.uid: dest_prompt + for dest_prompt in destination_prompts }, ) @@ -77,12 +78,3 @@ def sync( tmp_read_dir=self.tmp_read_dir, ), ] - - -class FakeDiffDeterminer(BaseDiffDeterminer): - def sync( - self, - source_prompts: Sequence[BasePrompt], - destination_prompts: Sequence[BasePrompt], - ) -> Sequence[PromptDestinationCommand]: - ... diff --git a/personal_mnemonic_medium/v2/domain/diff_determiner/test_diff_determiner.py b/personal_mnemonic_medium/v2/domain/diff_determiner/test_diff_determiner.py index 0dea7042..8a922fbe 100644 --- a/personal_mnemonic_medium/v2/domain/diff_determiner/test_diff_determiner.py +++ b/personal_mnemonic_medium/v2/domain/diff_determiner/test_diff_determiner.py @@ -4,6 +4,7 @@ DeletePrompts, PushPrompts, ) +from ..prompts.base_prompt import DestinationPrompt from ..prompts.qa_prompt import QAPrompt from .base_diff_determiner import GeneralSyncer, PromptDiffDeterminer @@ -27,8 +28,12 @@ def test_prompt_diff_determiner(tmp_path: Path): QAPrompt(question="b", answer="b"), ] destination_prompts = [ - QAPrompt(question="b", answer="b"), - QAPrompt(question="c", answer="c"), + DestinationPrompt( + QAPrompt(question="b", answer="b"), destination_id="2" + ), + DestinationPrompt( + QAPrompt(question="c", answer="c"), destination_id="3" + ), ] diff = syncer.sync( @@ -36,7 +41,14 @@ def test_prompt_diff_determiner(tmp_path: Path): destination_prompts=destination_prompts, ) assert diff == [ - DeletePrompts([QAPrompt(question="c", answer="c")]), + DeletePrompts( + [ + DestinationPrompt( + QAPrompt(question="c", answer="c"), + destination_id="3", + ) + ] + ), PushPrompts( [QAPrompt(question="a", answer="a")], tmp_write_dir=tmp_path, diff --git a/personal_mnemonic_medium/v2/domain/main.py b/personal_mnemonic_medium/v2/domain/main.py deleted file mode 100644 index 9673e76f..00000000 --- a/personal_mnemonic_medium/v2/domain/main.py +++ /dev/null @@ -1,17 +0,0 @@ -from .diff_determiner.base_diff_determiner import FakeDiffDeterminer -from .prompt_destination.base_prompt_destination import ( - FakePromptDestination, -) -from .prompt_source.base_prompt_source import FakePromptSource - -if __name__ == "__main__": - source_prompts = FakePromptSource().get_prompts() - - destination = FakePromptDestination() - destination_prompts = destination.get_all_prompts() - - sync_commands = FakeDiffDeterminer().sync( - source_prompts=source_prompts, - destination_prompts=destination_prompts, - ) - destination.update(sync_commands) diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py index fdb0fd6d..65e11f76 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/prompt_converter/test_anki_prompt_converter.py @@ -29,14 +29,11 @@ question="FakeQuestion", answer="FakeAnswer", add_tags=["FakeTag"], - remote_id="1", ), fake_anki_qa, ), ( - ClozeWithoutDoc( - text="FakeText", add_tags=["FakeTag"], remote_id="1" - ), + ClozeWithoutDoc(text="FakeText", add_tags=["FakeTag"]), fake_anki_cloze, ), ], diff --git a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py index b0a4694e..41b718de 100644 --- a/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py +++ b/personal_mnemonic_medium/v2/domain/prompt_destination/anki_connect/test_ankiconnect_destination.py @@ -65,12 +65,9 @@ def test_ankiconnect_push_prompts(tmpdir: Path): question="FakeQuestion", answer="FakeAnswer", add_tags=["FakeTag"], - remote_id="1", ), ClozeWithoutDoc( - text="FakeText", - add_tags=["FakeTag"], - remote_id="1", + text="FakeText", add_tags=["FakeTag"] ), ], tmp_write_dir=tmpdir,