diff --git a/anki/deck.py b/anki/deck.py index 32305f572..07bcbb244 100644 --- a/anki/deck.py +++ b/anki/deck.py @@ -268,20 +268,19 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""", # Card creation ########################################################################## - def findTemplates(self, fact, checkActive=True): + def findTemplates(self, fact): "Return (active), non-empty templates." ok = [] model = fact.model() avail = self.models.availOrds(model, joinFields(fact.fields)) ok = [] for t in model['tmpls']: - if t['actv'] or not checkActive: - if t['ord'] in avail: - ok.append(t) + if t['ord'] in avail: + ok.append(t) return ok - def genCards(self, fids, limit=None): - "Generate cards for active or limited, non-empty templates." + def genCards(self, fids): + "Generate cards for non-empty templates." # build map of (fid,ord) so we don't create dupes sfids = ids2str(fids) have = {} @@ -297,11 +296,7 @@ crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""", avail = self.models.availOrds(model, flds) ok = [] for t in model['tmpls']: - if not limit and not t['actv']: - continue - elif limit and t not in limit: - continue - elif (fid,t['ord']) in have: + if (fid,t['ord']) in have: continue if t['ord'] in avail: 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,"")""", 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 2 - when previewing in models dialog, all + # type 2 - when previewing in models dialog, all templates def previewCards(self, fact, type=0): - "Return uncommited cards for preview." if type == 0: - cms = self.findTemplates(fact, checkActive=True) + cms = self.findTemplates(fact) elif type == 1: cms = [c.template() for c in fact.cards()] else: diff --git a/anki/media.py b/anki/media.py index f68501a1e..140a5b608 100644 --- a/anki/media.py +++ b/anki/media.py @@ -84,7 +84,7 @@ If the same name exists, compare checksums.""" # String manipulation ########################################################################## - def files(self, mid, string, includeRemote=False): + def filesInStr(self, mid, string, includeRemote=False): l = [] # convert latex first model = self.deck.models.get(mid) @@ -161,7 +161,7 @@ If the same name exists, compare checksums.""" "Return a set of all referenced filenames." files = set() 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) return files diff --git a/anki/models.py b/anki/models.py index 411a349f1..a20778c78 100644 --- a/anki/models.py +++ b/anki/models.py @@ -51,7 +51,6 @@ defaultField = { defaultTemplate = { 'name': "", 'ord': None, - 'actv': True, 'qfmt': "", 'afmt': "", 'hideQ': False, @@ -74,13 +73,15 @@ class ModelManager(object): self.changed = False 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." if m: m['mod'] = intTime() m['usn'] = self.deck.usn() m['css'] = self._css(m) self._updateRequired(m) + if gencards: + self.deck.genCards(self.fids(m)) self.changed = True def flush(self): diff --git a/anki/stdmodels.py b/anki/stdmodels.py index 15c945d5d..606d4f875 100644 --- a/anki/stdmodels.py +++ b/anki/stdmodels.py @@ -22,11 +22,6 @@ def addBasicModel(deck): t['qfmt'] = "{{" + _("Front") + "}}" t['afmt'] = "{{" + _("Back") + "}}" mm.addTemplate(m, t) - t = mm.newTemplate(_("Reverse")) - t['qfmt'] = "{{" + _("Back") + "}}" - t['afmt'] = "{{" + _("Front") + "}}" - t['actv'] = False - mm.addTemplate(m, t) mm.save(m) return m diff --git a/anki/upgrade.py b/anki/upgrade.py index 893aa1948..41056db3d 100644 --- a/anki/upgrade.py +++ b/anki/upgrade.py @@ -379,13 +379,12 @@ order by ordinal""", mid)): dconf = anki.models.defaultTemplate tmpls = [] for c, row in enumerate(db.all(""" -select name, active, qformat, aformat, questionInAnswer, +select name, qformat, aformat, questionInAnswer, questionAlign, lastFontColour, typeAnswer from cardModels where modelId = ? order by ordinal""", mid)): conf = dconf.copy() (conf['name'], - conf['actv'], conf['qfmt'], conf['afmt'], conf['hideQ'], diff --git a/tests/test_cards.py b/tests/test_cards.py index 7898525db..4b82070f7 100644 --- a/tests/test_cards.py +++ b/tests/test_cards.py @@ -6,15 +6,6 @@ from anki.consts import * from anki.utils import hexifyID 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(): deck = getEmptyDeck() f = deck.newFact() @@ -26,7 +17,7 @@ def test_previewCards(): assert cards[0].ord == 0 # all templates cards = deck.previewCards(f, 2) - assert len(cards) == 2 + assert len(cards) == 1 # add the fact, and test existing preview deck.addFact(f) cards = deck.previewCards(f, 1) diff --git a/tests/test_deck.py b/tests/test_deck.py index 8f5e88c29..8862716f3 100644 --- a/tests/test_deck.py +++ b/tests/test_deck.py @@ -48,19 +48,28 @@ def test_factAddDelete(): f['Front'] = u"one"; f['Back'] = u"two" n = deck.addFact(f) assert n == 1 - deck.rollback() - assert deck.cardCount() == 0 - # try with two cards + # test multiple cards - add another template + m = deck.models.current(); mm = deck.models + 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['Front'] = u"one"; f['Back'] = u"two" - m = f.model() - m['tmpls'][1]['actv'] = True - deck.models.save(m) + f['Front'] = u"three"; f['Back'] = u"four" n = deck.addFact(f) assert n == 2 + assert deck.cardCount() == 4 # check q/a generation c0 = f.cards()[0] - assert re.sub("", "", c0.q()) == u"one" + assert re.sub("", "", c0.q()) == u"three" # it should not be a duplicate for p in f.problems(): assert not p @@ -74,15 +83,15 @@ def test_factAddDelete(): # try delete the first card cards = f.cards() id1 = cards[0].id; id2 = cards[1].id - assert deck.cardCount() == 2 - assert deck.factCount() == 1 + assert deck.cardCount() == 4 + assert deck.factCount() == 2 deck.remCards([id1]) - assert deck.cardCount() == 1 - assert deck.factCount() == 1 + assert deck.cardCount() == 3 + assert deck.factCount() == 2 # and the second should clear the fact deck.remCards([id2]) - assert deck.cardCount() == 0 - assert deck.factCount() == 0 + assert deck.cardCount() == 2 + assert deck.factCount() == 1 def test_fieldChecksum(): deck = getEmptyDeck() diff --git a/tests/test_find.py b/tests/test_find.py index 08f8aede4..4ab77737e 100644 --- a/tests/test_find.py +++ b/tests/test_find.py @@ -25,7 +25,12 @@ def test_findCards(): f = deck.newFact() f['Front'] = u'template test' 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) latestCardIds = [c.id for c in f.cards()] # tag searches diff --git a/tests/test_latex.py b/tests/test_latex.py index e2b71ff42..09978703f 100644 --- a/tests/test_latex.py +++ b/tests/test_latex.py @@ -21,7 +21,8 @@ def test_latex(): assert "executing latex" in msg assert "installed" in msg # 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" return # fix path @@ -30,10 +31,11 @@ def test_latex(): d.media.check() assert len(os.listdir(d.media.dir())) == 1 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['Front'] = u"[latex]world[/latex]" d.addFact(f) + f.cards()[0].q() assert len(os.listdir(d.media.dir())) == 2 # another fact with the same media should reuse f = d.newFact() diff --git a/tests/test_media.py b/tests/test_media.py index 35683a411..42a973c2f 100644 --- a/tests/test_media.py +++ b/tests/test_media.py @@ -21,7 +21,7 @@ def test_add(): def test_strings(): d = getEmptyDeck() - mf = d.media.files + mf = d.media.filesInStr mid = d.models.models.keys()[0] assert mf(mid, "aoeu") == [] assert mf(mid, "aoeuao") == ["foo.jpg"] diff --git a/tests/test_models.py b/tests/test_models.py index 7b6273b49..332856fbd 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -22,8 +22,8 @@ def test_modelCopy(): assert len(m2['flds']) == 2 assert len(m['flds']) == 2 assert len(m2['flds']) == len(m['flds']) - assert len(m['tmpls']) == 2 - assert len(m2['tmpls']) == 2 + assert len(m['tmpls']) == 1 + assert len(m2['tmpls']) == 1 assert deck.models.scmhash(m) == deck.models.scmhash(m2) def test_fields(): @@ -75,9 +75,12 @@ def test_fields(): def test_templates(): d = getEmptyDeck() - m = d.models.current() - m['tmpls'][1]['actv'] = True - d.models.save(m) + m = d.models.current(); mm = d.models + t = mm.newTemplate("Reverse") + t['qfmt'] = "{{Back}}" + t['afmt'] = "{{Front}}" + mm.addTemplate(m, t) + mm.save(m) f = d.newFact() f['Front'] = u'1' f['Back'] = u'2' @@ -177,8 +180,12 @@ def test_modelChange(): basic = deck.models.byName("Basic") cloze = deck.models.byName("Cloze") # enable second template and add a fact - basic['tmpls'][1]['actv'] = True - deck.models.save(basic) + m = deck.models.current(); mm = deck.models + t = mm.newTemplate("Reverse") + t['qfmt'] = "{{Back}}" + t['afmt'] = "{{Front}}" + mm.addTemplate(m, t) + mm.save(m) f = deck.newFact() f['Front'] = u'f' f['Back'] = u'b' diff --git a/tests/test_remote_sync.py b/tests/test_remote_sync.py index f627ec031..f3598b525 100644 --- a/tests/test_remote_sync.py +++ b/tests/test_remote_sync.py @@ -27,7 +27,7 @@ import anki.sync anki.sync.SYNC_URL = "http://localhost:6543/sync/" TEST_USER = "synctest@ichi2.net" TEST_PASS = "synctest" -TEST_HKEY = "k14LvSaEtXFITCJz" +TEST_HKEY = "tG5CD9eZbWOru3Yw" TEST_REMOTE = True def setup_remote(): @@ -42,7 +42,7 @@ def test_meta(): global TEST_REMOTE try: (mod, scm, usn, tstamp, dummy) = ts.server.meta() - except SyntaxError, e: + except Exception, e: if e.errno == 61: TEST_REMOTE = False print "aborting; server offline" @@ -107,6 +107,8 @@ def setup_remoteMedia(): @nose.with_setup(setup_remoteMedia) def test_media(): + if not TEST_REMOTE: + return ts.server.mediatest("reset") assert len(os.listdir(ts.deck1.media.dir())) == 0 assert ts.server.mediatest("count") == 0 diff --git a/tests/test_sched.py b/tests/test_sched.py index 27c506a95..e4292df53 100644 --- a/tests/test_sched.py +++ b/tests/test_sched.py @@ -32,9 +32,12 @@ def test_new(): assert c.due >= t # the default order should ensure siblings are not seen together, and # should show all cards - m = d.models.current() - m['tmpls'][1]['actv'] = True - d.models.save(m) + m = d.models.current(); mm = d.models + t = mm.newTemplate("Reverse") + t['qfmt'] = "{{Back}}" + t['afmt'] = "{{Front}}" + mm.addTemplate(m, t) + mm.save(m) f = d.newFact() f['Front'] = u"2"; f['Back'] = u"2" d.addFact(f) @@ -517,8 +520,12 @@ def test_cramLimits(): def test_adjIvl(): d = getEmptyDeck() # add two more templates and set second active - m = d.models.current() - m['tmpls'][1]['actv'] = True + m = d.models.current(); mm = d.models + t = mm.newTemplate("Reverse") + t['qfmt'] = "{{Back}}" + t['afmt'] = "{{Front}}" + mm.addTemplate(m, t) + mm.save(m) t = d.models.newTemplate(m) t['name'] = "f2" t['qfmt'] = "{{Front}}" @@ -582,15 +589,17 @@ def test_adjIvl(): def test_ordcycle(): d = getEmptyDeck() # add two more templates and set second active - m = d.models.current() - m['tmpls'][1]['actv'] = True - t = d.models.newTemplate(m) - t['name'] = "f2" + m = d.models.current(); mm = d.models + t = mm.newTemplate("Reverse") + t['qfmt'] = "{{Back}}" + t['afmt'] = "{{Front}}" + mm.addTemplate(m, t) + t = mm.newTemplate("f2") t['qfmt'] = "{{Front}}" t['afmt'] = "{{Back}}" - d.models.addTemplate(m, t) - d.models.save(m) - # create a new fact; it should have 4 cards + mm.addTemplate(m, t) + mm.save(m) + # create a new fact; it should have 3 cards f = d.newFact() f['Front'] = "1"; f['Back'] = "1" d.addFact(f)