From d056f8fed708ad1d9a857d052f2ea3fe363d6ec9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 24 Aug 2013 16:38:57 +0530 Subject: [PATCH] newdb: Fix tweak to sort dates by visible fields not being respected --- src/calibre/db/fields.py | 11 ++++++++++- src/calibre/db/tests/reading.py | 9 +++++++++ src/calibre/utils/config_base.py | 11 +++++++++++ src/calibre/utils/date.py | 12 ++++++------ 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 35ed4a25ef..aeee1b6f45 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -10,13 +10,14 @@ __docformat__ = 'restructuredtext en' from threading import Lock from collections import defaultdict, Counter +from functools import partial from calibre.db.tables import ONE_ONE, MANY_ONE, MANY_MANY, null from calibre.db.write import Writer from calibre.ebooks.metadata import title_sort, author_to_author_sort from calibre.utils.config_base import tweaks from calibre.utils.icu import sort_key -from calibre.utils.date import UNDEFINED_DATE +from calibre.utils.date import UNDEFINED_DATE, clean_date_for_sort from calibre.utils.localization import calibre_langcode_to_name class Field(object): @@ -44,6 +45,14 @@ class Field(object): self._default_sort_key = None elif dt == 'datetime': self._default_sort_key = UNDEFINED_DATE + if tweaks['sort_dates_using_visible_fields']: + fmt = None + if name in {'timestamp', 'pubdate', 'last_modified'}: + fmt = tweaks['gui_%s_display_format' % name] + elif self.metadata['is_custom']: + fmt = self.metadata.get('display', {}).get('date_format', None) + self._sort_key = partial(clean_date_for_sort, fmt=fmt) + if self.name == 'languages': self._sort_key = lambda x:sort_key(calibre_langcode_to_name(x)) self.is_multiple = (bool(self.metadata['is_multiple']) or self.name == diff --git a/src/calibre/db/tests/reading.py b/src/calibre/db/tests/reading.py index 5f752dbfa2..4c87662de3 100644 --- a/src/calibre/db/tests/reading.py +++ b/src/calibre/db/tests/reading.py @@ -180,6 +180,15 @@ class ReadingTest(BaseTest): self.assertEqual([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) self.assertEqual([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) + # Test tweak to sort dates by visible format + from calibre.utils.date import parse_only_date as p + from calibre.utils.config_base import Tweak + self.assertEqual(cache.set_field('pubdate', {1:p('2001-3-3'), 2:p('2002-2-3'), 3:p('2003-1-3')}), {1, 2, 3}) + self.assertEqual([1, 2, 3], cache.multisort([('pubdate', True)])) + with Tweak('gui_pubdate_display_format', 'MMM'), Tweak('sort_dates_using_visible_fields', True): + c2 = self.init_cache() + self.assertEqual([3, 2, 1], c2.multisort([('pubdate', True)])) + # }}} def test_get_metadata(self): # {{{ diff --git a/src/calibre/utils/config_base.py b/src/calibre/utils/config_base.py index c099574cb0..d9110d1279 100644 --- a/src/calibre/utils/config_base.py +++ b/src/calibre/utils/config_base.py @@ -478,3 +478,14 @@ def reset_tweaks_to_default(): exec default_tweaks in dg, dl tweaks = dl +class Tweak(object): + + def __init__(self, name, value): + self.name, self.value = name, value + + def __enter__(self): + self.origval = tweaks[self.name] + tweaks[self.name] = self.value + + def __exit__(self, *args): + tweaks[self.name] = self.origval diff --git a/src/calibre/utils/date.py b/src/calibre/utils/date.py index a0c1c77a7a..4e57dc1bf3 100644 --- a/src/calibre/utils/date.py +++ b/src/calibre/utils/date.py @@ -357,10 +357,10 @@ def cd_repl_func(tt, dt, match_object): return '' return cd_function_index[s[0]](tt, dt) -def clean_date_for_sort(dt, format): +def clean_date_for_sort(dt, fmt=None): ''' Return dt with fields not in shown in format set to a default ''' - if not format: - format = 'yyMd' + if not fmt: + fmt = 'yyMd' if not isinstance(dt, datetime): dt = datetime.combine(dt, dtime()) @@ -370,15 +370,15 @@ def clean_date_for_sort(dt, format): dt = dt.replace(tzinfo=_local_tz) dt = as_local_time(dt) - if format == 'iso': - format = 'yyMdhms' + if fmt == 'iso': + fmt = 'yyMdhms' tt = {'year':UNDEFINED_DATE.year, 'mon':UNDEFINED_DATE.month, 'day':UNDEFINED_DATE.day, 'hour':UNDEFINED_DATE.hour, 'min':UNDEFINED_DATE.minute, 'sec':UNDEFINED_DATE.second} repl_func = partial(cd_repl_func, tt, dt) - re.sub('(s{1,2})|(m{1,2})|(h{1,2})|(d{1,4}|M{1,4}|(?:yyyy|yy))', repl_func, format) + re.sub('(s{1,2})|(m{1,2})|(h{1,2})|(d{1,4}|M{1,4}|(?:yyyy|yy))', repl_func, fmt) return dt.replace(year=tt['year'], month=tt['mon'], day=tt['day'], hour=tt['hour'], minute=tt['min'], second=tt['sec'], microsecond=0)