mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
remove the concept of non-active templates
The old template handling was too complicated, and generated frequent questions on the forums. By dropping non-active templates we can do away with the generate cards function, and advanced users can simulate the old behaviour by using conditional field templates.
This commit is contained in:
parent
f8eefe5ee1
commit
795cdd7d3f
13 changed files with 89 additions and 75 deletions
20
anki/deck.py
20
anki/deck.py
|
@ -268,20 +268,19 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""",
|
||||||
# Card creation
|
# Card creation
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def findTemplates(self, fact, checkActive=True):
|
def findTemplates(self, fact):
|
||||||
"Return (active), non-empty templates."
|
"Return (active), non-empty templates."
|
||||||
ok = []
|
ok = []
|
||||||
model = fact.model()
|
model = fact.model()
|
||||||
avail = self.models.availOrds(model, joinFields(fact.fields))
|
avail = self.models.availOrds(model, joinFields(fact.fields))
|
||||||
ok = []
|
ok = []
|
||||||
for t in model['tmpls']:
|
for t in model['tmpls']:
|
||||||
if t['actv'] or not checkActive:
|
|
||||||
if t['ord'] in avail:
|
if t['ord'] in avail:
|
||||||
ok.append(t)
|
ok.append(t)
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def genCards(self, fids, limit=None):
|
def genCards(self, fids):
|
||||||
"Generate cards for active or limited, non-empty templates."
|
"Generate cards for non-empty templates."
|
||||||
# build map of (fid,ord) so we don't create dupes
|
# build map of (fid,ord) so we don't create dupes
|
||||||
sfids = ids2str(fids)
|
sfids = ids2str(fids)
|
||||||
have = {}
|
have = {}
|
||||||
|
@ -297,11 +296,7 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""",
|
||||||
avail = self.models.availOrds(model, flds)
|
avail = self.models.availOrds(model, flds)
|
||||||
ok = []
|
ok = []
|
||||||
for t in model['tmpls']:
|
for t in model['tmpls']:
|
||||||
if not limit and not t['actv']:
|
if (fid,t['ord']) in have:
|
||||||
continue
|
|
||||||
elif limit and t not in limit:
|
|
||||||
continue
|
|
||||||
elif (fid,t['ord']) in have:
|
|
||||||
continue
|
continue
|
||||||
if t['ord'] in avail:
|
if t['ord'] in avail:
|
||||||
data.append((ts, fid, t['gid'] or gid, t['ord'],
|
data.append((ts, fid, t['gid'] or gid, t['ord'],
|
||||||
|
@ -312,13 +307,12 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""",
|
||||||
insert into cards values (?,?,?,?,?,-1,0,0,?,0,0,0,0,0,0,0,"")""",
|
insert into cards values (?,?,?,?,?,-1,0,0,?,0,0,0,0,0,0,0,"")""",
|
||||||
data)
|
data)
|
||||||
|
|
||||||
# type 0 - when previewing in add dialog, only non-empty & active
|
# type 0 - when previewing in add dialog, only non-empty
|
||||||
# type 1 - when previewing edit, only existing
|
# type 1 - when previewing edit, only existing
|
||||||
# type 2 - when previewing in models dialog, all
|
# type 2 - when previewing in models dialog, all templates
|
||||||
def previewCards(self, fact, type=0):
|
def previewCards(self, fact, type=0):
|
||||||
"Return uncommited cards for preview."
|
|
||||||
if type == 0:
|
if type == 0:
|
||||||
cms = self.findTemplates(fact, checkActive=True)
|
cms = self.findTemplates(fact)
|
||||||
elif type == 1:
|
elif type == 1:
|
||||||
cms = [c.template() for c in fact.cards()]
|
cms = [c.template() for c in fact.cards()]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -84,7 +84,7 @@ If the same name exists, compare checksums."""
|
||||||
# String manipulation
|
# String manipulation
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def files(self, mid, string, includeRemote=False):
|
def filesInStr(self, mid, string, includeRemote=False):
|
||||||
l = []
|
l = []
|
||||||
# convert latex first
|
# convert latex first
|
||||||
model = self.deck.models.get(mid)
|
model = self.deck.models.get(mid)
|
||||||
|
@ -161,7 +161,7 @@ If the same name exists, compare checksums."""
|
||||||
"Return a set of all referenced filenames."
|
"Return a set of all referenced filenames."
|
||||||
files = set()
|
files = set()
|
||||||
for mid, flds in self.deck.db.execute("select mid, flds from facts"):
|
for mid, flds in self.deck.db.execute("select mid, flds from facts"):
|
||||||
for f in self.files(mid, flds):
|
for f in self.filesInStr(mid, flds):
|
||||||
files.add(f)
|
files.add(f)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ defaultField = {
|
||||||
defaultTemplate = {
|
defaultTemplate = {
|
||||||
'name': "",
|
'name': "",
|
||||||
'ord': None,
|
'ord': None,
|
||||||
'actv': True,
|
|
||||||
'qfmt': "",
|
'qfmt': "",
|
||||||
'afmt': "",
|
'afmt': "",
|
||||||
'hideQ': False,
|
'hideQ': False,
|
||||||
|
@ -74,13 +73,15 @@ class ModelManager(object):
|
||||||
self.changed = False
|
self.changed = False
|
||||||
self.models = simplejson.loads(json)
|
self.models = simplejson.loads(json)
|
||||||
|
|
||||||
def save(self, m=None):
|
def save(self, m=None, gencards=False):
|
||||||
"Mark M modified if provided, and schedule registry flush."
|
"Mark M modified if provided, and schedule registry flush."
|
||||||
if m:
|
if m:
|
||||||
m['mod'] = intTime()
|
m['mod'] = intTime()
|
||||||
m['usn'] = self.deck.usn()
|
m['usn'] = self.deck.usn()
|
||||||
m['css'] = self._css(m)
|
m['css'] = self._css(m)
|
||||||
self._updateRequired(m)
|
self._updateRequired(m)
|
||||||
|
if gencards:
|
||||||
|
self.deck.genCards(self.fids(m))
|
||||||
self.changed = True
|
self.changed = True
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
|
|
|
@ -22,11 +22,6 @@ def addBasicModel(deck):
|
||||||
t['qfmt'] = "{{" + _("Front") + "}}"
|
t['qfmt'] = "{{" + _("Front") + "}}"
|
||||||
t['afmt'] = "{{" + _("Back") + "}}"
|
t['afmt'] = "{{" + _("Back") + "}}"
|
||||||
mm.addTemplate(m, t)
|
mm.addTemplate(m, t)
|
||||||
t = mm.newTemplate(_("Reverse"))
|
|
||||||
t['qfmt'] = "{{" + _("Back") + "}}"
|
|
||||||
t['afmt'] = "{{" + _("Front") + "}}"
|
|
||||||
t['actv'] = False
|
|
||||||
mm.addTemplate(m, t)
|
|
||||||
mm.save(m)
|
mm.save(m)
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
|
@ -379,13 +379,12 @@ order by ordinal""", mid)):
|
||||||
dconf = anki.models.defaultTemplate
|
dconf = anki.models.defaultTemplate
|
||||||
tmpls = []
|
tmpls = []
|
||||||
for c, row in enumerate(db.all("""
|
for c, row in enumerate(db.all("""
|
||||||
select name, active, qformat, aformat, questionInAnswer,
|
select name, qformat, aformat, questionInAnswer,
|
||||||
questionAlign, lastFontColour, typeAnswer from cardModels
|
questionAlign, lastFontColour, typeAnswer from cardModels
|
||||||
where modelId = ?
|
where modelId = ?
|
||||||
order by ordinal""", mid)):
|
order by ordinal""", mid)):
|
||||||
conf = dconf.copy()
|
conf = dconf.copy()
|
||||||
(conf['name'],
|
(conf['name'],
|
||||||
conf['actv'],
|
|
||||||
conf['qfmt'],
|
conf['qfmt'],
|
||||||
conf['afmt'],
|
conf['afmt'],
|
||||||
conf['hideQ'],
|
conf['hideQ'],
|
||||||
|
|
|
@ -6,15 +6,6 @@ from anki.consts import *
|
||||||
from anki.utils import hexifyID
|
from anki.utils import hexifyID
|
||||||
from tests.shared import getEmptyDeck
|
from tests.shared import getEmptyDeck
|
||||||
|
|
||||||
def test_genCards():
|
|
||||||
deck = getEmptyDeck()
|
|
||||||
f = deck.newFact()
|
|
||||||
f['Front'] = u'1'
|
|
||||||
f['Back'] = u'2'
|
|
||||||
deck.addFact(f)
|
|
||||||
deck.genCards([f.id], f.model()['tmpls'])
|
|
||||||
assert deck.cardCount() == 2
|
|
||||||
|
|
||||||
def test_previewCards():
|
def test_previewCards():
|
||||||
deck = getEmptyDeck()
|
deck = getEmptyDeck()
|
||||||
f = deck.newFact()
|
f = deck.newFact()
|
||||||
|
@ -26,7 +17,7 @@ def test_previewCards():
|
||||||
assert cards[0].ord == 0
|
assert cards[0].ord == 0
|
||||||
# all templates
|
# all templates
|
||||||
cards = deck.previewCards(f, 2)
|
cards = deck.previewCards(f, 2)
|
||||||
assert len(cards) == 2
|
assert len(cards) == 1
|
||||||
# add the fact, and test existing preview
|
# add the fact, and test existing preview
|
||||||
deck.addFact(f)
|
deck.addFact(f)
|
||||||
cards = deck.previewCards(f, 1)
|
cards = deck.previewCards(f, 1)
|
||||||
|
|
|
@ -48,19 +48,28 @@ def test_factAddDelete():
|
||||||
f['Front'] = u"one"; f['Back'] = u"two"
|
f['Front'] = u"one"; f['Back'] = u"two"
|
||||||
n = deck.addFact(f)
|
n = deck.addFact(f)
|
||||||
assert n == 1
|
assert n == 1
|
||||||
deck.rollback()
|
# test multiple cards - add another template
|
||||||
assert deck.cardCount() == 0
|
m = deck.models.current(); mm = deck.models
|
||||||
# try with two cards
|
t = mm.newTemplate("Reverse")
|
||||||
|
t['qfmt'] = "{{Back}}"
|
||||||
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
|
# the default save doesn't generate cards
|
||||||
|
assert deck.cardCount() == 1
|
||||||
|
# but when templates are edited such as in the card layout screen, it
|
||||||
|
# should generate cards on close
|
||||||
|
mm.save(m, gencards=True)
|
||||||
|
assert deck.cardCount() == 2
|
||||||
|
# creating new facts should use both cards
|
||||||
f = deck.newFact()
|
f = deck.newFact()
|
||||||
f['Front'] = u"one"; f['Back'] = u"two"
|
f['Front'] = u"three"; f['Back'] = u"four"
|
||||||
m = f.model()
|
|
||||||
m['tmpls'][1]['actv'] = True
|
|
||||||
deck.models.save(m)
|
|
||||||
n = deck.addFact(f)
|
n = deck.addFact(f)
|
||||||
assert n == 2
|
assert n == 2
|
||||||
|
assert deck.cardCount() == 4
|
||||||
# check q/a generation
|
# check q/a generation
|
||||||
c0 = f.cards()[0]
|
c0 = f.cards()[0]
|
||||||
assert re.sub("</?.+?>", "", c0.q()) == u"one"
|
assert re.sub("</?.+?>", "", c0.q()) == u"three"
|
||||||
# it should not be a duplicate
|
# it should not be a duplicate
|
||||||
for p in f.problems():
|
for p in f.problems():
|
||||||
assert not p
|
assert not p
|
||||||
|
@ -74,15 +83,15 @@ def test_factAddDelete():
|
||||||
# try delete the first card
|
# try delete the first card
|
||||||
cards = f.cards()
|
cards = f.cards()
|
||||||
id1 = cards[0].id; id2 = cards[1].id
|
id1 = cards[0].id; id2 = cards[1].id
|
||||||
assert deck.cardCount() == 2
|
assert deck.cardCount() == 4
|
||||||
assert deck.factCount() == 1
|
assert deck.factCount() == 2
|
||||||
deck.remCards([id1])
|
deck.remCards([id1])
|
||||||
assert deck.cardCount() == 1
|
assert deck.cardCount() == 3
|
||||||
assert deck.factCount() == 1
|
assert deck.factCount() == 2
|
||||||
# and the second should clear the fact
|
# and the second should clear the fact
|
||||||
deck.remCards([id2])
|
deck.remCards([id2])
|
||||||
assert deck.cardCount() == 0
|
assert deck.cardCount() == 2
|
||||||
assert deck.factCount() == 0
|
assert deck.factCount() == 1
|
||||||
|
|
||||||
def test_fieldChecksum():
|
def test_fieldChecksum():
|
||||||
deck = getEmptyDeck()
|
deck = getEmptyDeck()
|
||||||
|
|
|
@ -25,7 +25,12 @@ def test_findCards():
|
||||||
f = deck.newFact()
|
f = deck.newFact()
|
||||||
f['Front'] = u'template test'
|
f['Front'] = u'template test'
|
||||||
f['Back'] = u'foo bar'
|
f['Back'] = u'foo bar'
|
||||||
f.model()['tmpls'][1]['actv'] = True
|
m = deck.models.current(); mm = deck.models
|
||||||
|
t = mm.newTemplate("Reverse")
|
||||||
|
t['qfmt'] = "{{Back}}"
|
||||||
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
deck.addFact(f)
|
deck.addFact(f)
|
||||||
latestCardIds = [c.id for c in f.cards()]
|
latestCardIds = [c.id for c in f.cards()]
|
||||||
# tag searches
|
# tag searches
|
||||||
|
|
|
@ -21,7 +21,8 @@ def test_latex():
|
||||||
assert "executing latex" in msg
|
assert "executing latex" in msg
|
||||||
assert "installed" in msg
|
assert "installed" in msg
|
||||||
# check if we have latex installed, and abort test if we don't
|
# check if we have latex installed, and abort test if we don't
|
||||||
if not os.path.exists("/usr/bin/latex"):
|
if (not os.path.exists("/usr/bin/latex") and
|
||||||
|
not os.path.exists("/usr/texbin/latex")):
|
||||||
print "aborting test; latex is not installed"
|
print "aborting test; latex is not installed"
|
||||||
return
|
return
|
||||||
# fix path
|
# fix path
|
||||||
|
@ -30,10 +31,11 @@ def test_latex():
|
||||||
d.media.check()
|
d.media.check()
|
||||||
assert len(os.listdir(d.media.dir())) == 1
|
assert len(os.listdir(d.media.dir())) == 1
|
||||||
assert ".png" in f.cards()[0].q()
|
assert ".png" in f.cards()[0].q()
|
||||||
# adding new facts should cause immediate generation
|
# adding new facts should cause generation on question display
|
||||||
f = d.newFact()
|
f = d.newFact()
|
||||||
f['Front'] = u"[latex]world[/latex]"
|
f['Front'] = u"[latex]world[/latex]"
|
||||||
d.addFact(f)
|
d.addFact(f)
|
||||||
|
f.cards()[0].q()
|
||||||
assert len(os.listdir(d.media.dir())) == 2
|
assert len(os.listdir(d.media.dir())) == 2
|
||||||
# another fact with the same media should reuse
|
# another fact with the same media should reuse
|
||||||
f = d.newFact()
|
f = d.newFact()
|
||||||
|
|
|
@ -21,7 +21,7 @@ def test_add():
|
||||||
|
|
||||||
def test_strings():
|
def test_strings():
|
||||||
d = getEmptyDeck()
|
d = getEmptyDeck()
|
||||||
mf = d.media.files
|
mf = d.media.filesInStr
|
||||||
mid = d.models.models.keys()[0]
|
mid = d.models.models.keys()[0]
|
||||||
assert mf(mid, "aoeu") == []
|
assert mf(mid, "aoeu") == []
|
||||||
assert mf(mid, "aoeu<img src='foo.jpg'>ao") == ["foo.jpg"]
|
assert mf(mid, "aoeu<img src='foo.jpg'>ao") == ["foo.jpg"]
|
||||||
|
|
|
@ -22,8 +22,8 @@ def test_modelCopy():
|
||||||
assert len(m2['flds']) == 2
|
assert len(m2['flds']) == 2
|
||||||
assert len(m['flds']) == 2
|
assert len(m['flds']) == 2
|
||||||
assert len(m2['flds']) == len(m['flds'])
|
assert len(m2['flds']) == len(m['flds'])
|
||||||
assert len(m['tmpls']) == 2
|
assert len(m['tmpls']) == 1
|
||||||
assert len(m2['tmpls']) == 2
|
assert len(m2['tmpls']) == 1
|
||||||
assert deck.models.scmhash(m) == deck.models.scmhash(m2)
|
assert deck.models.scmhash(m) == deck.models.scmhash(m2)
|
||||||
|
|
||||||
def test_fields():
|
def test_fields():
|
||||||
|
@ -75,9 +75,12 @@ def test_fields():
|
||||||
|
|
||||||
def test_templates():
|
def test_templates():
|
||||||
d = getEmptyDeck()
|
d = getEmptyDeck()
|
||||||
m = d.models.current()
|
m = d.models.current(); mm = d.models
|
||||||
m['tmpls'][1]['actv'] = True
|
t = mm.newTemplate("Reverse")
|
||||||
d.models.save(m)
|
t['qfmt'] = "{{Back}}"
|
||||||
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
f = d.newFact()
|
f = d.newFact()
|
||||||
f['Front'] = u'1'
|
f['Front'] = u'1'
|
||||||
f['Back'] = u'2'
|
f['Back'] = u'2'
|
||||||
|
@ -177,8 +180,12 @@ def test_modelChange():
|
||||||
basic = deck.models.byName("Basic")
|
basic = deck.models.byName("Basic")
|
||||||
cloze = deck.models.byName("Cloze")
|
cloze = deck.models.byName("Cloze")
|
||||||
# enable second template and add a fact
|
# enable second template and add a fact
|
||||||
basic['tmpls'][1]['actv'] = True
|
m = deck.models.current(); mm = deck.models
|
||||||
deck.models.save(basic)
|
t = mm.newTemplate("Reverse")
|
||||||
|
t['qfmt'] = "{{Back}}"
|
||||||
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
f = deck.newFact()
|
f = deck.newFact()
|
||||||
f['Front'] = u'f'
|
f['Front'] = u'f'
|
||||||
f['Back'] = u'b'
|
f['Back'] = u'b'
|
||||||
|
|
|
@ -27,7 +27,7 @@ import anki.sync
|
||||||
anki.sync.SYNC_URL = "http://localhost:6543/sync/"
|
anki.sync.SYNC_URL = "http://localhost:6543/sync/"
|
||||||
TEST_USER = "synctest@ichi2.net"
|
TEST_USER = "synctest@ichi2.net"
|
||||||
TEST_PASS = "synctest"
|
TEST_PASS = "synctest"
|
||||||
TEST_HKEY = "k14LvSaEtXFITCJz"
|
TEST_HKEY = "tG5CD9eZbWOru3Yw"
|
||||||
TEST_REMOTE = True
|
TEST_REMOTE = True
|
||||||
|
|
||||||
def setup_remote():
|
def setup_remote():
|
||||||
|
@ -42,7 +42,7 @@ def test_meta():
|
||||||
global TEST_REMOTE
|
global TEST_REMOTE
|
||||||
try:
|
try:
|
||||||
(mod, scm, usn, tstamp, dummy) = ts.server.meta()
|
(mod, scm, usn, tstamp, dummy) = ts.server.meta()
|
||||||
except SyntaxError, e:
|
except Exception, e:
|
||||||
if e.errno == 61:
|
if e.errno == 61:
|
||||||
TEST_REMOTE = False
|
TEST_REMOTE = False
|
||||||
print "aborting; server offline"
|
print "aborting; server offline"
|
||||||
|
@ -107,6 +107,8 @@ def setup_remoteMedia():
|
||||||
|
|
||||||
@nose.with_setup(setup_remoteMedia)
|
@nose.with_setup(setup_remoteMedia)
|
||||||
def test_media():
|
def test_media():
|
||||||
|
if not TEST_REMOTE:
|
||||||
|
return
|
||||||
ts.server.mediatest("reset")
|
ts.server.mediatest("reset")
|
||||||
assert len(os.listdir(ts.deck1.media.dir())) == 0
|
assert len(os.listdir(ts.deck1.media.dir())) == 0
|
||||||
assert ts.server.mediatest("count") == 0
|
assert ts.server.mediatest("count") == 0
|
||||||
|
|
|
@ -32,9 +32,12 @@ def test_new():
|
||||||
assert c.due >= t
|
assert c.due >= t
|
||||||
# the default order should ensure siblings are not seen together, and
|
# the default order should ensure siblings are not seen together, and
|
||||||
# should show all cards
|
# should show all cards
|
||||||
m = d.models.current()
|
m = d.models.current(); mm = d.models
|
||||||
m['tmpls'][1]['actv'] = True
|
t = mm.newTemplate("Reverse")
|
||||||
d.models.save(m)
|
t['qfmt'] = "{{Back}}"
|
||||||
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
f = d.newFact()
|
f = d.newFact()
|
||||||
f['Front'] = u"2"; f['Back'] = u"2"
|
f['Front'] = u"2"; f['Back'] = u"2"
|
||||||
d.addFact(f)
|
d.addFact(f)
|
||||||
|
@ -517,8 +520,12 @@ def test_cramLimits():
|
||||||
def test_adjIvl():
|
def test_adjIvl():
|
||||||
d = getEmptyDeck()
|
d = getEmptyDeck()
|
||||||
# add two more templates and set second active
|
# add two more templates and set second active
|
||||||
m = d.models.current()
|
m = d.models.current(); mm = d.models
|
||||||
m['tmpls'][1]['actv'] = True
|
t = mm.newTemplate("Reverse")
|
||||||
|
t['qfmt'] = "{{Back}}"
|
||||||
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
t = d.models.newTemplate(m)
|
t = d.models.newTemplate(m)
|
||||||
t['name'] = "f2"
|
t['name'] = "f2"
|
||||||
t['qfmt'] = "{{Front}}"
|
t['qfmt'] = "{{Front}}"
|
||||||
|
@ -582,15 +589,17 @@ def test_adjIvl():
|
||||||
def test_ordcycle():
|
def test_ordcycle():
|
||||||
d = getEmptyDeck()
|
d = getEmptyDeck()
|
||||||
# add two more templates and set second active
|
# add two more templates and set second active
|
||||||
m = d.models.current()
|
m = d.models.current(); mm = d.models
|
||||||
m['tmpls'][1]['actv'] = True
|
t = mm.newTemplate("Reverse")
|
||||||
t = d.models.newTemplate(m)
|
t['qfmt'] = "{{Back}}"
|
||||||
t['name'] = "f2"
|
t['afmt'] = "{{Front}}"
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
t = mm.newTemplate("f2")
|
||||||
t['qfmt'] = "{{Front}}"
|
t['qfmt'] = "{{Front}}"
|
||||||
t['afmt'] = "{{Back}}"
|
t['afmt'] = "{{Back}}"
|
||||||
d.models.addTemplate(m, t)
|
mm.addTemplate(m, t)
|
||||||
d.models.save(m)
|
mm.save(m)
|
||||||
# create a new fact; it should have 4 cards
|
# create a new fact; it should have 3 cards
|
||||||
f = d.newFact()
|
f = d.newFact()
|
||||||
f['Front'] = "1"; f['Back'] = "1"
|
f['Front'] = "1"; f['Back'] = "1"
|
||||||
d.addFact(f)
|
d.addFact(f)
|
||||||
|
|
Loading…
Reference in a new issue