more robust anki1 upgrading & anki2 importing

- base the 2.0 model id on the 1.2 one so we don't get new models each time we
  reimport the file
- when determining if we can reuse an existing note, it must have the same
  model id, and the model must have the same schema
- make sure we check templates when determining schema
- if schema has diverged, note needs new guid
This commit is contained in:
Damien Elmes 2012-10-27 20:55:08 +09:00
parent 6830ca99d9
commit bd1c6d4395
6 changed files with 47 additions and 9 deletions

View file

@ -4,7 +4,7 @@
import os import os
from anki import Collection from anki import Collection
from anki.utils import intTime, splitFields, joinFields, checksum from anki.utils import intTime, splitFields, joinFields, checksum, guid64
from anki.importing.base import Importer from anki.importing.base import Importer
from anki.lang import _ from anki.lang import _
from anki.lang import ngettext from anki.lang import ngettext
@ -96,8 +96,24 @@ class Anki2Importer(Importer):
# turn the db result into a mutable list # turn the db result into a mutable list
note = list(note) note = list(note)
guid, mid = note[1:3] guid, mid = note[1:3]
# missing from local col? duplicate = False
if guid not in self._notes: guidChange = False
# do we have the same guid?
if guid in self._notes:
# and do they share the same model id?
if self._notes[guid][2] == mid:
# and do they share the same schema?
srcM = self.src.models.get(mid)
dstM = self.dst.models.get(self._notes[guid][2])
if (self.src.models.scmhash(srcM) ==
self.src.models.scmhash(dstM)):
# then it's safe to treat as a duplicate
duplicate = True
if not duplicate:
# not identical models, so we need to change guid
guidChange = True
# missing from local col or divergent model?
if not duplicate:
# get corresponding local model # get corresponding local model
lmid = self._mid(mid) lmid = self._mid(mid)
# ensure id is unique # ensure id is unique
@ -111,11 +127,14 @@ class Anki2Importer(Importer):
note[6] = self._mungeMedia(mid, note[6]) note[6] = self._mungeMedia(mid, note[6])
add.append(note) add.append(note)
dirty.append(note[0]) dirty.append(note[0])
# if it was originally the same as a note in this deck but the
# models have diverged, we need to change the guid
if guidChange:
guid = guid64()
# note we have the added note # note we have the added note
self._notes[guid] = (note[0], note[3], note[2]) self._notes[guid] = (note[0], note[3], note[2])
else: else:
dupes += 1 dupes += 1
pass
## update existing note - not yet tested; for post 2.0 ## update existing note - not yet tested; for post 2.0
# newer = note[3] > mod # newer = note[3] > mod
# if self.allowUpdate and self._mid(mid) == mid and newer: # if self.allowUpdate and self._mid(mid) == mid and newer:

View file

@ -452,6 +452,8 @@ select id from notes where mid = ?)""" % " ".join(map),
s = "" s = ""
for f in m['flds']: for f in m['flds']:
s += f['name'] s += f['name']
for t in m['tmpls']:
s += t['name']
return fieldChecksum(s) return fieldChecksum(s)
# Required field/text cache # Required field/text cache

View file

@ -341,11 +341,8 @@ insert or replace into col select id, cast(created as int), :t,
mods = {} mods = {}
for row in db.all( for row in db.all(
"select id, name from models"): "select id, name from models"):
while 1: # use only first 31 bits
t = intTime(1000) t = abs(row[0]) >> 32
if t not in times:
times[t] = True
break
m = anki.models.defaultModel.copy() m = anki.models.defaultModel.copy()
m['id'] = t m['id'] = t
m['name'] = row[1] m['name'] = row[1]

Binary file not shown.

Binary file not shown.

View file

@ -138,6 +138,26 @@ def test_anki1():
imp.run() imp.run()
check() check()
def test_anki1_diffmodels():
# create a new empty deck
dst = getEmptyDeck()
# import the 1 card version of the model
tmp = getUpgradeDeckPath("diffmodels1.anki")
imp = Anki1Importer(dst, tmp)
imp.run()
before = dst.noteCount()
# repeating the process should do nothing
imp = Anki1Importer(dst, tmp)
imp.run()
assert before == dst.noteCount()
# then the 2 card version
tmp = getUpgradeDeckPath("diffmodels2.anki")
imp = Anki1Importer(dst, tmp)
imp.run()
after = dst.noteCount()
# as the model schemas differ, should have been imported as new model
assert after == before + 1
def test_csv(): def test_csv():
deck = getEmptyDeck() deck = getEmptyDeck()
file = unicode(os.path.join(testDir, "support/text-2fields.txt")) file = unicode(os.path.join(testDir, "support/text-2fields.txt"))