← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~tomasgroth/openlp/25bugfixes3 into lp:openlp

 

Tomas Groth has proposed merging lp:~tomasgroth/openlp/25bugfixes3 into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)
Related bugs:
  Bug #1582152 in OpenLP: "SongPro import fails with traceback"
  https://bugs.launchpad.net/openlp/+bug/1582152
  Bug #1585489 in OpenLP: "Traceback during songshowplus import"
  https://bugs.launchpad.net/openlp/+bug/1585489
  Bug #1590657 in OpenLP: "MediaShout import causes traceback"
  https://bugs.launchpad.net/openlp/+bug/1590657

For more details, see:
https://code.launchpad.net/~tomasgroth/openlp/25bugfixes3/+merge/297541

Fix various pyodbc related issues. Fixes bug 1590657.
Fix of tracback during SongPro import. Fixes bug 1582152.
Fix traceback during songshowplus import. Fixes bug 1585489.
Skip PresentationManager files we do not support.
-- 
Your team OpenLP Core is requested to review the proposed merge of lp:~tomasgroth/openlp/25bugfixes3 into lp:openlp.
=== modified file 'openlp/plugins/songs/lib/importers/mediashout.py'
--- openlp/plugins/songs/lib/importers/mediashout.py	2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/lib/importers/mediashout.py	2016-06-15 20:11:03 +0000
@@ -24,15 +24,17 @@
 a MediaShout database into the OpenLP database.
 """
 
-# WARNING: See https://docs.python.org/2/library/sqlite3.html for value substitution
+# WARNING: See https://docs.python.org/3/library/sqlite3.html for value substitution
 #          in SQL statements
 
 import pyodbc
+import logging
 
 from openlp.core.lib import translate
 from openlp.plugins.songs.lib.importers.songimport import SongImport
 
 VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E']
+log = logging.getLogger(__name__)
 
 
 class MediaShoutImport(SongImport):
@@ -44,17 +46,18 @@
         """
         Initialise the MediaShout importer.
         """
-        SongImport.__init__(self, manager, **kwargs)
+        super(MediaShoutImport, self).__init__(manager, **kwargs)
 
     def do_import(self):
         """
         Receive a single file to import.
         """
         try:
-            conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};'
-                                  'PWD=6NOZ4eHK7k'.format(sorce=self.import_source))
-        except:
+            conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};DBQ={source};'
+                                  'PWD=6NOZ4eHK7k'.format(source=self.import_source))
+        except Exception as e:
             # Unfortunately no specific exception type
+            log.exception(e)
             self.log_error(self.import_source, translate('SongsPlugin.MediaShoutImport',
                                                          'Unable to open the MediaShout database.'))
             return
@@ -63,17 +66,21 @@
         songs = cursor.fetchall()
         self.import_wizard.progress_bar.setMaximum(len(songs))
         for song in songs:
+            topics = []
             if self.stop_import_flag:
                 break
-            cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', song.Record)
+            cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number',
+                           float(song.Record))
             verses = cursor.fetchall()
-            cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', song.Record)
+            cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder',
+                           float(song.Record))
             verse_order = cursor.fetchall()
-            cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId '
-                           'WHERE SongThemes.Record = ?', song.Record)
-            topics = cursor.fetchall()
+            if cursor.tables(table='TableName', tableType='TABLE').fetchone():
+                cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId '
+                               'WHERE SongThemes.Record = ?', float(song.Record))
+                topics = cursor.fetchall()
             cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ON SongGroups.GroupId = Groups.GroupId '
-                           'WHERE SongGroups.Record = ?', song.Record)
+                           'WHERE SongGroups.Record = ?', float(song.Record))
             topics += cursor.fetchall()
             self.process_song(song, verses, verse_order, topics)
 

=== modified file 'openlp/plugins/songs/lib/importers/opspro.py'
--- openlp/plugins/songs/lib/importers/opspro.py	2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/lib/importers/opspro.py	2016-06-15 20:11:03 +0000
@@ -55,7 +55,7 @@
         """
         password = self.extract_mdb_password()
         try:
-            conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};'
+            conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};DBQ={source};'
                                   'PWD={password}'.format(source=self.import_source, password=password))
         except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e:
             log.warning('Unable to connect the OPS Pro database {source}. {error}'.format(source=self.import_source,
@@ -74,11 +74,11 @@
                 break
             # Type means: 0=Original, 1=Projection, 2=Own
             cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = ? AND Type < 2 '
-                           'ORDER BY Type DESC', song.ID)
+                           'ORDER BY Type DESC', float(song.ID))
             lyrics = cursor.fetchone()
             cursor.execute('SELECT CategoryName FROM Category INNER JOIN SongCategory '
                            'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = ? '
-                           'ORDER BY CategoryName', song.ID)
+                           'ORDER BY CategoryName', float(song.ID))
             topics = cursor.fetchall()
             try:
                 self.process_song(song, lyrics, topics)

=== modified file 'openlp/plugins/songs/lib/importers/presentationmanager.py'
--- openlp/plugins/songs/lib/importers/presentationmanager.py	2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/lib/importers/presentationmanager.py	2016-06-15 20:11:03 +0000
@@ -56,7 +56,13 @@
                 # Open file with detected encoding and remove encoding declaration
                 text = open(file_path, mode='r', encoding=encoding).read()
                 text = re.sub('.+\?>\n', '', text)
-                tree = etree.fromstring(text, parser=etree.XMLParser(recover=True))
+                try:
+                    tree = etree.fromstring(text, parser=etree.XMLParser(recover=True))
+                except ValueError:
+                    self.log_error(file_path,
+                                   translate('SongsPlugin.PresentationManagerImport',
+                                             'File is not in XML-format, which is the only format supported.'))
+                    continue
             root = objectify.fromstring(etree.tostring(tree))
             self.process_song(root)
 

=== modified file 'openlp/plugins/songs/lib/importers/songpro.py'
--- openlp/plugins/songs/lib/importers/songpro.py	2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/importers/songpro.py	2016-06-15 20:11:03 +0000
@@ -72,7 +72,7 @@
         Receive a single file or a list of files to import.
         """
         self.encoding = None
-        with open(self.import_source, 'rt') as songs_file:
+        with open(self.import_source, 'rt', errors='ignore') as songs_file:
             self.import_wizard.progress_bar.setMaximum(0)
             tag = ''
             text = ''

=== modified file 'openlp/plugins/songs/lib/importers/songshowplus.py'
--- openlp/plugins/songs/lib/importers/songshowplus.py	2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/lib/importers/songshowplus.py	2016-06-15 20:11:03 +0000
@@ -106,6 +106,7 @@
             song_data = open(file, 'rb')
             while True:
                 block_key, = struct.unpack("I", song_data.read(4))
+                log.debug('block_key: %d' % block_key)
                 # The file ends with 4 NULL's
                 if block_key == 0:
                     break
@@ -117,7 +118,13 @@
                     null, verse_name_length, = struct.unpack("BB", song_data.read(2))
                     verse_name = self.decode(song_data.read(verse_name_length))
                 length_descriptor_size, = struct.unpack("B", song_data.read(1))
-                log.debug(length_descriptor_size)
+                log.debug('length_descriptor_size: %d' % length_descriptor_size)
+                # In the case of song_numbers the number is in the data from the
+                # current position to the next block starts
+                if block_key == SONG_NUMBER:
+                    sn_bytes = song_data.read(length_descriptor_size - 1)
+                    self.song_number = int.from_bytes(sn_bytes, byteorder='little')
+                    continue
                 # Detect if/how long the length descriptor is
                 if length_descriptor_size == 12 or length_descriptor_size == 20:
                     length_descriptor, = struct.unpack("I", song_data.read(4))
@@ -127,8 +134,9 @@
                     length_descriptor = 0
                 else:
                     length_descriptor, = struct.unpack("B", song_data.read(1))
-                log.debug(length_descriptor_size)
+                log.debug('length_descriptor: %d' % length_descriptor)
                 data = song_data.read(length_descriptor)
+                log.debug(data)
                 if block_key == TITLE:
                     self.title = self.decode(data)
                 elif block_key == AUTHOR:
@@ -168,8 +176,6 @@
                         self.ssp_verse_order_list.append(verse_tag)
                 elif block_key == SONG_BOOK:
                     self.song_book_name = self.decode(data)
-                elif block_key == SONG_NUMBER:
-                    self.song_number = ord(data)
                 elif block_key == CUSTOM_VERSE:
                     verse_tag = self.to_openlp_verse_tag(verse_name)
                     self.add_verse(self.decode(data), verse_tag)

=== modified file 'openlp/plugins/songs/lib/importers/videopsalm.py'
--- openlp/plugins/songs/lib/importers/videopsalm.py	2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/lib/importers/videopsalm.py	2016-06-15 20:11:03 +0000
@@ -117,6 +117,4 @@
                 if not self.finish():
                     self.log_error('Could not import {title}'.format(title=self.title))
         except Exception as e:
-            self.log_error(translate('SongsPlugin.VideoPsalmImport', 'File {name}').format(name=file.name),
-                           translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e))
-        song_file.close()
+            self.log_error(song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e))

=== modified file 'openlp/plugins/songs/lib/importers/worshipcenterpro.py'
--- openlp/plugins/songs/lib/importers/worshipcenterpro.py	2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/lib/importers/worshipcenterpro.py	2016-06-15 20:11:03 +0000
@@ -49,7 +49,7 @@
         Receive a single file to import.
         """
         try:
