forked from openlp/openlp
Added WorshipCenter Pro song importer.
Also added associated tests.
This commit is contained in:
parent
7133c0ef0b
commit
5aee3198ae
@ -76,7 +76,13 @@ if os.name == u'nt':
|
||||
HAS_MEDIASHOUT = True
|
||||
except ImportError:
|
||||
log.exception('Error importing %s', 'MediaShoutImport')
|
||||
|
||||
HAS_WORSHIPCENTERPRO = False
|
||||
if os.name == u'nt':
|
||||
try:
|
||||
from worshipcenterproimport import WorshipCenterProImport
|
||||
HAS_WORSHIPCENTERPRO = True
|
||||
except ImportError:
|
||||
log.exception('Error importing %s', 'WorshipCenterProImport')
|
||||
|
||||
class SongFormatSelect(object):
|
||||
"""
|
||||
@ -160,7 +166,8 @@ class SongFormat(object):
|
||||
SongsOfFellowship = 15
|
||||
SundayPlus = 16
|
||||
WordsOfWorship = 17
|
||||
ZionWorx = 18
|
||||
WorshipCenterPro = 18
|
||||
ZionWorx = 19
|
||||
|
||||
# Set optional attribute defaults
|
||||
__defaults__ = {
|
||||
@ -311,6 +318,16 @@ class SongFormat(object):
|
||||
u'filter': u'%s (*.wsg *.wow-song)' %
|
||||
translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files')
|
||||
},
|
||||
WorshipCenterPro: {
|
||||
u'name': u'WorshipCenter Pro',
|
||||
u'prefix': u'worshipCenterPro',
|
||||
u'canDisable': True,
|
||||
u'selectMode': SongFormatSelect.SingleFile,
|
||||
u'filter': u'%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'WorshipCenter Pro Song Files'),
|
||||
u'disabledLabelText': translate('SongsPlugin.ImportWizardForm',
|
||||
'The WorshipCenter Pro importer is only supported on Windows. It has been disabled due to a missing '
|
||||
'Python module. If you want to use this importer, you will need to install the "pyodbc" module.')
|
||||
},
|
||||
ZionWorx: {
|
||||
u'class': ZionWorxImport,
|
||||
u'name': u'ZionWorx',
|
||||
@ -348,6 +365,7 @@ class SongFormat(object):
|
||||
SongFormat.SongsOfFellowship,
|
||||
SongFormat.SundayPlus,
|
||||
SongFormat.WordsOfWorship,
|
||||
SongFormat.WorshipCenterPro,
|
||||
SongFormat.ZionWorx
|
||||
]
|
||||
|
||||
@ -399,5 +417,9 @@ if HAS_OOO:
|
||||
SongFormat.set(SongFormat.MediaShout, u'availability', HAS_MEDIASHOUT)
|
||||
if HAS_MEDIASHOUT:
|
||||
SongFormat.set(SongFormat.MediaShout, u'class', MediaShoutImport)
|
||||
SongFormat.set(SongFormat.WorshipCenterPro, u'availability', HAS_WORSHIPCENTERPRO)
|
||||
if HAS_WORSHIPCENTERPRO:
|
||||
SongFormat.set(SongFormat.WorshipCenterPro, u'class', WorshipCenterProImport)
|
||||
|
||||
|
||||
__all__ = [u'SongFormat', u'SongFormatSelect']
|
||||
|
79
openlp/plugins/songs/lib/worshipcenterproimport.py
Normal file
79
openlp/plugins/songs/lib/worshipcenterproimport.py
Normal file
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
||||
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`worshipcenterpro` module provides the functionality for importing
|
||||
a WorshipCenter Pro database into the OpenLP database.
|
||||
"""
|
||||
import pyodbc
|
||||
|
||||
from openlp.core.lib import translate
|
||||
from openlp.plugins.songs.lib.songimport import SongImport
|
||||
|
||||
class WorshipCenterProImport(SongImport):
|
||||
"""
|
||||
The :class:`WorshipCenterProImport` class provides the ability to import the
|
||||
WorshipCenter Pro Access Database
|
||||
"""
|
||||
def __init__(self, manager, **kwargs):
|
||||
"""
|
||||
Initialise the WorshipCenter Pro importer.
|
||||
"""
|
||||
SongImport.__init__(self, manager, **kwargs)
|
||||
|
||||
def doImport(self):
|
||||
"""
|
||||
Receive a single file to import.
|
||||
"""
|
||||
try:
|
||||
conn = pyodbc.connect(u'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s' % self.import_source)
|
||||
except:
|
||||
# Unfortunately no specific exception type
|
||||
self.logError(self.import_source,
|
||||
translate('SongsPlugin.WorshipCenterProImport', 'Unable to connect the WorshipCenter Pro database.'))
|
||||
return
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(u'SELECT ID, Field, Value FROM __SONGDATA')
|
||||
records = cursor.fetchall()
|
||||
songs = {}
|
||||
for record in records:
|
||||
id = record.ID
|
||||
if not songs.has_key(id):
|
||||
songs[id] = {}
|
||||
songs[id][record.Field] = record.Value
|
||||
self.import_wizard.progress_bar.setMaximum(len(songs))
|
||||
for song in songs:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
self.setDefaults()
|
||||
self.title = songs[song][u'TITLE']
|
||||
lyrics = songs[song][u'LYRICS'].strip(u'&crlf;&crlf;')
|
||||
for verse in lyrics.split(u'&crlf;&crlf;'):
|
||||
verse = verse.replace(u'&crlf;', u'\n')
|
||||
self.addVerse(verse)
|
||||
self.finish()
|
@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
"""
|
||||
This module contains tests for the WorshipCenter/ Pro song importer.
|
||||
"""
|
||||
|
||||
from unittest import TestCase
|
||||
from mock import patch, MagicMock
|
||||
|
||||
from openlp.plugins.songs.lib.worshipcenterproimport import WorshipCenterProImport
|
||||
|
||||
class TestRecord:
|
||||
"""
|
||||
Microsoft Access Driver is not available on non Microsoft Systems for this reason the :class:`TestRecord` is used
|
||||
to simulate a recordset that would be returned by pyobdc.
|
||||
"""
|
||||
def __init__(self, id, field, value):
|
||||
# The case of the following instance variables is important as it needs to be the same as the ones in use in the
|
||||
# WorshipCenter Pro database.
|
||||
self.ID = id
|
||||
self.Field = field
|
||||
self.Value = value
|
||||
|
||||
|
||||
RECORDSET_TEST_DATA = [TestRecord(1, u'TITLE', u'Amazing Grace'),
|
||||
TestRecord(1, u'LYRICS',
|
||||
u'Amazing grace! How&crlf;sweet the sound&crlf;That saved a wretch like me!&crlf;'
|
||||
u'I once was lost,&crlf;but now am found;&crlf;Was blind, but now I see.&crlf;&crlf;'
|
||||
u'\'Twas grace that&crlf;taught my heart to fear,&crlf;And grace my fears relieved;&crlf;'
|
||||
u'How precious did&crlf;that grace appear&crlf;The hour I first believed.&crlf;&crlf;'
|
||||
u'Through many dangers,&crlf;toils and snares,&crlf;I have already come;&crlf;'
|
||||
u'\'Tis grace hath brought&crlf;me safe thus far,&crlf;'
|
||||
u'And grace will lead me home.&crlf;&crlf;The Lord has&crlf;promised good to me,&crlf;'
|
||||
u'His Word my hope secures;&crlf;He will my Shield&crlf;and Portion be,&crlf;'
|
||||
u'As long as life endures.&crlf;&crlf;Yea, when this flesh&crlf;and heart shall fail,&crlf;'
|
||||
u'And mortal life shall cease,&crlf;I shall possess,&crlf;within the veil,&crlf;'
|
||||
u'A life of joy and peace.&crlf;&crlf;The earth shall soon&crlf;dissolve like snow,&crlf;'
|
||||
u'The sun forbear to shine;&crlf;But God, Who called&crlf;me here below,&crlf;'
|
||||
u'Shall be forever mine.&crlf;&crlf;When we\'ve been there&crlf;ten thousand years,&crlf;'
|
||||
u'Bright shining as the sun,&crlf;We\'ve no less days to&crlf;sing God\'s praise&crlf;'
|
||||
u'Than when we\'d first begun.&crlf;&crlf;'),
|
||||
TestRecord(2, u'TITLE', u'Beautiful Garden Of Prayer, The'),
|
||||
TestRecord(2, u'LYRICS',
|
||||
u'There\'s a garden where&crlf;Jesus is waiting,&crlf;'
|
||||
u'There\'s a place that&crlf;is wondrously fair,&crlf;For it glows with the&crlf;'
|
||||
u'light of His presence.&crlf;\'Tis the beautiful&crlf;garden of prayer.&crlf;&crlf;'
|
||||
u'Oh, the beautiful garden,&crlf;the garden of prayer!&crlf;Oh, the beautiful&crlf;'
|
||||
u'garden of prayer!&crlf;There my Savior awaits,&crlf;and He opens the gates&crlf;'
|
||||
u'To the beautiful&crlf;garden of prayer.&crlf;&crlf;There\'s a garden where&crlf;'
|
||||
u'Jesus is waiting,&crlf;And I go with my&crlf;burden and care,&crlf;'
|
||||
u'Just to learn from His&crlf;lips words of comfort&crlf;In the beautiful&crlf;'
|
||||
u'garden of prayer.&crlf;&crlf;There\'s a garden where&crlf;Jesus is waiting,&crlf;'
|
||||
u'And He bids you to come,&crlf;meet Him there;&crlf;Just to bow and&crlf;'
|
||||
u'receive a new blessing&crlf;In the beautiful&crlf;garden of prayer.&crlf;&crlf;')]
|
||||
SONG_TEST_DATA = [{u'title': u'Amazing Grace',
|
||||
u'verses': [
|
||||
(u'Amazing grace! How\nsweet the sound\nThat saved a wretch like me!\nI once was lost,\n'
|
||||
u'but now am found;\nWas blind, but now I see.'),
|
||||
(u'\'Twas grace that\ntaught my heart to fear,\nAnd grace my fears relieved;\nHow precious did\n'
|
||||
u'that grace appear\nThe hour I first believed.'),
|
||||
(u'Through many dangers,\ntoils and snares,\nI have already come;\n\'Tis grace hath brought\n'
|
||||
u'me safe thus far,\nAnd grace will lead me home.'),
|
||||
(u'The Lord has\npromised good to me,\nHis Word my hope secures;\n'
|
||||
u'He will my Shield\nand Portion be,\nAs long as life endures.'),
|
||||
(u'Yea, when this flesh\nand heart shall fail,\nAnd mortal life shall cease,\nI shall possess,\n'
|
||||
u'within the veil,\nA life of joy and peace.'),
|
||||
(u'The earth shall soon\ndissolve like snow,\nThe sun forbear to shine;\nBut God, Who called\n'
|
||||
u'me here below,\nShall be forever mine.'),
|
||||
(u'When we\'ve been there\nten thousand years,\nBright shining as the sun,\n'
|
||||
u'We\'ve no less days to\nsing God\'s praise\nThan when we\'d first begun.')]},
|
||||
{u'title': u'Beautiful Garden Of Prayer, The',
|
||||
u'verses': [
|
||||
(u'There\'s a garden where\nJesus is waiting,\nThere\'s a place that\nis wondrously fair,\n'
|
||||
u'For it glows with the\nlight of His presence.\n\'Tis the beautiful\ngarden of prayer.'),
|
||||
(u'Oh, the beautiful garden,\nthe garden of prayer!\nOh, the beautiful\ngarden of prayer!\n'
|
||||
u'There my Savior awaits,\nand He opens the gates\nTo the beautiful\ngarden of prayer.'),
|
||||
(u'There\'s a garden where\nJesus is waiting,\nAnd I go with my\nburden and care,\n'
|
||||
u'Just to learn from His\nlips words of comfort\nIn the beautiful\ngarden of prayer.'),
|
||||
(u'There\'s a garden where\nJesus is waiting,\nAnd He bids you to come,\nmeet Him there;\n'
|
||||
u'Just to bow and\nreceive a new blessing\nIn the beautiful\ngarden of prayer.')]}]
|
||||
|
||||
class TestWorshipCenterProSongImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`worshipcenterproimport` module.
|
||||
"""
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
Test creating an instance of the WorshipCenter Pro file importer
|
||||
"""
|
||||
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
|
||||
with patch(u'openlp.plugins.songs.lib.worshipcenterproimport.SongImport'):
|
||||
mocked_manager = MagicMock()
|
||||
|
||||
# WHEN: An importer object is created
|
||||
importer = WorshipCenterProImport(mocked_manager)
|
||||
|
||||
# THEN: The importer object should not be None
|
||||
self.assertIsNotNone(importer, u'Import should not be none')
|
||||
|
||||
def pyodbc_exception_test(self):
|
||||
"""
|
||||
Test that exceptions raised by pyodbc are handled
|
||||
"""
|
||||
# GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method,
|
||||
# a mocked "manager" and a mocked out logError method.
|
||||
with patch(u'openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \
|
||||
patch(u'openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \
|
||||
patch(u'openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate:
|
||||
mocked_manager = MagicMock()
|
||||
mocked_log_error = MagicMock()
|
||||
mocked_translate.return_value = u'Translated Text'
|
||||
importer = WorshipCenterProImport(mocked_manager)
|
||||
importer.logError = mocked_log_error
|
||||
importer.import_source = u'import_source'
|
||||
|
||||
# WHEN: pyodbc raises and unspecified exception
|
||||
mocked_pyodbc.connect.side_effect = Exception()
|
||||
|
||||
# THEN: doImport should return None, and pyodbc, translate & logError are called with known calls
|
||||
self.assertIsNone(importer.doImport(), u'doImport should return None when pyodbc raises an exception.')
|
||||
mocked_pyodbc.connect.assert_called_with( u'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source')
|
||||
mocked_translate.assert_called_with('SongsPlugin.WorshipCenterProImport',
|
||||
'Unable to connect the WorshipCenter Pro database.')
|
||||
mocked_log_error.assert_called_with(u'import_source', u'Translated Text')
|
||||
|
||||
def song_import_test(self):
|
||||
"""
|
||||
Test that a simulated WorshipCenter Pro recordset is imported correctly
|
||||
"""
|
||||
# GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method,
|
||||
# a mocked "manager", logError method, addVerse method & mocked_finish method.
|
||||
with patch(u'openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \
|
||||
patch(u'openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \
|
||||
patch(u'openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate:
|
||||
mocked_manager = MagicMock()
|
||||
mocked_log_error = MagicMock()
|
||||
mocked_import_wizard = MagicMock()
|
||||
mocked_add_verse = MagicMock()
|
||||
mocked_finish = MagicMock()
|
||||
mocked_translate.return_value = u'Translated Text'
|
||||
importer = WorshipCenterProImport(mocked_manager)
|
||||
importer.logError = mocked_log_error
|
||||
importer.import_source = u'import_source'
|
||||
importer.import_wizard = mocked_import_wizard
|
||||
importer.addVerse = mocked_add_verse
|
||||
importer.stop_import_flag = False
|
||||
importer.finish = mocked_finish
|
||||
|
||||
# WHEN: the RECORDSET_TEST_DATA is simulated as fetched
|
||||
mocked_pyodbc.connect().cursor().fetchall.return_value = RECORDSET_TEST_DATA
|
||||
|
||||
# THEN: doImport should return None, and pyodbc, import_wizard, importer.title and addVerse are called with
|
||||
# known calls
|
||||
self.assertIsNone(importer.doImport(), u'doImport should return None when pyodbc raises an exception.')
|
||||
mocked_pyodbc.connect.assert_called_with(u'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source')
|
||||
mocked_pyodbc.connect().cursor.assert_any_call()
|
||||
mocked_pyodbc.connect().cursor().execute.assert_called_with(u'SELECT ID, Field, Value FROM __SONGDATA')
|
||||
mocked_pyodbc.connect().cursor().fetchall.assert_any_call()
|
||||
mocked_import_wizard.progress_bar.setMaximum.assert_called_with(2)
|
||||
for song_data in SONG_TEST_DATA:
|
||||
title_value = song_data[u'title']
|
||||
# Here is where I'm stuck.
|
||||
# importer.title, should have been first set to 'Amazing Grace' and then
|
||||
# 'Beautiful Garden Of Prayer, The' how can I capture past values? mohij suggested using properties,
|
||||
# I know very little about these, how would I be able to apply it from the test case?
|
||||
self.assertEqual(importer.title, title_value)
|
||||
verse_calls = song_data[u'verses']
|
||||
for call in verse_calls:
|
||||
mocked_add_verse.assert_any_call(call)
|
Loading…
Reference in New Issue
Block a user