mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
update supermemo importer; fix factor
This commit is contained in:
parent
beef571d95
commit
972526d265
4 changed files with 41 additions and 59 deletions
|
@ -62,7 +62,7 @@ acq_reps+ret_reps, lapses from cards"""):
|
||||||
continue
|
continue
|
||||||
# add the card
|
# add the card
|
||||||
c = ForeignCard()
|
c = ForeignCard()
|
||||||
c.factor = row[5]
|
c.factor = int(row[5]*1000)
|
||||||
c.reps = row[6]
|
c.reps = row[6]
|
||||||
c.lapses = row[7]
|
c.lapses = row[7]
|
||||||
# ivl is inferred in mnemosyne
|
# ivl is inferred in mnemosyne
|
||||||
|
|
|
@ -24,7 +24,7 @@ class ForeignCard(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.due = 0
|
self.due = 0
|
||||||
self.ivl = 1
|
self.ivl = 1
|
||||||
self.factor = 2.5
|
self.factor = 2500
|
||||||
self.reps = 0
|
self.reps = 0
|
||||||
self.lapses = 0
|
self.lapses = 0
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from anki.importing.noteimp import NoteImporter, ForeignNote
|
from anki.stdmodels import addBasicModel
|
||||||
|
from anki.importing.noteimp import NoteImporter, ForeignNote, ForeignCard
|
||||||
from anki.lang import _
|
from anki.lang import _
|
||||||
from anki.errors import *
|
from anki.errors import *
|
||||||
|
|
||||||
|
@ -12,10 +13,6 @@ from xml.dom import minidom, Node
|
||||||
from types import DictType, InstanceType
|
from types import DictType, InstanceType
|
||||||
from string import capwords, maketrans
|
from string import capwords, maketrans
|
||||||
import re, unicodedata, time
|
import re, unicodedata, time
|
||||||
#import chardet
|
|
||||||
|
|
||||||
|
|
||||||
#from anki import Deck
|
|
||||||
|
|
||||||
class SmartDict(dict):
|
class SmartDict(dict):
|
||||||
"""
|
"""
|
||||||
|
@ -81,8 +78,12 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""Initialize internal varables.
|
"""Initialize internal varables.
|
||||||
Pameters to be exposed to GUI are stored in self.META"""
|
Pameters to be exposed to GUI are stored in self.META"""
|
||||||
|
NoteImporter.__init__(self, *args)
|
||||||
|
m = addBasicModel(self.col)
|
||||||
|
m['name'] = "Supermemo"
|
||||||
|
self.col.models.save(m)
|
||||||
|
self.initMapping()
|
||||||
|
|
||||||
Importer.__init__(self, *args)
|
|
||||||
self.lines = None
|
self.lines = None
|
||||||
self.numFields=int(2)
|
self.numFields=int(2)
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
self.META.tagMemorizedItems = True # implemented
|
self.META.tagMemorizedItems = True # implemented
|
||||||
self.META.logToStdOutput = False # implemented
|
self.META.logToStdOutput = False # implemented
|
||||||
|
|
||||||
self.cards = []
|
self.notes = []
|
||||||
|
|
||||||
## TOOLS
|
## TOOLS
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
|
|
||||||
## DEFAULT IMPORTER METHODS
|
## DEFAULT IMPORTER METHODS
|
||||||
|
|
||||||
def foreignCards(self):
|
def foreignNotes(self):
|
||||||
|
|
||||||
# Load file and parse it by minidom
|
# Load file and parse it by minidom
|
||||||
self.loadSource(self.file)
|
self.loadSource(self.file)
|
||||||
|
@ -209,7 +210,7 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
self.logger(u'Parsing done.')
|
self.logger(u'Parsing done.')
|
||||||
|
|
||||||
# Return imported cards
|
# Return imported cards
|
||||||
return self.cards
|
return self.notes
|
||||||
|
|
||||||
def fields(self):
|
def fields(self):
|
||||||
return 2
|
return 2
|
||||||
|
@ -220,38 +221,28 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
"This method actually do conversion"
|
"This method actually do conversion"
|
||||||
|
|
||||||
# new anki card
|
# new anki card
|
||||||
card = ForeignCard()
|
note = ForeignNote()
|
||||||
|
|
||||||
# clean Q and A
|
# clean Q and A
|
||||||
card.fields.append(self._fudgeText(self._decode_htmlescapes(item.Question)))
|
note.fields.append(self._fudgeText(self._decode_htmlescapes(item.Question)))
|
||||||
card.fields.append(self._fudgeText(self._decode_htmlescapes(item.Answer)))
|
note.fields.append(self._fudgeText(self._decode_htmlescapes(item.Answer)))
|
||||||
card.tags = u""
|
note.tags = []
|
||||||
|
|
||||||
# pre-process scheduling data
|
# pre-process scheduling data
|
||||||
tLastrep = time.mktime(time.strptime(item.LastRepetition, '%d.%m.%Y'))
|
|
||||||
tToday = time.time()
|
|
||||||
|
|
||||||
# convert learning data
|
# convert learning data
|
||||||
if not self.META.resetLearningData:
|
if not self.META.resetLearningData and item.Interval >= 1:
|
||||||
# migration of LearningData algorithm
|
# migration of LearningData algorithm
|
||||||
card.interval = item.Interval
|
tLastrep = time.mktime(time.strptime(item.LastRepetition, '%d.%m.%Y'))
|
||||||
card.successive = item.Repetitions
|
tToday = time.time()
|
||||||
##card.due = tToday + (float(item.Interval) * 86400.0) - tLastrep
|
card = ForeignCard()
|
||||||
card.due = tLastrep + (float(item.Interval) * 86400.0)
|
card.ivl = int(item.Interval)
|
||||||
card.lastDue = 0
|
card.lapses = int(item.Lapses)
|
||||||
|
card.reps = int(item.Repetitions) + int(item.Lapses)
|
||||||
card.factor = float(item.AFactor.replace(',','.'))
|
nextDue = tLastrep + (float(item.Interval) * 86400.0)
|
||||||
card.lastFactor = float(item.AFactor.replace(',','.'))
|
remDays = max(0, int((nextDue - time.time())/86400))
|
||||||
|
card.due = self.col.sched.today+remDays
|
||||||
# SM is not exporting all the information Anki keeps track off, so it
|
card.factor = int(float(item.AFactor.replace(',','.'))*1000)
|
||||||
# needs to be fudged
|
note.cards[0] = card
|
||||||
card.youngEase0 = item.Lapses
|
|
||||||
card.youngEase3 = item.Repetitions + item.Lapses
|
|
||||||
card.yesCount = item.Repetitions
|
|
||||||
card.noCount = item.Lapses
|
|
||||||
card.reps = card.yesCount + card.noCount
|
|
||||||
card.spaceUntil = card.due
|
|
||||||
card.combinedDue = card.due
|
|
||||||
|
|
||||||
# categories & tags
|
# categories & tags
|
||||||
# it's worth to have every theme (tree structure of sm collection) stored in tags, but sometimes not
|
# it's worth to have every theme (tree structure of sm collection) stored in tags, but sometimes not
|
||||||
|
@ -275,14 +266,14 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
tmp = list(set([ capwords(i).replace(' ','') for i in tmp ]))
|
tmp = list(set([ capwords(i).replace(' ','') for i in tmp ]))
|
||||||
tags = [ j[0].lower() + j[1:] for j in tmp if j.strip() <> '']
|
tags = [ j[0].lower() + j[1:] for j in tmp if j.strip() <> '']
|
||||||
|
|
||||||
card.tags += u" ".join(tags)
|
note.tags += tags
|
||||||
|
|
||||||
if self.META.tagMemorizedItems and item.Interval >0:
|
if self.META.tagMemorizedItems and item.Interval >0:
|
||||||
card.tags += " Memorized"
|
note.tags.append("Memorized")
|
||||||
|
|
||||||
self.logger(u'Element tags\t- ' + card.tags, level=3)
|
self.logger(u'Element tags\t- ' + `note.tags`, level=3)
|
||||||
|
|
||||||
self.cards.append(card)
|
self.notes.append(note)
|
||||||
|
|
||||||
def logger(self,text,level=1):
|
def logger(self,text,level=1):
|
||||||
"Wrapper for Anki logger"
|
"Wrapper for Anki logger"
|
||||||
|
@ -323,7 +314,7 @@ class SupermemoXmlImporter(NoteImporter):
|
||||||
"""Load source file and parse with xml.dom.minidom"""
|
"""Load source file and parse with xml.dom.minidom"""
|
||||||
self.source = source
|
self.source = source
|
||||||
self.logger(u'Load started...')
|
self.logger(u'Load started...')
|
||||||
sock = self.openAnything(self.source)
|
sock = open(self.source)
|
||||||
self.xmldoc = minidom.parse(sock).documentElement
|
self.xmldoc = minidom.parse(sock).documentElement
|
||||||
sock.close()
|
sock.close()
|
||||||
self.logger(u'Load done.')
|
self.logger(u'Load done.')
|
||||||
|
|
|
@ -96,27 +96,17 @@ def test_csv():
|
||||||
assert i.total == 0
|
assert i.total == 0
|
||||||
deck.close()
|
deck.close()
|
||||||
|
|
||||||
def test_csv_tags():
|
|
||||||
print "disabled"; return
|
|
||||||
deck = getEmptyDeck()
|
|
||||||
file = unicode(os.path.join(testDir, "support/text-tags.txt"))
|
|
||||||
i = TextImporter(deck, file)
|
|
||||||
i.run()
|
|
||||||
notes = deck.db.query(Note).all()
|
|
||||||
assert len(notes) == 2
|
|
||||||
assert notes[0].tags == "baz qux" or notes[1].tags == "baz qux"
|
|
||||||
deck.close()
|
|
||||||
|
|
||||||
def test_supermemo_xml_01_unicode():
|
def test_supermemo_xml_01_unicode():
|
||||||
print "disabled"; return
|
deck = getEmptyDeck()
|
||||||
deck = Deck()
|
file = unicode(os.path.join(testDir, "support/supermemo1.xml"))
|
||||||
deck.addModel(BasicModel())
|
i = SupermemoXmlImporter(deck, file)
|
||||||
file = unicode(os.path.join(testDir, "importing/supermemo1.xml"))
|
|
||||||
i = supermemo_xml.SupermemoXmlImporter(deck, file)
|
|
||||||
#i.META.logToStdOutput = True
|
#i.META.logToStdOutput = True
|
||||||
i.run()
|
i.run()
|
||||||
# only returning top-level elements?
|
|
||||||
assert i.total == 1
|
assert i.total == 1
|
||||||
|
cid = deck.db.scalar("select id from cards")
|
||||||
|
c = deck.getCard(cid)
|
||||||
|
assert c.factor == 5701
|
||||||
|
assert c.reps == 7
|
||||||
deck.close()
|
deck.close()
|
||||||
|
|
||||||
def test_mnemo():
|
def test_mnemo():
|
||||||
|
@ -127,3 +117,4 @@ def test_mnemo():
|
||||||
assert deck.cardCount() == 7
|
assert deck.cardCount() == 7
|
||||||
assert "a_longer_tag" in deck.tags.all()
|
assert "a_longer_tag" in deck.tags.all()
|
||||||
assert deck.db.scalar("select count() from cards where type = 0") == 1
|
assert deck.db.scalar("select count() from cards where type = 0") == 1
|
||||||
|
deck.close()
|
||||||
|
|
Loading…
Reference in a new issue