This commit is contained in:
Soren I. Bjornstad 2013-12-01 09:58:34 -06:00
commit 684df05f51
15 changed files with 103 additions and 77 deletions

View file

@ -30,6 +30,6 @@ if arch[1] == "ELF":
sys.path.insert(0, os.path.join(ext, "py2.%d-%s" % (
sys.version_info[1], arch[0][0:2])))
version="2.0.17" # build scripts grep this line, so preserve formatting
version="2.0.18" # build scripts grep this line, so preserve formatting
from anki.storage import Collection
__all__ = ["Collection"]

View file

@ -4,19 +4,10 @@
import pprint
import time
from anki.hooks import runHook
from anki.utils import intTime, timestampID, joinFields
from anki.consts import *
# temporary
_warned = False
def warn():
global _warned
if _warned:
return
import sys
sys.stderr.write("Ignore the above, please download the fix assertion addon.")
_warned = True
# Cards
##########################################################################
@ -83,7 +74,7 @@ class Card(object):
self.usn = self.col.usn()
# bug check
if self.queue == 2 and self.odue and not self.col.decks.isDyn(self.did):
warn()
runHook("odueInvalid")
assert self.due < 4294967296
self.col.db.execute(
"""
@ -114,7 +105,7 @@ insert or replace into cards values
self.usn = self.col.usn()
# bug checks
if self.queue == 2 and self.odue and not self.col.decks.isDyn(self.did):
warn()
runHook("odueInvalid")
assert self.due < 4294967296
self.col.db.execute(
"""update cards set

View file

@ -741,6 +741,16 @@ select id from cards where nid not in (select id from notes)""")
ngettext("Deleted %d card with missing note.",
"Deleted %d cards with missing note.", cnt) % cnt)
self.remCards(ids)
# cards with odue set when it shouldn't be
ids = self.db.list("""
select id from cards where odue > 0 and (type=1 or queue=2) and not odid""")
if ids:
cnt = len(ids)
problems.append(
ngettext("Fixed %d card with invalid properties.",
"Fixed %d cards with invalid properties.", cnt) % cnt)
self.db.execute("update cards set odue=0 where id in "+
ids2str(ids))
# tags
self.tags.registerNotes()
# field cache

View file

@ -22,9 +22,9 @@ class MediaManager(object):
soundRegexps = ["(?i)(\[sound:(?P<fname>[^]]+)\])"]
imgRegexps = [
# src element quoted case
"(?i)(<img[^>]+src=(?P<str>[\"'])(?P<fname>[^>]+?)(?P=str)[^>]*>)",
"(?i)(<img[^>]* src=(?P<str>[\"'])(?P<fname>[^>]+?)(?P=str)[^>]*>)",
# unquoted case
"(?i)(<img[^>]+src=(?!['\"])(?P<fname>[^ >]+)[^>]*?>)",
"(?i)(<img[^>]* src=(?!['\"])(?P<fname>[^ >]+)[^>]*?>)",
]
regexps = soundRegexps + imgRegexps
@ -342,7 +342,7 @@ class MediaManager(object):
def hasIllegal(self, str):
# a file that couldn't be decoded to unicode is considered invalid
if not isinstance(str, unicode):
return False
return True
return not not re.search(self._illegalCharReg, str)
# Media syncing - bundling zip files to send to server

View file

@ -1333,9 +1333,10 @@ and (queue=0 or (queue=2 and due<=?))""",
def forgetCards(self, ids):
"Put cards at the end of the new queue."
self.remFromDyn(ids)
self.col.db.execute(
"update cards set type=0,queue=0,ivl=0,due=0,factor=? where odid=0 "
"and queue >= 0 and id in "+ids2str(ids), 2500)
"update cards set type=0,queue=0,ivl=0,due=0,odue=0,factor=?"
" where id in "+ids2str(ids), 2500)
pmax = self.col.db.scalar(
"select max(due) from cards where type=0") or 0
# takes care of mod + usn
@ -1351,10 +1352,10 @@ and (queue=0 or (queue=2 and due<=?))""",
r = random.randint(imin, imax)
d.append(dict(id=id, due=r+t, ivl=max(1, r), mod=mod,
usn=self.col.usn(), fact=2500))
self.removeLrn(ids)
self.remFromDyn(ids)
self.col.db.executemany("""
update cards set type=2,queue=2,ivl=:ivl,due=:due,
usn=:usn, mod=:mod, factor=:fact where id=:id and odid=0 and queue >=0""",
update cards set type=2,queue=2,ivl=:ivl,due=:due,odue=0,
usn=:usn,mod=:mod,factor=:fact where id=:id""",
d)
self.col.log(ids)

