Created
May 22, 2018 18:49
-
-
Save mtherieau/356445199db23daa776010710c68852a to your computer and use it in GitHub Desktop.
extending genanki for cloze notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import genanki | |
from cached_property import cached_property | |
import re | |
class ModelX(genanki.Model): | |
def __init__(self, model_id=None, name=None, fields=None, templates=None, css='', type=0): | |
super().__init__(model_id, name, fields, templates, css) | |
self._type = type | |
def to_json(self, now_ts, deck_id): | |
j = super().to_json(now_ts, deck_id) | |
j["type"] = self._type | |
return j | |
class NoteX(genanki.Note): | |
def _cloze_cards(self): | |
""" | |
returns a Card with unique ord for each unique cloze reference | |
""" | |
card_ords = set() | |
# find cloze replacements in first template's qfmt, e.g "{{cloze::Text}}" | |
cloze_replacements = set(re.findall("{{[^}]*?cloze:(?:[^}]?:)*(.+?)}}", self.model.templates[0]['qfmt']) + | |
re.findall("<%cloze:(.+?)%>", self.model.templates[0]['qfmt'])) | |
for field_name in cloze_replacements: | |
field_index = next((i for i, f in enumerate(self.model.fields) if f['name'] == field_name), -1) | |
field_value = self.fields[field_index] if field_index >= 0 else "" | |
# update card_ords with each cloze reference N, e.g. "{{cN::...}}" | |
card_ords.update([int(m)-1 for m in re.findall("{{c(\d+)::.+?}}", field_value) if int(m) > 0]) | |
if card_ords == {}: | |
card_ords = {0} | |
return([genanki.Card(ord) for ord in card_ords]) | |
@cached_property | |
def cards(self): | |
if self.model._type == 1: | |
return self._cloze_cards() | |
else: | |
return super().cards | |
my_cloze_model = ModelX( | |
998877661, | |
'My Cloze Model', | |
fields=[ | |
{'name': 'TextA'}, | |
{'name': 'TextB'}, | |
{'name': 'Extra'}, | |
], | |
templates=[ | |
{ | |
'name': 'My Cloze Card', | |
'qfmt': '{{cloze:TextA}}<hr>{{cloze:TextB}}', | |
'afmt': '{{cloze:TextA}}<hr>{{cloze:TextB}}<hr id="extra">{{Extra}}', | |
}, | |
], | |
type=1) | |
def test_cloze(): | |
assert my_cloze_model.to_json(0, 0)["type"] == 1 | |
my_cloze_note = NoteX(model=my_cloze_model, fields=['TextA: {{c1::single deletion::C1-CLOZE}}', 'TextB: empty', 'Extra']) | |
assert {card.ord for card in my_cloze_note.cards} == { 0 } | |
my_cloze_note = NoteX(model=my_cloze_model, fields=['TextA: {{c1::1st deletion::C1-CLOZE}} {{c2::2nd deletion::C2-CLOZE}} {{c3::3rd deletion::C3-CLOZE}}', 'TextB: empty', 'Extra']) | |
assert {card.ord for card in my_cloze_note.cards} == { 0, 1, 2 } | |
my_cloze_note = NoteX(model=my_cloze_model, fields=['TextA: {{c1::1st deletion::C1-CLOZE}}', 'TextB: {{c2::2nd deletion::C2-CLOZE}}', 'Extra']) | |
assert {card.ord for card in my_cloze_note.cards} == { 0, 1 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment