mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
strip out unused syncing code
This commit is contained in:
parent
8325f5b396
commit
d6874de8c8
2 changed files with 38 additions and 469 deletions
137
anki/sync.py
137
anki/sync.py
|
@ -54,9 +54,6 @@ class Syncer:
|
|||
rts = meta['ts']
|
||||
self.rmod = meta['mod']
|
||||
self.maxUsn = meta['usn']
|
||||
# this is a temporary measure to address the problem of users
|
||||
# forgetting which email address they've used - it will be removed
|
||||
# when enough time has passed
|
||||
self.uname = meta.get("uname", "")
|
||||
meta = self.meta()
|
||||
self.col.log("lmeta", meta)
|
||||
|
@ -143,13 +140,6 @@ class Syncer:
|
|||
d['crt'] = self.col.crt
|
||||
return d
|
||||
|
||||
def applyChanges(self, changes):
|
||||
self.rchg = changes
|
||||
lchg = self.changes()
|
||||
# merge our side before returning
|
||||
self.mergeChanges(lchg, self.rchg)
|
||||
return lchg
|
||||
|
||||
def mergeChanges(self, lchg, rchg):
|
||||
# then the other objects
|
||||
self.mergeModels(rchg['models'])
|
||||
|
@ -177,14 +167,8 @@ class Syncer:
|
|||
return "tag had usn = -1"
|
||||
found = False
|
||||
for m in self.col.models.all():
|
||||
if self.col.server:
|
||||
# the web upgrade was mistakenly setting usn
|
||||
if m['usn'] < 0:
|
||||
m['usn'] = 0
|
||||
found = True
|
||||
else:
|
||||
if m['usn'] == -1:
|
||||
return "model had usn = -1"
|
||||
if m['usn'] == -1:
|
||||
return "model had usn = -1"
|
||||
if found:
|
||||
self.col.models.save()
|
||||
self.col.sched.reset()
|
||||
|
@ -202,22 +186,10 @@ class Syncer:
|
|||
len(self.col.decks.allConf()),
|
||||
]
|
||||
|
||||
def sanityCheck2(self, client):
|
||||
server = self.sanityCheck()
|
||||
if client != server:
|
||||
return dict(status="bad", c=client, s=server)
|
||||
return dict(status="ok")
|
||||
|
||||
def usnLim(self):
|
||||
if self.col.server:
|
||||
return "usn >= %d" % self.minUsn
|
||||
else:
|
||||
return "usn = -1"
|
||||
return "usn = -1"
|
||||
|
||||
def finish(self, mod=None):
|
||||
if not mod:
|
||||
# server side; we decide new mod time
|
||||
mod = intTime(1000)
|
||||
self.col.ls = mod
|
||||
self.col._usn = self.maxUsn + 1
|
||||
# ensure we save the mod time even if no changes made
|
||||
|
@ -262,11 +234,10 @@ from notes where %s""" % d)
|
|||
# table is empty
|
||||
self.tablesLeft.pop(0)
|
||||
self.cursor = None
|
||||
# if we're the client, mark the objects as having been sent
|
||||
if not self.col.server:
|
||||
self.col.db.execute(
|
||||
"update %s set usn=? where usn=-1"%curTable,
|
||||
self.maxUsn)
|
||||
# mark the objects as having been sent
|
||||
self.col.db.execute(
|
||||
"update %s set usn=? where usn=-1"%curTable,
|
||||
self.maxUsn)
|
||||
buf[curTable] = rows
|
||||
lim -= fetched
|
||||
if not self.tablesLeft:
|
||||
|
@ -288,12 +259,10 @@ from notes where %s""" % d)
|
|||
cards = []
|
||||
notes = []
|
||||
decks = []
|
||||
if self.col.server:
|
||||
curs = self.col.db.execute(
|
||||
"select oid, type from graves where usn >= ?", self.minUsn)
|
||||
else:
|
||||
curs = self.col.db.execute(
|
||||
"select oid, type from graves where usn = -1")
|
||||
|
||||
curs = self.col.db.execute(
|
||||
"select oid, type from graves where usn = -1")
|
||||
|
||||
for oid, type in curs:
|
||||
if type == REM_CARD:
|
||||
cards.append(oid)
|
||||
|
@ -301,23 +270,16 @@ from notes where %s""" % d)
|
|||
notes.append(oid)
|
||||
else:
|
||||
decks.append(oid)
|
||||
if not self.col.server:
|
||||
self.col.db.execute("update graves set usn=? where usn=-1",
|
||||
self.maxUsn)
|
||||
return dict(cards=cards, notes=notes, decks=decks)
|
||||
|
||||
def start(self, minUsn, lnewer, graves):
|
||||
self.maxUsn = self.col._usn
|
||||
self.minUsn = minUsn
|
||||
self.lnewer = not lnewer
|
||||
lgraves = self.removed()
|
||||
self.remove(graves)
|
||||
return lgraves
|
||||
self.col.db.execute("update graves set usn=? where usn=-1",
|
||||
self.maxUsn)
|
||||
|
||||
return dict(cards=cards, notes=notes, decks=decks)
|
||||
|
||||
def remove(self, graves):
|
||||
# pretend to be the server so we don't set usn = -1
|
||||
wasServer = self.col.server
|
||||
self.col.server = True
|
||||
|
||||
# notes first, so we don't end up with duplicate graves
|
||||
self.col._remNotes(graves['notes'])
|
||||
# then cards
|
||||
|
@ -325,20 +287,18 @@ from notes where %s""" % d)
|
|||
# and decks
|
||||
for oid in graves['decks']:
|
||||
self.col.decks.rem(oid, childrenToo=False)
|
||||
self.col.server = wasServer
|
||||
|
||||
self.col.server = False
|
||||
|
||||
# Models
|
||||
##########################################################################
|
||||
|
||||
def getModels(self):
|
||||
if self.col.server:
|
||||
return [m for m in self.col.models.all() if m['usn'] >= self.minUsn]
|
||||
else:
|
||||
mods = [m for m in self.col.models.all() if m['usn'] == -1]
|
||||
for m in mods:
|
||||
m['usn'] = self.maxUsn
|
||||
self.col.models.save()
|
||||
return mods
|
||||
mods = [m for m in self.col.models.all() if m['usn'] == -1]
|
||||
for m in mods:
|
||||
m['usn'] = self.maxUsn
|
||||
self.col.models.save()
|
||||
return mods
|
||||
|
||||
def mergeModels(self, rchg):
|
||||
for r in rchg:
|
||||
|
@ -351,20 +311,14 @@ from notes where %s""" % d)
|
|||
##########################################################################
|
||||
|
||||
def getDecks(self):
|
||||
if self.col.server:
|
||||
return [
|
||||
[g for g in self.col.decks.all() if g['usn'] >= self.minUsn],
|
||||
[g for g in self.col.decks.allConf() if g['usn'] >= self.minUsn]
|
||||
]
|
||||
else:
|
||||
decks = [g for g in self.col.decks.all() if g['usn'] == -1]
|
||||
for g in decks:
|
||||
g['usn'] = self.maxUsn
|
||||
dconf = [g for g in self.col.decks.allConf() if g['usn'] == -1]
|
||||
for g in dconf:
|
||||
g['usn'] = self.maxUsn
|
||||
self.col.decks.save()
|
||||
return [decks, dconf]
|
||||
decks = [g for g in self.col.decks.all() if g['usn'] == -1]
|
||||
for g in decks:
|
||||
g['usn'] = self.maxUsn
|
||||
dconf = [g for g in self.col.decks.allConf() if g['usn'] == -1]
|
||||
for g in dconf:
|
||||
g['usn'] = self.maxUsn
|
||||
self.col.decks.save()
|
||||
return [decks, dconf]
|
||||
|
||||
def mergeDecks(self, rchg):
|
||||
for r in rchg[0]:
|
||||
|
@ -389,17 +343,13 @@ from notes where %s""" % d)
|
|||
##########################################################################
|
||||
|
||||
def getTags(self):
|
||||
if self.col.server:
|
||||
return [t for t, usn in self.col.tags.allItems()
|
||||
if usn >= self.minUsn]
|
||||
else:
|
||||
tags = []
|
||||
for t, usn in self.col.tags.allItems():
|
||||
if usn == -1:
|
||||
self.col.tags.tags[t] = self.maxUsn
|
||||
tags.append(t)
|
||||
self.col.tags.save()
|
||||
return tags
|
||||
tags = []
|
||||
for t, usn in self.col.tags.allItems():
|
||||
if usn == -1:
|
||||
self.col.tags.tags[t] = self.maxUsn
|
||||
tags.append(t)
|
||||
self.col.tags.save()
|
||||
return tags
|
||||
|
||||
def mergeTags(self, tags):
|
||||
self.col.tags.register(tags, usn=self.maxUsn)
|
||||
|
@ -448,17 +398,6 @@ from notes where %s""" % d)
|
|||
def mergeConf(self, conf):
|
||||
self.col.conf = conf
|
||||
|
||||
# Local syncing for unit tests
|
||||
##########################################################################
|
||||
|
||||
class LocalServer(Syncer):
|
||||
|
||||
# serialize/deserialize payload, so we don't end up sharing objects
|
||||
# between cols
|
||||
def applyChanges(self, changes):
|
||||
l = json.loads; d = json.dumps
|
||||
return l(d(Syncer.applyChanges(self, l(d(changes)))))
|
||||
|
||||
# Wrapper for requests that tracks upload/download progress
|
||||
##########################################################################
|
||||
|
||||
|
|
|
@ -1,370 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
import nose, os, shutil, time
|
||||
|
||||
from anki import Collection as aopen, Collection
|
||||
from anki.utils import intTime
|
||||
from anki.sync import Syncer, LocalServer
|
||||
from anki.consts import STARTING_FACTOR
|
||||
from tests.shared import getEmptyCol, getEmptyDeckWith
|
||||
import anki.stdmodels
|
||||
|
||||
# Local tests
|
||||
##########################################################################
|
||||
|
||||
deck1=None
|
||||
deck2=None
|
||||
client=None
|
||||
server=None
|
||||
server2=None
|
||||
|
||||
def setup_basic():
|
||||
global deck1, deck2, client, server
|
||||
deck1 = getEmptyCol()
|
||||
# add a note to deck 1
|
||||
f = deck1.newNote()
|
||||
f['Front'] = "foo"; f['Back'] = "bar"; f.tags = ["foo"]
|
||||
deck1.addNote(f)
|
||||
# answer it
|
||||
deck1.reset(); deck1.sched.answerCard(deck1.sched.getCard(), 4)
|
||||
# repeat for deck2
|
||||
deck2 = getEmptyDeckWith(server=True)
|
||||
f = deck2.newNote()
|
||||
f['Front'] = "bar"; f['Back'] = "bar"; f.tags = ["bar"]
|
||||
deck2.addNote(f)
|
||||
deck2.reset(); deck2.sched.answerCard(deck2.sched.getCard(), 4)
|
||||
# start with same schema and sync time
|
||||
deck1.scm = deck2.scm = 0
|
||||
# and same mod time, so sync does nothing
|
||||
t = intTime(1000)
|
||||
deck1.save(mod=t); deck2.save(mod=t)
|
||||
server = LocalServer(deck2)
|
||||
client = Syncer(deck1, server)
|
||||
|
||||
def setup_modified():
|
||||
setup_basic()
|
||||
# mark deck1 as changed
|
||||
time.sleep(0.1)
|
||||
deck1.setMod()
|
||||
deck1.save()
|
||||
|
||||
@nose.with_setup(setup_basic)
|
||||
def test_nochange():
|
||||
assert client.sync() == "noChanges"
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_changedSchema():
|
||||
deck1.scm += 1
|
||||
deck1.setMod()
|
||||
assert client.sync() == "fullSync"
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_sync():
|
||||
def check(num):
|
||||
for d in deck1, deck2:
|
||||
for t in ("revlog", "notes", "cards"):
|
||||
assert d.db.scalar("select count() from %s" % t) == num
|
||||
assert len(d.models.all()) == num*len(anki.stdmodels.models)
|
||||
# the default deck and config have an id of 1, so always 1
|
||||
assert len(d.decks.all()) == 1
|
||||
assert len(d.decks.dconf) == 1
|
||||
assert len(d.tags.all()) == num
|
||||
check(1)
|
||||
origUsn = deck1.usn()
|
||||
assert client.sync() == "success"
|
||||
# last sync times and mod times should agree
|
||||
assert deck1.mod == deck2.mod
|
||||
assert deck1._usn == deck2._usn
|
||||
assert deck1.mod == deck1.ls
|
||||
assert deck1._usn != origUsn
|
||||
# because everything was created separately it will be merged in. in
|
||||
# actual use, we use a full sync to ensure a common starting point.
|
||||
check(2)
|
||||
# repeating it does nothing
|
||||
assert client.sync() == "noChanges"
|
||||
# if we bump mod time, the decks will sync but should remain the same.
|
||||
deck1.setMod()
|
||||
deck1.save(mod=deck1.mod+1)
|
||||
assert client.sync() == "success"
|
||||
check(2)
|
||||
# crt should be synced
|
||||
deck1.crt = 123
|
||||
deck1.setMod()
|
||||
deck1.save(mod=deck1.mod+1)
|
||||
ret = client.sync(); assert ret == "success"
|
||||
assert deck1.crt == deck2.crt
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_models():
|
||||
test_sync()
|
||||
# update model one
|
||||
cm = deck1.models.current()
|
||||
cm['name'] = "new"
|
||||
time.sleep(1)
|
||||
deck1.models.save(cm)
|
||||
deck1.save()
|
||||
assert deck2.models.get(cm['id'])['name'].startswith("Basic")
|
||||
assert client.sync() == "success"
|
||||
assert deck2.models.get(cm['id'])['name'] == "new"
|
||||
# deleting triggers a full sync
|
||||
deck1.scm = deck2.scm = 0
|
||||
deck1.models.rem(cm)
|
||||
deck1.save()
|
||||
assert client.sync() == "fullSync"
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_notes():
|
||||
test_sync()
|
||||
# modifications should be synced
|
||||
nid = deck1.db.scalar("select id from notes")
|
||||
note = deck1.getNote(nid)
|
||||
assert note['Front'] != "abc"
|
||||
note['Front'] = "abc"
|
||||
note.flush()
|
||||
deck1.save()
|
||||
assert client.sync() == "success"
|
||||
assert deck2.getNote(nid)['Front'] == "abc"
|
||||
# deletions too
|
||||
assert deck1.db.scalar("select 1 from notes where id = ?", nid)
|
||||
deck1.remNotes([nid])
|
||||
deck1.save()
|
||||
assert client.sync() == "success"
|
||||
assert not deck1.db.scalar("select 1 from notes where id = ?", nid)
|
||||
assert not deck2.db.scalar("select 1 from notes where id = ?", nid)
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_cards():
|
||||
test_sync()
|
||||
nid = deck1.db.scalar("select id from notes")
|
||||
note = deck1.getNote(nid)
|
||||
card = note.cards()[0]
|
||||
# answer the card locally
|
||||
card.startTimer()
|
||||
deck1.sched.answerCard(card, 4)
|
||||
assert card.reps == 2
|
||||
deck1.save()
|
||||
assert deck2.getCard(card.id).reps == 1
|
||||
assert client.sync() == "success"
|
||||
assert deck2.getCard(card.id).reps == 2
|
||||
# if it's modified on both sides , later mod time should win
|
||||
for test in ((deck1, deck2), (deck2, deck1)):
|
||||
time.sleep(1)
|
||||
c = test[0].getCard(card.id)
|
||||
c.reps = 5; c.flush()
|
||||
test[0].save()
|
||||
time.sleep(1)
|
||||
c = test[1].getCard(card.id)
|
||||
c.reps = 3; c.flush()
|
||||
test[1].save()
|
||||
assert client.sync() == "success"
|
||||
assert test[1].getCard(card.id).reps == 3
|
||||
assert test[0].getCard(card.id).reps == 3
|
||||
# removals should work too
|
||||
deck1.remCards([card.id])
|
||||
deck1.save()
|
||||
assert deck2.db.scalar("select 1 from cards where id = ?", card.id)
|
||||
assert client.sync() == "success"
|
||||
assert not deck2.db.scalar("select 1 from cards where id = ?", card.id)
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_tags():
|
||||
test_sync()
|
||||
def sortedTags(deck):
|
||||
return sorted(deck.tags.all())
|
||||
assert sortedTags(deck1) == sortedTags(deck2)
|
||||
deck1.tags.register(["abc"])
|
||||
deck2.tags.register(["xyz"])
|
||||
assert sortedTags(deck1) != sortedTags(deck2)
|
||||
deck1.save()
|
||||
time.sleep(0.1)
|
||||
deck2.save()
|
||||
assert client.sync() == "success"
|
||||
assert sortedTags(deck1) == sortedTags(deck2)
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_decks():
|
||||
test_sync()
|
||||
assert len(deck1.decks.all()) == 1
|
||||
assert len(deck1.decks.all()) == len(deck2.decks.all())
|
||||
deck1.decks.id("new")
|
||||
assert len(deck1.decks.all()) != len(deck2.decks.all())
|
||||
time.sleep(0.1)
|
||||
deck2.decks.id("new2")
|
||||
deck1.save()
|
||||
time.sleep(0.1)
|
||||
deck2.save()
|
||||
assert client.sync() == "success"
|
||||
assert sorted(deck1.tags.all()) == sorted(deck2.tags.all())
|
||||
assert len(deck1.decks.all()) == len(deck2.decks.all())
|
||||
assert len(deck1.decks.all()) == 3
|
||||
assert deck1.decks.confForDid(1)['maxTaken'] == 60
|
||||
deck2.decks.confForDid(1)['maxTaken'] = 30
|
||||
deck2.decks.save(deck2.decks.confForDid(1))
|
||||
deck2.save()
|
||||
assert client.sync() == "success"
|
||||
assert deck1.decks.confForDid(1)['maxTaken'] == 30
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_conf():
|
||||
test_sync()
|
||||
assert deck2.conf['curDeck'] == 1
|
||||
deck1.conf['curDeck'] = 2
|
||||
time.sleep(0.1)
|
||||
deck1.setMod()
|
||||
deck1.save()
|
||||
assert client.sync() == "success"
|
||||
assert deck2.conf['curDeck'] == 2
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_threeway():
|
||||
test_sync()
|
||||
deck1.close(save=False)
|
||||
d3path = deck1.path.replace(".anki", "2.anki")
|
||||
shutil.copy2(deck1.path, d3path)
|
||||
deck1.reopen()
|
||||
deck3 = aopen(d3path)
|
||||
client2 = Syncer(deck3, server)
|
||||
assert client2.sync() == "noChanges"
|
||||
# client 1 adds a card at time 1
|
||||
time.sleep(1)
|
||||
f = deck1.newNote()
|
||||
f['Front'] = "1";
|
||||
deck1.addNote(f)
|
||||
deck1.save()
|
||||
# at time 2, client 2 syncs to server
|
||||
time.sleep(1)
|
||||
deck3.setMod()
|
||||
deck3.save()
|
||||
assert client2.sync() == "success"
|
||||
# at time 3, client 1 syncs, adding the older note
|
||||
time.sleep(1)
|
||||
assert client.sync() == "success"
|
||||
assert deck1.noteCount() == deck2.noteCount()
|
||||
# syncing client2 should pick it up
|
||||
assert client2.sync() == "success"
|
||||
assert deck1.noteCount() == deck2.noteCount() == deck3.noteCount()
|
||||
|
||||
def test_threeway2():
|
||||
# for this test we want ms precision of notes so we don't have to
|
||||
# sleep a lot
|
||||
import anki.notes
|
||||
intTime = anki.notes.intTime
|
||||
anki.notes.intTime = lambda x=1: intTime(1000)
|
||||
def setup():
|
||||
# create collection 1 with a single note
|
||||
c1 = getEmptyCol()
|
||||
f = c1.newNote()
|
||||
f['Front'] = "startingpoint"
|
||||
nid = f.id
|
||||
c1.addNote(f)
|
||||
cid = f.cards()[0].id
|
||||
c1.beforeUpload()
|
||||
# start both clients and server off in this state
|
||||
s1path = c1.path.replace(".anki2", "-s1.anki2")
|
||||
c2path = c1.path.replace(".anki2", "-c2.anki2")
|
||||
shutil.copy2(c1.path, s1path)
|
||||
shutil.copy2(c1.path, c2path)
|
||||
# open them
|
||||
c1 = Collection(c1.path)
|
||||
c2 = Collection(c2path)
|
||||
s1 = Collection(s1path, server=True)
|
||||
return c1, c2, s1, nid, cid
|
||||
c1, c2, s1, nid, cid = setup()
|
||||
# modify c1 then sync c1->s1
|
||||
n = c1.getNote(nid)
|
||||
t = "firstmod"
|
||||
n['Front'] = t
|
||||
n.flush()
|
||||
c1.db.execute("update cards set mod=1, usn=-1")
|
||||
srv = LocalServer(s1)
|
||||
clnt1 = Syncer(c1, srv)
|
||||
clnt1.sync()
|
||||
n.load()
|
||||
assert n['Front'] == t
|
||||
assert s1.getNote(nid)['Front'] == t
|
||||
assert s1.db.scalar("select mod from cards") == 1
|
||||
# sync s1->c2
|
||||
clnt2 = Syncer(c2, srv)
|
||||
clnt2.sync()
|
||||
assert c2.getNote(nid)['Front'] == t
|
||||
assert c2.db.scalar("select mod from cards") == 1
|
||||
# modify c1 and sync
|
||||
time.sleep(0.001)
|
||||
t = "secondmod"
|
||||
n = c1.getNote(nid)
|
||||
n['Front'] = t
|
||||
n.flush()
|
||||
c1.db.execute("update cards set mod=2, usn=-1")
|
||||
clnt1.sync()
|
||||
# modify c2 and sync - both c2 and server should be the same
|
||||
time.sleep(0.001)
|
||||
t2 = "thirdmod"
|
||||
n = c2.getNote(nid)
|
||||
n['Front'] = t2
|
||||
n.flush()
|
||||
c2.db.execute("update cards set mod=3, usn=-1")
|
||||
clnt2.sync()
|
||||
n.load()
|
||||
assert n['Front'] == t2
|
||||
assert c2.db.scalar("select mod from cards") == 3
|
||||
n = s1.getNote(nid)
|
||||
assert n['Front'] == t2
|
||||
assert s1.db.scalar("select mod from cards") == 3
|
||||
# and syncing c1 again should yield the updated note as well
|
||||
clnt1.sync()
|
||||
n = s1.getNote(nid)
|
||||
assert n['Front'] == t2
|
||||
assert s1.db.scalar("select mod from cards") == 3
|
||||
n = c1.getNote(nid)
|
||||
assert n['Front'] == t2
|
||||
assert c1.db.scalar("select mod from cards") == 3
|
||||
|
||||
def _test_speed():
|
||||
t = time.time()
|
||||
deck1 = aopen(os.path.expanduser("~/rapid.anki"))
|
||||
for tbl in "revlog", "cards", "notes", "graves":
|
||||
deck1.db.execute("update %s set usn = -1 where usn != -1"%tbl)
|
||||
for m in deck1.models.all():
|
||||
m['usn'] = -1
|
||||
for tx in deck1.tags.all():
|
||||
deck1.tags.tags[tx] = -1
|
||||
deck1._usn = -1
|
||||
deck1.save()
|
||||
deck2 = getEmptyDeckWith(server=True)
|
||||
deck1.scm = deck2.scm = 0
|
||||
server = LocalServer(deck2)
|
||||
client = Syncer(deck1, server)
|
||||
print("load %d" % ((time.time() - t)*1000)); t = time.time()
|
||||
assert client.sync() == "success"
|
||||
print("sync %d" % ((time.time() - t)*1000)); t = time.time()
|
||||
|
||||
@nose.with_setup(setup_modified)
|
||||
def test_filtered_delete():
|
||||
test_sync()
|
||||
nid = deck1.db.scalar("select id from notes")
|
||||
note = deck1.getNote(nid)
|
||||
card = note.cards()[0]
|
||||
card.queue = 2
|
||||
card.type = 2
|
||||
card.ivl = 10
|
||||
card.factor = STARTING_FACTOR
|
||||
card.due = deck1.sched.today
|
||||
card.flush()
|
||||
# put cards into a filtered deck
|
||||
did = deck1.decks.newDyn("dyn")
|
||||
deck1.sched.rebuildDyn(did)
|
||||
# sync the filtered deck
|
||||
assert client.sync() == "success"
|
||||
# answer the card locally
|
||||
time.sleep(1)
|
||||
card.load()
|
||||
card.startTimer()
|
||||
deck1.sched.answerCard(card, 4)
|
||||
assert card.ivl > 10
|
||||
# delete the filtered deck
|
||||
deck1.decks.rem(did)
|
||||
# sync again
|
||||
assert client.sync() == "success"
|
||||
card.load()
|
||||
assert card.ivl > 10
|
||||
return
|
Loading…
Reference in a new issue