From c8f200b20fd77b5b4486a1306f1bdd96e2cd9ea4 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Fri, 13 Feb 2015 18:29:42 +0000 Subject: [PATCH 01/12] fixed bug #1280295 'Enable natural sorting for song book searches' --fixes 1280294 --- openlp/plugins/songs/lib/mediaitem.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index c0c58ff90..ae804878e 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -255,7 +255,7 @@ class SongMediaItem(MediaManagerItem): log.debug('display results Book') self.list_view.clear() for book in search_results: - songs = sorted(book.songs, key=lambda song: int(re.match(r'[0-9]+', '0' + song.song_number).group())) + songs = sorted(book.songs, key=lambda song: self._natural_sort_key(song.song_number)) for song in songs: # Do not display temporary songs if song.temporary: @@ -583,6 +583,24 @@ class SongMediaItem(MediaManagerItem): # List must be empty at the end return not author_list + def _try_int(self, s): + """ + Convert string s to an integer if possible. Fail silently and return + the string as-is if it isn't an integer. + :param s: The string to try to convert. + """ + try: + return int(s) + except (TypeError, ValueError): + return s + + def _natural_sort_key(self, s): + """ + Return a tuple by which s is sorted. + :param s: A string value from the list we want to sort. + """ + return list(map(self._try_int, re.findall(r'(\d+|\D+)', s))) + def search(self, string, show_error): """ Search for some songs From 81908970b341c10ba39d057f16ba3259040befdd Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 20 Jun 2015 23:29:03 +0100 Subject: [PATCH 02/12] added unit tests --- .../openlp_plugins/songs/test_mediaitem.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index 4e28eed93..e3585546f 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -48,6 +48,10 @@ class TestMediaItem(TestCase, TestMixin): with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \ patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'): self.media_item = SongMediaItem(None, MagicMock()) + self.media_item.list_view = MagicMock() + self.media_item.list_view.save_auto_select_id = MagicMock() + self.media_item.list_view.clear = MagicMock() + self.media_item.list_view.addItem = MagicMock() self.media_item.display_songbook = False self.media_item.display_copyright_symbol = False self.setup_application() @@ -60,6 +64,37 @@ class TestMediaItem(TestCase, TestMixin): """ self.destroy_settings() + def display_results_book_test(self): + """ + Test displaying song search results grouped by book with basic song + """ + # GIVEN: Search results grouped by book, plus a mocked QtListWidgetItem + with patch('openlp.core.lib.QtGui.QListWidgetItem') as MockedQListWidgetItem, \ + patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole: + mock_search_results = [] + mock_book = MagicMock() + mock_song = MagicMock() + mock_book.name = 'My Book' + mock_book.songs = [] + mock_song.id = 1 + mock_song.title = 'My Song' + mock_song.sort_key = 'My Song' + mock_song.song_number = '123' + mock_song.temporary = False + mock_book.songs.append(mock_song) + mock_search_results.append(mock_book) + mock_qlist_widget = MagicMock() + MockedQListWidgetItem.return_value = mock_qlist_widget + + # WHEN: I display song search results grouped by book + self.media_item.display_results_book(mock_search_results) + + # THEN: The current list view is cleared, the widget is created, and the relevant attributes set + self.media_item.list_view.clear.assert_called_with() + MockedQListWidgetItem.assert_called_with('My Book - 123 (My Song)') + mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_song.id) + self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget) + def build_song_footer_one_author_test(self): """ Test build songs footer with basic song and one author @@ -257,3 +292,44 @@ class TestMediaItem(TestCase, TestMixin): # THEN: They should not match self.assertFalse(result, "Authors should not match") + + def try_int_with_string_integer_test(self): + """ + Test the _try_int function with a string containing an integer + """ + # GIVEN: A string that is an integer + string_integer = '123' + + # WHEN: We "convert" it to an integer + integer_result = self.media_item._try_int(string_integer) + + # THEN: We should get back an integer + self.assertIsInstance(integer_result, int, 'The result should be an integer') + self.assertEqual(integer_result, 123, 'The result should be 123') + + def try_int_with_string_noninteger_test(self): + """ + Test the _try_int function with a string not containing an integer + """ + # GIVEN: A string that is not an integer + string_noninteger = 'abc' + + # WHEN: We "convert" it to an integer + noninteger_result = self.media_item._try_int(string_noninteger) + + # THEN: We should get back the original string + self.assertIsInstance(noninteger_result, type(string_noninteger), 'The result type should be the same') + self.assertEqual(noninteger_result, string_noninteger, 'The result value should be the same') + + def natural_sort_key_test(self): + """ + Test the _natural_sort_key function + """ + # GIVEN: A string to be converted into a sort key + string_sort_key = 'A1B12C123' + + # WHEN: We attempt to create a sort key + sort_key_result = self.media_item._natural_sort_key(string_sort_key) + + # THEN: We should get back a tuple split on integers + self.assertEqual(sort_key_result, ['A', 1, 'B', 12, 'C', 123]) From 442f9578d1658314d6253ccea510f3df4f6f9171 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 13 Feb 2016 17:09:46 +0000 Subject: [PATCH 03/12] test fix for trunk --- .../openlp_plugins/songs/test_mediaitem.py | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index 0f7cdb7fc..428f9bca3 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -48,10 +48,6 @@ class TestMediaItem(TestCase, TestMixin): with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \ patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'): self.media_item = SongMediaItem(None, MagicMock()) - self.media_item.list_view = MagicMock() - self.media_item.list_view.save_auto_select_id = MagicMock() - self.media_item.list_view.clear = MagicMock() - self.media_item.list_view.addItem = MagicMock() self.media_item.display_songbook = False self.media_item.display_copyright_symbol = False self.setup_application() @@ -64,37 +60,6 @@ class TestMediaItem(TestCase, TestMixin): """ self.destroy_settings() - def display_results_book_test(self): - """ - Test displaying song search results grouped by book with basic song - """ - # GIVEN: Search results grouped by book, plus a mocked QtListWidgetItem - with patch('openlp.core.lib.QtGui.QListWidgetItem') as MockedQListWidgetItem, \ - patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole: - mock_search_results = [] - mock_book = MagicMock() - mock_song = MagicMock() - mock_book.name = 'My Book' - mock_book.songs = [] - mock_song.id = 1 - mock_song.title = 'My Song' - mock_song.sort_key = 'My Song' - mock_song.song_number = '123' - mock_song.temporary = False - mock_book.songs.append(mock_song) - mock_search_results.append(mock_book) - mock_qlist_widget = MagicMock() - MockedQListWidgetItem.return_value = mock_qlist_widget - - # WHEN: I display song search results grouped by book - self.media_item.display_results_book(mock_search_results) - - # THEN: The current list view is cleared, the widget is created, and the relevant attributes set - self.media_item.list_view.clear.assert_called_with() - MockedQListWidgetItem.assert_called_with('My Book - 123 (My Song)') - mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_song.id) - self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget) - def build_song_footer_one_author_test(self): """ Test build songs footer with basic song and one author From 7887dcbf2b977fb851ab725d3ae849c9beca41d9 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 13 Feb 2016 17:11:35 +0000 Subject: [PATCH 04/12] cosmetic --- openlp/plugins/songs/lib/mediaitem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index fda607bbe..420379e2b 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -253,7 +253,7 @@ class SongMediaItem(MediaManagerItem): search_keywords = search_keywords.rpartition(' ') search_book = search_keywords[0] search_entry = re.sub(r'[^0-9]', '', search_keywords[2]) - + songbook_entries = (self.plugin.manager.session.query(SongBookEntry) .join(Book)) songbook_entries = sorted(songbook_entries, key=lambda songbook_entry: (songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) From bb0adc6f5dc1afdb3a15e69ea8682f8f63675423 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 19 Mar 2016 15:01:10 +0000 Subject: [PATCH 05/12] fixed bug #1280295 'Enable natural sorting for song book searches', refactored to move filtering to database, updated test Fixes: https://launchpad.net/bugs/1280295 --- openlp/plugins/songs/lib/mediaitem.py | 30 +++++++---------- .../openlp_plugins/songs/test_mediaitem.py | 32 +++++++++++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 12579c56d..12ef3de3d 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -203,7 +203,13 @@ class SongMediaItem(MediaManagerItem): self.display_results_topic(search_results) elif search_type == SongSearch.Books: log.debug('Songbook Search') - self.display_results_book(search_keywords) + search_keywords = search_keywords.rpartition(' ') + search_book = search_keywords[0] + '%' + search_entry = search_keywords[2] + '%' + search_results = (self.plugin.manager.session.query(SongBookEntry) + .join(Book) + .filter(Book.name.like(search_book), SongBookEntry.entry.like(search_entry)).all()) + self.display_results_book(search_results) elif search_type == SongSearch.Themes: log.debug('Theme Search') search_string = '%' + search_keywords + '%' @@ -288,31 +294,19 @@ class SongMediaItem(MediaManagerItem): song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) - def display_results_book(self, search_keywords): + def display_results_book(self, search_results): """ - Display the song search results in the media manager list, grouped by book + Display the song search results in the media manager list, grouped by book and entry - :param search_keywords: A list of search keywords - book first, then number + :param search_results: A list of db SongBookEntry objects :return: None """ - log.debug('display results Book') self.list_view.clear() - - search_keywords = search_keywords.rpartition(' ') - search_book = search_keywords[0] - search_entry = re.sub(r'[^0-9]', '', search_keywords[2]) - - songbook_entries = (self.plugin.manager.session.query(SongBookEntry) - .join(Book)) - songbook_entries = sorted(songbook_entries, key=lambda songbook_entry: (songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) - for songbook_entry in songbook_entries: + search_results = sorted(search_results, key=lambda songbook_entry: (songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) + for songbook_entry in search_results: if songbook_entry.song.temporary: continue - if search_book.lower() not in songbook_entry.songbook.name.lower(): - continue - if search_entry not in songbook_entry.entry: - continue song_detail = '%s #%s: %s' % (songbook_entry.songbook.name, songbook_entry.entry, songbook_entry.song.title) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, songbook_entry.song.id) diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index d09f5b76e..865b81ba9 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -127,6 +127,38 @@ class TestMediaItem(TestCase, TestMixin): mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_song.id) self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget) + def display_results_book_test(self): + """ + Test displaying song search results grouped by book and entry with basic song + """ + # GIVEN: Search results grouped by book and entry, plus a mocked QtListWidgetItem + with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \ + patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole: + mock_search_results = [] + mock_songbook_entry = MagicMock() + mock_songbook = MagicMock() + mock_song = MagicMock() + mock_songbook_entry.entry = '1' + mock_songbook.name = 'My Book' + mock_song.id = 1 + mock_song.title = 'My Song' + mock_song.sort_key = 'My Song' + mock_song.temporary = False + mock_songbook_entry.song = mock_song + mock_songbook_entry.songbook = mock_songbook + mock_search_results.append(mock_songbook_entry) + mock_qlist_widget = MagicMock() + MockedQListWidgetItem.return_value = mock_qlist_widget + + # WHEN: I display song search results grouped by book + self.media_item.display_results_book(mock_search_results) + + # THEN: The current list view is cleared, the widget is created, and the relevant attributes set + self.media_item.list_view.clear.assert_called_with() + MockedQListWidgetItem.assert_called_with('My Book #1: My Song') + mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_songbook_entry.song.id) + self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget) + def display_results_topic_test(self): """ Test displaying song search results grouped by topic with basic song From 3db138ea8d1334a2aabec934c3b663260143eea8 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 19 Mar 2016 15:50:56 +0000 Subject: [PATCH 06/12] coding standards fix --- openlp/plugins/songs/lib/mediaitem.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 67dee4023..06636bcc6 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -207,8 +207,8 @@ class SongMediaItem(MediaManagerItem): search_book = search_keywords[0] + '%' search_entry = search_keywords[2] + '%' search_results = (self.plugin.manager.session.query(SongBookEntry) - .join(Book) - .filter(Book.name.like(search_book), SongBookEntry.entry.like(search_entry)).all()) + .join(Book) + .filter(Book.name.like(search_book), SongBookEntry.entry.like(search_entry)).all()) self.display_results_book(search_results) elif search_type == SongSearch.Themes: log.debug('Theme Search') @@ -303,7 +303,8 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Book') self.list_view.clear() - search_results = sorted(search_results, key=lambda songbook_entry: (songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) + search_results = sorted(search_results, key=lambda songbook_entry: ( + songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) for songbook_entry in search_results: if songbook_entry.song.temporary: continue From 5e33c0508055807318d7ca9c559b718025496a09 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 19 Mar 2016 16:00:35 +0000 Subject: [PATCH 07/12] coding standards fix 2 --- openlp/plugins/songs/lib/mediaitem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 06636bcc6..fd7dfe986 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -304,7 +304,7 @@ class SongMediaItem(MediaManagerItem): log.debug('display results Book') self.list_view.clear() search_results = sorted(search_results, key=lambda songbook_entry: ( - songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) + songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) for songbook_entry in search_results: if songbook_entry.song.temporary: continue From 2feedf6f383c8fad2e11b4928900a43bf51ee668 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sat, 19 Mar 2016 16:01:23 +0000 Subject: [PATCH 08/12] coding standards fix --- openlp/plugins/songs/lib/mediaitem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index fd7dfe986..e46b95fbf 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -303,8 +303,8 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Book') self.list_view.clear() - search_results = sorted(search_results, key=lambda songbook_entry: ( - songbook_entry.songbook.name, self._natural_sort_key(songbook_entry.entry))) + search_results = sorted(search_results, key=lambda songbook_entry: (songbook_entry.songbook.name, + self._natural_sort_key(songbook_entry.entry))) for songbook_entry in search_results: if songbook_entry.song.temporary: continue From 330a1758c8a1295a468f458383ed5aa2882bb98a Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sun, 3 Apr 2016 11:57:39 +0100 Subject: [PATCH 09/12] Use get_natural_key instead of _natural_sort_key --- openlp/core/utils/__init__.py | 2 +- openlp/plugins/songs/lib/mediaitem.py | 25 ++++++++----------- .../openlp_plugins/songs/test_mediaitem.py | 13 ---------- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 086c69c79..69187ed74 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -529,7 +529,7 @@ def get_natural_key(string): key = [int(part) if part.isdigit() else get_locale_key(part) for part in key] # Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str # and int. - if string[0].isdigit(): + if string and string[0].isdigit(): return [b''] + key return key diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index e46b95fbf..deefa2acd 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -32,6 +32,7 @@ from openlp.core.common import Registry, AppLocation, Settings, check_directory_ from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \ check_item_selected, create_separated_list from openlp.core.lib.ui import create_widget_action +from openlp.core.utils import get_natural_key from openlp.plugins.songs.forms.editsongform import EditSongForm from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm from openlp.plugins.songs.forms.songimportform import SongImportForm @@ -284,8 +285,10 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Author') self.list_view.clear() + search_results = sorted(search_results, key=lambda author: (get_natural_key(author.display_name))) for author in search_results: - for song in author.songs: + songs = sorted(author.songs, key=lambda song: song.sort_key) + for song in songs: # Do not display temporary songs if song.temporary: continue @@ -303,8 +306,8 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Book') self.list_view.clear() - search_results = sorted(search_results, key=lambda songbook_entry: (songbook_entry.songbook.name, - self._natural_sort_key(songbook_entry.entry))) + search_results = sorted(search_results, key=lambda songbook_entry: (get_natural_key(songbook_entry.songbook.name), + get_natural_key(songbook_entry.entry))) for songbook_entry in search_results: if songbook_entry.song.temporary: continue @@ -322,7 +325,7 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Topic') self.list_view.clear() - search_results = sorted(search_results, key=lambda topic: self._natural_sort_key(topic.name)) + search_results = sorted(search_results, key=lambda topic: get_natural_key(topic.name)) for topic in search_results: songs = sorted(topic.songs, key=lambda song: song.sort_key) for song in songs: @@ -343,6 +346,8 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Themes') self.list_view.clear() + search_results = sorted(search_results, key=lambda song: (get_natural_key(song.theme_name), + song.sort_key)) for song in search_results: # Do not display temporary songs if song.temporary: @@ -361,8 +366,8 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results CCLI number') self.list_view.clear() - songs = sorted(search_results, key=lambda song: self._natural_sort_key(song.ccli_number)) - for song in songs: + search_results = sorted(search_results, key=lambda song: get_natural_key(song.ccli_number)) + for song in search_results: # Do not display temporary songs if song.temporary: continue @@ -688,14 +693,6 @@ class SongMediaItem(MediaManagerItem): # List must be empty at the end return not author_list - def _natural_sort_key(self, s): - """ - Return a tuple by which s is sorted. - :param s: A string value from the list we want to sort. - """ - return [int(text) if text.isdecimal() else text.lower() - for text in re.split('(\d+)', s)] - def search(self, string, show_error): """ Search for some songs diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index 5e343fc9d..3cd5f97ba 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -448,19 +448,6 @@ class TestMediaItem(TestCase, TestMixin): # THEN: They should not match self.assertFalse(result, "Authors should not match") - def natural_sort_key_test(self): - """ - Test the _natural_sort_key function - """ - # GIVEN: A string to be converted into a sort key - string_sort_key = 'A1B12C' - - # WHEN: We attempt to create a sort key - sort_key_result = self.media_item._natural_sort_key(string_sort_key) - - # THEN: We should get back a tuple split on integers - self.assertEqual(sort_key_result, ['a', 1, 'b', 12, 'c']) - def build_remote_search_test(self): """ Test results for the remote search api From efb71b4f3125033704b43d555ae59341db899504 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sun, 3 Apr 2016 11:58:35 +0100 Subject: [PATCH 10/12] Merge w/ trunk --- openlp/plugins/songs/lib/mediaitem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index deefa2acd..2644ef125 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -285,7 +285,7 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Author') self.list_view.clear() - search_results = sorted(search_results, key=lambda author: (get_natural_key(author.display_name))) + search_results = sorted(search_results, key=lambda author: get_natural_key(author.display_name)) for author in search_results: songs = sorted(author.songs, key=lambda song: song.sort_key) for song in songs: From ae394cf028539e2ba73fab8a955218960083ed9d Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sun, 3 Apr 2016 12:02:53 +0100 Subject: [PATCH 11/12] Minor fixes --- openlp/plugins/songs/lib/mediaitem.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 2644ef125..7842d7cfc 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -366,8 +366,9 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results CCLI number') self.list_view.clear() - search_results = sorted(search_results, key=lambda song: get_natural_key(song.ccli_number)) - for song in search_results: + songs = sorted(search_results, key=lambda song: (get_natural_key(song.ccli_number), + song.sort_key)) + for song in songs: # Do not display temporary songs if song.temporary: continue From 33cbda294d290f95d297ea6600298e7cdd0b8254 Mon Sep 17 00:00:00 2001 From: Chris Hill Date: Sun, 3 Apr 2016 12:14:17 +0100 Subject: [PATCH 12/12] Coding standards fixes --- openlp/plugins/songs/lib/mediaitem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 7842d7cfc..b84e557c2 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -306,8 +306,8 @@ class SongMediaItem(MediaManagerItem): """ log.debug('display results Book') self.list_view.clear() - search_results = sorted(search_results, key=lambda songbook_entry: (get_natural_key(songbook_entry.songbook.name), - get_natural_key(songbook_entry.entry))) + search_results = sorted(search_results, key=lambda songbook_entry: + (get_natural_key(songbook_entry.songbook.name), get_natural_key(songbook_entry.entry))) for songbook_entry in search_results: if songbook_entry.song.temporary: continue @@ -367,7 +367,7 @@ class SongMediaItem(MediaManagerItem): log.debug('display results CCLI number') self.list_view.clear() songs = sorted(search_results, key=lambda song: (get_natural_key(song.ccli_number), - song.sort_key)) + song.sort_key)) for song in songs: # Do not display temporary songs if song.temporary: