From 9155f838f1f43d878c083bd1a9b9ce955d1c32c8 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Wed, 8 Sep 2010 19:39:57 +0100 Subject: [PATCH] Fix some bugs found after or introduced by trunk merges --- src/calibre/ebooks/metadata/book/__init__.py | 3 ++- src/calibre/ebooks/metadata/book/base.py | 26 ++++++++++---------- src/calibre/library/save_to_disk.py | 25 ++++++++++--------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/calibre/ebooks/metadata/book/__init__.py b/src/calibre/ebooks/metadata/book/__init__.py index ca7f4f7074..e7f58ce858 100644 --- a/src/calibre/ebooks/metadata/book/__init__.py +++ b/src/calibre/ebooks/metadata/book/__init__.py @@ -109,7 +109,8 @@ COPYABLE_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union( CALIBRE_METADATA_FIELDS) - \ frozenset(['title', 'title_sort', 'authors', 'author_sort', 'author_sort_map' 'comments', - 'cover_data', 'tags', 'language', 'lpath']) + 'cover_data', 'tags', 'language', 'lpath', + 'size']) SERIALIZABLE_FIELDS = SOCIAL_METADATA_FIELDS.union( USER_METADATA_FIELDS).union( diff --git a/src/calibre/ebooks/metadata/book/base.py b/src/calibre/ebooks/metadata/book/base.py index 648beb7b5c..69a3c42f4d 100644 --- a/src/calibre/ebooks/metadata/book/base.py +++ b/src/calibre/ebooks/metadata/book/base.py @@ -201,6 +201,11 @@ class Metadata(object): Merge the information in C{other} into self. In case of conflicts, the information in C{other} takes precedence, unless the information in other is NULL. ''' + def copy_not_none(dest, src, attr): + v = getattr(src, attr, None) + if v is not None: + setattr(dest, attr, copy.deepcopy(v)) + if other.title and other.title != _('Unknown'): self.title = other.title if hasattr(other, 'title_sort'): @@ -220,21 +225,19 @@ class Metadata(object): self.tags = other.tags self.cover_data = getattr(other, 'cover_data', '') self.set_all_user_metadata(other.get_all_user_metadata(make_copy=True)) - self.comments = getattr(other, 'comments', '') - self.language = getattr(other, 'language', None) - lpath = getattr(other, 'lpath', None) - if lpath is not None: - self.lpath = lpath + copy_not_none(self, other, 'lpath') + copy_not_none(self, other, 'size') + copy_not_none(self, other, 'comments') + # language is handled below else: for attr in COPYABLE_METADATA_FIELDS: if hasattr(other, attr): + copy_not_none(self, other, attr) val = getattr(other, attr) if val is not None: setattr(self, attr, copy.deepcopy(val)) - if other.tags: self.tags += list(set(self.tags + other.tags)) - if getattr(other, 'cover_data', False): other_cover = other.cover_data[-1] self_cover = self.cover_data[-1] if self.cover_data else '' @@ -242,13 +245,11 @@ class Metadata(object): if not other_cover: other_cover = '' if len(other_cover) > len(self_cover): self.cover_data = other.cover_data - if getattr(other, 'user_metadata_keys', None): for x in other.user_metadata_keys: meta = other.get_user_metadata(x, make_copy=True) if meta is not None: self.set_user_metadata(x, meta) # get... did the deepcopy - my_comments = getattr(self, 'comments', '') other_comments = getattr(other, 'comments', '') if not my_comments: @@ -257,10 +258,9 @@ class Metadata(object): other_comments = '' if len(other_comments.strip()) > len(my_comments.strip()): self.comments = other_comments - - other_lang = getattr(other, 'language', None) - if other_lang and other_lang.lower() != 'und': - self.language = other_lang + other_lang = getattr(other, 'language', None) + if other_lang and other_lang.lower() != 'und': + self.language = other_lang def format_series_index(self, val=None): from calibre.ebooks.metadata import fmt_sidx diff --git a/src/calibre/library/save_to_disk.py b/src/calibre/library/save_to_disk.py index c940cc006b..d33cbb04b5 100644 --- a/src/calibre/library/save_to_disk.py +++ b/src/calibre/library/save_to_disk.py @@ -6,7 +6,7 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, traceback, cStringIO, re +import os, traceback, cStringIO, re, string from calibre.utils.config import Config, StringConfig, tweaks from calibre.utils.filenames import shorten_components_to, supports_long_names, \ @@ -98,17 +98,20 @@ def preprocess_template(template): template = template.decode(preferred_encoding, 'replace') return template +class SafeFormat(string.Formatter): + ''' + Provides a format function that substitutes '' for any missing value + ''' + def get_value(self, key, args, kwargs): + try: + return kwargs[key] + except: + return '' +safe_formatter = SafeFormat() + def safe_format(x, format_args): - try: - ans = x.format(**format_args).strip() - return re.sub(r'\s+', ' ', ans) - except IndexError: # Thrown if user used [] and index is out of bounds - pass - except AttributeError: # Thrown if user used a non existing attribute - pass - except KeyError: # Thrown if user used custom field w/value None - pass - return '' + ans = safe_formatter.vformat(x, [], format_args).strip() + return re.sub(r'\s+', ' ', ans) def get_components(template, mi, id, timefmt='%b %Y', length=250, sanitize_func=ascii_filename, replace_whitespace=False,