← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~openlp-core/openlp/python3-productive into lp:openlp

 

Andreas Preikschat has proposed merging lp:~openlp-core/openlp/python3-productive into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~openlp-core/openlp/python3-productive/+merge/175454

Hello,

I thought you should start to review the python 3 changes.

Procedure:
1) We merge the changes below in a proposal.
2) After merging I will propose again with only changes made by 2to3.

To review this run:
    2to3 --write --nobackups --no-diffs -x next print *
    sh scripts/generate_resources.sh

- changes required to run openlp with python3
- python3 does not have a buffer type, however, it is said that the "the memoryview API is similar but not exactly the same as that of buffer" [1], that is why I removed the check (we do not know if we get a memoryview object)
- ICU is now not required on linux and mac

[1] http://docs.python.org/2/library/2to3.html#fixers
-- 
https://code.launchpad.net/~openlp-core/openlp/python3-productive/+merge/175454
Your team OpenLP Core is requested to review the proposed merge of lp:~openlp-core/openlp/python3-productive into lp:openlp.
=== modified file 'openlp.py'
--- openlp.py	2013-01-31 18:40:17 +0000
+++ openlp.py	2013-07-18 06:15:35 +0000
@@ -27,15 +27,7 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 
-import sip
 import sys
-sip.setapi(u'QDate', 2)
-sip.setapi(u'QDateTime', 2)
-sip.setapi(u'QString', 2)
-sip.setapi(u'QTextStream', 2)
-sip.setapi(u'QTime', 2)
-sip.setapi(u'QUrl', 2)
-sip.setapi(u'QVariant', 2)
 
 from openlp.core import main
 

=== modified file 'openlp/__init__.py'
--- openlp/__init__.py	2013-02-01 19:58:18 +0000
+++ openlp/__init__.py	2013-07-18 06:15:35 +0000
@@ -30,7 +30,7 @@
 The :mod:`openlp` module contains all the project produced OpenLP functionality
 """
 
-import core
-import plugins
+import openlp.core
+import openlp.plugins
 
 __all__ = [u'core', u'plugins']

=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2013-06-03 17:19:42 +0000
+++ openlp/core/lib/__init__.py	2013-07-18 06:15:35 +0000
@@ -121,20 +121,19 @@
     if not os.path.isfile(text_file):
         return False
     file_handle = None
-    content_string = None
+    content = None
     try:
         file_handle = open(text_file, u'r')
         if not file_handle.read(3) == '\xEF\xBB\xBF':
             # no BOM was found
             file_handle.seek(0)
         content = file_handle.read()
-        content_string = content.decode(u'utf-8')
     except (IOError, UnicodeError):
         log.exception(u'Failed to open text file %s' % text_file)
     finally:
         if file_handle:
             file_handle.close()
-    return content_string
+    return content
 
 
 def str_to_bool(string_value):
@@ -186,7 +185,7 @@
     image.save(buffie, "PNG")
     log.debug(u'image_to_byte - end')
     # convert to base64 encoding so does not get missed!
-    return byte_array.toBase64()
+    return bytes(byte_array.toBase64()).decode('utf-8')
 
 
 def create_thumb(image_path, thumb_path, return_icon=True, size=None):

=== modified file 'openlp/core/lib/formattingtags.py'
--- openlp/core/lib/formattingtags.py	2013-06-30 18:36:52 +0000
+++ openlp/core/lib/formattingtags.py	2013-07-18 06:15:35 +0000
@@ -156,15 +156,10 @@
             u'end html': u'', u'protected': True, u'temporary': False})
         FormattingTags.add_html_tags(base_tags)
         FormattingTags.add_html_tags(temporary_tags)
-        # Formatting Tags were also known as display tags.
         user_expands_string = str(Settings().value(u'formattingTags/html_tags'))
+        # If we have some user ones added them as well
         if user_expands_string:
             user_tags = json.loads(user_expands_string)
-            for tag in user_tags:
-                for element in tag:
-                    if isinstance(tag[element], str):
-                        tag[element] = tag[element].decode('utf8')
-            # If we have some user ones added them as well
             FormattingTags.add_html_tags(user_tags)
 
     @staticmethod

=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py	2013-03-01 09:20:26 +0000
+++ openlp/core/lib/theme.py	2013-07-18 06:15:35 +0000
@@ -473,7 +473,7 @@
         Pull out the XML string formatted for human consumption
         """
         self._build_xml_from_attrs()
-        return self.theme_xml.toprettyxml(indent=u'    ', newl=u'\n', encoding=u'utf-8')
+        return self.theme_xml.toprettyxml(indent='    ', newl='\n', encoding='utf-8')
 
     def parse(self, xml):
         """

=== modified file 'openlp/core/ui/filerenameform.py'
--- openlp/core/ui/filerenameform.py	2013-03-01 11:12:23 +0000
+++ openlp/core/ui/filerenameform.py	2013-07-18 06:15:35 +0000
@@ -45,7 +45,7 @@
         """
         Constructor
         """
-        QtGui.QDialog.__init__(self, self.main_window)
+        super(FileRenameForm, self).__init__(Registry().get(u'main_window'))
         self.setupUi(self)
 
     def exec_(self, copy=False):

=== modified file 'openlp/core/ui/firsttimeform.py'
--- openlp/core/ui/firsttimeform.py	2013-07-03 20:20:12 +0000
+++ openlp/core/ui/firsttimeform.py	2013-07-18 06:15:35 +0000
@@ -29,20 +29,20 @@
 """
 This module contains the first time wizard.
 """
-import io
 import logging
 import os
 import sys
 import time
-import urllib
-import urllib2
+import urllib.request
+import urllib.parse
+import urllib.error
 from tempfile import gettempdir
 from ConfigParser import SafeConfigParser
 
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import PluginStatus, Settings, Registry, build_icon, check_directory_exists, translate
-from openlp.core.utils import AppLocation, get_web_page, get_filesystem_encoding
+from openlp.core.utils import AppLocation, get_web_page
 from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
 
 log = logging.getLogger(__name__)
@@ -67,7 +67,7 @@
             filename = config.get(u'theme_%s' % theme, u'filename')
             screenshot = config.get(u'theme_%s' % theme, u'screenshot')
             urllib.urlretrieve(u'%s%s' % (self.parent().web, screenshot),
-                os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp', screenshot))
+                os.path.join(gettempdir(), u'openlp', screenshot))
             item = QtGui.QListWidgetItem(title, self.parent().themes_list_widget)
             item.setData(QtCore.Qt.UserRole, filename)
             item.setCheckState(QtCore.Qt.Unchecked)
@@ -93,7 +93,7 @@
         self.web_access = get_web_page(u'%s%s' % (self.web, u'download.cfg'))
         if self.web_access:
             files = self.web_access.read()
-            self.config.readfp(io.BytesIO(files))
+            self.config.read_string(files.decode())
         self.update_screen_list_combo()
         self.was_download_cancelled = False
         self.theme_screenshot_thread = None
@@ -115,7 +115,7 @@
         Set up display at start of theme edit.
         """
         self.restart()
-        check_directory_exists(os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
+        check_directory_exists(os.path.join(gettempdir(), u'openlp'))
         self.no_internet_finish_button.setVisible(False)
         # Check if this is a re-run of the wizard.
         self.has_run_wizard = Settings().value(u'core/has run wizard')
@@ -124,8 +124,8 @@
             songs = self.config.get(u'songs', u'languages')
             songs = songs.split(u',')
             for song in songs:
-                title = unicode(self.config.get(u'songs_%s' % song, u'title'), u'utf8')
-                filename = unicode(self.config.get(u'songs_%s' % song, u'filename'), u'utf8')
+                title = self.config.get(u'songs_%s' % song, u'title')
+                filename = self.config.get(u'songs_%s' % song, u'filename')
                 item = QtGui.QListWidgetItem(title, self.songs_list_widget)
                 item.setData(QtCore.Qt.UserRole, filename)
                 item.setCheckState(QtCore.Qt.Unchecked)
@@ -133,13 +133,13 @@
             bible_languages = self.config.get(u'bibles', u'languages')
             bible_languages = bible_languages.split(u',')
             for lang in bible_languages:
-                language = unicode(self.config.get(u'bibles_%s' % lang, u'title'), u'utf8')
+                language = self.config.get(u'bibles_%s' % lang, u'title')
                 langItem = QtGui.QTreeWidgetItem(self.bibles_tree_widget, [language])
                 bibles = self.config.get(u'bibles_%s' % lang, u'translations')
                 bibles = bibles.split(u',')
                 for bible in bibles:
-                    title = unicode(self.config.get(u'bible_%s' % bible, u'title'), u'utf8')
-                    filename = unicode(self.config.get(u'bible_%s' % bible, u'filename'))
+                    title = self.config.get(u'bible_%s' % bible, u'title')
+                    filename = self.config.get(u'bible_%s' % bible, u'filename')
                     item = QtGui.QTreeWidgetItem(langItem, [title])
                     item.setData(0, QtCore.Qt.UserRole, filename)
                     item.setCheckState(0, QtCore.Qt.Unchecked)
@@ -292,8 +292,7 @@
                 item = self.themes_list_widget.item(index)
                 if item.data(QtCore.Qt.UserRole) == filename:
                     break
-            item.setIcon(build_icon(os.path.join(unicode(gettempdir(),
-                get_filesystem_encoding()), u'openlp', screenshot)))
+            item.setIcon(build_icon(os.path.join(gettempdir(), u'openlp', screenshot)))
 
     def _getFileSize(self, url):
         """
@@ -302,9 +301,9 @@
         ``url``
             The URL of the file we want to download.
         """
-        site = urllib.urlopen(url)
+        site = urllib.request.urlopen(url)
         meta = site.info()
-        return int(meta.getheaders("Content-Length")[0])
+        return int(meta.get("Content-Length"))
 
     def _download_progress(self, count, block_size):
         """
@@ -426,8 +425,7 @@
         self._set_plugin_status(self.alert_check_box, u'alerts/status')
         if self.web_access:
             # Build directories for downloads
-            songs_destination = os.path.join(
-                unicode(gettempdir(), get_filesystem_encoding()), u'openlp')
+            songs_destination = os.path.join(gettempdir(), u'openlp')
             bibles_destination = AppLocation.get_section_data_path(u'bibles')
             themes_destination = AppLocation.get_section_data_path(u'themes')
             # Download songs

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2013-07-03 20:20:12 +0000
+++ openlp/core/ui/mainwindow.py	2013-07-18 06:15:35 +0000
@@ -47,8 +47,7 @@
 from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, SlideController, PluginForm, \
     MediaDockManager, ShortcutListForm, FormattingTagForm
 from openlp.core.ui.media import MediaController
-from openlp.core.utils import AppLocation, LanguageManager, add_actions, get_application_version, \
-    get_filesystem_encoding
+from openlp.core.utils import AppLocation, LanguageManager, add_actions, get_application_version
 from openlp.core.utils.actions import ActionList, CategoryOrder
 from openlp.core.ui.firsttimeform import FirstTimeForm
 
@@ -903,7 +902,7 @@
             # Make sure it's a .conf file.
         if not export_file_name.endswith(u'conf'):
             export_file_name += u'.conf'
-        temp_file = os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp', u'exportConf.tmp')
+        temp_file = os.path.join(gettempdir(), u'openlp', u'exportConf.tmp')
         self.save_settings()
         setting_sections = []
         # Add main sections.

=== modified file 'openlp/core/ui/media/playertab.py'
--- openlp/core/ui/media/playertab.py	2013-03-17 20:00:39 +0000
+++ openlp/core/ui/media/playertab.py	2013-07-18 06:15:35 +0000
@@ -55,7 +55,7 @@
         """
         Constructor
         """
-        self.media_players = self.media_controller.media_players
+        self.media_players = Registry().get('media_controller').media_players
         self.saved_used_players = None
         self.icon_path = u':/media/multimedia-player.png'
         player_translated = translate('OpenLP.PlayerTab', 'Players')

=== modified file 'openlp/core/ui/media/vlcplayer.py'
--- openlp/core/ui/media/vlcplayer.py	2013-03-23 07:28:24 +0000
+++ openlp/core/ui/media/vlcplayer.py	2013-07-18 06:15:35 +0000
@@ -58,10 +58,12 @@
 
 if VLC_AVAILABLE:
     try:
-        VERSION = vlc.libvlc_get_version()
+        VERSION = vlc.libvlc_get_version().decode('UTF-8')
     except:
         VERSION = u'0.0.0'
-    if LooseVersion(VERSION) < LooseVersion('1.1.0'):
+    # LooseVersion does not work when a string contains letter and digits (e. g. 2.0.5 Twoflower).
+    # http://bugs.python.org/issue14894
+    if LooseVersion(VERSION.split()[0]) < LooseVersion('1.1.0'):
         VLC_AVAILABLE = False
         log.debug(u'VLC could not be loaded, because the vlc version is too old: %s' % VERSION)
 

=== modified file 'openlp/core/ui/printserviceform.py'
--- openlp/core/ui/printserviceform.py	2013-03-07 10:25:27 +0000
+++ openlp/core/ui/printserviceform.py	2013-07-18 06:15:35 +0000
@@ -118,7 +118,7 @@
         """
         Constructor
         """
-        QtGui.QDialog.__init__(self, self.main_window)
+        QtGui.QDialog.__init__(self, Registry().get('main_window'))
         self.printer = QtGui.QPrinter()
         self.print_dialog = QtGui.QPrintDialog(self.printer, self)
         self.document = QtGui.QTextDocument()
@@ -183,7 +183,7 @@
             self._add_element(
                 u'span', translate('OpenLP.ServiceManager', 'Custom Service Notes: '), div, classId=u'customNotesTitle')
             self._add_element(u'span', cgi.escape(self.footer_text_edit.toPlainText()), div, classId=u'customNotesText')
-        self.document.setHtml(html.tostring(html_data))
+        self.document.setHtml(html.tostring(html_data).decode())
         self.preview_widget.updatePreview()
 
     def _add_preview_item(self, body, item, index):

=== modified file 'openlp/core/ui/serviceitemeditform.py'
--- openlp/core/ui/serviceitemeditform.py	2013-03-05 13:55:50 +0000
+++ openlp/core/ui/serviceitemeditform.py	2013-07-18 06:15:35 +0000
@@ -43,7 +43,7 @@
         """
         Constructor
         """
-        QtGui.QDialog.__init__(self, self.main_window)
+        super(ServiceItemEditForm, self).__init__(Registry().get(u'main_window'))
         self.setupUi(self)
         self.item_list = []
         self.list_widget.currentRowChanged.connect(self.on_current_row_changed)

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2013-07-06 10:27:08 +0000
+++ openlp/core/ui/servicemanager.py	2013-07-18 06:15:35 +0000
@@ -30,7 +30,7 @@
 The service manager sets up, loads, saves and manages services.
 """
 import cgi
-import cPickle
+import pickle
 import logging
 import os
 import shutil
@@ -522,11 +522,11 @@
         self.main_window.increment_progress_bar()
         try:
             zip_file = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED, allow_zip_64)
