Skip to content

Commit

Permalink
refactor: decrease file nesting (#414)
Browse files Browse the repository at this point in the history
refactor: decrease file nesting

Fixes #350

phase 1

fix: imports

style: linting

misc.
  • Loading branch information
MartinBernstorff authored Dec 23, 2023
2 parents 908ed5e + c7fc6f9 commit 0acd631
Show file tree
Hide file tree
Showing 55 changed files with 230 additions and 479 deletions.
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"ms-vscode.makefile-tools",
"github.vscode-github-actions",
"markis.code-coverage",
"Gerrnperl.outline-map"
"Gerrnperl.outline-map",
"SeeLog.python-init-generator"
]
}
},
Expand Down
4 changes: 1 addition & 3 deletions git.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
get_issues_assigned_to_me,
issue_dialog,
)
from .personal_mnemonic_medium.subtasks.graphite import (
create_branch_from_issue,
)
from .personal_mnemonic_medium.subtasks.graphite import create_branch_from_issue


@inv.task(aliases=("new",)) # type: ignore
Expand Down
19 changes: 5 additions & 14 deletions personal_mnemonic_medium/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,11 @@ def sync(
],
watch: Annotated[
bool,
typer.Option(
help="Keep running, updating Anki deck every 15 seconds"
),
typer.Option(help="Keep running, updating Anki deck every 15 seconds"),
],
deck_name: Annotated[
str,
typer.Option(
help="Anki path to deck, e.g. 'Parent deck::Child deck'"
),
typer.Option(help="Anki path to deck, e.g. 'Parent deck::Child deck'"),
] = "Personal Mnemonic Medium",
max_deletions_per_run: Annotated[
int,
Expand All @@ -66,8 +62,7 @@ def sync(
),
] = False,
skip_sync: Annotated[
bool,
typer.Option(help="Skip all syncing, useful for smoketest"),
bool, typer.Option(help="Skip all syncing, useful for smoketest")
] = False,
):
logging.basicConfig(
Expand All @@ -77,9 +72,7 @@ def sync(
)

# Use apkg_output_filepath if host_ankiconnect_dir is not set
host_apkg_dir = (
host_apkg_dir if host_apkg_dir else apkg_output_dir
)
host_apkg_dir = host_apkg_dir if host_apkg_dir else apkg_output_dir

sentry_sdk.init(
dsn="https://37f17d6aa7742424652663a04154e032@o4506053997166592.ingest.sentry.io/4506053999984640",
Expand All @@ -98,9 +91,7 @@ def sync(

if watch:
sleep_seconds = 60
log.info(
f"Sync complete, sleeping for {sleep_seconds} seconds"
)
log.info(f"Sync complete, sleeping for {sleep_seconds} seconds")
sync_deck(
base_deck=deck_name,
input_dir=input_dir,
Expand Down
1 change: 1 addition & 0 deletions personal_mnemonic_medium/data_access/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

44 changes: 16 additions & 28 deletions personal_mnemonic_medium/data_access/ankiconnect_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,9 @@ def __init__(
self.max_deletions_per_run = max_deletions_per_run

seconds_waited = 0
while (
not anki_connect_is_live()
and seconds_waited < max_wait_seconds
):
while not anki_connect_is_live() and seconds_waited < max_wait_seconds:
wait_seconds = 2
print(
f"AnkiConnect is not live, waiting {wait_seconds} seconds..."
)
print(f"AnkiConnect is not live, waiting {wait_seconds} seconds...")
seconds_waited += wait_seconds
sleep(wait_seconds)

Expand All @@ -85,15 +80,15 @@ def update_model(self, model: genanki.Model) -> None:
)

def import_package(self, package: genanki.Package) -> None:
apkg_name = f"{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.apkg"
apkg_name = (
f"{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.apkg"
)
write_path = self.tmp_write_dir / apkg_name
package.write_to_file(write_path) # type: ignore

read_path = self.tmp_read_dir / apkg_name
try:
self._invoke(
AnkiConnectCommand.IMPORT_PACKAGE, path=str(read_path)
)
self._invoke(AnkiConnectCommand.IMPORT_PACKAGE, path=str(read_path))
print(f"Imported from {read_path}!")
write_path.unlink()
except Exception:
Expand All @@ -114,8 +109,7 @@ def delete_notes(self, note_ids: Sequence[int]) -> None:

def get_all_note_infos(self) -> Sequence[NoteInfo]:
anki_card_ids: list[int] = self._invoke(
AnkiConnectCommand.FIND_CARDS,
query=f'"deck:{self.deck_name}"',
AnkiConnectCommand.FIND_CARDS, query=f'"deck:{self.deck_name}"'
)

# get a list of anki notes in the deck
Expand All @@ -133,9 +127,7 @@ def get_all_note_infos(self) -> Sequence[NoteInfo]:
def _request(self, action: Any, **params: Any) -> dict[str, Any]:
return {"action": action, "params": params, "version": 6}

def _invoke(
self, action: AnkiConnectCommand, **params: Any
) -> Any:
def _invoke(self, action: AnkiConnectCommand, **params: Any) -> Any:
"""Helper for invoking actions with anki-connect
Args:
action (string): the action to invoke
Expand All @@ -144,20 +136,16 @@ def _invoke(
Returns:
Any: the response from anki connect
"""
requestJson = json.dumps(
self._request(action.value, **params)
).encode("utf-8")
requestJson = json.dumps(self._request(action.value, **params)).encode(
"utf-8"
)
response = json.load(
urllib.request.urlopen(
urllib.request.Request(
self.ankiconnect_url, requestJson
)
urllib.request.Request(self.ankiconnect_url, requestJson)
)
)
if len(response) != 2:
raise Exception(
"response has an unexpected number of fields"
)
raise Exception("response has an unexpected number of fields")
if response["error"] is not None:
raise Exception(response["error"])
return response["result"]
Expand All @@ -184,12 +172,12 @@ def __init__(self, note_infos: Sequence[NoteInfo] = ()) -> None:
self.note_infos: list[NoteInfo] = list(note_infos)
self.executed_commands: list[FakeAnkiCommand] = []

def get_all_note_infos(self) -> Sequence[NoteInfo]:
return self.note_infos

def update_model(self, model: genanki.Model) -> None:
self.executed_commands.append(UpdateModel(model=model))

def get_all_note_infos(self) -> Sequence[NoteInfo]:
return self.note_infos

def import_package(self, package: genanki.Package) -> None:
self.executed_commands.append(ImportPackage(package=package))

Expand Down
8 changes: 2 additions & 6 deletions personal_mnemonic_medium/data_access/test_ankiconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ def test_import_package(self):
assert note.tags == ["TestTag"]

# Phase 3: Deleting
self.gateway.delete_notes(
note_ids=[n.noteId for n in all_notes]
)
self.gateway.delete_notes(note_ids=[n.noteId for n in all_notes])
assert len(self.gateway.get_all_note_infos()) == 0


Expand All @@ -94,7 +92,5 @@ def test_error_if_deleting_more_than_allowed():
max_deletions_per_run=0,
max_wait_seconds=0,
)
with pytest.raises(
ValueError, match="are scheduled for deletion"
):
with pytest.raises(ValueError, match="are scheduled for deletion"):
gateway.delete_notes(note_ids=[1])
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,25 @@

from functionalpy._sequence import Seq

from personal_mnemonic_medium.domain.prompt_destination.anki_connect.prompt_converter.prompts.anki_cloze import (
AnkiCloze,
)
from personal_mnemonic_medium.domain.prompt_destination.anki_connect.prompt_converter.prompts.anki_qa import (
AnkiQA,
)
from personal_mnemonic_medium.domain.prompt_destination.anki_connect.prompt_converter.prompts.base_anki_prompt import (
AnkiCard,
)

from ....prompts.base_prompt import BasePrompt
from ....prompts.cloze_prompt import ClozePrompt
from ....prompts.qa_prompt import QAPrompt
from ...source.prompts.prompt import BasePrompt
from ...source.prompts.prompt_cloze import ClozePrompt
from ...source.prompts.prompt_qa import QAPrompt
from .anki_card import AnkiCard
from .anki_prompt_cloze import AnkiCloze
from .anki_prompt_qa import AnkiQA


class AnkiPromptConverter:
def __init__(
self,
base_deck: str,
card_css: str,
deck_prefix: str = "#anki_deck",
self, base_deck: str, card_css: str, deck_prefix: str = "#anki_deck"
) -> None:
self.base_deck = base_deck
self.deck_prefix = deck_prefix
self.card_css = card_css

def _prompt_to_card(self, prompt: BasePrompt) -> AnkiCard:
deck_in_tags = [
tag
for tag in prompt.tags
if tag.startswith(self.deck_prefix)
tag for tag in prompt.tags if tag.startswith(self.deck_prefix)
]
deck = deck_in_tags[0] if deck_in_tags else self.base_deck

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import genanki

from .....utils.hash_cleaned_str import clean_str, int_hash_str
from .base_anki_prompt import AnkiCard
from ...utils.hash_cleaned_str import clean_str, int_hash_str
from .anki_card import AnkiCard


@dataclass(frozen=True)
Expand Down Expand Up @@ -46,11 +46,6 @@ def to_genanki_note(self) -> genanki.Note:
return genanki.Note(
guid=str(self.uuid),
model=self.genanki_model,
fields=[
self.text,
"",
" ".join(self.tags),
str(self.uuid),
],
fields=[self.text, "", " ".join(self.tags), str(self.uuid)],
tags=self.tags,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import genanki

from .....utils.hash_cleaned_str import clean_str, int_hash_str
from .base_anki_prompt import AnkiCard
from ...utils.hash_cleaned_str import clean_str, int_hash_str
from .anki_card import AnkiCard


@dataclass(frozen=True)
Expand All @@ -17,9 +17,7 @@ class AnkiQA(AnkiCard):

@property
def uuid(self) -> int:
return int_hash_str(
clean_str(f"{self.question}{self.answer}")
)
return int_hash_str(clean_str(f"{self.question}{self.answer}"))

@property
def genanki_model(self) -> genanki.Model:
Expand All @@ -31,7 +29,9 @@ def genanki_model(self) -> genanki.Model:
]

QUESTION_STR = r"{{ Question }}"
TTS_QUESTION_STR = r"{{ tts en_US voices=Apple_Samantha speed=1.05:Question }}"
TTS_QUESTION_STR = (
r"{{ tts en_US voices=Apple_Samantha speed=1.05:Question }}"
)

ANSWER_STR = r"{{ Answer }}"
TTS_ANSWER_STR = (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import pytest

from ....prompts.base_prompt import BasePrompt
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
from .prompts.base_anki_prompt import AnkiCard
from ...source.prompts.prompt import BasePrompt
from ...source.prompts.prompt_cloze import ClozeWithoutDoc
from ...source.prompts.prompt_qa import QAWithoutDoc
from .anki_card import AnkiCard
from .anki_converter import AnkiPromptConverter
from .anki_prompt_cloze import AnkiCloze
from .anki_prompt_qa import AnkiQA

fake_anki_qa = AnkiQA(
question="FakeQuestion",
Expand All @@ -17,10 +17,7 @@
)

fake_anki_cloze = AnkiCloze(
text="FakeText",
base_deck="FakeDeck",
tags=["FakeTag"],
css="FakeCSS",
text="FakeText", base_deck="FakeDeck", tags=["FakeTag"], css="FakeCSS"
)


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections.abc import Sequence
from dataclasses import dataclass, field

from .anki_qa import AnkiQA
from .anki_prompt_qa import AnkiQA


def fake_tag_factory() -> Sequence[str]:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
from collections.abc import Sequence
from typing import Protocol

from ..prompts.base_prompt import DestinationPrompt
from ..source.prompts.prompt import DestinationPrompt
from .destination_commands import PromptDestinationCommand


class PromptDestination(Protocol):
def get_all_prompts(self) -> Sequence[DestinationPrompt]:
...

def update(
self, commands: Sequence[PromptDestinationCommand]
) -> None:
def update(self, commands: Sequence[PromptDestinationCommand]) -> None:
...


class FakePromptDestination(PromptDestination):
def get_all_prompts(self) -> Sequence[DestinationPrompt]:
...

def update(
self, commands: Sequence[PromptDestinationCommand]
) -> None:
def update(self, commands: Sequence[PromptDestinationCommand]) -> None:
...
Loading

0 comments on commit 0acd631

Please sign in to comment.