diff --git a/application/main.py b/application/main.py
index 54b858d..d457f88 100644
--- a/application/main.py
+++ b/application/main.py
@@ -10,7 +10,9 @@
AnkiPackageGenerator,
)
from personal_mnemonic_medium.exporters.anki.sync import sync_deck
-from personal_mnemonic_medium.note_factories.markdown import MarkdownNoteFactory
+from personal_mnemonic_medium.note_factories.markdown import (
+ MarkdownNoteFactory,
+)
from personal_mnemonic_medium.prompt_extractors.cloze_extractor import (
ClozePromptExtractor,
)
@@ -32,12 +34,16 @@ def main(
host_output_dir: Path,
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"
+ ),
],
):
"""Run the thing."""
if not input_dir.exists():
- raise FileNotFoundError(f"Input directory {input_dir} does not exist")
+ raise FileNotFoundError(
+ f"Input directory {input_dir} does not exist"
+ )
if not host_output_dir.exists():
msg.info(f"Creating output directory {host_output_dir}")
@@ -65,11 +71,15 @@ def main(
input_path=input_dir,
)
- grouped_cards = Seq(cards).group_by(lambda card: card.deckname).to_iter()
+ grouped_cards = (
+ Seq(cards).group_by(lambda card: card.deckname).to_iter()
+ )
for group in grouped_cards:
cards = group.group_contents.to_list()
- deck_bundle = AnkiPackageGenerator().cards_to_deck_bundle(cards=cards)
+ deck_bundle = AnkiPackageGenerator().cards_to_deck_bundle(
+ cards=cards
+ )
sync_deck(
deck_bundle=deck_bundle,
sync_dir_path=host_output_dir,
@@ -79,9 +89,15 @@ def main(
if watch:
sleep_seconds = 60
- msg.good(f"Sync complete, sleeping for {sleep_seconds} seconds")
+ msg.good(
+ f"Sync complete, sleeping for {sleep_seconds} seconds"
+ )
sleep(sleep_seconds)
- main(input_dir=input_dir, watch=watch, host_output_dir=host_output_dir)
+ main(
+ input_dir=input_dir,
+ watch=watch,
+ host_output_dir=host_output_dir,
+ )
if __name__ == "__main__":
diff --git a/pyproject.toml b/pyproject.toml
index f426daa..f3bcea6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -54,7 +54,7 @@ reportMissingTypeStubs = false
[tool.ruff]
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
-line-length = 80
+line-length = 70
select = [
"A",
"ANN",
diff --git a/src/personal_mnemonic_medium/card_pipeline.py b/src/personal_mnemonic_medium/card_pipeline.py
index f42e511..cfb14eb 100644
--- a/src/personal_mnemonic_medium/card_pipeline.py
+++ b/src/personal_mnemonic_medium/card_pipeline.py
@@ -1,11 +1,17 @@
from collections.abc import Sequence
from pathlib import Path
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
from personal_mnemonic_medium.exporters.base import CardExporter
-from personal_mnemonic_medium.note_factories.base import DocumentFactory
+from personal_mnemonic_medium.note_factories.base import (
+ DocumentFactory,
+)
from personal_mnemonic_medium.note_factories.note import Document
-from personal_mnemonic_medium.prompt_extractors.base import PromptExtractor
+from personal_mnemonic_medium.prompt_extractors.base import (
+ PromptExtractor,
+)
from personal_mnemonic_medium.prompt_extractors.prompt import Prompt
@@ -27,7 +33,9 @@ def run(
notes: list[Document] = []
if input_path.is_dir():
notes += list(
- self.document_factory.get_notes_from_dir(dir_path=input_path)
+ self.document_factory.get_notes_from_dir(
+ dir_path=input_path
+ )
)
if not input_path.is_dir():
diff --git a/src/personal_mnemonic_medium/exporters/anki/card_types/base.py b/src/personal_mnemonic_medium/exporters/anki/card_types/base.py
index 25041df..a0ab01a 100644
--- a/src/personal_mnemonic_medium/exporters/anki/card_types/base.py
+++ b/src/personal_mnemonic_medium/exporters/anki/card_types/base.py
@@ -24,7 +24,9 @@ def __init__(
self,
fields: list[str],
source_prompt: Prompt,
- url_generator: Callable[[Path, int | None], str] = get_obsidian_url,
+ url_generator: Callable[
+ [Path, int | None], str
+ ] = get_obsidian_url,
html_compiler: Callable[[str], str] = compile_field,
):
self.markdown_fields = fields
@@ -112,7 +114,9 @@ def to_genanki_note(self) -> genanki.Note:
)
if len(self.html_fields) < len(self.genanki_model.fields): # type: ignore
- while len(self.html_fields) < len(self.genanki_model.fields): # type: ignore
+ while len(self.html_fields) < len(
+ self.genanki_model.fields
+ ): # type: ignore
before_extras_field = len(self.html_fields) == 2
if before_extras_field:
self.add_field(self.get_source_button())
@@ -146,7 +150,9 @@ def get_deck_dir(self) -> Path:
# This is all it takes
return Path(self.source_doc.source_path).parent
- def determine_media_references(self) -> Iterator[tuple[Path, Path]]:
+ def determine_media_references(
+ self
+ ) -> Iterator[tuple[Path, Path]]:
"""Find all media references in a card"""
for i, field in enumerate(self.html_fields):
current_stage = field
@@ -157,13 +163,19 @@ def determine_media_references(self) -> Iterator[tuple[Path, Path]]:
def process_match(m) -> str: # noqa # type: ignore
initial_contents = m.group(1) # type: ignore
- abspath, newpath = self.make_ref_pair(initial_contents) # type: ignore
+ abspath, newpath = self.make_ref_pair(
+ initial_contents
+ ) # type: ignore
results.append((abspath, newpath)) # noqa # type: ignore
return r'src="' + newpath + '"'
- current_stage = re.sub(regex, process_match, current_stage) # type: ignore
+ current_stage = re.sub(
+ regex, process_match, current_stage
+ ) # type: ignore
yield from results
# Anki seems to hate alt tags :(
- self.html_fields[i] = re.sub(r'alt="[^"]*?"', "", current_stage)
+ self.html_fields[i] = re.sub(
+ r'alt="[^"]*?"', "", current_stage
+ )
diff --git a/src/personal_mnemonic_medium/exporters/anki/card_types/cloze.py b/src/personal_mnemonic_medium/exporters/anki/card_types/cloze.py
index 6500187..a8736b3 100644
--- a/src/personal_mnemonic_medium/exporters/anki/card_types/cloze.py
+++ b/src/personal_mnemonic_medium/exporters/anki/card_types/cloze.py
@@ -3,7 +3,9 @@
from pathlib import Path
import genanki
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
from personal_mnemonic_medium.exporters.markdown_to_html.html_compiler import (
compile_field,
)
@@ -19,7 +21,9 @@ def __init__(
self,
fields: list[str],
source_prompt: Prompt,
- url_generator: Callable[[Path, int | None], str] = get_obsidian_url,
+ url_generator: Callable[
+ [Path, int | None], str
+ ] = get_obsidian_url,
html_compiler: Callable[[str], str] = compile_field,
):
super().__init__(
diff --git a/src/personal_mnemonic_medium/exporters/anki/card_types/qa.py b/src/personal_mnemonic_medium/exporters/anki/card_types/qa.py
index 45f4b02..1ef7ab1 100644
--- a/src/personal_mnemonic_medium/exporters/anki/card_types/qa.py
+++ b/src/personal_mnemonic_medium/exporters/anki/card_types/qa.py
@@ -2,7 +2,9 @@
from pathlib import Path
import genanki
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
from personal_mnemonic_medium.exporters.markdown_to_html.html_compiler import (
compile_field,
)
@@ -18,7 +20,9 @@ def __init__(
self,
fields: list[str],
source_prompt: Prompt,
- url_generator: Callable[[Path, int | None], str] = get_obsidian_url,
+ url_generator: Callable[
+ [Path, int | None], str
+ ] = get_obsidian_url,
html_compiler: Callable[[str], str] = compile_field,
):
super().__init__(
diff --git a/src/personal_mnemonic_medium/exporters/anki/globals.py b/src/personal_mnemonic_medium/exporters/anki/globals.py
index 037b3bd..c633ea8 100644
--- a/src/personal_mnemonic_medium/exporters/anki/globals.py
+++ b/src/personal_mnemonic_medium/exporters/anki/globals.py
@@ -2,7 +2,9 @@
import textwrap
from typing import Any
-from personal_mnemonic_medium.exporters.anki.anki_css import CARD_MODEL_CSS
+from personal_mnemonic_medium.exporters.anki.anki_css import (
+ CARD_MODEL_CSS,
+)
ANKICONNECT_URL = (
"http://host.docker.internal:8765"
@@ -19,8 +21,12 @@
QUESTION_STR = r"{{ Question }}"
ANSWER_STR = r"{{ Answer }}"
EXTRA_STR = r"{{ Extra }}"
-TTS_QUESTION_STR = r"{{ tts en_US voices=Apple_Samantha speed=1.05:Question }}"
-TTS_ANSWER_STR = r"{{ tts en_US voices=Apple_Samantha speed=1.05:Answer }}"
+TTS_QUESTION_STR = (
+ r"{{ tts en_US voices=Apple_Samantha speed=1.05:Question }}"
+)
+TTS_ANSWER_STR = (
+ r"{{ tts en_US voices=Apple_Samantha speed=1.05:Answer }}"
+)
QA_MODEL_TEMPLATE = [
{
diff --git a/src/personal_mnemonic_medium/exporters/anki/package_generator.py b/src/personal_mnemonic_medium/exporters/anki/package_generator.py
index ea11050..ac29f79 100644
--- a/src/personal_mnemonic_medium/exporters/anki/package_generator.py
+++ b/src/personal_mnemonic_medium/exporters/anki/package_generator.py
@@ -11,15 +11,23 @@
import genanki
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
-from personal_mnemonic_medium.exporters.anki.card_types.cloze import AnkiCloze
-from personal_mnemonic_medium.exporters.anki.card_types.qa import AnkiQA
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
+from personal_mnemonic_medium.exporters.anki.card_types.cloze import (
+ AnkiCloze,
+)
+from personal_mnemonic_medium.exporters.anki.card_types.qa import (
+ AnkiQA,
+)
from personal_mnemonic_medium.exporters.base import CardExporter
from personal_mnemonic_medium.prompt_extractors.cloze_extractor import (
ClozePrompt,
)
from personal_mnemonic_medium.prompt_extractors.prompt import Prompt
-from personal_mnemonic_medium.prompt_extractors.qa_extractor import QAPrompt
+from personal_mnemonic_medium.prompt_extractors.qa_extractor import (
+ QAPrompt,
+)
from personal_mnemonic_medium.utils.hasher import simple_hash
log = logging.getLogger(__name__)
@@ -84,7 +92,9 @@ def cards_to_deck(
) # This is inefficient but definitely works on all platforms.
media.add(newpath)
except FileNotFoundError as e:
- log.debug(f"Could not find file {abspath} for media, {e}.")
+ log.debug(
+ f"Could not find file {abspath} for media, {e}."
+ )
try:
deck.add_note(card.to_genanki_note())
diff --git a/src/personal_mnemonic_medium/exporters/anki/sync.py b/src/personal_mnemonic_medium/exporters/anki/sync.py
index e457746..a2bf6e3 100644
--- a/src/personal_mnemonic_medium/exporters/anki/sync.py
+++ b/src/personal_mnemonic_medium/exporters/anki/sync.py
@@ -8,8 +8,12 @@
from genanki import Model, Note
from wasabi import Printer
-from personal_mnemonic_medium.exporters.anki.globals import ANKICONNECT_URL
-from personal_mnemonic_medium.exporters.anki.package_generator import DeckBundle
+from personal_mnemonic_medium.exporters.anki.globals import (
+ ANKICONNECT_URL,
+)
+from personal_mnemonic_medium.exporters.anki.package_generator import (
+ DeckBundle,
+)
msg = Printer(timestamp=True)
@@ -29,7 +33,9 @@ def invoke(action: Any, **params: Any) -> Any:
Returns:
Any: the response from anki connect
"""
- requestJson = json.dumps(request(action, **params)).encode("utf-8")
+ requestJson = json.dumps(request(action, **params)).encode(
+ "utf-8"
+ )
response = json.load(
urllib.request.urlopen(
urllib.request.Request(ANKICONNECT_URL, requestJson)
@@ -84,7 +90,9 @@ def sync_deck(
return
# get a list of anki cards in the deck
- anki_note_info_by_guid, anki_note_guids = get_anki_note_infos(deck_bundle)
+ anki_note_info_by_guid, anki_note_guids = get_anki_note_infos(
+ deck_bundle
+ )
# get the unique guids of the md notes
md_note_guids = get_md_note_infos(deck_bundle)
@@ -125,7 +133,9 @@ def sync_deck(
"deleteNotes",
notes=note_ids,
)
- msg.good(f"Deleted {len(guids_to_delete)} notes")
+ msg.good(
+ f"Deleted {len(guids_to_delete)} notes"
+ )
except Exception:
msg.fail(
@@ -159,7 +169,9 @@ def get_anki_note_infos(
)
# get a list of anki notes in the deck
- anki_note_ids: list[int] = invoke("cardsToNotes", cards=anki_card_ids)
+ anki_note_ids: list[int] = invoke(
+ "cardsToNotes", cards=anki_card_ids
+ )
# get the note info for the notes in the deck
anki_notes_info = invoke("notesInfo", notes=anki_note_ids)
@@ -186,7 +198,9 @@ def sync_model(model: Model):
if model.name not in model_names_to_ids:
return
except Exception as e:
- msg.good("\tUnable to fetch existing model names and ids from anki")
+ msg.good(
+ "\tUnable to fetch existing model names and ids from anki"
+ )
msg.good(f"\t\t{e}")
if anki_connect_is_live():
@@ -206,7 +220,9 @@ def sync_model(model: Model):
)
msg.good(f"\tUpdated model {model.name} template")
except Exception as e:
- msg.good(f"\tUnable to update model {model.name} template")
+ msg.good(
+ f"\tUnable to update model {model.name} template"
+ )
msg.good(f"\t\t{e}")
try:
diff --git a/src/personal_mnemonic_medium/exporters/base.py b/src/personal_mnemonic_medium/exporters/base.py
index f489121..3e13b75 100644
--- a/src/personal_mnemonic_medium/exporters/base.py
+++ b/src/personal_mnemonic_medium/exporters/base.py
@@ -1,11 +1,15 @@
from abc import ABC, abstractmethod
from collections.abc import Sequence
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
from personal_mnemonic_medium.prompt_extractors.prompt import Prompt
class CardExporter(ABC):
@abstractmethod
- def prompts_to_cards(self, prompts: Sequence[Prompt]) -> list[AnkiCard]:
+ def prompts_to_cards(
+ self, prompts: Sequence[Prompt]
+ ) -> list[AnkiCard]:
pass
diff --git a/src/personal_mnemonic_medium/exporters/markdown_to_html/html_compiler.py b/src/personal_mnemonic_medium/exporters/markdown_to_html/html_compiler.py
index b88f326..294b33b 100644
--- a/src/personal_mnemonic_medium/exporters/markdown_to_html/html_compiler.py
+++ b/src/personal_mnemonic_medium/exporters/markdown_to_html/html_compiler.py
@@ -50,7 +50,11 @@ def field_to_html(field: Any) -> str:
def compile_field(fieldtext: str) -> str:
"""Turn source markdown into an HTML field suitable for Anki."""
- fieldtext_sans_wiki = fieldtext.replace("[[", "").replace("]]", "")
- fieldtext_sans_comments = re.sub(r"", "", fieldtext_sans_wiki)
+ fieldtext_sans_wiki = fieldtext.replace("[[", "").replace(
+ "]]", ""
+ )
+ fieldtext_sans_comments = re.sub(
+ r"", "", fieldtext_sans_wiki
+ )
return field_to_html(fieldtext_sans_comments)
diff --git a/src/personal_mnemonic_medium/exporters/url_generators/obsidian_url.py b/src/personal_mnemonic_medium/exporters/url_generators/obsidian_url.py
index a53ea40..75d4d03 100644
--- a/src/personal_mnemonic_medium/exporters/url_generators/obsidian_url.py
+++ b/src/personal_mnemonic_medium/exporters/url_generators/obsidian_url.py
@@ -2,7 +2,9 @@
from pathlib import Path
-def get_obsidian_url(source_path: Path, line_nr: int | None = None) -> str:
+def get_obsidian_url(
+ source_path: Path, line_nr: int | None = None
+) -> str:
"""Get the obsidian URI for the source document."""
vault: str = urllib.parse.quote(source_path.parent.name) # type: ignore
file: str = urllib.parse.quote(source_path.name) # type: ignore
diff --git a/src/personal_mnemonic_medium/note_factories/base.py b/src/personal_mnemonic_medium/note_factories/base.py
index cd64ce8..75f91c7 100644
--- a/src/personal_mnemonic_medium/note_factories/base.py
+++ b/src/personal_mnemonic_medium/note_factories/base.py
@@ -7,7 +7,9 @@
class DocumentFactory(ABC):
@abstractmethod
- def get_notes_from_dir(self, dir_path: Path) -> Sequence[Document]:
+ def get_notes_from_dir(
+ self, dir_path: Path
+ ) -> Sequence[Document]:
pass
@abstractmethod
diff --git a/src/personal_mnemonic_medium/note_factories/markdown.py b/src/personal_mnemonic_medium/note_factories/markdown.py
index da97818..089d77c 100644
--- a/src/personal_mnemonic_medium/note_factories/markdown.py
+++ b/src/personal_mnemonic_medium/note_factories/markdown.py
@@ -5,7 +5,9 @@
from tqdm import tqdm
-from personal_mnemonic_medium.note_factories.base import DocumentFactory
+from personal_mnemonic_medium.note_factories.base import (
+ DocumentFactory,
+)
from personal_mnemonic_medium.note_factories.note import Document
@@ -42,7 +44,9 @@ def get_note_from_file(self, file_path: Path) -> Document | None:
note_title = file_path.stem
if self.cut_note_after in file_contents:
- file_contents = file_contents.split(self.cut_note_after)[0]
+ file_contents = file_contents.split(
+ self.cut_note_after
+ )[0]
return Document(
title=note_title,
@@ -51,7 +55,9 @@ def get_note_from_file(self, file_path: Path) -> Document | None:
source_path=file_path,
)
- def get_notes_from_dir(self, dir_path: Path) -> Sequence[Document]:
+ def get_notes_from_dir(
+ self, dir_path: Path
+ ) -> Sequence[Document]:
notes: list[Document] = []
for parent_dir, _, files in os.walk(dir_path):
diff --git a/src/personal_mnemonic_medium/note_factories/note.py b/src/personal_mnemonic_medium/note_factories/note.py
index 4b35706..e8bd73c 100644
--- a/src/personal_mnemonic_medium/note_factories/note.py
+++ b/src/personal_mnemonic_medium/note_factories/note.py
@@ -16,7 +16,9 @@ def __init__(
self.content = self.replace_alias_wiki_links(content)
self.source_path = source_path
- import_time_formatted = datetime.datetime.now().strftime("%Y-%m-%d")
+ import_time_formatted = datetime.datetime.now().strftime(
+ "%Y-%m-%d"
+ )
self.tags = self.get_tags(
self.content, import_time=import_time_formatted
@@ -25,7 +27,9 @@ def __init__(
@staticmethod
def replace_alias_wiki_links(text: str) -> str:
tokens_in_link = r"[\w|\s|\d|\(|\)\-]"
- regex_pattern = rf"\[\[{tokens_in_link}+\|{tokens_in_link}+\]\]"
+ regex_pattern = (
+ rf"\[\[{tokens_in_link}+\|{tokens_in_link}+\]\]"
+ )
pattern_matches = re.findall(
pattern=regex_pattern,
string=text,
@@ -34,7 +38,9 @@ def replace_alias_wiki_links(text: str) -> str:
for match in pattern_matches:
link_name = (
- re.findall(pattern=rf"\|{tokens_in_link}+\]\]", string=match)[0]
+ re.findall(
+ pattern=rf"\|{tokens_in_link}+\]\]", string=match
+ )[0]
.replace("|", "")
.replace("]", "")
)
diff --git a/src/personal_mnemonic_medium/prompt_extractors/cloze_extractor.py b/src/personal_mnemonic_medium/prompt_extractors/cloze_extractor.py
index d1fb405..ba12e99 100644
--- a/src/personal_mnemonic_medium/prompt_extractors/cloze_extractor.py
+++ b/src/personal_mnemonic_medium/prompt_extractors/cloze_extractor.py
@@ -4,7 +4,9 @@
from typing import Any
from personal_mnemonic_medium.note_factories.note import Document
-from personal_mnemonic_medium.prompt_extractors.base import PromptExtractor
+from personal_mnemonic_medium.prompt_extractors.base import (
+ PromptExtractor,
+)
from personal_mnemonic_medium.prompt_extractors.prompt import Prompt
@@ -19,7 +21,9 @@ def __init__(self) -> None:
pass
@staticmethod
- def _break_string_by_two_or_more_newlines(string: str) -> list[str]:
+ def _break_string_by_two_or_more_newlines(
+ string: str
+ ) -> list[str]:
"""Break string into a list by 2+ newlines in a row."""
return re.split(r"(\n\n)+", string)
@@ -52,11 +56,16 @@ def _replace_cloze_id_with_unique(
if selected_cloze is not None:
selected_clozes = [selected_cloze]
else:
- selected_clozes = re.findall(r"{(?!BearID).[^}]*}", string)
+ selected_clozes = re.findall(
+ r"{(?!BearID).[^}]*}", string
+ )
for cloze in selected_clozes:
output_hash = (
- int(hashlib.sha256(cloze.encode("utf-8")).hexdigest(), 16)
+ int(
+ hashlib.sha256(cloze.encode("utf-8")).hexdigest(),
+ 16,
+ )
% 10**3
)
@@ -66,19 +75,27 @@ def _replace_cloze_id_with_unique(
return string
- def extract_prompts(self, note: Document) -> Sequence[ClozePrompt]:
+ def extract_prompts(
+ self, note: Document
+ ) -> Sequence[ClozePrompt]:
prompts = []
- blocks = self._break_string_by_two_or_more_newlines(note.content)
+ blocks = self._break_string_by_two_or_more_newlines(
+ note.content
+ )
for block_string in blocks:
if self._has_cloze(block_string):
- clozes = re.findall(r"{(?!BearID).[^}]*}", block_string)
+ clozes = re.findall(
+ r"{(?!BearID).[^}]*}", block_string
+ )
for selected_cloze in clozes:
- prompt_content = self._replace_cloze_id_with_unique(
- block_string,
- selected_cloze=selected_cloze,
+ prompt_content = (
+ self._replace_cloze_id_with_unique(
+ block_string,
+ selected_cloze=selected_cloze,
+ )
)
prompts.append(
diff --git a/src/personal_mnemonic_medium/prompt_extractors/qa_extractor.py b/src/personal_mnemonic_medium/prompt_extractors/qa_extractor.py
index 701527d..655538a 100644
--- a/src/personal_mnemonic_medium/prompt_extractors/qa_extractor.py
+++ b/src/personal_mnemonic_medium/prompt_extractors/qa_extractor.py
@@ -4,7 +4,9 @@
from typing import Any
from personal_mnemonic_medium.note_factories.note import Document
-from personal_mnemonic_medium.prompt_extractors.base import PromptExtractor
+from personal_mnemonic_medium.prompt_extractors.base import (
+ PromptExtractor,
+)
from personal_mnemonic_medium.prompt_extractors.prompt import Prompt
log = logging.getLogger(__name__)
@@ -54,7 +56,9 @@ def _get_first_answer(self, string: str) -> str:
return answer[len(self.answer_prefix) + 2 :].rstrip()
@staticmethod
- def _break_string_by_two_or_more_newlines(string: str) -> list[str]:
+ def _break_string_by_two_or_more_newlines(
+ string: str
+ ) -> list[str]:
"""Break string into a list by 2+ newlines in a row."""
return re.split(r"(\n\n)+", string)
@@ -63,7 +67,9 @@ def _has_qa(self, string: str) -> bool:
if (
len(
re.findall(
- r"^(?![:>]).*" + self.question_prefix + r"{0,1}\. ",
+ r"^(?![:>]).*"
+ + self.question_prefix
+ + r"{0,1}\. ",
string,
flags=re.DOTALL,
),
@@ -76,7 +82,9 @@ def _has_qa(self, string: str) -> bool:
def extract_prompts(self, note: Document) -> Sequence[QAPrompt]:
prompts = []
- blocks = self._break_string_by_two_or_more_newlines(note.content)
+ blocks = self._break_string_by_two_or_more_newlines(
+ note.content
+ )
block_starting_line_nr = 1
for block_string in blocks:
@@ -101,7 +109,9 @@ def extract_prompts(self, note: Document) -> Sequence[QAPrompt]:
),
)
- block_lines = len(re.findall(r"\n", block_string, flags=re.DOTALL))
+ block_lines = len(
+ re.findall(r"\n", block_string, flags=re.DOTALL)
+ )
block_starting_line_nr += block_lines
return prompts
diff --git a/src/personal_mnemonic_medium/utils/hasher.py b/src/personal_mnemonic_medium/utils/hasher.py
index d36db00..631538d 100644
--- a/src/personal_mnemonic_medium/utils/hasher.py
+++ b/src/personal_mnemonic_medium/utils/hasher.py
@@ -4,7 +4,8 @@
def simple_hash(text: str) -> int:
"""MD5 of text, mod 2^63. Probably not a great hash function."""
comp_hash = (
- int(hashlib.sha256(text.encode("utf-8")).hexdigest(), 16) % 10**10
+ int(hashlib.sha256(text.encode("utf-8")).hexdigest(), 16)
+ % 10**10
)
return comp_hash
diff --git a/tests/exporters/anki/test_card_converter.py b/tests/exporters/anki/test_card_converter.py
index 628e68e..5766db7 100644
--- a/tests/exporters/anki/test_card_converter.py
+++ b/tests/exporters/anki/test_card_converter.py
@@ -3,16 +3,26 @@
import genanki
from personal_mnemonic_medium.card_pipeline import CardPipeline
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
-from personal_mnemonic_medium.exporters.anki.card_types.qa import AnkiQA
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
+from personal_mnemonic_medium.exporters.anki.card_types.qa import (
+ AnkiQA,
+)
from personal_mnemonic_medium.exporters.anki.package_generator import (
AnkiPackageGenerator,
)
from personal_mnemonic_medium.exporters.base import CardExporter
-from personal_mnemonic_medium.note_factories.base import DocumentFactory
-from personal_mnemonic_medium.note_factories.markdown import MarkdownNoteFactory
+from personal_mnemonic_medium.note_factories.base import (
+ DocumentFactory,
+)
+from personal_mnemonic_medium.note_factories.markdown import (
+ MarkdownNoteFactory,
+)
from personal_mnemonic_medium.note_factories.note import Document
-from personal_mnemonic_medium.prompt_extractors.base import PromptExtractor
+from personal_mnemonic_medium.prompt_extractors.base import (
+ PromptExtractor,
+)
from personal_mnemonic_medium.prompt_extractors.cloze_extractor import (
ClozePromptExtractor,
)
@@ -94,7 +104,9 @@ def test_qa_uuid_generation():
/ "test_md_files"
/ "test_card_guid.md"
)
- cards = TestCardPipeline(prompt_extractors=[QAPromptExtractor()]).run(
+ cards = TestCardPipeline(
+ prompt_extractors=[QAPromptExtractor()]
+ ).run(
input_path=file_path,
)
notes = [c.to_genanki_note() for c in cards]
@@ -137,15 +149,23 @@ def test_get_bear_id():
def test_alias_wiki_link_substitution():
alias = "Here I am [[alias|wiki link]], and another [[alias2|wiki link2]]"
output = Document.replace_alias_wiki_links(alias)
- assert output == "Here I am [[wiki link]], and another [[wiki link2]]"
+ assert (
+ output
+ == "Here I am [[wiki link]], and another [[wiki link2]]"
+ )
no_alias = "Here I am [[wiki link]] and another [[wiki link2]]"
output = Document.replace_alias_wiki_links(no_alias)
- assert output == "Here I am [[wiki link]] and another [[wiki link2]]"
+ assert (
+ output == "Here I am [[wiki link]] and another [[wiki link2]]"
+ )
test_3 = "How was ice climbing [[Franz Josef]] with [[Vibeke Christiansen|Vibeke]]?"
output = Document.replace_alias_wiki_links(test_3)
- assert output == "How was ice climbing [[Franz Josef]] with [[Vibeke]]?"
+ assert (
+ output
+ == "How was ice climbing [[Franz Josef]] with [[Vibeke]]?"
+ )
alias = "[[Isolation (database design)|Isolation]]"
output = Document.replace_alias_wiki_links(alias)
diff --git a/tests/exporters/anki/test_package_generator.py b/tests/exporters/anki/test_package_generator.py
index 47f6873..0676951 100644
--- a/tests/exporters/anki/test_package_generator.py
+++ b/tests/exporters/anki/test_package_generator.py
@@ -1,13 +1,19 @@
from pathlib import Path
import genanki
-from personal_mnemonic_medium.exporters.anki.card_types.base import AnkiCard
-from personal_mnemonic_medium.exporters.anki.card_types.qa import AnkiQA
+from personal_mnemonic_medium.exporters.anki.card_types.base import (
+ AnkiCard,
+)
+from personal_mnemonic_medium.exporters.anki.card_types.qa import (
+ AnkiQA,
+)
from personal_mnemonic_medium.exporters.anki.package_generator import (
AnkiPackageGenerator,
)
from personal_mnemonic_medium.note_factories.note import Document
-from personal_mnemonic_medium.prompt_extractors.qa_extractor import QAPrompt
+from personal_mnemonic_medium.prompt_extractors.qa_extractor import (
+ QAPrompt,
+)
def test_cards_to_decks():
@@ -31,7 +37,9 @@ def test_cards_to_decks():
for _ in range(4)
]
- deck, media = AnkiPackageGenerator().cards_to_deck(cards=genanki_notes)
+ deck, media = AnkiPackageGenerator().cards_to_deck(
+ cards=genanki_notes
+ )
assert isinstance(deck, genanki.Deck)
assert isinstance(media, set)
diff --git a/tests/note_factories/test_markdown_extractor.py b/tests/note_factories/test_markdown_extractor.py
index ddd8636..cb09106 100644
--- a/tests/note_factories/test_markdown_extractor.py
+++ b/tests/note_factories/test_markdown_extractor.py
@@ -2,7 +2,9 @@
PROJECT_ROOT = Path(__file__).parent.parent.parent
-from personal_mnemonic_medium.note_factories.markdown import MarkdownNoteFactory
+from personal_mnemonic_medium.note_factories.markdown import (
+ MarkdownNoteFactory,
+)
def test_get_notes_from_dir():
@@ -11,6 +13,16 @@ def test_get_notes_from_dir():
)
assert len(notes) == 4
- assert len([note for note in notes if note.title == "test_card_guid"]) == 1
- assert len([note for note in notes if "7696CDCD" in note.content]) == 1
- assert len([note for note in notes if "7696CDCD" in note.uuid]) == 1
+ assert (
+ len(
+ [note for note in notes if note.title == "test_card_guid"]
+ )
+ == 1
+ )
+ assert (
+ len([note for note in notes if "7696CDCD" in note.content])
+ == 1
+ )
+ assert (
+ len([note for note in notes if "7696CDCD" in note.uuid]) == 1
+ )
diff --git a/tests/prompt_extractors/test_cloze_extractor.py b/tests/prompt_extractors/test_cloze_extractor.py
index 1d5f567..8267a4b 100644
--- a/tests/prompt_extractors/test_cloze_extractor.py
+++ b/tests/prompt_extractors/test_cloze_extractor.py
@@ -32,6 +32,8 @@ def test_cloze_no_hits():
source_path=Path(__file__),
)
- prompts = ClozePromptExtractor().extract_prompts(note_without_cloze)
+ prompts = ClozePromptExtractor().extract_prompts(
+ note_without_cloze
+ )
assert len(prompts) == 0
diff --git a/tests/prompt_extractors/test_qa_prompt_extractor.py b/tests/prompt_extractors/test_qa_prompt_extractor.py
index 66dca9b..9a96dc0 100644
--- a/tests/prompt_extractors/test_qa_prompt_extractor.py
+++ b/tests/prompt_extractors/test_qa_prompt_extractor.py
@@ -38,7 +38,9 @@ def test_has_qa_matches(qa_extractor: QAPromptExtractor):
"\\Q. Testing newlines as well!",
]
matches = [
- string for string in example_strings if qa_extractor._has_qa(string)
+ string
+ for string in example_strings
+ if qa_extractor._has_qa(string)
]
assert len(matches) == 3