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