-            # First we add service contents. We save ALL file_names into ZIP using UTF-8.
-            zip_file.writestr(service_file_name.encode(u'utf-8'), service_content)
+            # First we add service contents..
+            zip_file.writestr(service_file_name, service_content)
             # Finally add all the listed media files.
             for write_from in write_list:
-                zip_file.write(write_from, write_from.encode(u'utf-8'))
+                zip_file.write(write_from, write_from)
             for audio_from, audio_to in audio_files:
                 if audio_from.startswith(u'audio'):
                     # When items are saved, they get new unique_identifier. Let's copy the file to the new location.
@@ -537,7 +537,7 @@
                 check_directory_exists(save_path)
                 if not os.path.exists(save_file):
                     shutil.copy(audio_from, save_file)
-                zip_file.write(audio_from, audio_to.encode(u'utf-8'))
+                zip_file.write(audio_from, audio_to)
         except IOError:
             log.exception(u'Failed to save service to disk: %s', temp_file_name)
             self.main_window.error_message(translate(u'OpenLP.ServiceManager', u'Error Saving File'),
@@ -594,7 +594,7 @@
             zip_file = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED,
                 True)
             # First we add service contents.
-            zip_file.writestr(service_file_name.encode(u'utf-8'), service_content)
+            zip_file.writestr(service_file_name, service_content)
         except IOError:
             log.exception(u'Failed to save service to disk: %s', temp_file_name)
             self.main_window.error_message(translate(u'OpenLP.ServiceManager', u'Error Saving File'),
@@ -686,14 +686,13 @@
             zip_file = zipfile.ZipFile(file_name)
             for zip_info in zip_file.infolist():
                 try:
-                    ucsfile = zip_info.filename.decode(u'utf-8')
+                    ucs_file = zip_info.filename
                 except UnicodeDecodeError:
-                    log.exception(u'file_name "%s" is not valid UTF-8' %
-                        zip_info.file_name.decode(u'utf-8', u'replace'))
+                    log.exception(u'file_name "%s" is not valid UTF-8' % zip_info.file_name)
                     critical_error_message_box(message=translate('OpenLP.ServiceManager',
                         'File is not a valid service.\n The content encoding is not UTF-8.'))
                     continue
-                osfile = ucsfile.replace(u'/', os.path.sep)
+                osfile = ucs_file.replace(u'/', os.path.sep)
                 if not osfile.startswith(u'audio'):
                     osfile = os.path.split(osfile)[1]
                 log.debug(u'Extract file: %s', osfile)

=== modified file 'openlp/core/ui/servicenoteform.py'
--- openlp/core/ui/servicenoteform.py	2013-02-05 08:05:28 +0000
+++ openlp/core/ui/servicenoteform.py	2013-07-18 06:15:35 +0000
@@ -43,7 +43,7 @@
         """
         Constructor
         """
-        QtGui.QDialog.__init__(self, self.main_window)
+        super(ServiceNoteForm, self).__init__(Registry().get(u'main_window'))
         self.setupUi()
         self.retranslateUi()
 

=== modified file 'openlp/core/ui/starttimeform.py'
--- openlp/core/ui/starttimeform.py	2013-03-01 09:20:26 +0000
+++ openlp/core/ui/starttimeform.py	2013-07-18 06:15:35 +0000
@@ -45,7 +45,7 @@
         """
         Constructor
         """
-        QtGui.QDialog.__init__(self, self.main_window)
+        super(StartTimeForm, self).__init__(Registry().get(u'main_window'))
         self.setupUi(self)
 
     def exec_(self):

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2013-06-24 16:54:23 +0000
+++ openlp/core/ui/thememanager.py	2013-07-18 06:15:35 +0000
@@ -514,23 +514,17 @@
                 else:
                     abort_import = False
                 for name in theme_zip.namelist():
-                    try:
-                        uname = unicode(name, u'utf-8')
-                    except UnicodeDecodeError:
-                        log.exception(u'Theme file contains non utf-8 filename "%s"' %
-                            name.decode(u'utf-8', u'replace'))
-                        raise Exception(u'validation')
-                    uname = uname.replace(u'/', os.path.sep)
-                    split_name = uname.split(os.path.sep)
+                    name = name.replace(u'/', os.path.sep)
+                    split_name = name.split(os.path.sep)
                     if split_name[-1] == u'' or len(split_name) == 1:
                         # is directory or preview file
                         continue
-                    full_name = os.path.join(directory, uname)
+                    full_name = os.path.join(directory, name)
                     check_directory_exists(os.path.dirname(full_name))
-                    if os.path.splitext(uname)[1].lower() == u'.xml':
+                    if os.path.splitext(name)[1].lower() == u'.xml':
                         file_xml = unicode(theme_zip.read(name), u'utf-8')
                         out_file = open(full_name, u'w')
-                        out_file.write(file_xml.encode(u'utf-8'))
+                        out_file.write(file_xml)
                     else:
                         out_file = open(full_name, u'wb')
                         out_file.write(theme_zip.read(name))
@@ -637,7 +631,7 @@
         out_file = None
         try:
             out_file = open(theme_file, u'w')
-            out_file.write(theme_pretty_xml)
+            out_file.write(theme_pretty_xml.decode('UTF-8'))
         except IOError:
             log.exception(u'Saving theme to file failed')
         finally:

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2013-07-13 16:33:32 +0000
+++ openlp/core/utils/__init__.py	2013-07-18 06:15:35 +0000
@@ -239,7 +239,7 @@
     global IMAGES_FILTER
     if not IMAGES_FILTER:
         log.debug(u'Generating images filter.')
-        formats = map(unicode, QtGui.QImageReader.supportedImageFormats())
+        formats = list(map(bytes.decode, map(bytes, QtGui.QImageReader.supportedImageFormats())))
         visible_formats = u'(*.%s)' % u'; *.'.join(formats)
         actual_formats = u'(*.%s)' % u' *.'.join(formats)
         IMAGES_FILTER = u'%s %s %s' % (translate('OpenLP', 'Image Files'), visible_formats, actual_formats)
@@ -393,16 +393,21 @@
 def get_locale_key(string):
     """
     Creates a key for case insensitive, locale aware string sorting.
+
+    ``string``
+        The corresponding string.
     """
     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)
