diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index a23e243a23..513f0bc690 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -7,8 +7,8 @@ __docformat__ = 'restructuredtext en' The database used to store ebook metadata ''' import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \ - json, uuid, hashlib, copy -from collections import defaultdict + json, uuid, hashlib, copy, weakref +from collections import defaultdict, MutableMapping, MutableSequence import threading, random from itertools import repeat from math import ceil @@ -81,6 +81,109 @@ class Tag(object): def __repr__(self): return str(self) +class MutablePrintMixin(object): # {{{ + def __str__(self): + self._resolve() + return str(self.values) + + def __repr__(self): + self._resolve() + return repr(self.values) + + def __unicode__(self): + self._resolve() + return unicode(self.values) +# }}} + +class FormatMetadata(MutableMapping, MutablePrintMixin): # {{{ + + def __init__(self, db, id_, formats): + self.dbwref = weakref.ref(db) + self.id_ = id_ + self.formats = formats + self._must_do = True + self.values = {} + + def _resolve(self): + if self._must_do: + self._must_do = False + db = self.dbwref() + for f in self.formats: + try: + self.values[f] = db.format_metadata(self.id_, f) + except: + pass + + def __contains__(self, key): + self._resolve() + return key in self.values + + def __getitem__(self, fmt): + self._resolve() + return self.values[fmt] + + def __setitem__(self, key, val): + self._resolve() + self.values[key] = val + + def __delitem__(self, key): + self._resolve() + self.values.__delitem__(key) + + def __len__(self): + self._resolve() + return len(self.values) + + def __iter__(self): + self._resolve() + return self.values.__iter__() + + +class FormatsList(MutableSequence, MutablePrintMixin): + + def __init__(self, formats, format_metadata): + self.formats = formats + self.format_metadata = format_metadata + self._must_do = True + self.values = [] + + def _resolve(self): + if self._must_do: + self._must_do = False + for f in self.formats: + try: + if f in self.format_metadata: + self.values.append(f) + except: + pass + + def __getitem__(self, dex): + self._resolve() + return self.values[dex] + + def __setitem__(self, key, dex): + self._resolve() + self.values[key] = dex + + def __delitem__(self, dex): + self._resolve() + self.values.__delitem__(dex) + + def __len__(self): + self._resolve() + return len(self.values) + + def __iter__(self): + self._resolve() + return self.values.__iter__() + + def insert(self, idx, val): + self._resolve() + self.values.insert(idx, val) + +# }}} + + class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): ''' @@ -944,14 +1047,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): good_formats = None else: formats = sorted(formats.split(',')) - good_formats = [] - for f in formats: - try: - mi.format_metadata[f] = self.format_metadata(id, f) - except: - pass - else: - good_formats.append(f) + mi.format_metadata = FormatMetadata(self, id, formats) + good_formats = FormatsList(formats, mi.format_metadata) mi.formats = good_formats tags = row[fm['tags']] if tags: