Skip to content

Instantly share code, notes, and snippets.

@mtherieau
Created May 22, 2018 18:49
Show Gist options
  • Save mtherieau/356445199db23daa776010710c68852a to your computer and use it in GitHub Desktop.
Save mtherieau/356445199db23daa776010710c68852a to your computer and use it in GitHub Desktop.
extending genanki for cloze notes
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