+    if os.name == 'nt':
+        global ICU_COLLATOR
+        if ICU_COLLATOR is None:
+            from languagemanager import LanguageManager
+            language = LanguageManager.get_language()
+            icu_locale = icu.Locale(language)
+            ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
+        return ICU_COLLATOR.getSortKey(string)
+    return locale.strxfrm(string).encode()
 
 
 def get_natural_key(string):
@@ -412,9 +417,10 @@
     """
     key = DIGITS_OR_NONDIGITS.findall(string)
     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
+    # 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 [b''] + key
     return key
 
 

=== modified file 'openlp/core/utils/actions.py'
--- openlp/core/utils/actions.py	2013-03-07 11:20:57 +0000
+++ openlp/core/utils/actions.py	2013-07-18 06:15:35 +0000
@@ -103,12 +103,6 @@
             self.index += 1
             return self.actions[self.index - 1][1]
 
-    def next(self):
-        """
-        Python 2 "next" method.
-        """
-        return self.__next__()
-
     def has_key(self, key):
         """
         Implement the has_key() method to make this class a dictionary type
@@ -167,12 +161,6 @@
                 return category
         raise KeyError(u'Category "%s" does not exist.' % key)
 
-    def __contains__(self, item):
-        """
-        Implement the __contains__() method to make this class like a dictionary
-        """
-        return self.has_key(item)
-
     def __len__(self):
         """
         Implement the __len__() method to make this class like a dictionary
@@ -196,12 +184,6 @@
             self.index += 1
             return self.categories[self.index - 1]
 
-    def next(self):
-        """
-        Python 2 "next" method for iterator.
-        """
-        return self.__next__()
-
     def has_key(self, key):
         """
         Implement the has_key() method to make this class like a dictionary

=== modified file 'openlp/core/utils/applocation.py'
--- openlp/core/utils/applocation.py	2013-07-06 19:21:21 +0000
+++ openlp/core/utils/applocation.py	2013-07-18 06:15:35 +0000
@@ -143,20 +143,19 @@
     """
     Return a path based on which OS and environment we are running in.
     """
-    encoding = sys.getfilesystemencoding()
     if sys.platform == u'win32':
         if dir_type == AppLocation.DataDir:
-            return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data')
+            return os.path.join(unicode(os.getenv(u'APPDATA')), u'openlp', u'data')
         elif dir_type == AppLocation.LanguageDir:
             return os.path.split(openlp.__file__)[0]
-        return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp')
+        return os.path.join(unicode(os.getenv(u'APPDATA')), u'openlp')
     elif sys.platform == u'darwin':
         if dir_type == AppLocation.DataDir:
-            return os.path.join(unicode(os.getenv(u'HOME'), encoding),
+            return os.path.join(unicode(os.getenv(u'HOME')),
                                 u'Library', u'Application Support', u'openlp', u'Data')
         elif dir_type == AppLocation.LanguageDir:
             return os.path.split(openlp.__file__)[0]
-        return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp')
+        return os.path.join(unicode(os.getenv(u'HOME')), u'Library', u'Application Support', u'openlp')
     else:
         if dir_type == AppLocation.LanguageDir:
             for prefix in [u'/usr/local', u'/usr']:
@@ -166,10 +165,10 @@
             return os.path.join(u'/usr', u'share', u'openlp')
         if XDG_BASE_AVAILABLE:
             if dir_type == AppLocation.DataDir:
-                return os.path.join(unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
+                return os.path.join(unicode(BaseDirectory.xdg_data_home), u'openlp')
             elif dir_type == AppLocation.CacheDir:
-                return os.path.join(unicode(BaseDirectory.xdg_cache_home, encoding), u'openlp')
+                return os.path.join(unicode(BaseDirectory.xdg_cache_home), u'openlp')
         if dir_type == AppLocation.DataDir:
-            return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp', u'data')
-        return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp')
+            return os.path.join(unicode(os.getenv(u'HOME')), u'.openlp', u'data')
+        return os.path.join(unicode(os.getenv(u'HOME')), u'.openlp')
 

=== modified file 'openlp/plugins/bibles/forms/bibleupgradeform.py'
--- openlp/plugins/bibles/forms/bibleupgradeform.py	2013-04-25 17:58:37 +0000
+++ openlp/plugins/bibles/forms/bibleupgradeform.py	2013-07-18 06:15:35 +0000
@@ -39,7 +39,7 @@
 from openlp.core.lib import Registry, Settings, UiStrings, translate, check_directory_exists
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
-from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding
+from openlp.core.utils import AppLocation, delete_file
 from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB
 from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract
 
@@ -71,7 +71,7 @@
         self.suffix = u'.sqlite'
         self.settings_section = u'bibles'
         self.path = AppLocation.get_section_data_path(self.settings_section)
-        self.temp_dir = os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp')
+        self.temp_dir = os.path.join(gettempdir(), u'openlp')
         self.files = self.manager.old_bible_databases
         self.success = {}
         self.new_bibles = {}

=== modified file 'openlp/plugins/remotes/lib/httpserver.py'
--- openlp/plugins/remotes/lib/httpserver.py	2013-07-12 18:13:06 +0000
+++ openlp/plugins/remotes/lib/httpserver.py	2013-07-18 06:15:35 +0000
@@ -445,7 +445,7 @@
             u'display': self.live_controller.desktop_screen.isChecked()
         }
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': result})
+        return json.dumps({u'results': result}).encode()
 
     def main_poll(self):
         """
@@ -455,7 +455,7 @@
             u'slide_count': self.live_controller.slide_count
         }
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': result})
+        return json.dumps({u'results': result}).encode()
 
     def main_image(self):
         """
@@ -465,7 +465,7 @@
             u'slide_image': u'data:image/png;base64,' + str(image_to_byte(self.live_controller.slide_image))
         }
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': result})
+        return json.dumps({u'results': result}).encode()
 
     def display(self, action):
         """
@@ -477,7 +477,7 @@
         """
         self.live_controller.emit(QtCore.SIGNAL(u'slidecontroller_toggle_display'), action)
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': {u'success': True}})
+        return json.dumps({u'results': {u'success': True}}).encode()
 
     def alert(self):
         """
@@ -495,7 +495,7 @@
         else:
             success = False
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': {u'success': success}})
+        return json.dumps({u'results': {u'success': success}}).encode()
 
     def controller(self, display_type, action):
         """
@@ -543,7 +543,7 @@
                 self.live_controller.emit(QtCore.SIGNAL(event))
             json_data = {u'results': {u'success': True}}
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps(json_data)
+        return json.dumps(json_data).encode()
 
     def service(self, action):
         """
@@ -555,7 +555,7 @@
         event = u'servicemanager_%s' % action
         if action == u'list':
             cherrypy.response.headers['Content-Type'] = u'application/json'
-            return json.dumps({u'results': {u'items': self._get_service_items()}})
+            return json.dumps({u'results': {u'items': self._get_service_items()}}).encode()
         event += u'_item'
         if self.request_data:
             try:
@@ -566,7 +566,7 @@
         else:
             Registry().execute(event)
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': {u'success': True}})
+        return json.dumps({u'results': {u'success': True}}).encode()
 
     def plugin_info(self, action):
         """
@@ -582,7 +582,7 @@
                 if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
                     searches.append([plugin.name, unicode(plugin.text_strings[StringContent.Name][u'plural'])])
             cherrypy.response.headers['Content-Type'] = u'application/json'
-            return json.dumps({u'results': {u'items': searches}})
+            return json.dumps({u'results': {u'items': searches}}).encode()
 
     def search(self, plugin_name):
         """
@@ -602,7 +602,7 @@
         else:
             results = []
         cherrypy.response.headers['Content-Type'] = u'application/json'
-        return json.dumps({u'results': {u'items': results}})
+        return json.dumps({u'results': {u'items': results}}).encode()
 
     def go_live(self, plugin_name):
         """
@@ -648,7 +648,7 @@
         Set the HTTP not found return code.
         """
         cherrypy.response.status = 404
-        cherrypy.response.body = ["<html><body>Sorry, an error occurred </body></html>"]
+        cherrypy.response.body = [b'<html><body>Sorry, an error occurred </body></html>']
 
     def _get_service_manager(self):
         """

=== modified file 'openlp/plugins/songs/forms/duplicatesongremovalform.py'
--- openlp/plugins/songs/forms/duplicatesongremovalform.py	2013-06-24 16:54:23 +0000
+++ openlp/plugins/songs/forms/duplicatesongremovalform.py	2013-07-18 06:15:35 +0000
@@ -67,7 +67,7 @@
         self.review_total_count = 0
         # Used to interrupt ongoing searches when cancel is clicked.
         self.break_search = False
