From 76ea8126294d088d5ae4e002cd860b3f1faf7764 Mon Sep 17 00:00:00 2001 From: M2j Date: Sat, 30 Mar 2013 22:54:42 +0100 Subject: [PATCH 01/10] - switch to Python3 style sorting - use ICU for string sorting --- openlp/core/ui/exceptionform.py | 6 +++ openlp/core/ui/thememanager.py | 4 +- openlp/core/utils/__init__.py | 47 ++++++++++++++----- .../plugins/bibles/forms/bibleimportform.py | 4 +- openlp/plugins/bibles/lib/mediaitem.py | 6 +-- openlp/plugins/custom/lib/db.py | 7 ++- openlp/plugins/images/lib/mediaitem.py | 12 ++--- openlp/plugins/media/lib/mediaitem.py | 6 +-- openlp/plugins/presentations/lib/mediaitem.py | 5 +- openlp/plugins/songs/forms/songexportform.py | 4 +- openlp/plugins/songs/lib/__init__.py | 36 +------------- openlp/plugins/songs/lib/mediaitem.py | 6 +-- scripts/check_dependencies.py | 1 + 13 files changed, 69 insertions(+), 75 deletions(-) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 25f8201b1..e4854d0c0 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -69,6 +69,11 @@ try: MAKO_VERSION = mako.__version__ except ImportError: MAKO_VERSION = u'-' +try: + import icu + ICU_VERSION = u'OK' +except ImportError: + ICU_VERSION = u'-' try: import uno arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue') @@ -143,6 +148,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): u'PyEnchant: %s\n' % ENCHANT_VERSION + \ u'PySQLite: %s\n' % SQLITE_VERSION + \ u'Mako: %s\n' % MAKO_VERSION + \ + u'pyICU: %s\n' % ICU_VERSION + \ u'pyUNO bridge: %s\n' % UNO_VERSION + \ u'VLC: %s\n' % VLC_VERSION if platform.system() == u'Linux': diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 89bbe86f8..53d4a513b 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -44,7 +44,7 @@ from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, Backgr from openlp.core.lib.ui import critical_error_message_box, create_widget_action from openlp.core.theme import Theme from openlp.core.ui import FileRenameForm, ThemeForm -from openlp.core.utils import AppLocation, delete_file, locale_compare, get_filesystem_encoding +from openlp.core.utils import AppLocation, delete_file, get_local_key, get_filesystem_encoding log = logging.getLogger(__name__) @@ -418,7 +418,7 @@ class ThemeManager(QtGui.QWidget): self.theme_list_widget.clear() files = AppLocation.get_files(self.settings_section, u'.png') # Sort the themes by its name considering language specific - files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare) + files.sort(key=lambda file_name: get_local_key(unicode(file_name))) # now process the file list of png files for name in files: # check to see file is in theme root directory diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index d32729699..625bd25b5 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -38,6 +38,7 @@ import re from subprocess import Popen, PIPE import sys import urllib2 +import icu from PyQt4 import QtGui, QtCore @@ -56,6 +57,7 @@ from openlp.core.lib import translate log = logging.getLogger(__name__) APPLICATION_VERSION = {} IMAGES_FILTER = None +ICU_COLLATOR = None UNO_CONNECTION_TYPE = u'pipe' #UNO_CONNECTION_TYPE = u'socket' CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE) @@ -379,21 +381,42 @@ def format_time(text, local_time): return re.sub('\%[a-zA-Z]', match_formatting, text) -def locale_compare(string1, string2): +def get_local_key(string): """ - Compares two strings according to the current locale settings. - - As any other compare function, returns a negative, or a positive value, - or 0, depending on whether string1 collates before or after string2 or - is equal to it. Comparison is case insensitive. + Creates a key for case insensitive, locale aware string sorting. """ - # Function locale.strcoll() from standard Python library does not work properly on Windows. - return locale.strcoll(string1.lower(), string2.lower()) + string = string.lower() + # For Python 3 on platforms other than Windows ICU is not necessary. In those cases locale.strxfrm(str) can be used. + global ICU_COLLATOR + if ICU_COLLATOR is None: + from languagemanager import LanguageManager + locale = LanguageManager.get_language() + icu_locale = icu.Locale(locale) + ICU_COLLATOR = icu.Collator.createInstance(icu_locale) + return ICU_COLLATOR.getSortKey(string) -# For performance reasons provide direct reference to compare function without wrapping it in another function making -# the string lowercase. This is needed for sorting songs. -locale_direct_compare = locale.strcoll +def get_natural_key(string): + """ + Generate a key for locale aware natural string sorting. Returns a list of strings and integers. + + ``string`` + A string, list or tuple which represents the item string. + """ + if isinstance(string, basestring): + string = re.findall(r'(\d+|\D+)', string) + if len(string) == 1: + return list(get_local_key(string[0])) + elif isinstance(string, tuple): + string = list(string) + if isinstance(string, list): + for index, part in enumerate(string): + if isinstance(part, basestring): + if part.isdigit(): + string[index] = int(part) + else: + string[index] = get_local_key(part) + return string from applocation import AppLocation @@ -403,4 +426,4 @@ from actions import ActionList __all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version', u'add_actions', u'get_filesystem_encoding', u'get_web_page', u'get_uno_command', u'get_uno_instance', - u'delete_file', u'clean_filename', u'format_time', u'locale_compare', u'locale_direct_compare'] + u'delete_file', u'clean_filename', u'format_time', u'get_local_key', u'get_natural_key'] diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index e360cd4a1..319989433 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -38,7 +38,7 @@ from openlp.core.lib import Settings, UiStrings, translate from openlp.core.lib.db import delete_database from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import AppLocation, locale_compare +from openlp.core.utils import AppLocation, get_local_key from openlp.plugins.bibles.lib.manager import BibleFormat from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename @@ -455,7 +455,7 @@ class BibleImportForm(OpenLPWizard): """ self.webTranslationComboBox.clear() bibles = self.web_bible_list[index].keys() - bibles.sort(cmp=locale_compare) + bibles.sort(key=get_local_key) self.webTranslationComboBox.addItems(bibles) def onOsisBrowseButtonClicked(self): diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index abe3cc45a..4ae7e76b5 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -36,7 +36,7 @@ from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, Servic from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \ critical_error_message_box, find_and_set_in_combo_box, build_icon -from openlp.core.utils import locale_compare +from openlp.core.utils import get_local_key from openlp.plugins.bibles.forms import BibleImportForm, EditBibleForm from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \ LanguageSelection, BibleStrings @@ -325,7 +325,7 @@ class BibleMediaItem(MediaManagerItem): # Get all bibles and sort the list. bibles = self.plugin.manager.get_bibles().keys() bibles = filter(None, bibles) - bibles.sort(cmp=locale_compare) + bibles.sort(key=get_local_key) # Load the bibles into the combo boxes. self.quickVersionComboBox.addItems(bibles) self.quickSecondComboBox.addItems(bibles) @@ -461,7 +461,7 @@ class BibleMediaItem(MediaManagerItem): for book in book_data: data = BiblesResourcesDB.get_book_by_id(book.book_reference_id) books.append(data[u'name'] + u' ') - books.sort(cmp=locale_compare) + books.sort(key=get_local_key) set_case_insensitive_completer(books, self.quickSearchEdit) def on_import_click(self): diff --git a/openlp/plugins/custom/lib/db.py b/openlp/plugins/custom/lib/db.py index cc6e45742..ad876b6b6 100644 --- a/openlp/plugins/custom/lib/db.py +++ b/openlp/plugins/custom/lib/db.py @@ -35,7 +35,7 @@ from sqlalchemy import Column, Table, types from sqlalchemy.orm import mapper from openlp.core.lib.db import BaseModel, init_db -from openlp.core.utils import locale_compare +from openlp.core.utils import get_local_key class CustomSlide(BaseModel): """ @@ -44,11 +44,10 @@ class CustomSlide(BaseModel): # By default sort the customs by its title considering language specific # characters. def __lt__(self, other): - r = locale_compare(self.title, other.title) - return True if r < 0 else False + return get_local_key(self.title) < get_local_key(other.title) def __eq__(self, other): - return 0 == locale_compare(self.title, other.title) + return get_local_key(self.title) == get_local_key(other.title) def init_schema(url): diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index d74b1ccab..8c6bc8d9f 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -36,7 +36,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem, Registry, Servic StringContent, TreeWidgetWithDnD, UiStrings, build_icon, check_directory_exists, check_item_selected, \ create_thumb, translate, validate_thumb from openlp.core.lib.ui import create_widget_action, critical_error_message_box -from openlp.core.utils import AppLocation, delete_file, locale_compare, get_images_filter +from openlp.core.utils import AppLocation, delete_file, get_local_key, get_images_filter from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups @@ -255,7 +255,7 @@ class ImageMediaItem(MediaManagerItem): The ID of the group that will be added recursively """ image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id) - image_groups.sort(cmp=locale_compare, key=lambda group_object: group_object.group_name) + image_groups.sort(key=lambda group_object: get_local_key(group_object.group_name)) folder_icon = build_icon(u':/images/image_group.png') for image_group in image_groups: group = QtGui.QTreeWidgetItem() @@ -286,7 +286,7 @@ class ImageMediaItem(MediaManagerItem): combobox.clear() combobox.top_level_group_added = False image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id) - image_groups.sort(cmp=locale_compare, key=lambda group_object: group_object.group_name) + image_groups.sort(key=lambda group_object: get_local_key(group_object.group_name)) for image_group in image_groups: combobox.addItem(prefix + image_group.group_name, image_group.id) self.fill_groups_combobox(combobox, image_group.id, prefix + ' ') @@ -338,7 +338,7 @@ class ImageMediaItem(MediaManagerItem): self.expand_group(open_group.id) # Sort the images by its filename considering language specific # characters. - images.sort(cmp=locale_compare, key=lambda image_object: os.path.split(unicode(image_object.filename))[1]) + images.sort(key=lambda image_object: get_local_key(os.path.split(unicode(image_object.filename))[1])) for imageFile in images: log.debug(u'Loading image: %s', imageFile.filename) filename = os.path.split(imageFile.filename)[1] @@ -525,9 +525,9 @@ class ImageMediaItem(MediaManagerItem): group_items.append(item) if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames): image_items.append(item) - group_items.sort(cmp=locale_compare, key=lambda item: item.text(0)) + group_items.sort(key=lambda item: get_local_key(item.text(0))) target_group.addChildren(group_items) - image_items.sort(cmp=locale_compare, key=lambda item: item.text(0)) + image_items.sort(key=lambda item: get_local_key(item.text(0))) target_group.addChildren(image_items) def generate_slide_data(self, service_item, item=None, xmlVersion=False, diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 57bc6947b..26cb35cd2 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -37,7 +37,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, Regist from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.ui import DisplayController, Display, DisplayControllerType from openlp.core.ui.media import get_media_players, set_media_players -from openlp.core.utils import AppLocation, locale_compare +from openlp.core.utils import AppLocation, get_local_key log = logging.getLogger(__name__) @@ -261,7 +261,7 @@ class MediaMediaItem(MediaManagerItem): def load_list(self, media, target_group=None): # Sort the media by its filename considering language specific # characters. - media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1]) + media.sort(key=lambda filename: get_local_key(os.path.split(unicode(filename))[1])) for track in media: track_info = QtCore.QFileInfo(track) if not os.path.exists(track): @@ -287,7 +287,7 @@ class MediaMediaItem(MediaManagerItem): def getList(self, type=MediaType.Audio): media = Settings().value(self.settings_section + u'/media files') - media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1]) + media.sort(key=lambda filename: get_local_key(os.path.split(unicode(filename))[1])) ext = [] if type == MediaType.Audio: ext = self.media_controller.audio_extensions_list diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index f92562541..a87821e8c 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -35,7 +35,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, Registry, ItemCapabilities, ServiceItemContext, Settings, UiStrings, \ build_icon, check_item_selected, create_thumb, translate, validate_thumb from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box -from openlp.core.utils import locale_compare +from openlp.core.utils import get_local_key from openlp.plugins.presentations.lib import MessageListener log = logging.getLogger(__name__) @@ -153,8 +153,7 @@ class PresentationMediaItem(MediaManagerItem): if not initialLoad: self.main_window.display_progress_bar(len(files)) # Sort the presentations by its filename considering language specific characters. - files.sort(cmp=locale_compare, - key=lambda filename: os.path.split(unicode(filename))[1]) + files.sort(key=lambda filename: get_local_key(os.path.split(unicode(filename))[1])) for file in files: if not initialLoad: self.main_window.increment_progress_bar() diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 79f21a454..94748d3e4 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -37,7 +37,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Registry, UiStrings, create_separated_list, build_icon, translate from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.plugins.songs.lib import natcmp +from openlp.core.utils import get_natural_key from openlp.plugins.songs.lib.db import Song from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport @@ -222,7 +222,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. self.application.set_busy_cursor() songs = self.plugin.manager.get_all_objects(Song) - songs.sort(cmp=natcmp, key=lambda song: song.sort_key) + songs.sort(key=lambda song: get_natural_key(song.sort_key)) for song in songs: # No need to export temporary songs. if song.temporary: diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 5c1485b9e..abeec1253 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -34,7 +34,7 @@ import re from PyQt4 import QtGui from openlp.core.lib import translate -from openlp.core.utils import CONTROL_CHARS, locale_direct_compare +from openlp.core.utils import CONTROL_CHARS from db import Author from ui import SongStrings @@ -592,37 +592,3 @@ def strip_rtf(text, default_encoding=None): text = u''.join(out) return text, default_encoding - -def natcmp(a, b): - """ - Natural string comparison which mimics the behaviour of Python's internal cmp function. - """ - if len(a) <= len(b): - for i, key in enumerate(a): - if isinstance(key, int) and isinstance(b[i], int): - result = cmp(key, b[i]) - elif isinstance(key, int) and not isinstance(b[i], int): - result = locale_direct_compare(str(key), b[i]) - elif not isinstance(key, int) and isinstance(b[i], int): - result = locale_direct_compare(key, str(b[i])) - else: - result = locale_direct_compare(key, b[i]) - if result != 0: - return result - if len(a) == len(b): - return 0 - else: - return -1 - else: - for i, key in enumerate(b): - if isinstance(a[i], int) and isinstance(key, int): - result = cmp(a[i], key) - elif isinstance(a[i], int) and not isinstance(key, int): - result = locale_direct_compare(str(a[i]), key) - elif not isinstance(a[i], int) and isinstance(key, int): - result = locale_direct_compare(a[i], str(key)) - else: - result = locale_direct_compare(a[i], key) - if result != 0: - return result - return 1 diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 0c4898fd9..81aab4d0f 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -38,12 +38,12 @@ from sqlalchemy.sql import or_ from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, Settings, \ UiStrings, translate, check_item_selected, create_separated_list, check_directory_exists from openlp.core.lib.ui import create_widget_action -from openlp.core.utils import AppLocation +from openlp.core.utils import AppLocation, 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 from openlp.plugins.songs.forms.songexportform import SongExportForm -from openlp.plugins.songs.lib import VerseType, clean_string, natcmp +from openlp.plugins.songs.lib import VerseType, clean_string from openlp.plugins.songs.lib.db import Author, Song, Book, MediaFile from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.xml import OpenLyrics, SongXML @@ -225,7 +225,7 @@ class SongMediaItem(MediaManagerItem): log.debug(u'display results Song') self.save_auto_select_id() self.list_view.clear() - searchresults.sort(cmp=natcmp, key=lambda song: song.sort_key) + searchresults.sort(key=lambda song: get_natural_key(song.sort_key)) for song in searchresults: # Do not display temporary songs if song.temporary: diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 4c0f69b91..a6e075db4 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -83,6 +83,7 @@ MODULES = [ 'mako', 'migrate', 'uno', + 'icu', ] From 118f295204a1c8548c31919c0cce31610b382a4b Mon Sep 17 00:00:00 2001 From: M2j Date: Sun, 31 Mar 2013 12:31:54 +0200 Subject: [PATCH 02/10] Precompute the whole comparision key for song sorting. --- openlp/core/utils/__init__.py | 29 ++++++++------------ openlp/plugins/songs/forms/songexportform.py | 3 +- openlp/plugins/songs/lib/db.py | 28 +++---------------- openlp/plugins/songs/lib/mediaitem.py | 4 +-- 4 files changed, 18 insertions(+), 46 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 625bd25b5..ba7e4dd25 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -398,25 +398,18 @@ def get_local_key(string): def get_natural_key(string): """ - Generate a key for locale aware natural string sorting. Returns a list of strings and integers. - - ``string`` - A string, list or tuple which represents the item string. + Generate a key for locale aware natural string sorting. + Returns a list of string compare keys and integers. """ - if isinstance(string, basestring): - string = re.findall(r'(\d+|\D+)', string) - if len(string) == 1: - return list(get_local_key(string[0])) - elif isinstance(string, tuple): - string = list(string) - if isinstance(string, list): - for index, part in enumerate(string): - if isinstance(part, basestring): - if part.isdigit(): - string[index] = int(part) - else: - string[index] = get_local_key(part) - return string + key = re.findall(r'(\d+|\D+)', string) + if len(key) == 1: + return list(get_local_key(string)) + for index, part in enumerate(key): + if part.isdigit(): + key[index] = int(part) + else: + key[index] = get_local_key(part) + return key from applocation import AppLocation diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 94748d3e4..f0554f588 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -37,7 +37,6 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Registry, UiStrings, create_separated_list, build_icon, translate from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import get_natural_key from openlp.plugins.songs.lib.db import Song from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport @@ -222,7 +221,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. self.application.set_busy_cursor() songs = self.plugin.manager.get_all_objects(Song) - songs.sort(key=lambda song: get_natural_key(song.sort_key)) + songs.sort(key=lambda song: song.sort_key) for song in songs: # No need to export temporary songs. if song.temporary: diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index db5f59357..015caa87d 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -38,6 +38,7 @@ from sqlalchemy.orm import mapper, relation, reconstructor from sqlalchemy.sql.expression import func from openlp.core.lib.db import BaseModel, init_db +from openlp.core.utils import get_natural_key class Author(BaseModel): @@ -69,36 +70,15 @@ class Song(BaseModel): def __init__(self): self.sort_key = () - def _try_int(self, s): - """ - Convert to integer if possible. - """ - try: - return int(s) - except: - return s.lower() - - def _natsort_key(self, s): - """ - Used internally to get a tuple by which s is sorted. - """ - return map(self._try_int, re.findall(r'(\d+|\D+)', s)) - - # This decorator tells sqlalchemy to call this method everytime - # any data on this object is updated. - @reconstructor def init_on_load(self): """ - Precompute a tuple to be used for sorting. + Precompute a natural sorting, locale aware sorting key. Song sorting is performance sensitive operation. - To get maximum speed lets precompute the string - used for comparison. + To get maximum speed lets precompute the sorting key. """ - # Avoid the overhead of converting string to lowercase and to QString - # with every call to sort(). - self.sort_key = self._natsort_key(self.title) + self.sort_key = get_natural_key(self.title) class Topic(BaseModel): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 81aab4d0f..d75124d84 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -38,7 +38,7 @@ from sqlalchemy.sql import or_ from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, Settings, \ UiStrings, translate, check_item_selected, create_separated_list, check_directory_exists from openlp.core.lib.ui import create_widget_action -from openlp.core.utils import AppLocation, get_natural_key +from openlp.core.utils import AppLocation from openlp.plugins.songs.forms.editsongform import EditSongForm from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm from openlp.plugins.songs.forms.songimportform import SongImportForm @@ -225,7 +225,7 @@ class SongMediaItem(MediaManagerItem): log.debug(u'display results Song') self.save_auto_select_id() self.list_view.clear() - searchresults.sort(key=lambda song: get_natural_key(song.sort_key)) + searchresults.sort(key=lambda song: song.sort_key) for song in searchresults: # Do not display temporary songs if song.temporary: From 8696db9f75f018c5c344a208bad6423a371018b4 Mon Sep 17 00:00:00 2001 From: M2j Date: Sun, 31 Mar 2013 18:30:22 +0200 Subject: [PATCH 03/10] - use list compression in get_natural_key - define DIGIT_OR_NONDIGIT --- openlp/core/utils/__init__.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index ba7e4dd25..739d4ad2e 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -62,6 +62,7 @@ UNO_CONNECTION_TYPE = u'pipe' #UNO_CONNECTION_TYPE = u'socket' CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE) INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE) +DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE) class VersionThread(QtCore.QThread): @@ -401,14 +402,8 @@ def get_natural_key(string): Generate a key for locale aware natural string sorting. Returns a list of string compare keys and integers. """ - key = re.findall(r'(\d+|\D+)', string) - if len(key) == 1: - return list(get_local_key(string)) - for index, part in enumerate(key): - if part.isdigit(): - key[index] = int(part) - else: - key[index] = get_local_key(part) + key = DIGITS_OR_NONDIGITS.findall(string) + key = [int(part) if part.isdigit() else get_local_key(part) for part in key] return key From b3bb9bc0c0c1a5fa38b672b954188a57c6dd27f5 Mon Sep 17 00:00:00 2001 From: M2j Date: Sun, 31 Mar 2013 18:43:08 +0200 Subject: [PATCH 04/10] Python 3 transition comment --- openlp/core/utils/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 739d4ad2e..092e67913 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -404,6 +404,9 @@ def get_natural_key(string): """ key = DIGITS_OR_NONDIGITS.findall(string) key = [int(part) if part.isdigit() else get_local_key(part) for part in key] + # Python 3 does not support comparision of different types anymore. So make sure, that we do not compare str and int. + #if string[0].isdigit(): + # return [''] + key return key From 316902fb88c65acce89cbe143e0430419560dff1 Mon Sep 17 00:00:00 2001 From: M2j Date: Tue, 2 Apr 2013 19:51:19 +0200 Subject: [PATCH 05/10] Add unit tests for get_local_key and get_natural_key. --- .../openlp_core_utils/test_utils.py | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_utils/test_utils.py b/tests/functional/openlp_core_utils/test_utils.py index 2e826bc61..ac4da275b 100644 --- a/tests/functional/openlp_core_utils/test_utils.py +++ b/tests/functional/openlp_core_utils/test_utils.py @@ -5,7 +5,7 @@ from unittest import TestCase from mock import patch -from openlp.core.utils import get_filesystem_encoding, _get_frozen_path +from openlp.core.utils import get_filesystem_encoding, _get_frozen_path, get_local_key, get_natural_key class TestUtils(TestCase): """ @@ -56,3 +56,28 @@ class TestUtils(TestCase): # THEN: The frozen parameter is returned assert _get_frozen_path(u'frozen', u'not frozen') == u'frozen', u'Should return "frozen"' + def get_local_key_test(self): + """ + Test the get_local_key(string) function + """ + with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language: + # GIVEN: The language is German + # 0x00C3 (A with diaresis) should be sorted as "A". 0x00DF (sharp s) should be sorted as "ss". + mocked_get_language.return_value = u'de' + unsorted_list = [u'Auszug', u'Aushang', u'\u00C4u\u00DFerung'] + # WHEN: We sort the list and use get_locale_key() to generate the sorting keys + # THEN: We get a properly sorted list + assert sorted(unsorted_list, key=get_local_key) == [u'Aushang', u'\u00C4u\u00DFerung', u'Auszug'], u'Strings should be sorted properly' + + def get_natural_key_test(self): + """ + Test the get_natural_key(string) function + """ + with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language: + # GIVEN: The language is English (a language, which sorts digits before letters) + mocked_get_language.return_value = u'en' + unsorted_list = [u'item 10a', u'item 3b', u'1st item'] + # WHEN: We sort the list and use get_natural_key() to generate the sorting keys + # THEN: We get a properly sorted list + assert sorted(unsorted_list, key=get_natural_key) == [u'1st item', u'item 3b', u'item 10a'], u'Numbers should be sortet naturally' + From 9612a52211e32a3fda02965eb3898232d1fc2f60 Mon Sep 17 00:00:00 2001 From: M2j Date: Tue, 2 Apr 2013 19:54:23 +0200 Subject: [PATCH 06/10] typo --- tests/functional/openlp_core_utils/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_utils/test_utils.py b/tests/functional/openlp_core_utils/test_utils.py index ac4da275b..1546e9a7b 100644 --- a/tests/functional/openlp_core_utils/test_utils.py +++ b/tests/functional/openlp_core_utils/test_utils.py @@ -79,5 +79,5 @@ class TestUtils(TestCase): unsorted_list = [u'item 10a', u'item 3b', u'1st item'] # WHEN: We sort the list and use get_natural_key() to generate the sorting keys # THEN: We get a properly sorted list - assert sorted(unsorted_list, key=get_natural_key) == [u'1st item', u'item 3b', u'item 10a'], u'Numbers should be sortet naturally' + assert sorted(unsorted_list, key=get_natural_key) == [u'1st item', u'item 3b', u'item 10a'], u'Numbers should be sorted naturally' From 2598674d2a2b6c23a85605e888a57e1a23553005 Mon Sep 17 00:00:00 2001 From: M2j Date: Tue, 2 Apr 2013 22:52:31 +0200 Subject: [PATCH 07/10] Add ICU version string to exception form. --- openlp/core/ui/exceptionform.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index e4854d0c0..6b77a8c6f 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -71,7 +71,10 @@ except ImportError: MAKO_VERSION = u'-' try: import icu - ICU_VERSION = u'OK' + try: + ICU_VERSION = icu.VERSION + except AttributeError: + ICU_VERSION = u'OK' except ImportError: ICU_VERSION = u'-' try: From 042bf4ed2d6567b3e4c64a0bd1ba3f9e12591217 Mon Sep 17 00:00:00 2001 From: M2j Date: Fri, 5 Apr 2013 19:41:01 +0200 Subject: [PATCH 08/10] rename openlp.core.utils.get_local_key to openlp.core.utils.get_locale_key --- openlp/core/ui/thememanager.py | 4 ++-- openlp/core/utils/__init__.py | 6 +++--- openlp/plugins/bibles/forms/bibleimportform.py | 4 ++-- openlp/plugins/bibles/lib/mediaitem.py | 6 +++--- openlp/plugins/custom/lib/db.py | 6 +++--- openlp/plugins/images/lib/mediaitem.py | 12 ++++++------ openlp/plugins/media/lib/mediaitem.py | 6 +++--- openlp/plugins/presentations/lib/mediaitem.py | 4 ++-- tests/interfaces/openlp_plugins/__init__.pyc | Bin 184 -> 166 bytes 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 53d4a513b..be0e3bfa1 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -44,7 +44,7 @@ from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, Backgr from openlp.core.lib.ui import critical_error_message_box, create_widget_action from openlp.core.theme import Theme from openlp.core.ui import FileRenameForm, ThemeForm -from openlp.core.utils import AppLocation, delete_file, get_local_key, get_filesystem_encoding +from openlp.core.utils import AppLocation, delete_file, get_locale_key, get_filesystem_encoding log = logging.getLogger(__name__) @@ -418,7 +418,7 @@ class ThemeManager(QtGui.QWidget): self.theme_list_widget.clear() files = AppLocation.get_files(self.settings_section, u'.png') # Sort the themes by its name considering language specific - files.sort(key=lambda file_name: get_local_key(unicode(file_name))) + files.sort(key=lambda file_name: get_locale_key(unicode(file_name))) # now process the file list of png files for name in files: # check to see file is in theme root directory diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 092e67913..0e48f2fa5 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -382,7 +382,7 @@ def format_time(text, local_time): return re.sub('\%[a-zA-Z]', match_formatting, text) -def get_local_key(string): +def get_locale_key(string): """ Creates a key for case insensitive, locale aware string sorting. """ @@ -403,7 +403,7 @@ def get_natural_key(string): Returns a list of string compare keys and integers. """ key = DIGITS_OR_NONDIGITS.findall(string) - key = [int(part) if part.isdigit() else get_local_key(part) for part in key] + key = [int(part) if part.isdigit() else get_locale_key(part) for part in key] # Python 3 does not support comparision of different types anymore. So make sure, that we do not compare str and int. #if string[0].isdigit(): # return [''] + key @@ -417,4 +417,4 @@ from actions import ActionList __all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version', u'add_actions', u'get_filesystem_encoding', u'get_web_page', u'get_uno_command', u'get_uno_instance', - u'delete_file', u'clean_filename', u'format_time', u'get_local_key', u'get_natural_key'] + u'delete_file', u'clean_filename', u'format_time', u'get_locale_key', u'get_natural_key'] diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 319989433..f8d771e77 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -38,7 +38,7 @@ from openlp.core.lib import Settings, UiStrings, translate from openlp.core.lib.db import delete_database from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import AppLocation, get_local_key +from openlp.core.utils import AppLocation, get_locale_key from openlp.plugins.bibles.lib.manager import BibleFormat from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename @@ -455,7 +455,7 @@ class BibleImportForm(OpenLPWizard): """ self.webTranslationComboBox.clear() bibles = self.web_bible_list[index].keys() - bibles.sort(key=get_local_key) + bibles.sort(key=get_locale_key) self.webTranslationComboBox.addItems(bibles) def onOsisBrowseButtonClicked(self): diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 4ae7e76b5..86a507612 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -36,7 +36,7 @@ from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, Servic from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \ critical_error_message_box, find_and_set_in_combo_box, build_icon -from openlp.core.utils import get_local_key +from openlp.core.utils import get_locale_key from openlp.plugins.bibles.forms import BibleImportForm, EditBibleForm from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \ LanguageSelection, BibleStrings @@ -325,7 +325,7 @@ class BibleMediaItem(MediaManagerItem): # Get all bibles and sort the list. bibles = self.plugin.manager.get_bibles().keys() bibles = filter(None, bibles) - bibles.sort(key=get_local_key) + bibles.sort(key=get_locale_key) # Load the bibles into the combo boxes. self.quickVersionComboBox.addItems(bibles) self.quickSecondComboBox.addItems(bibles) @@ -461,7 +461,7 @@ class BibleMediaItem(MediaManagerItem): for book in book_data: data = BiblesResourcesDB.get_book_by_id(book.book_reference_id) books.append(data[u'name'] + u' ') - books.sort(key=get_local_key) + books.sort(key=get_locale_key) set_case_insensitive_completer(books, self.quickSearchEdit) def on_import_click(self): diff --git a/openlp/plugins/custom/lib/db.py b/openlp/plugins/custom/lib/db.py index ad876b6b6..253ca5432 100644 --- a/openlp/plugins/custom/lib/db.py +++ b/openlp/plugins/custom/lib/db.py @@ -35,7 +35,7 @@ from sqlalchemy import Column, Table, types from sqlalchemy.orm import mapper from openlp.core.lib.db import BaseModel, init_db -from openlp.core.utils import get_local_key +from openlp.core.utils import get_locale_key class CustomSlide(BaseModel): """ @@ -44,10 +44,10 @@ class CustomSlide(BaseModel): # By default sort the customs by its title considering language specific # characters. def __lt__(self, other): - return get_local_key(self.title) < get_local_key(other.title) + return get_locale_key(self.title) < get_locale_key(other.title) def __eq__(self, other): - return get_local_key(self.title) == get_local_key(other.title) + return get_locale_key(self.title) == get_locale_key(other.title) def init_schema(url): diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 8c6bc8d9f..fc575ec0a 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -36,7 +36,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem, Registry, Servic StringContent, TreeWidgetWithDnD, UiStrings, build_icon, check_directory_exists, check_item_selected, \ create_thumb, translate, validate_thumb from openlp.core.lib.ui import create_widget_action, critical_error_message_box -from openlp.core.utils import AppLocation, delete_file, get_local_key, get_images_filter +from openlp.core.utils import AppLocation, delete_file, get_locale_key, get_images_filter from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups @@ -255,7 +255,7 @@ class ImageMediaItem(MediaManagerItem): The ID of the group that will be added recursively """ image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id) - image_groups.sort(key=lambda group_object: get_local_key(group_object.group_name)) + image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name)) folder_icon = build_icon(u':/images/image_group.png') for image_group in image_groups: group = QtGui.QTreeWidgetItem() @@ -286,7 +286,7 @@ class ImageMediaItem(MediaManagerItem): combobox.clear() combobox.top_level_group_added = False image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id) - image_groups.sort(key=lambda group_object: get_local_key(group_object.group_name)) + image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name)) for image_group in image_groups: combobox.addItem(prefix + image_group.group_name, image_group.id) self.fill_groups_combobox(combobox, image_group.id, prefix + ' ') @@ -338,7 +338,7 @@ class ImageMediaItem(MediaManagerItem): self.expand_group(open_group.id) # Sort the images by its filename considering language specific # characters. - images.sort(key=lambda image_object: get_local_key(os.path.split(unicode(image_object.filename))[1])) + images.sort(key=lambda image_object: get_locale_key(os.path.split(unicode(image_object.filename))[1])) for imageFile in images: log.debug(u'Loading image: %s', imageFile.filename) filename = os.path.split(imageFile.filename)[1] @@ -525,9 +525,9 @@ class ImageMediaItem(MediaManagerItem): group_items.append(item) if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames): image_items.append(item) - group_items.sort(key=lambda item: get_local_key(item.text(0))) + group_items.sort(key=lambda item: get_locale_key(item.text(0))) target_group.addChildren(group_items) - image_items.sort(key=lambda item: get_local_key(item.text(0))) + image_items.sort(key=lambda item: get_locale_key(item.text(0))) target_group.addChildren(image_items) def generate_slide_data(self, service_item, item=None, xmlVersion=False, diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 26cb35cd2..7d492bc69 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -37,7 +37,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, Regist from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box from openlp.core.ui import DisplayController, Display, DisplayControllerType from openlp.core.ui.media import get_media_players, set_media_players -from openlp.core.utils import AppLocation, get_local_key +from openlp.core.utils import AppLocation, get_locale_key log = logging.getLogger(__name__) @@ -261,7 +261,7 @@ class MediaMediaItem(MediaManagerItem): def load_list(self, media, target_group=None): # Sort the media by its filename considering language specific # characters. - media.sort(key=lambda filename: get_local_key(os.path.split(unicode(filename))[1])) + media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1])) for track in media: track_info = QtCore.QFileInfo(track) if not os.path.exists(track): @@ -287,7 +287,7 @@ class MediaMediaItem(MediaManagerItem): def getList(self, type=MediaType.Audio): media = Settings().value(self.settings_section + u'/media files') - media.sort(key=lambda filename: get_local_key(os.path.split(unicode(filename))[1])) + media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1])) ext = [] if type == MediaType.Audio: ext = self.media_controller.audio_extensions_list diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index a87821e8c..52dcd891f 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -35,7 +35,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, Registry, ItemCapabilities, ServiceItemContext, Settings, UiStrings, \ build_icon, check_item_selected, create_thumb, translate, validate_thumb from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box -from openlp.core.utils import get_local_key +from openlp.core.utils import get_locale_key from openlp.plugins.presentations.lib import MessageListener log = logging.getLogger(__name__) @@ -153,7 +153,7 @@ class PresentationMediaItem(MediaManagerItem): if not initialLoad: self.main_window.display_progress_bar(len(files)) # Sort the presentations by its filename considering language specific characters. - files.sort(key=lambda filename: get_local_key(os.path.split(unicode(filename))[1])) + files.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1])) for file in files: if not initialLoad: self.main_window.increment_progress_bar() diff --git a/tests/interfaces/openlp_plugins/__init__.pyc b/tests/interfaces/openlp_plugins/__init__.pyc index 0d24c9eff54ac7d86f14523ef46194c4bbc24cad..41b2c438107d1adf4a5d502219772f510965f920 100644 GIT binary patch delta 58 zcmdnNxQvmV`7~wiuL^qQuBNQ e^oxKJ`MJ79sp& Date: Sat, 6 Apr 2013 19:17:59 +0200 Subject: [PATCH 09/10] removed tests/interfaces/openlp_plugins/__init__.pyc --- tests/interfaces/openlp_plugins/__init__.pyc | Bin 166 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/interfaces/openlp_plugins/__init__.pyc diff --git a/tests/interfaces/openlp_plugins/__init__.pyc b/tests/interfaces/openlp_plugins/__init__.pyc deleted file mode 100644 index 41b2c438107d1adf4a5d502219772f510965f920..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmZSn%*(|R7ao|*00oRd+5w1*S%5?e14FO|NW@PANHCxg#r{As{fzwFRQ=r4%)Hd1 z68*puegA^gJf8slq|$U Date: Sat, 6 Apr 2013 20:21:23 +0200 Subject: [PATCH 10/10] renameing openlp.core.utils.get_local_key in tests --- tests/functional/openlp_core_utils/test_utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/functional/openlp_core_utils/test_utils.py b/tests/functional/openlp_core_utils/test_utils.py index 1546e9a7b..b9decb37e 100644 --- a/tests/functional/openlp_core_utils/test_utils.py +++ b/tests/functional/openlp_core_utils/test_utils.py @@ -5,7 +5,7 @@ from unittest import TestCase from mock import patch -from openlp.core.utils import get_filesystem_encoding, _get_frozen_path, get_local_key, get_natural_key +from openlp.core.utils import get_filesystem_encoding, _get_frozen_path, get_locale_key, get_natural_key class TestUtils(TestCase): """ @@ -56,9 +56,9 @@ class TestUtils(TestCase): # THEN: The frozen parameter is returned assert _get_frozen_path(u'frozen', u'not frozen') == u'frozen', u'Should return "frozen"' - def get_local_key_test(self): + def get_locale_key_test(self): """ - Test the get_local_key(string) function + Test the get_locale_key(string) function """ with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language: # GIVEN: The language is German @@ -67,7 +67,8 @@ class TestUtils(TestCase): unsorted_list = [u'Auszug', u'Aushang', u'\u00C4u\u00DFerung'] # WHEN: We sort the list and use get_locale_key() to generate the sorting keys # THEN: We get a properly sorted list - assert sorted(unsorted_list, key=get_local_key) == [u'Aushang', u'\u00C4u\u00DFerung', u'Auszug'], u'Strings should be sorted properly' + test_passes = sorted(unsorted_list, key=get_locale_key) == [u'Aushang', u'\u00C4u\u00DFerung', u'Auszug'] + assert test_passes, u'Strings should be sorted properly' def get_natural_key_test(self): """ @@ -79,5 +80,6 @@ class TestUtils(TestCase): unsorted_list = [u'item 10a', u'item 3b', u'1st item'] # WHEN: We sort the list and use get_natural_key() to generate the sorting keys # THEN: We get a properly sorted list - assert sorted(unsorted_list, key=get_natural_key) == [u'1st item', u'item 3b', u'item 10a'], u'Numbers should be sorted naturally' + test_passes = sorted(unsorted_list, key=get_natural_key) == [u'1st item', u'item 3b', u'item 10a'] + assert test_passes, u'Numbers should be sorted naturally'