View file

@ -716,6 +716,8 @@ by clicking on one on the left."""))
hh.setResizeMode(i, QHeaderView.Stretch)
else:
hh.setResizeMode(i, QHeaderView.Interactive)
# this must be set post-resize or it doesn't work
hh.setCascadingSectionResizes(False)
def onColumnMoved(self, a, b, c):
self.setColumnSizes()

View file

@ -191,6 +191,7 @@ Please create a new card type first."""))
if self.redrawing:
return
self.card = self.cards[idx]
self.ord = idx
self.tab = self.forms[idx]
self.tabs.setCurrentIndex(idx)
self.playedAudio = {}

View file

@ -814,7 +814,7 @@ to a cloze type first, via Edit>Change Note Type."""))
for suffix in pics+audio:
if l.endswith(suffix):
return self._retrieveURL(url)
# not a supported type; return link verbatim
# not a supported type
return
def isURL(self, s):
@ -1121,6 +1121,8 @@ class EditorWebView(AnkiWebView):
link = self.editor.urlToLink(url)
if link:
mime.setHtml(link)
else:
mime.setText(url)
return mime
# if the user has used 'copy link location' in the browser, the clipboard

View file

@ -79,7 +79,7 @@ class ImportDialog(QDialog):
self.onDelimiter)
self.updateDelimiterButtonText()
self.frm.allowHTML.setChecked(self.mw.pm.profile.get('allowHTML', True))
self.frm.importMode.setCurrentIndex(self.mw.pm.profile.get('importMode', 0))
self.frm.importMode.setCurrentIndex(self.mw.pm.profile.get('importMode', 1))
self.exec_()
def setupOptions(self):

View file

@ -863,6 +863,12 @@ Difference to correct time: %s.""") % diffText
def setupHooks(self):
addHook("modSchema", self.onSchemaMod)
addHook("remNotes", self.onRemNotes)
addHook("odueInvalid", self.onOdueInvalid)
def onOdueInvalid(self):
showWarning(_("""\
Invalid property found on card. Please use Tools>Check Database, \
and if the problem comes up again, please ask on the support site."""))
# Log note deletion
##########################################################################

View file

@ -56,7 +56,7 @@ profileConf = dict(
autoSync=True,
# importing
allowHTML=False,
importMode=0,
importMode=1,
)
class ProfileManager(object):

View file

