mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
top level groups
As discussed on the forums, moving to a single collection requires moving some deck-level configuration into groups so users can have different settings like new cards/day for each top level item. Also: - store id in groups - add mod time to gconf updates - move the limiting code that's not specific to scheduling into groups.py - store the current model id per top level group
This commit is contained in:
parent
5179d82f7f
commit
de8a5b69ed
11 changed files with 175 additions and 104 deletions
20
anki/deck.py
20
anki/deck.py
|
@ -20,19 +20,12 @@ import anki.cards, anki.facts, anki.template, anki.cram, anki.find
|
|||
|
||||
defaultConf = {
|
||||
# scheduling options
|
||||
'groups': [],
|
||||
'newPerDay': 20,
|
||||
'newToday': [0, 0], # currentDay, count
|
||||
'newTodayOrder': NEW_TODAY_ORD,
|
||||
'newOrder': NEW_CARDS_DUE,
|
||||
'newSpread': NEW_CARDS_DISTRIBUTE,
|
||||
'activeGroups': [],
|
||||
'topGroup': 1,
|
||||
'curGroup': None,
|
||||
'revOrder': REV_CARDS_RANDOM,
|
||||
'collapseTime': 1200,
|
||||
'repLim': 0,
|
||||
'timeLim': 600,
|
||||
# other config
|
||||
'nextPos': 1,
|
||||
'mediaURL': "",
|
||||
'fontFamilies': [
|
||||
[u'MS 明朝',u'ヒラギノ明朝 Pro W3',u'Kochi Mincho', u'東風明朝']
|
||||
],
|
||||
|
@ -228,7 +221,7 @@ crt=?, mod=?, scm=?, dty=?, syncName=?, lastSync=?, conf=?""",
|
|||
return 0
|
||||
fact.flush()
|
||||
# randomize?
|
||||
if self.randomNew():
|
||||
if self.models.randomNew():
|
||||
due = self._randPos()
|
||||
else:
|
||||
due = self.nextID("pos")
|
||||
|
@ -284,7 +277,7 @@ crt=?, mod=?, scm=?, dty=?, syncName=?, lastSync=?, conf=?""",
|
|||
"Generate cards for templates if cards not empty. Return cards."
|
||||
cards = []
|
||||
# if random mode, determine insertion point
|
||||
if self.randomNew():
|
||||
if self.models.randomNew():
|
||||
# if this fact has existing new cards, use their due time
|
||||
due = self.db.scalar(
|
||||
"select due from cards where fid = ? and queue = 0", fact.id)
|
||||
|
@ -331,9 +324,6 @@ crt=?, mod=?, scm=?, dty=?, syncName=?, lastSync=?, conf=?""",
|
|||
card.flush()
|
||||
return card
|
||||
|
||||
def randomNew(self):
|
||||
return self.conf['newOrder'] == NEW_CARDS_RANDOM
|
||||
|
||||
# Cards
|
||||
##########################################################################
|
||||
|
||||
|
|
|
@ -4,7 +4,27 @@
|
|||
|
||||
import simplejson
|
||||
from anki.utils import intTime
|
||||
from anki.consts import *
|
||||
|
||||
# fixmes:
|
||||
# - make sure lists like new[delays] are not being shared by multiple groups
|
||||
# - make sure all children have parents (create as necessary)
|
||||
# - when renaming a group, top level properties should be added or removed as
|
||||
# appropriate
|
||||
|
||||
# configuration only available to top level groups
|
||||
defaultTopConf = {
|
||||
'newPerDay': 20,
|
||||
'newToday': [0, 0], # currentDay, count
|
||||
'newTodayOrder': NEW_TODAY_ORD,
|
||||
'newSpread': NEW_CARDS_DISTRIBUTE,
|
||||
'collapseTime': 1200,
|
||||
'repLim': 0,
|
||||
'timeLim': 600,
|
||||
'curModel': None,
|
||||
}
|
||||
|
||||
# configuration available to all groups
|
||||
defaultConf = {
|
||||
'new': {
|
||||
'delays': [1, 10],
|
||||
|
@ -33,11 +53,7 @@ defaultConf = {
|
|||
'minSpace': 1,
|
||||
},
|
||||
'maxTaken': 60,
|
||||
}
|
||||
|
||||
defaultData = {
|
||||
'activeTags': None,
|
||||
'inactiveTags': None,
|
||||
'mod': 0,
|
||||
}
|
||||
|
||||
class GroupManager(object):
|
||||
|
@ -54,6 +70,7 @@ class GroupManager(object):
|
|||
self.changed = False
|
||||
|
||||
def save(self, g):
|
||||
"Can be called with either a group or a group configuration."
|
||||
g['mod'] = intTime()
|
||||
self.changed = True
|
||||
|
||||
|
@ -73,12 +90,20 @@ class GroupManager(object):
|
|||
return int(id)
|
||||
if not create:
|
||||
return None
|
||||
g = dict(name=name, conf=1, mod=intTime())
|
||||
if "::" not in name:
|
||||
# if it's a top level group, it gets the top level config
|
||||
g = defaultTopConf.copy()
|
||||
else:
|
||||
# not top level. calling code should ensure parents already exist?
|
||||
g = {}
|
||||
g['name'] = name
|
||||
g['conf'] = 1
|
||||
while 1:
|
||||
id = str(intTime(1000))
|
||||
if id in self.groups:
|
||||
id = intTime(1000)
|
||||
if str(id) in self.groups:
|
||||
continue
|
||||
self.groups[id] = g
|
||||
g['id'] = id
|
||||
self.groups[str(id)] = g
|
||||
self.save(g)
|
||||
return int(id)
|
||||
|
||||
|
@ -89,11 +114,15 @@ class GroupManager(object):
|
|||
self.deck.db.execute("delete from groups where id = ?", gid)
|
||||
print "fixme: loop through models and update stale gid references"
|
||||
|
||||
def all(self):
|
||||
def allNames(self):
|
||||
"An unsorted list of all group names."
|
||||
return [x['name'] for x in self.groups.values()]
|
||||
|
||||
# Utils
|
||||
def all(self):
|
||||
"A list of all groups."
|
||||
return self.groups.values()
|
||||
|
||||
# Group utils
|
||||
#############################################################
|
||||
|
||||
def name(self, gid):
|
||||
|
@ -102,6 +131,46 @@ class GroupManager(object):
|
|||
def conf(self, gid):
|
||||
return self.gconf[str(self.groups[str(gid)]['conf'])]
|
||||
|
||||
def get(self, gid):
|
||||
return self.groups[str(gid)]
|
||||
|
||||
def setGroup(self, cids, gid):
|
||||
self.db.execute(
|
||||
"update cards set gid = ? where id in "+ids2str(cids), gid)
|
||||
|
||||
# Group selection
|
||||
#############################################################
|
||||
|
||||
def top(self):
|
||||
"The current top level group as an object, and marks as modified."
|
||||
g = self.get(self.deck.conf['topGroup'])
|
||||
self.save(g)
|
||||
return g
|
||||
|
||||
def active(self):
|
||||
"The currrently active gids."
|
||||
return self.deck.conf['activeGroups']
|
||||
|
||||
def selected(self):
|
||||
"The currently selected gid, or None if whole collection."
|
||||
return self.deck.conf['curGroup']
|
||||
|
||||
def select(self, gid):
|
||||
"Select a new group. If gid is None, select whole collection."
|
||||
if not gid:
|
||||
self.deck.conf['topGroup'] = 1
|
||||
self.deck.conf['curGroup'] = None
|
||||
self.deck.conf['activeGroups'] = []
|
||||
return
|
||||
# save the top level group
|
||||
name = self.groups[str(gid)]['name']
|
||||
path = name.split("::")
|
||||
self.deck.conf['topGroup'] = self.id(path[0])
|
||||
# current group
|
||||
self.deck.conf['curGroup'] = gid
|
||||
# and active groups (current + all children)
|
||||
actv = [gid]
|
||||
for g in self.all():
|
||||
if g['name'].startswith(name + "::"):
|
||||
actv.append(g['id'])
|
||||
self.deck.conf['activeGroups'] = actv
|
||||
|
|
|
@ -6,6 +6,7 @@ import simplejson, copy
|
|||
from anki.utils import intTime, hexifyID, joinFields, splitFields, ids2str, \
|
||||
timestampID
|
||||
from anki.lang import _
|
||||
from anki.consts import *
|
||||
|
||||
# Models
|
||||
##########################################################################
|
||||
|
@ -16,6 +17,7 @@ defaultModel = {
|
|||
'sortf': 0,
|
||||
'gid': 1,
|
||||
'clozectx': False,
|
||||
'newOrder': NEW_CARDS_DUE,
|
||||
'latexPre': """\
|
||||
\\documentclass[12pt]{article}
|
||||
\\special{papersize=3in,5in}
|
||||
|
@ -87,7 +89,13 @@ class ModelManager(object):
|
|||
|
||||
def current(self):
|
||||
"Get current model."
|
||||
return self.get(self.deck.conf['currentModelId'])
|
||||
try:
|
||||
return self.get(self.deck.groups.top()['curModel'])
|
||||
except:
|
||||
return self.models.values()[0]
|
||||
|
||||
def setCurrent(self, m):
|
||||
self.deck.groups.top()['curModel'] = m['id']
|
||||
|
||||
def get(self, id):
|
||||
"Get model with ID."
|
||||
|
@ -117,6 +125,7 @@ class ModelManager(object):
|
|||
def rem(self, m):
|
||||
"Delete model, and all its cards/facts."
|
||||
self.deck.modSchema()
|
||||
current = self.current()['id'] == m['id']
|
||||
# delete facts/cards
|
||||
self.deck.remCards(self.deck.db.list("""
|
||||
select id from cards where fid in (select id from facts where mid = ?)""",
|
||||
|
@ -125,14 +134,14 @@ select id from cards where fid in (select id from facts where mid = ?)""",
|
|||
del self.models[m['id']]
|
||||
self.save()
|
||||
# GUI should ensure last model is not deleted
|
||||
if self.deck.conf['currentModelId'] == m['id']:
|
||||
self.deck.conf['currentModelId'] = int(self.models.keys()[0])
|
||||
if current:
|
||||
self.setCurrent(self.models.values()[0])
|
||||
|
||||
def _add(self, m):
|
||||
self._setID(m)
|
||||
self.models[m['id']] = m
|
||||
self.save(m)
|
||||
self.deck.conf['currentModelId'] = m['id']
|
||||
self.setCurrent(m)
|
||||
return m
|
||||
|
||||
def _setID(self, m):
|
||||
|
@ -155,6 +164,9 @@ select id from cards where fid in (select id from facts where mid = ?)""",
|
|||
return self.deck.db.scalar(
|
||||
"select count() from facts where mid = ?", m['id'])
|
||||
|
||||
def randomNew(self):
|
||||
return self.current()['newOrder'] == NEW_CARDS_RANDOM
|
||||
|
||||
# Copying
|
||||
##################################################
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ class Scheduler(object):
|
|||
# put it in the learn queue
|
||||
card.queue = 1
|
||||
card.type = 1
|
||||
self.deck.conf['newToday'][1] += 1
|
||||
self.deck.groups.top()['newToday'][1] += 1
|
||||
if card.queue == 1:
|
||||
self._answerLrnCard(card, ease)
|
||||
elif card.queue == 2:
|
||||
|
@ -98,20 +98,6 @@ order by due""" % self._groupLimit(),
|
|||
# Counts
|
||||
##########################################################################
|
||||
|
||||
def selCounts(self):
|
||||
"Return counts for selected groups, without building queue."
|
||||
self._resetCounts()
|
||||
return self.counts()
|
||||
|
||||
def allCounts(self):
|
||||
"Return counts for all groups, without building queue."
|
||||
conf = self.deck.conf['groups']
|
||||
if conf:
|
||||
self.deck.conf['groups'] = []
|
||||
self._resetCounts()
|
||||
self.deck.conf['groups'] = conf
|
||||
return self.counts()
|
||||
|
||||
def _resetCounts(self):
|
||||
self._updateCutoff()
|
||||
self._resetLrnCount()
|
||||
|
@ -212,7 +198,7 @@ from cards group by gid""", self.today):
|
|||
# FIXME: need to keep track of reps for timebox and new card introduction
|
||||
|
||||
def _resetNewCount(self):
|
||||
l = self.deck.conf
|
||||
l = self.deck.groups.top()
|
||||
if l['newToday'][0] != self.today:
|
||||
# it's a new day; reset counts
|
||||
l['newToday'] = [self.today, 0]
|
||||
|
@ -241,7 +227,7 @@ queue = 0 %s order by due limit %d""" % (self._groupLimit(),
|
|||
if self.newQueue:
|
||||
(id, due) = self.newQueue.pop()
|
||||
# move any siblings to the end?
|
||||
if self.deck.conf['newTodayOrder'] == NEW_TODAY_ORD:
|
||||
if self.deck.groups.top()['newTodayOrder'] == NEW_TODAY_ORD:
|
||||
n = len(self.newQueue)
|
||||
while self.newQueue and self.newQueue[-1][1] == due:
|
||||
self.newQueue.insert(0, self.newQueue.pop())
|
||||
|
@ -253,7 +239,7 @@ queue = 0 %s order by due limit %d""" % (self._groupLimit(),
|
|||
return id
|
||||
|
||||
def _updateNewCardRatio(self):
|
||||
if self.deck.conf['newSpread'] == NEW_CARDS_DISTRIBUTE:
|
||||
if self.deck.groups.top()['newSpread'] == NEW_CARDS_DISTRIBUTE:
|
||||
if self.newCount:
|
||||
self.newCardModulus = (
|
||||
(self.newCount + self.revCount) / self.newCount)
|
||||
|
@ -267,9 +253,9 @@ queue = 0 %s order by due limit %d""" % (self._groupLimit(),
|
|||
"True if it's time to display a new card when distributing."
|
||||
if not self.newCount:
|
||||
return False
|
||||
if self.deck.conf['newSpread'] == NEW_CARDS_LAST:
|
||||
if self.deck.groups.top()['newSpread'] == NEW_CARDS_LAST:
|
||||
return False
|
||||
elif self.deck.conf['newSpread'] == NEW_CARDS_FIRST:
|
||||
elif self.deck.groups.top()['newSpread'] == NEW_CARDS_FIRST:
|
||||
return True
|
||||
elif self.newCardModulus:
|
||||
return self.reps and self.reps % self.newCardModulus == 0
|
||||
|
@ -282,7 +268,7 @@ queue = 0 %s order by due limit %d""" % (self._groupLimit(),
|
|||
select count() from (select id from cards where
|
||||
queue = 1 %s and due < ? limit %d)""" % (
|
||||
self._groupLimit(), self.reportLimit),
|
||||
intTime() + self.deck.conf['collapseTime'])
|
||||
intTime() + self.deck.groups.top()['collapseTime'])
|
||||
|
||||
def _resetLrn(self):
|
||||
self.lrnQueue = self.deck.db.all("""
|
||||
|
@ -294,7 +280,7 @@ limit %d""" % (self._groupLimit(), self.reportLimit), lim=self.dayCutoff)
|
|||
if self.lrnQueue:
|
||||
cutoff = time.time()
|
||||
if collapse:
|
||||
cutoff += self.deck.conf['collapseTime']
|
||||
cutoff += self.deck.groups.top()['collapseTime']
|
||||
if self.lrnQueue[0][0] < cutoff:
|
||||
id = heappop(self.lrnQueue)[1]
|
||||
self.lrnCount -= 1
|
||||
|
@ -327,7 +313,7 @@ limit %d""" % (self._groupLimit(), self.reportLimit), lim=self.dayCutoff)
|
|||
card.due = int(time.time() + delay)
|
||||
heappush(self.lrnQueue, (card.due, card.id))
|
||||
# if it's due within the cutoff, increment count
|
||||
if delay <= self.deck.conf['collapseTime']:
|
||||
if delay <= self.deck.groups.top()['collapseTime']:
|
||||
self.lrnCount += 1
|
||||
self._logLrn(card, ease, conf, leaving, type)
|
||||
|
||||
|
@ -578,7 +564,7 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
|
|||
return self.deck.groups.conf(card.gid)
|
||||
|
||||
def _groupLimit(self):
|
||||
l = self.deck.conf['groups']
|
||||
l = self.deck.groups.active()
|
||||
if not l:
|
||||
# everything
|
||||
return ""
|
||||
|
@ -605,16 +591,10 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
|
|||
def finishedMsg(self):
|
||||
return (
|
||||
"<h1>"+_("Congratulations!")+"</h1>"+
|
||||
self._finishedSubtitle()+
|
||||
_("You have finished the selected groups for now.") +
|
||||
"<br><br>"+
|
||||
self._nextDueMsg())
|
||||
|
||||
def _finishedSubtitle(self):
|
||||
if self.deck.conf['groups']:
|
||||
return _("You have finished the selected groups for now.")
|
||||
else:
|
||||
return _("You have finished the deck for now.")
|
||||
|
||||
def _nextDueMsg(self):
|
||||
line = []
|
||||
rev = self.revTomorrow() + self.lrnTomorrow()
|
||||
|
@ -650,7 +630,7 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
|
|||
|
||||
def newTomorrow(self):
|
||||
"Number of new cards tomorrow."
|
||||
lim = self.deck.conf['newPerDay']
|
||||
lim = self.deck.groups.top()['newPerDay']
|
||||
return self.deck.db.scalar(
|
||||
"select count() from (select id from cards where "
|
||||
"queue = 0 %s limit %d)" % (self._groupLimit(), lim))
|
||||
|
@ -764,7 +744,7 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
|
|||
self.deck.db.execute(
|
||||
"update cards set type=0, queue=0, ivl=0 where id in "+ids2str(ids))
|
||||
pmax = self.deck.db.scalar("select max(due) from cards where type=0")
|
||||
self.sortCards(ids, start=pmax+1, shuffle=self.deck.randomNew())
|
||||
self.sortCards(ids, start=pmax+1, shuffle=self.deck.models.randomNew())
|
||||
|
||||
def reschedCards(self, ids, imin, imax):
|
||||
"Put cards in review queue with a new interval in days (min, max)."
|
||||
|
@ -816,6 +796,8 @@ and due >= ?""" % scids, now, shiftby, low)
|
|||
self.deck.db.executemany(
|
||||
"update cards set due = :due, mod = :now where id = :cid""", d)
|
||||
|
||||
# fixme: because it's a model property now, these should be done on a
|
||||
# per-model basis
|
||||
def randomizeCards(self):
|
||||
self.sortCards(self.deck.db.list("select id from cards"), shuffle=True)
|
||||
|
||||
|
|
|
@ -675,7 +675,7 @@ $(function () {
|
|||
return ""
|
||||
|
||||
def _revlogLimit(self):
|
||||
lim = self.deck.conf['groups']
|
||||
lim = self.deck.groups.active()
|
||||
if self.selective and lim:
|
||||
return ("cid in (select id from cards where gid in %s)" %
|
||||
ids2str(lim))
|
||||
|
|
|
@ -131,11 +131,15 @@ values(1,0,0,0,%(v)s,0,'',0,'','{}','','','{}');
|
|||
import anki.deck
|
||||
import anki.groups
|
||||
if setDeckConf:
|
||||
g = anki.groups.defaultTopConf.copy()
|
||||
g['id'] = 1
|
||||
g['name'] = _("Default")
|
||||
g['conf'] = 1
|
||||
g['mod'] = intTime()
|
||||
db.execute("""
|
||||
update deck set conf = ?, groups = ?, gconf = ?""",
|
||||
simplejson.dumps(anki.deck.defaultConf),
|
||||
simplejson.dumps({'1': {'name': _("Default"), 'conf': 1,
|
||||
'mod': intTime()}}),
|
||||
simplejson.dumps({'1': g}),
|
||||
simplejson.dumps({'1': anki.groups.defaultConf}))
|
||||
|
||||
def _updateIndices(db):
|
||||
|
@ -339,28 +343,29 @@ def _migrateDeckTbl(db):
|
|||
insert or replace into deck select id, cast(created as int), :t,
|
||||
:t, 99, 0, ifnull(syncName, ""), cast(lastSync as int),
|
||||
"", "", "", "", "" from decks""", t=intTime())
|
||||
# update selective study
|
||||
# prepare a group to store the old deck options
|
||||
import anki.groups
|
||||
g = anki.groups.defaultTopConf.copy()
|
||||
g['id'] = 1
|
||||
g['name'] = _("Default")
|
||||
g['conf'] = 1
|
||||
g['mod'] = intTime()
|
||||
# and deck conf
|
||||
conf = anki.deck.defaultConf.copy()
|
||||
# delete old selective study settings, which we can't auto-upgrade easily
|
||||
keys = ("newActive", "newInactive", "revActive", "revInactive")
|
||||
for k in keys:
|
||||
db.execute("delete from deckVars where key=:k", k=k)
|
||||
# copy other settings, ignoring deck order as there's a new default
|
||||
conf['newSpread'] = db.scalar(
|
||||
"select newCardSpacing from decks")
|
||||
conf['newOrder'] = db.scalar(
|
||||
"select newCardOrder from decks")
|
||||
conf['newPerDay'] = db.scalar(
|
||||
"select newCardsPerDay from decks")
|
||||
# fetch remaining settings from decks table
|
||||
data = {}
|
||||
keys = ("sessionRepLimit", "sessionTimeLimit")
|
||||
for k in keys:
|
||||
conf[k] = db.scalar("select %s from decks" % k)
|
||||
# random and due options merged
|
||||
conf['revOrder'] = 2
|
||||
g['newSpread'] = db.scalar("select newCardSpacing from decks")
|
||||
g['newPerDay'] = db.scalar("select newCardsPerDay from decks")
|
||||
g['repLim'] = db.scalar("select sessionRepLimit from decks")
|
||||
g['timeLim'] = db.scalar("select sessionTimeLimit from decks")
|
||||
|
||||
# this needs to be placed in the model later on
|
||||
conf['oldNewOrder'] = db.scalar("select newCardOrder from decks")
|
||||
# no reverse option anymore
|
||||
conf['newOrder'] = min(1, conf['newOrder'])
|
||||
conf['oldNewOrder'] = min(1, conf['oldNewOrder'])
|
||||
# add any deck vars and save
|
||||
dkeys = ("hexCache", "cssCache")
|
||||
for (k, v) in db.execute("select * from deckVars").fetchall():
|
||||
|
@ -368,10 +373,9 @@ insert or replace into deck select id, cast(created as int), :t,
|
|||
pass
|
||||
else:
|
||||
conf[k] = v
|
||||
import anki.groups
|
||||
db.execute("update deck set conf=:c,groups=:g,gconf=:gc",
|
||||
c=simplejson.dumps(conf),
|
||||
g=simplejson.dumps({'1': {'name': _("Default"), 'conf': 1}}),
|
||||
g=simplejson.dumps({'1': g}),
|
||||
gc=simplejson.dumps({'1': anki.groups.defaultConf}))
|
||||
# clean up
|
||||
db.execute("drop table decks")
|
||||
|
@ -479,10 +483,12 @@ def _postSchemaUpgrade(deck):
|
|||
"Handle the rest of the upgrade to 2.0."
|
||||
import anki.deck
|
||||
# make sure we have a current model id
|
||||
deck.conf['currentModelId'] = deck.models.models.keys()[0]
|
||||
# regenerate css
|
||||
deck.models.setCurrent(deck.models.models.values()[0])
|
||||
# regenerate css, and set new card order
|
||||
for m in deck.models.all():
|
||||
m['newOrder'] = deck.conf['oldNewOrder']
|
||||
deck.models.save(m)
|
||||
del deck.conf['oldNewOrder']
|
||||
# fix creation time
|
||||
deck.sched._updateCutoff()
|
||||
d = datetime.datetime.today()
|
||||
|
@ -521,7 +527,7 @@ update cards set due = cast(
|
|||
((due-:stamp)/86400) as int)+:today where type = 2
|
||||
""", stamp=deck.sched.dayCutoff, today=deck.sched.today)
|
||||
# possibly re-randomize
|
||||
if deck.randomNew():
|
||||
if deck.models.randomNew():
|
||||
deck.sched.randomizeCards()
|
||||
# update insertion id
|
||||
deck.conf['nextPos'] = deck.db.scalar("select max(id) from facts")+1
|
||||
|
|
|
@ -18,7 +18,7 @@ def test_genCards():
|
|||
assert deck.cardCount() == 2
|
||||
assert cards[0].due == f.id
|
||||
# should work on random mode too
|
||||
deck.conf['newOrder'] = NEW_CARDS_RANDOM
|
||||
deck.models.current()['newOrder'] = NEW_CARDS_RANDOM
|
||||
f = deck.newFact()
|
||||
f['Front'] = u'1'
|
||||
f['Back'] = u'2'
|
||||
|
@ -74,6 +74,6 @@ def test_misc():
|
|||
f['Back'] = u'2'
|
||||
d.addFact(f)
|
||||
c = f.cards()[0]
|
||||
id = d.conf['currentModelId']
|
||||
id = d.models.current()['id']
|
||||
assert c.cssClass() == "cm%s-0" % hexifyID(id)
|
||||
assert c.template()['ord'] == 0
|
||||
|
|
|
@ -137,13 +137,30 @@ def test_groups():
|
|||
# it should have an id of 1
|
||||
assert deck.groups.name(1)
|
||||
# create a new group
|
||||
g = deck.groups.id("new group")
|
||||
assert g
|
||||
parentId = deck.groups.id("new group")
|
||||
assert parentId
|
||||
assert len(deck.groups.groups) == 2
|
||||
# should get the same id
|
||||
assert deck.groups.id("new group") == g
|
||||
assert deck.groups.id("new group") == parentId
|
||||
# by default, everything should be shown
|
||||
assert not deck.conf['groups']
|
||||
assert not deck.groups.selected()
|
||||
assert not deck.groups.active()
|
||||
# and the default group is used
|
||||
assert deck.groups.top()['id'] == 1
|
||||
# we can select the default explicitly
|
||||
deck.groups.select(1)
|
||||
assert deck.groups.selected() == 1
|
||||
assert deck.groups.active() == [1]
|
||||
assert deck.groups.top()['id'] == 1
|
||||
# let's create a child and select that
|
||||
childId = deck.groups.id("new group::child")
|
||||
deck.groups.select(childId)
|
||||
assert deck.groups.selected() == childId
|
||||
assert deck.groups.active() == [childId]
|
||||
assert deck.groups.top()['id'] == parentId
|
||||
# if we select the parent, the child gets included
|
||||
deck.groups.select(parentId)
|
||||
assert sorted(deck.groups.active()) == [parentId, childId]
|
||||
|
||||
def test_selective():
|
||||
deck = getEmptyDeck()
|
||||
|
|
|
@ -10,7 +10,7 @@ def test_modelDelete():
|
|||
f['Back'] = u'2'
|
||||
deck.addFact(f)
|
||||
assert deck.cardCount() == 1
|
||||
deck.models.rem(deck.models.get(deck.conf['currentModelId']))
|
||||
deck.models.rem(deck.models.current())
|
||||
assert deck.cardCount() == 0
|
||||
|
||||
def test_modelCopy():
|
||||
|
@ -109,7 +109,7 @@ def test_text():
|
|||
|
||||
def test_cloze():
|
||||
d = getEmptyDeck()
|
||||
d.conf['currentModelId'] = d.models.byName("Cloze")['id']
|
||||
d.models.setCurrent(d.models.byName("Cloze"))
|
||||
f = d.newFact()
|
||||
assert f.model()['name'] == "Cloze"
|
||||
# a cloze model with no clozes is empty
|
||||
|
|
|
@ -581,11 +581,11 @@ def test_ordcycle():
|
|||
def test_counts():
|
||||
d = getEmptyDeck()
|
||||
# add a second group
|
||||
assert d.groups.id("new group")
|
||||
grp = d.groups.id("new group")
|
||||
# for each card type
|
||||
for type in range(3):
|
||||
# and each of the groups
|
||||
for gid in (1,2):
|
||||
for gid in (1,grp):
|
||||
# create a new fact
|
||||
f = d.newFact()
|
||||
f['Front'] = u"one"
|
||||
|
@ -601,13 +601,9 @@ def test_counts():
|
|||
# with the default settings, there's no count limit
|
||||
assert d.sched.counts() == (2,2,2)
|
||||
# check limit to one group
|
||||
d.conf['groups'] = [1]
|
||||
d.groups.select(1)
|
||||
d.reset()
|
||||
assert d.sched.counts() == (1,1,1)
|
||||
# we don't need to build the queue to get the counts
|
||||
assert d.sched.allCounts() == (2,2,2)
|
||||
assert d.sched.selCounts() == (1,1,1)
|
||||
assert d.sched.allCounts() == (2,2,2)
|
||||
|
||||
def test_counts2():
|
||||
d = getEmptyDeck()
|
||||
|
|
|
@ -7,9 +7,8 @@ def test_op():
|
|||
# should have no undo by default
|
||||
assert not d.undoName()
|
||||
# let's adjust a study option
|
||||
assert d.conf['repLim'] == 0
|
||||
d.save("studyopts")
|
||||
d.conf['repLim'] = 10
|
||||
d.conf['revOrder'] = 5
|
||||
# it should be listed as undoable
|
||||
assert d.undoName() == "studyopts"
|
||||
# with about 5 minutes until it's clobbered
|
||||
|
@ -17,7 +16,7 @@ def test_op():
|
|||
# undoing should restore the old value
|
||||
d.undo()
|
||||
assert not d.undoName()
|
||||
assert d.conf['repLim'] == 0
|
||||
assert d.conf['revOrder'] != 5
|
||||
# an (auto)save will clear the undo
|
||||
d.save("foo")
|
||||
assert d.undoName() == "foo"
|
||||
|
|
Loading…
Reference in a new issue