-        OpenLPWizard.__init__(self, self.main_window, plugin, u'duplicateSongRemovalWizard',
+        OpenLPWizard.__init__(self, Registry().get('main_window'), plugin, u'duplicateSongRemovalWizard',
             u':/wizards/wizard_duplicateremoval.bmp', False)
         self.setMinimumWidth(730)
 
@@ -312,7 +312,7 @@
                 self.review_scroll_area_layout.removeItem(item)
         # Process next set of duplicates.
         self.process_current_duplicate_entry()
-    
+
     def process_current_duplicate_entry(self):
         """
         Update the review counter in the wizard header, add song widgets for
@@ -359,4 +359,5 @@
                 self._application = Registry().get(u'application')
             return self._application
 
-    application = property(_get_application)
\ No newline at end of file
+    application = property(_get_application)
+

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2013-06-21 18:13:59 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2013-07-18 06:15:35 +0000
@@ -385,9 +385,6 @@
         # lazy xml migration for now
         self.verse_list_widget.clear()
         self.verse_list_widget.setRowCount(0)
-        # This is just because occasionally the lyrics come back as a "buffer"
-        if isinstance(self.song.lyrics, buffer):
-            self.song.lyrics = unicode(self.song.lyrics)
         verse_tags_translated = False
         if self.song.lyrics.startswith(u'<?xml version='):
             songXML = SongXML()

=== modified file 'openlp/plugins/songs/forms/songimportform.py'
--- openlp/plugins/songs/forms/songimportform.py	2013-06-27 08:30:34 +0000
+++ openlp/plugins/songs/forms/songimportform.py	2013-07-18 06:15:35 +0000
@@ -60,8 +60,8 @@
         ``plugin``
             The songs plugin.
         """
+        OpenLPWizard.__init__(self, parent, plugin, u'songImportWizard', u':/wizards/wizard_importsong.bmp')
         self.clipboard = self.main_window.clipboard
-        OpenLPWizard.__init__(self, parent, plugin, u'songImportWizard', u':/wizards/wizard_importsong.bmp')
 
     def setupUi(self, image):
         """

=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py	2013-06-14 20:20:26 +0000
+++ openlp/plugins/songs/lib/__init__.py	2013-07-18 06:15:35 +0000
@@ -395,12 +395,6 @@
     """
     from xml import SongXML
 
-    if isinstance(song.title, buffer):
-        song.title = unicode(song.title)
-    if isinstance(song.alternate_title, buffer):
-        song.alternate_title = unicode(song.alternate_title)
-    if isinstance(song.lyrics, buffer):
-        song.lyrics = unicode(song.lyrics)
     if song.title:
         song.title = clean_title(song.title)
     else:

=== modified file 'openlp/plugins/songs/lib/db.py'
--- openlp/plugins/songs/lib/db.py	2013-03-31 10:31:54 +0000
+++ openlp/plugins/songs/lib/db.py	2013-07-18 06:15:35 +0000
@@ -68,7 +68,7 @@
     Song model
     """
     def __init__(self):
-        self.sort_key = ()
+        self.sort_key = []
 
     @reconstructor
     def init_on_load(self):

=== modified file 'openlp/plugins/songs/lib/dreambeamimport.py'
--- openlp/plugins/songs/lib/dreambeamimport.py	2013-03-07 08:05:43 +0000
+++ openlp/plugins/songs/lib/dreambeamimport.py	2013-07-18 06:15:35 +0000
@@ -100,12 +100,11 @@
                     log.exception(u'XML syntax error in file %s' % file)
                     self.logError(file, SongStrings.XMLSyntaxError)
                     continue
-                xml = unicode(etree.tostring(parsed_file))
+                xml = etree.tostring(parsed_file).decode()
                 song_xml = objectify.fromstring(xml)
                 if song_xml.tag != u'DreamSong':
-                    self.logError(file, unicode(
-                        translate('SongsPlugin.DreamBeamImport',
-                            ('Invalid DreamBeam song file. Missing DreamSong tag.'))))
+                    self.logError(file,
+                        translate('SongsPlugin.DreamBeamImport', 'Invalid DreamBeam song file. Missing DreamSong tag.'))
                     continue
                 if hasattr(song_xml, u'Version'):
                     self.version = float(song_xml.Version.text)

=== modified file 'openlp/plugins/songs/lib/easyslidesimport.py'
--- openlp/plugins/songs/lib/easyslidesimport.py	2013-03-07 08:05:43 +0000
+++ openlp/plugins/songs/lib/easyslidesimport.py	2013-07-18 06:15:35 +0000
@@ -54,7 +54,7 @@
         log.info(u'Importing EasySlides XML file %s', self.import_source)
         parser = etree.XMLParser(remove_blank_text=True)
         parsed_file = etree.parse(self.import_source, parser)
-        xml = unicode(etree.tostring(parsed_file))
+        xml = etree.tostring(parsed_file).decode()
         song_xml = objectify.fromstring(xml)
         self.import_wizard.progress_bar.setMaximum(len(song_xml.Item))
         for song in song_xml.Item:

=== modified file 'openlp/plugins/songs/lib/foilpresenterimport.py'
--- openlp/plugins/songs/lib/foilpresenterimport.py	2013-03-07 08:05:43 +0000
+++ openlp/plugins/songs/lib/foilpresenterimport.py	2013-07-18 06:15:35 +0000
@@ -126,11 +126,10 @@
         for file_path in self.import_source:
             if self.stop_import_flag:
                 return
-            self.import_wizard.increment_progress_bar(
-                WizardStrings.ImportingType % os.path.basename(file_path))
+            self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
             try:
                 parsed_file = etree.parse(file_path, parser)
-                xml = unicode(etree.tostring(parsed_file))
+                xml = etree.tostring(parsed_file).decode()
                 self.FoilPresenter.xml_to_song(xml)
             except etree.XMLSyntaxError:
                 self.logError(file_path, SongStrings.XMLSyntaxError)

=== modified file 'openlp/plugins/songs/lib/openlyricsexport.py'
--- openlp/plugins/songs/lib/openlyricsexport.py	2013-06-24 16:54:23 +0000
+++ openlp/plugins/songs/lib/openlyricsexport.py	2013-07-18 06:15:35 +0000
@@ -78,7 +78,7 @@
             filename = u'%s.xml' % filename[0:250 - len(self.save_path)]
             # Pass a file object, because lxml does not cope with some special
             # characters in the path (see lp:757673 and lp:744337).
-            tree.write(open(os.path.join(self.save_path, filename), u'w'),
+            tree.write(open(os.path.join(self.save_path, filename), u'wb'),
                 encoding=u'utf-8', xml_declaration=True, pretty_print=True)
         return True
 

=== modified file 'openlp/plugins/songs/lib/openlyricsimport.py'
--- openlp/plugins/songs/lib/openlyricsimport.py	2013-03-08 08:14:39 +0000
+++ openlp/plugins/songs/lib/openlyricsimport.py	2013-07-18 06:15:35 +0000
@@ -70,7 +70,7 @@
                 # Pass a file object, because lxml does not cope with some
                 # special characters in the path (see lp:757673 and lp:744337).
                 parsed_file = etree.parse(open(file_path, u'r'), parser)
-                xml = unicode(etree.tostring(parsed_file))
+                xml = etree.tostring(parsed_file).decode()
                 self.openLyrics.xml_to_song(xml)
             except etree.XMLSyntaxError:
                 log.exception(u'XML syntax error in file %s' % file_path)

=== modified file 'openlp/plugins/songs/lib/songshowplusimport.py'
--- openlp/plugins/songs/lib/songshowplusimport.py	2013-03-31 10:13:56 +0000
+++ openlp/plugins/songs/lib/songshowplusimport.py	2013-07-18 06:15:35 +0000
@@ -27,7 +27,7 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 """
-The :mod:`songshowplusimport` module provides the functionality for importing 
+The :mod:`songshowplusimport` module provides the functionality for importing
 SongShow Plus songs into the OpenLP database.
 """
 import os
@@ -132,43 +132,41 @@
                 else:
                     length_descriptor, = struct.unpack("B", song_data.read(1))
                 log.debug(length_descriptor_size)
-                data = song_data.read(length_descriptor)
+                data = song_data.read(length_descriptor).decode()
                 if block_key == TITLE:
-                    self.title = unicode(data, u'cp1252')
+                    self.title = data
                 elif block_key == AUTHOR:
                     authors = data.split(" / ")
                     for author in authors:
                         if author.find(",") !=-1:
                             authorParts = author.split(", ")
                             author = authorParts[1] + " " + authorParts[0]
-                        self.parse_author(unicode(author, u'cp1252'))
+                        self.parse_author(author)
                 elif block_key == COPYRIGHT:
-                    self.addCopyright(unicode(data, u'cp1252'))
+                    self.addCopyright(data)
                 elif block_key == CCLI_NO:
                     self.ccliNumber = int(data)
                 elif block_key == VERSE:
-                    self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no))
+                    self.addVerse(data, "%s%s" % (VerseType.tags[VerseType.Verse], verse_no))
                 elif block_key == CHORUS:
-                    self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no))
+                    self.addVerse(data, "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no))
                 elif block_key == BRIDGE:
-                    self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no))
+                    self.addVerse(data, "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no))
                 elif block_key == TOPIC:
-                    self.topics.append(unicode(data, u'cp1252'))
+                    self.topics.append(data)
                 elif block_key == COMMENTS:
-                    self.comments = unicode(data, u'cp1252')
+                    self.comments = data
                 elif block_key == VERSE_ORDER:
                     verse_tag = self.to_openlp_verse_tag(data, True)
                     if verse_tag:
-                        if not isinstance(verse_tag, unicode):
-                            verse_tag = unicode(verse_tag, u'cp1252')
                         self.ssp_verse_order_list.append(verse_tag)
                 elif block_key == SONG_BOOK:
-                    self.songBookName = unicode(data, u'cp1252')
+                    self.songBookName = data
                 elif block_key == SONG_NUMBER:
                     self.songNumber = ord(data)
                 elif block_key == CUSTOM_VERSE:
                     verse_tag = self.to_openlp_verse_tag(verse_name)
-                    self.addVerse(unicode(data, u'cp1252'), verse_tag)
+                    self.addVerse(data, verse_tag)
                 else:
                     log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data))
                     song_data.seek(next_block_starts)

=== modified file 'openlp/plugins/songs/lib/xml.py'
--- openlp/plugins/songs/lib/xml.py	2013-02-24 18:13:50 +0000
+++ openlp/plugins/songs/lib/xml.py	2013-07-18 06:15:35 +0000
@@ -340,7 +340,7 @@
                 # Do not add the break attribute to the last lines element.
                 if index < len(optional_verses) - 1:
                     lines_element.set(u'break', u'optional')
-        return self._extract_xml(song_xml)
+        return self._extract_xml(song_xml).decode()
 
     def _get_missing_tags(self, text):
         """

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2013-06-11 05:31:11 +0000
+++ openlp/plugins/songs/songsplugin.py	2013-07-18 06:15:35 +0000
@@ -41,7 +41,6 @@
 from openlp.core.lib import Plugin, StringContent, UiStrings, build_icon, translate
 from openlp.core.lib.db import Manager
 from openlp.core.lib.ui import create_action
-from openlp.core.utils import get_filesystem_encoding
 from openlp.core.utils.actions import ActionList
 from openlp.plugins.songs.lib import clean_song, upgrade
 from openlp.plugins.songs.lib.db import init_schema, Song
@@ -263,7 +262,7 @@
         self.application.process_events()
         self.on_tools_reindex_item_triggered()
         self.application.process_events()
-        db_dir = unicode(os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
+        db_dir = os.path.join(gettempdir(), u'openlp')
         if not os.path.exists(db_dir):
             return
         song_dbs = []

=== modified file 'scripts/generate_resources.sh'
--- scripts/generate_resources.sh	2013-03-29 12:19:40 +0000
+++ scripts/generate_resources.sh	2013-07-18 06:15:35 +0000
@@ -44,7 +44,7 @@
 mv openlp/core/resources.py openlp/core/resources.py.old
 
 # Create the new data from the updated qrc
-pyrcc4 -o openlp/core/resources.py.new resources/images/openlp-2.qrc
+pyrcc4 -py3 -o openlp/core/resources.py.new resources/images/openlp-2.qrc
 
 # Remove patch breaking lines
 cat openlp/core/resources.py.new | sed '/# Created: /d;/#      by: /d' > openlp/core/resources.py

=== modified file 'tests/functional/openlp_core_lib/test_image_manager.py'
--- tests/functional/openlp_core_lib/test_image_manager.py	2013-03-12 08:19:47 +0000
+++ tests/functional/openlp_core_lib/test_image_manager.py	2013-07-18 06:15:35 +0000
@@ -46,11 +46,11 @@
         # WHEN: The image bytes are requested.
         byte_array = self.image_manager.get_image_bytes(TEST_PATH, u'church.jpg')
 
-        # THEN: Type should be a byte array.
-        self.assertEqual(isinstance(byte_array, QtCore.QByteArray), True, u'The returned object should be a QByteArray')
+        # THEN: Type should be a str.
+        self.assertEqual(isinstance(byte_array, str), True, u'The returned object should be a str')
 
         # WHEN the image is retrieved has not been loaded
         # THEN a KeyError is thrown
         with self.assertRaises(KeyError) as context:
             self.image_manager.get_image(TEST_PATH, u'church1.jpg')
-        self.assertNotEquals(context.exception[0], u'', u'KeyError exception should have been thrown for missing image')
+        self.assertNotEquals(context.exception, u'', u'KeyError exception should have been thrown for missing image')

=== modified file 'tests/functional/openlp_core_lib/test_lib.py'
--- tests/functional/openlp_core_lib/test_lib.py	2013-06-23 15:29:16 +0000
+++ tests/functional/openlp_core_lib/test_lib.py	2013-07-18 06:15:35 +0000
@@ -187,7 +187,7 @@
         """
         Test the get_text_file_string() method when a read error happens
         """
-        with patch(u'openlp.core.lib.os.path.isfile') as mocked_isfile, patch(u'__builtin__.open') as mocked_open:
+        with patch(u'openlp.core.lib.os.path.isfile') as mocked_isfile, patch(u'builtins.open') as mocked_open:
             # GIVEN: A mocked-out open() which raises an exception and isfile returns True
             filename = u'testfile.txt'
             mocked_isfile.return_value = True

=== modified file 'tests/functional/openlp_core_lib/test_registry.py'
--- tests/functional/openlp_core_lib/test_registry.py	2013-02-17 07:54:43 +0000
+++ tests/functional/openlp_core_lib/test_registry.py	2013-07-18 06:15:35 +0000
@@ -31,14 +31,14 @@
         # THEN  and I will get an exception
         with self.assertRaises(KeyError) as context:
             Registry().register(u'test1', mock_1)
-        self.assertEqual(context.exception[0], u'Duplicate service exception test1',
+        self.assertEqual(context.exception, u'Duplicate service exception test1',
             u'KeyError exception should have been thrown for duplicate service')
 
         # WHEN I try to get back a non existent component
         # THEN I will get an exception
         with self.assertRaises(KeyError) as context:
             temp = Registry().get(u'test2')
-        self.assertEqual(context.exception[0], u'Service test2 not found in list',
+        self.assertEqual(context.exception, u'Service test2 not found in list',
             u'KeyError exception should have been thrown for missing service')
 
         # WHEN I try to replace a component I should be allowed (testing only)
@@ -46,7 +46,7 @@
         # THEN I will get an exception
         with self.assertRaises(KeyError) as context:
             temp = Registry().get(u'test1')
-        self.assertEqual(context.exception[0], u'Service test1 not found in list',
+        self.assertEqual(context.exception, u'Service test1 not found in list',
             u'KeyError exception should have been thrown for deleted service')
 
     def registry_function_test(self):
@@ -81,4 +81,5 @@
         return "function_1"
 
     def dummy_function_2(self):
-        return "function_2"
\ No newline at end of file
+        return "function_2"
+

=== modified file 'tests/functional/openlp_core_lib/test_serviceitem.py'
--- tests/functional/openlp_core_lib/test_serviceitem.py	2013-07-05 07:47:09 +0000
+++ tests/functional/openlp_core_lib/test_serviceitem.py	2013-07-18 06:15:35 +0000
@@ -2,6 +2,7 @@
     Package to test the openlp.core.lib package.
 """
 import os
+
 from unittest import TestCase
 from mock import MagicMock, patch
 

=== modified file 'tests/functional/openlp_core_utils/test_utils.py'
--- tests/functional/openlp_core_utils/test_utils.py	2013-04-15 15:43:18 +0000
+++ tests/functional/openlp_core_utils/test_utils.py	2013-07-18 06:15:35 +0000
@@ -105,14 +105,33 @@
         # THEN: The file name should be cleaned.
         assert result == wanted_name, u'The file name should not contain any special characters.'
 
-    def get_locale_key_test(self):
-        """
-        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
-            # 0x00C3 (A with diaresis) should be sorted as "A". 0x00DF (sharp s) should be sorted as "ss".
-            mocked_get_language.return_value = u'de'
+    def get_locale_key_windows_test(self):
+        """
+        Test the get_locale_key(string) function
+        """
+        with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language,  \
+                patch(u'openlp.core.utils.os') as mocked_os:
+            # 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'
+            mocked_os.name = u'nt'
+            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
+            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_locale_key_linux_test(self):
+
+        """
+        Test the get_locale_key(string) function
+        """
+        with patch(u'openlp.core.utils.languagemanager.LanguageManager.get_language') as mocked_get_language,  \
+                patch(u'openlp.core.utils.os.name') as mocked_os:
+            # 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'
+            mocked_os.name = u'linux'
             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


Follow ups