diff --git a/anki/__init__.py b/anki/__init__.py index d0bebb64e..ee9ddb6ec 100644 --- a/anki/__init__.py +++ b/anki/__init__.py @@ -2,7 +2,7 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import sys as _sys, simplejson as _simplejson, httplib2 as _httplib2, \ +import sys as _sys, httplib2 as _httplib2, \ BeautifulSoup as _bs if _sys.version_info[0] > 2: @@ -11,12 +11,17 @@ elif _sys.version_info[1] < 5: raise Exception("Anki requires Python 2.5+") elif _sys.getfilesystemencoding().lower() in ("ascii", "ansi_x3.4-1968"): raise Exception("Anki requires a UTF-8 locale.") -elif _simplejson.__version__ < "1.7.3": - raise Exception("SimpleJSON must be 1.7.3 or later.") elif _httplib2.__version__ < "0.7.0": raise Exception("Httplib2 must be 0.7.0 or later.") elif _bs.__version__ < "3.2": raise Exception("Please install BeautifulSoup 3.2+") +try: + import simplejson as _json +except: + import json as _json +if _json.__version__ < "1.7.3": + raise Exception("SimpleJSON must be 1.7.3 or later.") + version = "1.99" from anki.storage import Collection diff --git a/anki/collection.py b/anki/collection.py index 3d2500a68..36444bb77 100644 --- a/anki/collection.py +++ b/anki/collection.py @@ -2,10 +2,10 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import time, os, random, re, stat, simplejson, datetime, copy, shutil, sys +import time, os, random, re, stat, datetime, copy, shutil, sys from anki.lang import _, ngettext from anki.utils import ids2str, hexifyID, checksum, fieldChecksum, stripHTML, \ - intTime, splitFields, joinFields, maxID + intTime, splitFields, joinFields, maxID, json from anki.hooks import runHook, runFilter from anki.sched import Scheduler from anki.models import ModelManager @@ -81,7 +81,7 @@ class _Collection(object): tags) = self.db.first(""" select crt, mod, scm, dty, usn, ls, conf, models, decks, dconf, tags from col""") - self.conf = simplejson.loads(self.conf) + self.conf = json.loads(self.conf) self.models.load(models) self.decks.load(decks, dconf) self.tags.load(tags) @@ -100,7 +100,7 @@ is only necessary if you modify properties of this object or the conf dict.""" """update col set crt=?, mod=?, scm=?, dty=?, usn=?, ls=?, conf=?""", self.crt, self.mod, self.scm, self.dty, - self._usn, self.ls, simplejson.dumps(self.conf)) + self._usn, self.ls, json.dumps(self.conf)) def save(self, name=None, mod=None): "Flush, commit DB, and take out another write lock." diff --git a/anki/decks.py b/anki/decks.py index c020379bf..2e6baf72f 100644 --- a/anki/decks.py +++ b/anki/decks.py @@ -2,8 +2,8 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import simplejson, copy -from anki.utils import intTime, ids2str +import copy +from anki.utils import intTime, ids2str, json from anki.consts import * from anki.lang import _ from anki.errors import DeckRenameError @@ -83,8 +83,8 @@ class DeckManager(object): self.col = col def load(self, decks, dconf): - self.decks = simplejson.loads(decks) - self.dconf = simplejson.loads(dconf) + self.decks = json.loads(decks) + self.dconf = json.loads(dconf) self.changed = False def save(self, g=None): @@ -97,8 +97,8 @@ class DeckManager(object): def flush(self): if self.changed: self.col.db.execute("update col set decks=?, dconf=?", - simplejson.dumps(self.decks), - simplejson.dumps(self.dconf)) + json.dumps(self.decks), + json.dumps(self.dconf)) self.changed = False # Deck save/load diff --git a/anki/exporting.py b/anki/exporting.py index 3f43fc5e8..e57cd4846 100644 --- a/anki/exporting.py +++ b/anki/exporting.py @@ -2,11 +2,11 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import itertools, time, re, os, HTMLParser, zipfile, simplejson +import itertools, time, re, os, HTMLParser, zipfile from operator import itemgetter from anki.cards import Card from anki.lang import _ -from anki.utils import stripHTML, ids2str, splitFields +from anki.utils import stripHTML, ids2str, splitFields, json from anki import Collection class Exporter(object): @@ -225,7 +225,7 @@ class AnkiPackageExporter(AnkiExporter): z.write(file, c) media[c] = file # media map - z.writestr("media", simplejson.dumps(media)) + z.writestr("media", json.dumps(media)) z.close() # tidy up intermediate files os.unlink(colfile) diff --git a/anki/importing/apkg.py b/anki/importing/apkg.py index c08ac25ab..29944790f 100644 --- a/anki/importing/apkg.py +++ b/anki/importing/apkg.py @@ -2,8 +2,8 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import zipfile, simplejson, os -from anki.utils import tmpfile +import zipfile, os +from anki.utils import tmpfile, json from anki.importing.anki2 import Anki2Importer class AnkiPackageImporter(Anki2Importer): @@ -18,7 +18,7 @@ class AnkiPackageImporter(Anki2Importer): self.file = colpath Anki2Importer.run(self) # import media - media = simplejson.loads(z.read("media")) + media = json.loads(z.read("media")) for c, file in media.items(): path = os.path.join(self.col.media.dir(), file) if not os.path.exists(path): diff --git a/anki/media.py b/anki/media.py index 91e55215d..e8a4105e1 100644 --- a/anki/media.py +++ b/anki/media.py @@ -3,9 +3,9 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import os, shutil, re, urllib, urllib2, time, unicodedata, \ - urllib, sys, simplejson, zipfile + urllib, sys, zipfile from cStringIO import StringIO -from anki.utils import checksum, intTime, namedtmp, isWin, isMac +from anki.utils import checksum, intTime, namedtmp, isWin, isMac, json from anki.lang import _ from anki.db import DB from anki.consts import * @@ -229,7 +229,7 @@ If the same name exists, compare checksums.""" sizecnt = 0 # get meta info first assert z.getinfo("_meta").file_size < 100000 - meta = simplejson.loads(z.read("_meta")) + meta = json.loads(z.read("_meta")) nextUsn = int(z.read("_usn")) # then loop through all files for i in z.infolist(): @@ -306,7 +306,7 @@ If the same name exists, compare checksums.""" if sz > SYNC_ZIP_SIZE: break cnt += 1 - z.writestr("_meta", simplejson.dumps(files)) + z.writestr("_meta", json.dumps(files)) z.close() return f.getvalue(), fnames diff --git a/anki/models.py b/anki/models.py index 50f6b5c97..3b0d9ac57 100644 --- a/anki/models.py +++ b/anki/models.py @@ -2,9 +2,9 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import simplejson, copy, re +import copy, re from anki.utils import intTime, hexifyID, joinFields, splitFields, ids2str, \ - timestampID, fieldChecksum + timestampID, fieldChecksum, json from anki.lang import _ from anki.consts import * @@ -69,10 +69,10 @@ class ModelManager(object): def __init__(self, col): self.col = col - def load(self, json): + def load(self, json_): "Load registry from JSON." self.changed = False - self.models = simplejson.loads(json) + self.models = json.loads(json_) def save(self, m=None, templates=False): "Mark M modified if provided, and schedule registry flush." @@ -88,7 +88,7 @@ class ModelManager(object): "Flush the registry if any models were changed." if self.changed: self.col.db.execute("update col set models = ?", - simplejson.dumps(self.models)) + json.dumps(self.models)) self.changed = False # Retrieving and creating models diff --git a/anki/sched.py b/anki/sched.py index 15ac07625..5cb886636 100644 --- a/anki/sched.py +++ b/anki/sched.py @@ -2,7 +2,7 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import time, datetime, simplejson, random, itertools, math +import time, datetime, random, itertools, math from operator import itemgetter from heapq import * #from anki.cards import Card diff --git a/anki/stats.py b/anki/stats.py index 364127d54..cb1d7cd33 100644 --- a/anki/stats.py +++ b/anki/stats.py @@ -2,7 +2,7 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import time, sys, os, datetime, simplejson +import time, sys, os, datetime, json import anki.js from anki.utils import fmtTimeSpan, fmtFloat, ids2str from anki.consts import * @@ -670,7 +670,7 @@ $(function () { """ % dict( id=id, w=width, h=height, ylab=ylabel, - data=simplejson.dumps(data), conf=simplejson.dumps(conf))) + data=json.dumps(data), conf=json.dumps(conf))) def _limit(self): if self.wholeCollection: diff --git a/anki/storage.py b/anki/storage.py index 84c48140c..772884f6f 100644 --- a/anki/storage.py +++ b/anki/storage.py @@ -2,9 +2,9 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import os, simplejson, copy, re +import os, copy, re from anki.lang import _ -from anki.utils import intTime, ids2str +from anki.utils import intTime, ids2str, json from anki.db import DB from anki.collection import _Collection from anki.consts import * @@ -218,9 +218,9 @@ def _getColVars(db): def _addColVars(db, g, gc, c): db.execute(""" update col set conf = ?, decks = ?, dconf = ?""", - simplejson.dumps(c), - simplejson.dumps({'1': g}), - simplejson.dumps({'1': gc})) + json.dumps(c), + json.dumps({'1': g}), + json.dumps({'1': gc})) def _updateIndices(db): "Add indices to the DB." diff --git a/anki/sync.py b/anki/sync.py index e64c07e46..d1cd05d54 100644 --- a/anki/sync.py +++ b/anki/sync.py @@ -2,12 +2,12 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import urllib, simplejson, os, sys, httplib2, gzip +import urllib, os, sys, httplib2, gzip from cStringIO import StringIO from datetime import date from anki.db import DB from anki.errors import * -from anki.utils import ids2str, checksum, intTime +from anki.utils import ids2str, checksum, intTime, json from anki.consts import * from anki.lang import _ from hooks import runHook @@ -393,7 +393,7 @@ class LocalServer(Syncer): # serialize/deserialize payload, so we don't end up sharing objects # between cols def applyChanges(self, changes): - l = simplejson.loads; d = simplejson.dumps + l = json.loads; d = json.dumps return l(d(Syncer.applyChanges(self, l(d(changes))))) # HTTP syncing tools @@ -483,22 +483,22 @@ class RemoteServer(HttpSyncer): def hostKey(self, user, pw): "Returns hkey or none if user/pw incorrect." ret = self.req( - "hostKey", StringIO(simplejson.dumps(dict(u=user, p=pw))), + "hostKey", StringIO(json.dumps(dict(u=user, p=pw))), badAuthRaises=False, hkey=False) if not ret: # invalid auth return - self.hkey = simplejson.loads(ret)['key'] + self.hkey = json.loads(ret)['key'] return self.hkey def meta(self): ret = self.req( - "meta", StringIO(simplejson.dumps(dict(v=SYNC_VER))), + "meta", StringIO(json.dumps(dict(v=SYNC_VER))), badAuthRaises=False) if not ret: # invalid auth return - return simplejson.loads(ret) + return json.loads(ret) def applyChanges(self, **kw): return self._run("applyChanges", kw) @@ -519,8 +519,8 @@ class RemoteServer(HttpSyncer): return self._run("finish", kw) def _run(self, cmd, data): - return simplejson.loads( - self.req(cmd, StringIO(simplejson.dumps(data)))) + return json.loads( + self.req(cmd, StringIO(json.dumps(data)))) # Full syncing ########################################################################## @@ -635,23 +635,23 @@ class RemoteMediaServer(HttpSyncer): HttpSyncer.__init__(self, hkey, con) def remove(self, **kw): - return simplejson.loads( - self.req("remove", StringIO(simplejson.dumps(kw)))) + return json.loads( + self.req("remove", StringIO(json.dumps(kw)))) def files(self, **kw): - return self.req("files", StringIO(simplejson.dumps(kw))) + return self.req("files", StringIO(json.dumps(kw))) def addFiles(self, zip): # no compression, as we compress the zip file instead - return simplejson.loads( + return json.loads( self.req("addFiles", StringIO(zip), comp=0)) def mediaSanity(self): - return simplejson.loads( + return json.loads( self.req("mediaSanity")) # only for unit tests def mediatest(self, n): - return simplejson.loads( + return json.loads( self.req("mediatest", StringIO( - simplejson.dumps(dict(n=n))))) + json.dumps(dict(n=n))))) diff --git a/anki/tags.py b/anki/tags.py index a9096d9f8..229903a72 100644 --- a/anki/tags.py +++ b/anki/tags.py @@ -2,8 +2,7 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import simplejson -from anki.utils import intTime, ids2str +from anki.utils import intTime, ids2str, json from anki.hooks import runHook """ @@ -22,14 +21,14 @@ class TagManager(object): def __init__(self, col): self.col = col - def load(self, json): - self.tags = simplejson.loads(json) + def load(self, json_): + self.tags = json.loads(json_) self.changed = False def flush(self): if self.changed: self.col.db.execute("update col set tags=?", - simplejson.dumps(self.tags)) + json.dumps(self.tags)) self.changed = False # Registering and fetching tags diff --git a/anki/upgrade.py b/anki/upgrade.py index 05cb89c78..a5047edc0 100644 --- a/anki/upgrade.py +++ b/anki/upgrade.py @@ -2,9 +2,9 @@ # Copyright: Damien Elmes # License: GNU AGPL, version 3 or later; http://www.gnu.org/copyleft/agpl.html -import os, time, simplejson, re, datetime, shutil +import os, time, re, datetime, shutil from anki.lang import _ -from anki.utils import intTime, tmpfile, ids2str, splitFields, base91 +from anki.utils import intTime, tmpfile, ids2str, splitFields, base91, json from anki.db import DB from anki.collection import _Collection from anki.consts import * @@ -280,7 +280,7 @@ yesCount from reviewHistory"""): tags = {} for t in db.list("select tag from tags"): tags[t] = intTime() - db.execute("update col set tags = ?", simplejson.dumps(tags)) + db.execute("update col set tags = ?", json.dumps(tags)) db.execute("drop table tags") db.execute("drop table cardTags") @@ -346,7 +346,7 @@ insert or replace into col select id, cast(created as int), :t, mods[m['id']] = m db.execute("update notes set mid = ? where mid = ?", t, row[0]) # save and clean up - db.execute("update col set models = ?", simplejson.dumps(mods)) + db.execute("update col set models = ?", json.dumps(mods)) db.execute("drop table fieldModels") db.execute("drop table cardModels") db.execute("drop table models") diff --git a/anki/utils.py b/anki/utils.py index 34f350cd6..8cff266a4 100644 --- a/anki/utils.py +++ b/anki/utils.py @@ -14,6 +14,11 @@ if sys.version_info[1] < 5: return a % b locale.format_string = format_string +try: + import simplejson as json +except ImportError: + import json + # Time handling ##############################################################################