@ -126,8 +126,8 @@ Please visit AnkiWeb, upgrade your deck, then try again."""))
self._checkFailed()
elif evt == "mediaSanity":
showWarning(_("""\
A problem occurred while syncing media. Please sync again and Anki will \
correct the issue."""))
A problem occurred while syncing media. Please use Tools>Check Media, then \
sync again to correct the issue."""))
elif evt == "noChanges":
pass
elif evt == "fullSync":
@ -167,7 +167,7 @@ AnkiWeb is too busy at the moment. Please try again in a few minutes.""")
return _("504 gateway timeout error received. Please try temporarily disabling your antivirus.")
elif "code: 409" in err:
return _("Only one client can access AnkiWeb at a time. If a previous sync failed, please try again in a few minutes.")
elif "10061" in err or "10013" in err:
elif "10061" in err or "10013" in err or "10053" in err:
return _(
"Antivirus or firewall software is preventing Anki from connecting to the internet.")
elif "Unable to find the server" in err:
@ -337,12 +337,9 @@ class SyncThread(QThread):
ret = self.client.sync()
except Exception, e:
log = traceback.format_exc()
try:
err = unicode(e[0], "utf8", "ignore")
except:
# number, exception with no args, etc
err = ""
if "Unable to find the server" in err:
err = repr(str(e))
if ("Unable to find the server" in err or
"Errno 2" in err):
self.fireEvent("offline")
else:
if not err:
@ -451,46 +448,53 @@ httplib.HTTPConnection.send = _incrementalSend
# this is an augmented version of httplib's request routine that:
# - doesn't assume requests will be tried more than once
# - calls a hook for each chunk of data so we can update the gui
# - retries only when keep-alive connection is closed
def _conn_request(self, conn, request_uri, method, body, headers):
try:
if conn.sock is None:
conn.connect()
conn.request(method, request_uri, body, headers)
except socket.timeout:
raise
except socket.gaierror:
conn.close()
raise httplib2.ServerNotFoundError(
"Unable to find the server at %s" % conn.host)
except httplib2.ssl_SSLError:
conn.close()
raise
except socket.error, e:
conn.close()
raise
except httplib.HTTPException:
conn.close()
raise
try:
response = conn.getresponse()
except (socket.error, httplib.HTTPException):
raise
else:
content = ""
if method == "HEAD":
response.close()
for i in range(2):
try:
if conn.sock is None:
conn.connect()
conn.request(method, request_uri, body, headers)
except socket.timeout:
raise
except socket.gaierror:
conn.close()
raise httplib2.ServerNotFoundError(
"Unable to find the server at %s" % conn.host)
except httplib2.ssl_SSLError:
conn.close()
raise
except socket.error, e:
conn.close()
raise
except httplib.HTTPException:
conn.close()
raise
try:
response = conn.getresponse()
except httplib.BadStatusLine:
print "retry bad line"
conn.close()
conn.connect()
continue
except (socket.error, httplib.HTTPException):
raise
else:
buf = StringIO()
while 1:
data = response.read(CHUNK_SIZE)
if not data:
break
buf.write(data)
runHook("httpRecv", len(data))
content = buf.getvalue()
response = httplib2.Response(response)
if method != "HEAD":
content = httplib2._decompressContent(response, content)
return (response, content)
content = ""
if method == "HEAD":
response.close()
else:
buf = StringIO()
while 1:
data = response.read(CHUNK_SIZE)
if not data:
break
buf.write(data)
runHook("httpRecv", len(data))
content = buf.getvalue()
response = httplib2.Response(response)
if method != "HEAD":
content = httplib2._decompressContent(response, content)
return (response, content)
httplib2.Http._conn_request = _conn_request

View file

@ -173,7 +173,7 @@
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>true</bool>
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>

View file

@ -1,8 +1,12 @@
# coding: utf-8
import tempfile, os, time
import tempfile
import os
import time
from shared import getEmptyDeck, testDir
# copying files to media folder
def test_add():
d = getEmptyDeck()
@ -100,8 +104,8 @@ def test_changes():
def test_illegal():
d = getEmptyDeck()
aString = "a:b|cd\\e/f\0g*h"
good = "abcdefgh"
aString = u"a:b|cd\\e/f\0g*h"
good = u"abcdefgh"
assert d.media.stripIllegal(aString) == good
for c in aString:
bad = d.media.hasIllegal("somestring"+c+"morestring")

View file

@ -1,10 +1,13 @@
# coding: utf-8
import time, copy, sys
import time
import copy
from tests.shared import getEmptyDeck
from anki.utils import intTime
from anki.hooks import addHook
def test_clock():
d = getEmptyDeck()
if (d.sched.dayCutoff - intTime()) < 10*60:
@ -173,8 +176,10 @@ def test_learn():
c.queue = 1
c.odue = 321
c.flush()
print "----begin"
d.sched.removeLrn()
c.load()
print c.__dict__
assert c.queue == 2
assert c.due == 321