From 433f2b06f93e829bc26fa3646f156bb9fa84140a Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 3 Nov 2013 16:12:43 +0900 Subject: [PATCH 1/4] make sure suspended/buried cards are reset on export too --- anki/sched.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anki/sched.py b/anki/sched.py index 790a494bf..9c05df4e9 100644 --- a/anki/sched.py +++ b/anki/sched.py @@ -1366,7 +1366,7 @@ usn=:usn, mod=:mod, factor=:fact where id=:id and odid=0 and queue >=0""", % sids) # reset all cards self.col.db.execute( - "update cards set reps=0,lapses=0,odid=0,odue=0" + "update cards set reps=0,lapses=0,odid=0,odue=0,queue=0" " where id in %s" % sids ) # and forget any non-new cards, changing their due numbers From 1d2ef1dbfb0d5113bc0a6726888978b04af3e864 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sun, 3 Nov 2013 18:39:03 +0900 Subject: [PATCH 2/4] seeking on win32 is slow, so keep file handle around --- aqt/main.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/aqt/main.py b/aqt/main.py index 46ff38327..00d5617e0 100644 --- a/aqt/main.py +++ b/aqt/main.py @@ -268,6 +268,7 @@ To import into a password protected profile, please open the profile before atte def loadCollection(self): self.hideSchemaMsg = True + self._openLog() try: self.col = Collection(self.pm.collectionPath()) except anki.db.Error: @@ -315,6 +316,7 @@ when the collection is stored on a network or cloud drive. Please see \ the manual for information on how to restore from an automatic backup.")) self.col.close() self.col = None + self._closeLog() if not corrupt: self.backup() self.progress.finish() @@ -894,11 +896,18 @@ Difference to correct time: %s.""") % diffText limit=4+kwargs.get("stack", 0))[0] buf = u"[%s] %s:%s(): %s" % (intTime(), os.path.basename(path), fn, ", ".join([customRepr(x) for x in args])) - lpath = re.sub("\.anki2$", ".log", self.pm.collectionPath()) - open(lpath, "ab").write(buf.encode("utf8") + "\n") + self._logHnd.write(buf.encode("utf8") + "\n") + self._logHnd.flush() if os.environ.get("ANKIDEV"): print buf + def _openLog(self): + lpath = re.sub("\.anki2$", ".log", self.pm.collectionPath()) + self._logHnd = open(lpath, "ab") + + def _closeLog(self): + self._logHnd = None + # Schema modifications ########################################################################## From 2e22b6218b5bc7ccf5c6e35d7b025da2ebe65d1c Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 4 Nov 2013 06:35:30 +0900 Subject: [PATCH 3/4] don't close log on profile close we want the log to stick around for syncs, and if the user changes to another profile the log will be closed then --- aqt/main.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aqt/main.py b/aqt/main.py index 00d5617e0..0951d5cab 100644 --- a/aqt/main.py +++ b/aqt/main.py @@ -316,7 +316,6 @@ when the collection is stored on a network or cloud drive. Please see \ the manual for information on how to restore from an automatic backup.")) self.col.close() self.col = None - self._closeLog() if not corrupt: self.backup() self.progress.finish() @@ -888,6 +887,8 @@ Difference to correct time: %s.""") % diffText ########################################################################## def onLog(self, args, kwargs): + if not self._logHnd: + return def customRepr(x): if isinstance(x, basestring): return x @@ -905,9 +906,6 @@ Difference to correct time: %s.""") % diffText lpath = re.sub("\.anki2$", ".log", self.pm.collectionPath()) self._logHnd = open(lpath, "ab") - def _closeLog(self): - self._logHnd = None - # Schema modifications ########################################################################## From 5dfe95aa67a77aa2b68f94cb04d5b93ec4fbfe3e Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 4 Nov 2013 23:03:33 +0900 Subject: [PATCH 4/4] move debug logging into libanki we want to be able to log the initial automatic sync, which happens before the debug logging was set up in ankiqt also skip the flush, as it should eventually get written --- anki/collection.py | 29 ++++++++++++++++++++++++++++- aqt/main.py | 28 ++-------------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/anki/collection.py b/anki/collection.py index 4f9a92059..f04ab3eaf 100644 --- a/anki/collection.py +++ b/anki/collection.py @@ -2,12 +2,15 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +import pprint +import re import time import os import random import stat import datetime import copy +import traceback from anki.lang import _, ngettext from anki.utils import ids2str, fieldChecksum, stripHTML, \ @@ -48,9 +51,12 @@ defaultConf = { # this is initialized by storage.Collection class _Collection(object): + debugLog = False + def __init__(self, db, server=False): self.db = db self.path = db._path + self._openLog() self.log(self.path, anki.version) self.server = server self._lastSave = time.time() @@ -773,4 +779,25 @@ and queue = 0""", intTime(), self.usn()) ########################################################################## def log(self, *args, **kwargs): - runHook("log", args, kwargs) + if not self.debugLog: + return + def customRepr(x): + if isinstance(x, basestring): + return x + return pprint.pformat(x) + path, num, fn, y = traceback.extract_stack( + limit=2+kwargs.get("stack", 0))[0] + buf = u"[%s] %s:%s(): %s" % (intTime(), os.path.basename(path), fn, + ", ".join([customRepr(x) for x in args])) + self._logHnd.write(buf.encode("utf8") + "\n") + if os.environ.get("ANKIDEV"): + print buf + + def _openLog(self): + if not self.debugLog: + return + lpath = re.sub("\.anki2$", ".log", self.path) + self._logHnd = open(lpath, "ab") + + def _closeLog(self): + self._logHnd = None diff --git a/aqt/main.py b/aqt/main.py index 0951d5cab..a8133f561 100644 --- a/aqt/main.py +++ b/aqt/main.py @@ -3,7 +3,6 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import os -import pprint import sys import re import traceback @@ -32,6 +31,8 @@ class AnkiQt(QMainWindow): self.state = "startup" aqt.mw = self self.app = app + from anki.collection import _Collection + _Collection.debugLog = True if isWin: self._xpstyle = QStyleFactory.create("WindowsXP") self.app.setStyle(self._xpstyle) @@ -268,7 +269,6 @@ To import into a password protected profile, please open the profile before atte def loadCollection(self): self.hideSchemaMsg = True - self._openLog() try: self.col = Collection(self.pm.collectionPath()) except anki.db.Error: @@ -865,7 +865,6 @@ Difference to correct time: %s.""") % diffText def setupHooks(self): addHook("modSchema", self.onSchemaMod) addHook("remNotes", self.onRemNotes) - addHook("log", self.onLog) # Log note deletion ########################################################################## @@ -883,29 +882,6 @@ Difference to correct time: %s.""") % diffText f.write(("\t".join([str(id), str(mid)] + fields)).encode("utf8")) f.write("\n") - # Debug logging - ########################################################################## - - def onLog(self, args, kwargs): - if not self._logHnd: - return - def customRepr(x): - if isinstance(x, basestring): - return x - return pprint.pformat(x) - path, num, fn, y = traceback.extract_stack( - limit=4+kwargs.get("stack", 0))[0] - buf = u"[%s] %s:%s(): %s" % (intTime(), os.path.basename(path), fn, - ", ".join([customRepr(x) for x in args])) - self._logHnd.write(buf.encode("utf8") + "\n") - self._logHnd.flush() - if os.environ.get("ANKIDEV"): - print buf - - def _openLog(self): - lpath = re.sub("\.anki2$", ".log", self.pm.collectionPath()) - self._logHnd = open(lpath, "ab") - # Schema modifications ##########################################################################