-            conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};'
+            conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};'
                                   'DBQ={source}'.format(source=self.import_source))
         except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e:
             log.warning('Unable to connect the WorshipCenter Pro '

=== modified file 'tests/functional/openlp_plugins/songs/test_songshowplusimport.py'
--- tests/functional/openlp_plugins/songs/test_songshowplusimport.py	2016-05-31 21:40:13 +0000
+++ tests/functional/openlp_plugins/songs/test_songshowplusimport.py	2016-06-15 20:11:03 +0000
@@ -52,6 +52,8 @@
                          self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
         self.file_import([os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong')],
                          self.load_external_result_data(os.path.join(TEST_PATH, 'a mighty fortress is our god.json')))
+        self.file_import([os.path.join(TEST_PATH, 'cleanse-me.sbsong')],
+                         self.load_external_result_data(os.path.join(TEST_PATH, 'cleanse-me.json')))
 
 
 class TestSongShowPlusImport(TestCase):

=== added file 'tests/resources/songshowplussongs/cleanse-me.json'
--- tests/resources/songshowplussongs/cleanse-me.json	1970-01-01 00:00:00 +0000
+++ tests/resources/songshowplussongs/cleanse-me.json	2016-06-15 20:11:03 +0000
@@ -0,0 +1,38 @@
+{
+    "authors": [
+        "J. Edwin Orr"
+    ],
+    "ccli_number": 56307,
+    "comments": "",
+    "copyright": "Public Domain ",
+    "song_book_name": "",
+    "song_number": 438,
+    "title": "Cleanse Me [438]",
+    "topics": [
+        "Cleansing",
+        "Communion",
+        "Consecration",
+        "Holiness",
+        "Holy Spirit",
+        "Revival"
+    ],
+    "verse_order_list": [],
+    "verses": [
+        [
+            "Search me, O God,\r\nAnd know my heart today;\r\nTry me, O Savior,\r\nKnow my thoughts, I pray.\r\nSee if there be\r\nSome wicked way in me;\r\nCleanse me from every sin\r\nAnd set me free.",
+            "v1"
+        ],
+        [
+            "I praise Thee, Lord,\r\nFor cleansing me from sin;\r\nFulfill Thy Word,\r\nAnd make me pure within.\r\nFill me with fire\r\nWhere once I burned with shame;\r\nGrant my desire\r\nTo magnify Thy name.",
+            "v2"
+        ],
+        [
+            "Lord, take my life,\r\nAnd make it wholly Thine;\r\nFill my poor heart\r\nWith Thy great love divine.\r\nTake all my will,\r\nMy passion, self and pride;\r\nI now surrender, Lord\r\nIn me abide.",
+            "v3"
+        ],
+        [
+            "O Holy Ghost,\r\nRevival comes from Thee;\r\nSend a revival,\r\nStart the work in me.\r\nThy Word declares\r\nThou wilt supply our need;\r\nFor blessings now,\r\nO Lord, I humbly plead.",
+            "v4"
+        ]
+    ]
+}

=== added file 'tests/resources/songshowplussongs/cleanse-me.sbsong'
Binary files tests/resources/songshowplussongs/cleanse-me.sbsong	1970-01-01 00:00:00 +0000 and tests/resources/songshowplussongs/cleanse-me.sbsong	2016-06-15 20:11:03 +0000 differ

References