From b2ef0032077fbec4ff339469d8604a5572bcf816 Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Tue, 11 Feb 2020 16:16:38 -0800 Subject: [PATCH 1/3] hook note_is_being_flushed I created multiple add-ons which want to transform a note before it is being saved. For example, one add-on trim it, and remove useless line break which arrived by accident. Another add-on want to compile LaTeX as soon as the note is done, and warn the user if LaTeX can't be compiled. Having a hook in pre-flush would be useful here --- pylib/anki/hooks.py | 27 +++++++++++++++++++++++++++ pylib/anki/notes.py | 2 ++ pylib/tools/genhooks.py | 5 +++++ 3 files changed, 34 insertions(+) diff --git a/pylib/anki/hooks.py b/pylib/anki/hooks.py index 5ab0f341a..1c1627401 100644 --- a/pylib/anki/hooks.py +++ b/pylib/anki/hooks.py @@ -18,6 +18,7 @@ import decorator import anki from anki.cards import Card +from anki.notes import Note # New hook/filter handling ############################################################################## @@ -277,6 +278,32 @@ class _NoteTypeAddedHook: note_type_added = _NoteTypeAddedHook() +class _NoteWillFlushHook: + """Allow to change a note before it is added/updated in the database.""" + + _hooks: List[Callable[[Note], None]] = [] + + def append(self, cb: Callable[[Note], None]) -> None: + """(note: Note)""" + self._hooks.append(cb) + + def remove(self, cb: Callable[[Note], None]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, note: Note) -> None: + for hook in self._hooks: + try: + hook(note) + except: + # if the hook fails, remove it + self._hooks.remove(hook) + raise + + +note_will_flush = _NoteWillFlushHook() + + class _NotesWillBeDeletedHook: _hooks: List[Callable[["anki.storage._Collection", List[int]], None]] = [] diff --git a/pylib/anki/notes.py b/pylib/anki/notes.py index 266733d64..6d6cf4174 100644 --- a/pylib/anki/notes.py +++ b/pylib/anki/notes.py @@ -6,6 +6,7 @@ from __future__ import annotations from typing import Any, Dict, List, Optional, Tuple import anki # pylint: disable=unused-import +from anki import hooks from anki.models import Field, NoteType from anki.utils import ( fieldChecksum, @@ -202,6 +203,7 @@ insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)""", ################################################## def _preFlush(self) -> None: + hooks.note_will_flush(self) # have we been added yet? self.newlyAdded = not self.col.db.scalar( "select 1 from cards where nid = ?", self.id diff --git a/pylib/tools/genhooks.py b/pylib/tools/genhooks.py index df83e73fa..0923dba6b 100644 --- a/pylib/tools/genhooks.py +++ b/pylib/tools/genhooks.py @@ -67,6 +67,11 @@ hooks = [ Your add-on can check filter_name to decide whether it should modify field_text or not before returning it.""", ), + Hook( + name="note_will_flush", + args=["note: Note"], + doc="Allow to change a note before it is added/updated in the database.", + ), Hook( name="card_did_render", args=[ From 81daad878e819ae59df0ac5f7226004c71582d8e Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Tue, 11 Feb 2020 16:20:37 -0800 Subject: [PATCH 2/3] Factorizing card's flush --- pylib/anki/cards.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/pylib/anki/cards.py b/pylib/anki/cards.py index 2de6960e5..a31c0fb81 100644 --- a/pylib/anki/cards.py +++ b/pylib/anki/cards.py @@ -84,7 +84,7 @@ class Card: self._render_output = None self._note = None - def flush(self) -> None: + def _preFlush(self) -> none: self.mod = intTime() self.usn = self.col.usn() # bug check @@ -95,6 +95,9 @@ class Card: ): hooks.card_odue_was_invalid() assert self.due < 4294967296 + + def flush(self) -> None: + self._preFlush() self.col.db.execute( """ insert or replace into cards values @@ -121,16 +124,8 @@ insert or replace into cards values self.col.log(self) def flushSched(self) -> None: - self.mod = intTime() - self.usn = self.col.usn() + self._preFlush() # bug checks - if ( - self.queue == QUEUE_TYPE_REV - and self.odue - and not self.col.decks.isDyn(self.did) - ): - hooks.card_odue_was_invalid() - assert self.due < 4294967296 self.col.db.execute( """update cards set mod=?, usn=?, type=?, queue=?, due=?, ivl=?, factor=?, reps=?, From fcfa78bba35e0510747e0f28923bc5fd557573f8 Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Tue, 11 Feb 2020 16:23:20 -0800 Subject: [PATCH 3/3] Hook card_is_being_flushed It often arrives that I want to know when a card is going to be flushed and in this case change it. This could be the case if I want to change the scheduler without implementing a whole scheduler. It simply reads the card history and change interval and due date. It's also the case for the "'trigger -> action' rules", which apply some coded actions when some event occurs. E.g. suspend/unsuspend a sibling when card become mature/is forgotten. --- pylib/anki/cards.py | 3 ++- pylib/anki/hooks.py | 26 ++++++++++++++++++++++++++ pylib/tools/genhooks.py | 5 +++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/pylib/anki/cards.py b/pylib/anki/cards.py index a31c0fb81..480986ebc 100644 --- a/pylib/anki/cards.py +++ b/pylib/anki/cards.py @@ -84,7 +84,8 @@ class Card: self._render_output = None self._note = None - def _preFlush(self) -> none: + def _preFlush(self) -> None: + hooks.card_will_flush(self) self.mod = intTime() self.usn = self.col.usn() # bug check diff --git a/pylib/anki/hooks.py b/pylib/anki/hooks.py index 1c1627401..d46465e4e 100644 --- a/pylib/anki/hooks.py +++ b/pylib/anki/hooks.py @@ -134,6 +134,32 @@ class _CardOdueWasInvalidHook: card_odue_was_invalid = _CardOdueWasInvalidHook() +class _CardWillFlushHook: + """Allow to change a card before it is added/updated in the database.""" + + _hooks: List[Callable[[Card], None]] = [] + + def append(self, cb: Callable[[Card], None]) -> None: + """(card: Card)""" + self._hooks.append(cb) + + def remove(self, cb: Callable[[Card], None]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, card: Card) -> None: + for hook in self._hooks: + try: + hook(card) + except: + # if the hook fails, remove it + self._hooks.remove(hook) + raise + + +card_will_flush = _CardWillFlushHook() + + class _DeckAddedHook: _hooks: List[Callable[[Dict[str, Any]], None]] = [] diff --git a/pylib/tools/genhooks.py b/pylib/tools/genhooks.py index 0923dba6b..9e124be77 100644 --- a/pylib/tools/genhooks.py +++ b/pylib/tools/genhooks.py @@ -72,6 +72,11 @@ hooks = [ args=["note: Note"], doc="Allow to change a note before it is added/updated in the database.", ), + Hook( + name="card_will_flush", + args=["card: Card"], + doc="Allow to change a card before it is added/updated in the database.", + ), Hook( name="card_did_render", args=[