Make Metadata smart update handle classifiers correctly

This commit is contained in:
Charles Haley 2010-10-04 11:51:27 +01:00
parent 3941b9c4a1
commit 4ae7a3b8c9
2 changed files with 27 additions and 3 deletions

View File

@ -104,7 +104,8 @@ STANDARD_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
SC_FIELDS_NOT_COPIED = frozenset(['title', 'title_sort', 'authors', SC_FIELDS_NOT_COPIED = frozenset(['title', 'title_sort', 'authors',
'author_sort', 'author_sort_map', 'author_sort', 'author_sort_map',
'cover_data', 'tags', 'language']) 'cover_data', 'tags', 'language',
'classifiers'])
# Metadata fields that smart update should copy only if the source is not None # Metadata fields that smart update should copy only if the source is not None
SC_FIELDS_COPY_NOT_NULL = frozenset(['lpath', 'size', 'comments', 'thumbnail']) SC_FIELDS_COPY_NOT_NULL = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
@ -114,8 +115,7 @@ SC_COPYABLE_FIELDS = SOCIAL_METADATA_FIELDS.union(
PUBLICATION_METADATA_FIELDS).union( PUBLICATION_METADATA_FIELDS).union(
BOOK_STRUCTURE_FIELDS).union( BOOK_STRUCTURE_FIELDS).union(
DEVICE_METADATA_FIELDS).union( DEVICE_METADATA_FIELDS).union(
CALIBRE_METADATA_FIELDS).union( CALIBRE_METADATA_FIELDS) - \
TOP_LEVEL_CLASSIFIERS) - \
SC_FIELDS_NOT_COPIED.union( SC_FIELDS_NOT_COPIED.union(
SC_FIELDS_COPY_NOT_NULL) SC_FIELDS_COPY_NOT_NULL)

View File

@ -164,6 +164,18 @@ class Metadata(object):
def set(self, field, val, extra=None): def set(self, field, val, extra=None):
self.__setattr__(field, val, extra) self.__setattr__(field, val, extra)
def get_classifiers(self):
'''
Return a copy of the classifiers dictionary.
The dict is small, and the penalty for using a reference where a copy is
needed is large. Also, we don't want any manipulations of the returned
dict to show up in the book.
'''
return copy.deepcopy(object.__getattribute__(self, '_data')['classifiers'])
def set_classifiers(self, classifiers):
object.__getattribute__(self, '_data')['classifiers'] = classifiers
# field-oriented interface. Intended to be the same as in LibraryDatabase # field-oriented interface. Intended to be the same as in LibraryDatabase
def standard_field_keys(self): def standard_field_keys(self):
@ -369,6 +381,7 @@ class Metadata(object):
self.set_all_user_metadata(other.get_all_user_metadata(make_copy=True)) self.set_all_user_metadata(other.get_all_user_metadata(make_copy=True))
for x in SC_FIELDS_COPY_NOT_NULL: for x in SC_FIELDS_COPY_NOT_NULL:
copy_not_none(self, other, x) copy_not_none(self, other, x)
self.set_classifiers(other.get_classifiers())
# language is handled below # language is handled below
else: else:
for attr in SC_COPYABLE_FIELDS: for attr in SC_COPYABLE_FIELDS:
@ -423,6 +436,17 @@ class Metadata(object):
if len(other_comments.strip()) > len(my_comments.strip()): if len(other_comments.strip()) > len(my_comments.strip()):
self.comments = other_comments self.comments = other_comments
# Copy all the non-none classifiers
if callable(getattr(other, 'get_classifiers', None)):
d = self.get_classifiers()
s = other.get_classifiers()
d.update([v for v in s.iteritems() if v[1] is not None])
self.set_classifiers(d)
else:
# other structure not Metadata. Copy the top-level classifiers
for attr in TOP_LEVEL_CLASSIFIERS:
copy_not_none(self, other, attr)
other_lang = getattr(other, 'language', None) other_lang = getattr(other, 'language', None)
if other_lang and other_lang.lower() != 'und': if other_lang and other_lang.lower() != 'und':
self.language = other_lang self.language = other_lang