Song import cleanups

This commit is contained in:
Tim Bentley 2014-03-05 18:58:22 +00:00
parent 1301b4cfa3
commit 75281b5cf1
28 changed files with 241 additions and 246 deletions

View File

@ -201,7 +201,7 @@ class SongImportForm(OpenLPWizard):
def validateCurrentPage(self): def validateCurrentPage(self):
""" """
Re-implement the validateCurrentPage() method. Validate the current page before moving on to the next page. Re-implement the validateCurrentPage() method. Validate the current page before moving on to the next page.
Provide each song format class with a chance to validate its input by overriding isValidSource(). Provide each song format class with a chance to validate its input by overriding is_valid_source().
""" """
if self.currentPage() == self.welcome_page: if self.currentPage() == self.welcome_page:
return True return True
@ -217,7 +217,7 @@ class SongImportForm(OpenLPWizard):
import_source = self.format_widgets[this_format]['file_path_edit'].text() import_source = self.format_widgets[this_format]['file_path_edit'].text()
error_title = (UiStrings().IFSs if select_mode == SongFormatSelect.SingleFile else UiStrings().IFdSs) error_title = (UiStrings().IFSs if select_mode == SongFormatSelect.SingleFile else UiStrings().IFdSs)
focus_button = self.format_widgets[this_format]['browseButton'] focus_button = self.format_widgets[this_format]['browseButton']
if not class_.isValidSource(import_source): if not class_.is_valid_source(import_source):
critical_error_message_box(error_title, error_msg) critical_error_message_box(error_title, error_msg)
focus_button.setFocus() focus_button.setFocus()
return False return False

View File

@ -38,6 +38,7 @@ from .songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class CCLIFileImport(SongImport): class CCLIFileImport(SongImport):
""" """
The :class:`CCLIFileImport` class provides OpenLP with the ability to import The :class:`CCLIFileImport` class provides OpenLP with the ability to import
@ -86,13 +87,13 @@ class CCLIFileImport(SongImport):
if ext.lower() == '.usr': if ext.lower() == '.usr':
log.info('SongSelect .usr format file found: %s', filename) log.info('SongSelect .usr format file found: %s', filename)
if not self.doImportUsrFile(lines): if not self.doImportUsrFile(lines):
self.logError(filename) self.log_error(filename)
elif ext.lower() == '.txt': elif ext.lower() == '.txt':
log.info('SongSelect .txt format file found: %s', filename) log.info('SongSelect .txt format file found: %s', filename)
if not self.doImportTxtFile(lines): if not self.doImportTxtFile(lines):
self.logError(filename) self.log_error(filename)
else: else:
self.logError(filename, self.log_error(filename,
translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid extension.')) translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid extension.'))
log.info('Extension %s is not valid', filename) log.info('Extension %s is not valid', filename)
if self.stop_import_flag: if self.stop_import_flag:
@ -163,9 +164,9 @@ class CCLIFileImport(SongImport):
if line.startswith('[S '): if line.startswith('[S '):
ccli, line = line.split(']', 1) ccli, line = line.split(']', 1)
if ccli.startswith('[S A'): if ccli.startswith('[S A'):
self.ccliNumber = ccli[4:].strip() self.ccli_number = ccli[4:].strip()
else: else:
self.ccliNumber = ccli[3:].strip() self.ccli_number = ccli[3:].strip()
if line.startswith('Title='): if line.startswith('Title='):
self.title = line[6:].strip() self.title = line[6:].strip()
elif line.startswith('Author='): elif line.startswith('Author='):
@ -213,7 +214,7 @@ class CCLIFileImport(SongImport):
verse_type = VerseType.tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
verse_text = verse_lines[1] verse_text = verse_lines[1]
if verse_text: if verse_text:
self.addVerse(verse_text, verse_type) self.add_verse(verse_text, verse_type)
check_first_verse_line = False check_first_verse_line = False
# Handle multiple authors # Handle multiple authors
author_list = song_author.split('/') author_list = song_author.split('/')
@ -223,7 +224,7 @@ class CCLIFileImport(SongImport):
separated = author.split(',') separated = author.split(',')
if len(separated) > 1: if len(separated) > 1:
author = ' '.join(map(str.strip, reversed(separated))) author = ' '.join(map(str.strip, reversed(separated)))
self.addAuthor(author.strip()) self.add_author(author.strip())
self.topics = [topic.strip() for topic in song_topics.split('/t')] self.topics = [topic.strip() for topic in song_topics.split('/t')]
return self.finish() return self.finish()
@ -272,7 +273,7 @@ class CCLIFileImport(SongImport):
continue continue
elif verse_start: elif verse_start:
if verse_text: if verse_text:
self.addVerse(verse_text, verse_type) self.add_verse(verse_text, verse_type)
verse_text = '' verse_text = ''
verse_start = False verse_start = False
else: else:
@ -286,7 +287,7 @@ class CCLIFileImport(SongImport):
if clean_line.startswith('CCLI'): if clean_line.startswith('CCLI'):
line_number += 1 line_number += 1
ccli_parts = clean_line.split(' ') ccli_parts = clean_line.split(' ')
self.ccliNumber = ccli_parts[len(ccli_parts) - 1] self.ccli_number = ccli_parts[len(ccli_parts) - 1]
elif not verse_start: elif not verse_start:
# We have the verse descriptor # We have the verse descriptor
verse_desc_parts = clean_line.split(' ') verse_desc_parts = clean_line.split(' ')
@ -348,5 +349,5 @@ class CCLIFileImport(SongImport):
author_list = song_author.split('|') author_list = song_author.split('|')
# Clean spaces before and after author names. # Clean spaces before and after author names.
for author_name in author_list: for author_name in author_list:
self.addAuthor(author_name.strip()) self.add_author(author_name.strip())
return self.finish() return self.finish()

View File

@ -92,18 +92,18 @@ class DreamBeamImport(SongImport):
for file in self.import_source: for file in self.import_source:
if self.stop_import_flag: if self.stop_import_flag:
return return
self.setDefaults() self.set_defaults()
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
try: try:
parsed_file = etree.parse(open(file, 'r'), parser) parsed_file = etree.parse(open(file, 'r'), parser)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
log.exception('XML syntax error in file %s' % file) log.exception('XML syntax error in file %s' % file)
self.logError(file, SongStrings.XMLSyntaxError) self.log_error(file, SongStrings.XMLSyntaxError)
continue continue
xml = etree.tostring(parsed_file).decode() xml = etree.tostring(parsed_file).decode()
song_xml = objectify.fromstring(xml) song_xml = objectify.fromstring(xml)
if song_xml.tag != 'DreamSong': if song_xml.tag != 'DreamSong':
self.logError(file, self.log_error(file,
translate('SongsPlugin.DreamBeamImport', 'Invalid DreamBeam song file. Missing DreamSong tag.')) translate('SongsPlugin.DreamBeamImport', 'Invalid DreamBeam song file. Missing DreamSong tag.'))
continue continue
if hasattr(song_xml, 'Version'): if hasattr(song_xml, 'Version'):
@ -121,14 +121,14 @@ class DreamBeamImport(SongImport):
verse_type = lyrics_item.get('Type') verse_type = lyrics_item.get('Type')
verse_number = lyrics_item.get('Number') verse_number = lyrics_item.get('Number')
verse_text = str(lyrics_item.text) verse_text = str(lyrics_item.text)
self.addVerse(verse_text, ('%s%s' % (verse_type[:1], verse_number))) self.add_verse(verse_text, ('%s%s' % (verse_type[:1], verse_number)))
if hasattr(song_xml, 'Collection'): if hasattr(song_xml, 'Collection'):
self.songBookName = str(song_xml.Collection.text) self.song_book_name = str(song_xml.Collection.text)
if hasattr(song_xml, 'Number'): if hasattr(song_xml, 'Number'):
self.songNumber = str(song_xml.Number.text) self.song_number = str(song_xml.Number.text)
if hasattr(song_xml, 'Sequence'): if hasattr(song_xml, 'Sequence'):
for LyricsSequenceItem in (song_xml.Sequence.iterchildren()): for LyricsSequenceItem in (song_xml.Sequence.iterchildren()):
self.verseOrderList.append("%s%s" % (LyricsSequenceItem.get('Type')[:1], self.verse_order_list.append("%s%s" % (LyricsSequenceItem.get('Type')[:1],
LyricsSequenceItem.get('Number'))) LyricsSequenceItem.get('Number')))
if hasattr(song_xml, 'Notes'): if hasattr(song_xml, 'Notes'):
self.comments = str(song_xml.Notes.text) self.comments = str(song_xml.Notes.text)
@ -138,15 +138,15 @@ class DreamBeamImport(SongImport):
if hasattr(song_xml.Text1, 'Text'): if hasattr(song_xml.Text1, 'Text'):
self.lyrics = str(song_xml.Text1.Text.text) self.lyrics = str(song_xml.Text1.Text.text)
for verse in self.lyrics.split('\n\n\n'): for verse in self.lyrics.split('\n\n\n'):
self.addVerse(verse) self.add_verse(verse)
if hasattr(song_xml.Text2, 'Text'): if hasattr(song_xml.Text2, 'Text'):
author_copyright = song_xml.Text2.Text.text author_copyright = song_xml.Text2.Text.text
if author_copyright: if author_copyright:
author_copyright = str(author_copyright) author_copyright = str(author_copyright)
if author_copyright.find( if author_copyright.find(
str(SongStrings.CopyrightSymbol)) >= 0: str(SongStrings.CopyrightSymbol)) >= 0:
self.addCopyright(author_copyright) self.add_copyright(author_copyright)
else: else:
self.parse_author(author_copyright) self.parse_author(author_copyright)
if not self.finish(): if not self.finish():
self.logError(file) self.log_error(file)

View File

@ -68,9 +68,9 @@ class EasySlidesImport(SongImport):
if hasattr(song, 'Title2'): if hasattr(song, 'Title2'):
self._add_unicode_attribute('alternateTitle', song.Title2) self._add_unicode_attribute('alternateTitle', song.Title2)
if hasattr(song, 'SongNumber'): if hasattr(song, 'SongNumber'):
self._add_unicode_attribute('songNumber', song.SongNumber) self._add_unicode_attribute('song_number', song.SongNumber)
if self.songNumber == '0': if self.song_number == '0':
self.songNumber = '' self.song_number = ''
self._addAuthors(song) self._addAuthors(song)
if hasattr(song, 'Copyright'): if hasattr(song, 'Copyright'):
self._add_copyright(song.Copyright) self._add_copyright(song.Copyright)
@ -79,13 +79,13 @@ class EasySlidesImport(SongImport):
if hasattr(song, 'LicenceAdmin2'): if hasattr(song, 'LicenceAdmin2'):
self._add_copyright(song.LicenceAdmin2) self._add_copyright(song.LicenceAdmin2)
if hasattr(song, 'BookReference'): if hasattr(song, 'BookReference'):
self._add_unicode_attribute('songBookName', song.BookReference) self._add_unicode_attribute('song_book_name', song.BookReference)
self._parseAndAddLyrics(song) self._parseAndAddLyrics(song)
if self._success: if self._success:
if not self.finish(): if not self.finish():
self.logError(song.Title1 if song.Title1 else '') self.log_error(song.Title1 if song.Title1 else '')
else: else:
self.setDefaults() self.set_defaults()
def _add_unicode_attribute(self, self_attribute, import_attribute, mandatory=False): def _add_unicode_attribute(self, self_attribute, import_attribute, mandatory=False):
""" """
@ -132,7 +132,7 @@ class EasySlidesImport(SongImport):
The imported variable to get the data from. The imported variable to get the data from.
""" """
try: try:
self.addCopyright(str(element).strip()) self.add_copyright(str(element).strip())
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception('Unicode error on decoding copyright: %s' % element) log.exception('Unicode error on decoding copyright: %s' % element)
self._success = False self._success = False
@ -235,7 +235,7 @@ class EasySlidesImport(SongImport):
verses[reg].setdefault(vt, {}) verses[reg].setdefault(vt, {})
verses[reg][vt].setdefault(vn, {}) verses[reg][vt].setdefault(vn, {})
verses[reg][vt][vn].setdefault(inst, []) verses[reg][vt][vn].setdefault(inst, [])
verses[reg][vt][vn][inst].append(self.tidyText(line)) verses[reg][vt][vn][inst].append(self.tidy_text(line))
# done parsing # done parsing
versetags = [] versetags = []
@ -271,7 +271,7 @@ class EasySlidesImport(SongImport):
else: else:
continue continue
if tag in versetags: if tag in versetags:
self.verseOrderList.append(tag) self.verse_order_list.append(tag)
else: else:
log.info('Got order item %s, which is not in versetags, dropping item from presentation order', log.info('Got order item %s, which is not in versetags, dropping item from presentation order',
tag) tag)

View File

@ -163,7 +163,7 @@ class EasyWorshipSongImport(SongImport):
break break
raw_record = db_file.read(record_size) raw_record = db_file.read(record_size)
self.fields = self.recordStruct.unpack(raw_record) self.fields = self.recordStruct.unpack(raw_record)
self.setDefaults() self.set_defaults()
self.title = self.getField(fi_title).decode() self.title = self.getField(fi_title).decode()
# Get remaining fields. # Get remaining fields.
copy = self.getField(fi_copy) copy = self.getField(fi_copy)
@ -180,7 +180,7 @@ class EasyWorshipSongImport(SongImport):
self.copyright += translate('SongsPlugin.EasyWorshipSongImport', self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
'Administered by %s') % admin.decode() 'Administered by %s') % admin.decode()
if ccli: if ccli:
self.ccliNumber = ccli.decode() self.ccli_number = ccli.decode()
if authors: if authors:
# Split up the authors # Split up the authors
author_list = authors.split(b'/') author_list = authors.split(b'/')
@ -189,7 +189,7 @@ class EasyWorshipSongImport(SongImport):
if len(author_list) < 2: if len(author_list) < 2:
author_list = authors.split(b',') author_list = authors.split(b',')
for author_name in author_list: for author_name in author_list:
self.addAuthor(author_name.decode().strip()) self.add_author(author_name.decode().strip())
if words: if words:
# Format the lyrics # Format the lyrics
result = strip_rtf(words.decode(), self.encoding) result = strip_rtf(words.decode(), self.encoding)
@ -227,14 +227,14 @@ class EasyWorshipSongImport(SongImport):
if not number_found: if not number_found:
verse_type += '1' verse_type += '1'
break break
self.addVerse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type) self.add_verse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type)
if len(self.comments) > 5: if len(self.comments) > 5:
self.comments += str(translate('SongsPlugin.EasyWorshipSongImport', self.comments += str(translate('SongsPlugin.EasyWorshipSongImport',
'\n[above are Song Tags with notes imported from EasyWorship]')) '\n[above are Song Tags with notes imported from EasyWorship]'))
if self.stop_import_flag: if self.stop_import_flag:
break break
if not self.finish(): if not self.finish():
self.logError(self.import_source) self.log_error(self.import_source)
db_file.close() db_file.close()
self.memoFile.close() self.memoFile.close()

View File

@ -133,7 +133,7 @@ class FoilPresenterImport(SongImport):
xml = etree.tostring(parsed_file).decode() xml = etree.tostring(parsed_file).decode()
self.FoilPresenter.xml_to_song(xml) self.FoilPresenter.xml_to_song(xml)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
self.logError(file_path, SongStrings.XMLSyntaxError) self.log_error(file_path, SongStrings.XMLSyntaxError)
log.exception('XML syntax error in file %s' % file_path) log.exception('XML syntax error in file %s' % file_path)
@ -423,7 +423,7 @@ class FoilPresenter(object):
VerseType.tags[VerseType.PreChorus]: 1 VerseType.tags[VerseType.PreChorus]: 1
} }
if not hasattr(foilpresenterfolie.strophen, 'strophe'): if not hasattr(foilpresenterfolie.strophen, 'strophe'):
self.importer.logError(self._child(foilpresenterfolie.titel), self.importer.log_error(self._child(foilpresenterfolie.titel),
str(translate('SongsPlugin.FoilPresenterSongImport', str(translate('SongsPlugin.FoilPresenterSongImport',
'Invalid Foilpresenter song file. No verses found.'))) 'Invalid Foilpresenter song file. No verses found.')))
self.save_song = False self.save_song = False

View File

@ -137,7 +137,7 @@ class SongFormat(object):
Title for ``QFileDialog`` (default includes the format's ``u'name'``). Title for ``QFileDialog`` (default includes the format's ``u'name'``).
``u'invalidSourceMsg'`` ``u'invalidSourceMsg'``
Message displayed if ``isValidSource()`` returns ``False``. Message displayed if ``is_valid_source()`` returns ``False``.
``u'descriptionText'`` ``u'descriptionText'``
Short description (1-2 lines) about the song format. Short description (1-2 lines) about the song format.

View File

@ -57,7 +57,7 @@ class MediaShoutImport(SongImport):
'DBQ=%s;PWD=6NOZ4eHK7k' % self.import_source) 'DBQ=%s;PWD=6NOZ4eHK7k' % self.import_source)
except: except:
# Unfortunately no specific exception type # Unfortunately no specific exception type
self.logError(self.import_source, self.log_error(self.import_source,
translate('SongsPlugin.MediaShoutImport', 'Unable to open the MediaShout database.')) translate('SongsPlugin.MediaShoutImport', 'Unable to open the MediaShout database.'))
return return
cursor = conn.cursor() cursor = conn.cursor()
@ -88,21 +88,21 @@ class MediaShoutImport(SongImport):
""" """
Create the song, i.e. title, verse etc. Create the song, i.e. title, verse etc.
""" """
self.setDefaults() self.set_defaults()
self.title = song.Title self.title = song.Title
self.parse_author(song.Author) self.parse_author(song.Author)
self.addCopyright(song.Copyright) self.add_copyright(song.Copyright)
self.comments = song.Notes self.comments = song.Notes
for topic in topics: for topic in topics:
self.topics.append(topic.Name) self.topics.append(topic.Name)
if '-' in song.SongID: if '-' in song.SongID:
self.songBookName, self.songNumber = song.SongID.split('-', 1) self.song_book_name, self.song_number = song.SongID.split('-', 1)
else: else:
self.songBookName = song.SongID self.song_book_name = song.SongID
for verse in verses: for verse in verses:
tag = VERSE_TAGS[verse.Type] + str(verse.Number) if verse.Type < len(VERSE_TAGS) else 'O' tag = VERSE_TAGS[verse.Type] + str(verse.Number) if verse.Type < len(VERSE_TAGS) else 'O'
self.addVerse(verse.Text, tag) self.add_verse(verse.Text, tag)
for order in verse_order: for order in verse_order:
if order.Type < len(VERSE_TAGS): if order.Type < len(VERSE_TAGS):
self.verseOrderList.append(VERSE_TAGS[order.Type] + str(order.Number)) self.verse_order_list.append(VERSE_TAGS[order.Type] + str(order.Number))
self.finish() self.finish()

View File

@ -107,7 +107,7 @@ class OpenLPSongImport(SongImport):
# Check the file type # Check the file type
if not self.import_source.endswith('.sqlite'): if not self.import_source.endswith('.sqlite'):
self.logError(self.import_source, self.log_error(self.import_source,
translate('SongsPlugin.OpenLPSongImport', 'Not a valid OpenLP 2.0 song database.')) translate('SongsPlugin.OpenLPSongImport', 'Not a valid OpenLP 2.0 song database.'))
return return
self.import_source = 'sqlite:///%s' % self.import_source self.import_source = 'sqlite:///%s' % self.import_source

View File

@ -71,7 +71,7 @@ class OooImport(SongImport):
try: try:
self.startOoo() self.startOoo()
except NoConnectException as exc: except NoConnectException as exc:
self.logError( self.log_error(
self.import_source[0], self.import_source[0],
translate('SongsPlugin.SongImport', 'Cannot access OpenOffice or LibreOffice')) translate('SongsPlugin.SongImport', 'Cannot access OpenOffice or LibreOffice'))
log.error(exc) log.error(exc)
@ -87,9 +87,9 @@ class OooImport(SongImport):
self.processOooDocument() self.processOooDocument()
self.closeOooFile() self.closeOooFile()
else: else:
self.logError(self.filepath, translate('SongsPlugin.SongImport', 'Unable to open file')) self.log_error(self.filepath, translate('SongsPlugin.SongImport', 'Unable to open file'))
else: else:
self.logError(self.filepath, translate('SongsPlugin.SongImport', 'File not found')) self.log_error(self.filepath, translate('SongsPlugin.SongImport', 'File not found'))
self.closeOoo() self.closeOoo()
def processOooDocument(self): def processOooDocument(self):
@ -228,13 +228,13 @@ class OooImport(SongImport):
self.processSongsText(text) self.processSongsText(text)
def processSongsText(self, text): def processSongsText(self, text):
songtexts = self.tidyText(text).split('\f') songtexts = self.tidy_text(text).split('\f')
self.setDefaults() self.set_defaults()
for songtext in songtexts: for songtext in songtexts:
if songtext.strip(): if songtext.strip():
self.processSongText(songtext.strip()) self.process_song_text(songtext.strip())
if self.checkComplete(): if self.check_complete():
self.finish() self.finish()
self.setDefaults() self.set_defaults()
if self.checkComplete(): if self.check_complete():
self.finish() self.finish()

View File

@ -74,8 +74,8 @@ class OpenLyricsImport(SongImport):
self.openLyrics.xml_to_song(xml) self.openLyrics.xml_to_song(xml)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
log.exception('XML syntax error in file %s' % file_path) log.exception('XML syntax error in file %s' % file_path)
self.logError(file_path, SongStrings.XMLSyntaxError) self.log_error(file_path, SongStrings.XMLSyntaxError)
except OpenLyricsError as exception: except OpenLyricsError as exception:
log.exception('OpenLyricsException %d in file %s: %s' log.exception('OpenLyricsException %d in file %s: %s'
% (exception.type, file_path, exception.log_message)) % (exception.type, file_path, exception.log_message))
self.logError(file_path, exception.display_message) self.log_error(file_path, exception.display_message)

View File

@ -122,21 +122,21 @@ class OpenSongImport(SongImport):
""" """
Process the OpenSong file - pass in a file-like object, not a file path. Process the OpenSong file - pass in a file-like object, not a file path.
""" """
self.setDefaults() self.set_defaults()
try: try:
tree = objectify.parse(file) tree = objectify.parse(file)
except (Error, LxmlError): except (Error, LxmlError):
self.logError(file.name, SongStrings.XMLSyntaxError) self.log_error(file.name, SongStrings.XMLSyntaxError)
log.exception('Error parsing XML') log.exception('Error parsing XML')
return return
root = tree.getroot() root = tree.getroot()
if root.tag != 'song': if root.tag != 'song':
self.logError(file.name, str( self.log_error(file.name, str(
translate('SongsPlugin.OpenSongImport', ('Invalid OpenSong song file. Missing song tag.')))) translate('SongsPlugin.OpenSongImport', ('Invalid OpenSong song file. Missing song tag.'))))
return return
fields = dir(root) fields = dir(root)
decode = { decode = {
'copyright': self.addCopyright, 'copyright': self.add_copyright,
'ccli': 'ccli_number', 'ccli': 'ccli_number',
'author': self.parse_author, 'author': self.parse_author,
'title': 'title', 'title': 'title',
@ -207,7 +207,7 @@ class OpenSongImport(SongImport):
verses[verse_tag][verse_num][inst] = [] verses[verse_tag][verse_num][inst] = []
our_verse_order.append([verse_tag, verse_num, inst]) our_verse_order.append([verse_tag, verse_num, inst])
# Tidy text and remove the ____s from extended words # Tidy text and remove the ____s from extended words
this_line = self.tidyText(this_line) this_line = self.tidy_text(this_line)
this_line = this_line.replace('_', '') this_line = this_line.replace('_', '')
this_line = this_line.replace('|', '\n') this_line = this_line.replace('|', '\n')
this_line = this_line.strip() this_line = this_line.strip()
@ -224,9 +224,9 @@ class OpenSongImport(SongImport):
verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \ verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \
if verse_def in verse_joints else lines if verse_def in verse_joints else lines
for verse_def, lines in verse_joints.items(): for verse_def, lines in verse_joints.items():
self.addVerse(lines, verse_def) self.add_verse(lines, verse_def)
if not self.verses: if not self.verses:
self.addVerse('') self.add_verse('')
# figure out the presentation order, if present # figure out the presentation order, if present
if 'presentation' in fields and root.presentation: if 'presentation' in fields and root.presentation:
order = str(root.presentation) order = str(root.presentation)
@ -246,9 +246,9 @@ class OpenSongImport(SongImport):
verse_num = '1' verse_num = '1'
verse_def = '%s%s' % (verse_tag, verse_num) verse_def = '%s%s' % (verse_tag, verse_num)
if verse_num in verses.get(verse_tag, {}): if verse_num in verses.get(verse_tag, {}):
self.verseOrderList.append(verse_def) self.verse_order_list.append(verse_def)
else: else:
log.info('Got order %s but not in verse tags, dropping' log.info('Got order %s but not in verse tags, dropping'
'this item from presentation order', verse_def) 'this item from presentation order', verse_def)
if not self.finish(): if not self.finish():
self.logError(file.name) self.log_error(file.name)

View File

@ -73,7 +73,7 @@ class PowerSongImport(SongImport):
* .song * .song
""" """
@staticmethod @staticmethod
def isValidSource(import_source): def is_valid_source(import_source):
""" """
Checks if source is a PowerSong 1.0 folder: Checks if source is a PowerSong 1.0 folder:
* is a directory * is a directory
@ -101,14 +101,14 @@ class PowerSongImport(SongImport):
else: else:
self.import_source = '' self.import_source = ''
if not self.import_source or not isinstance(self.import_source, list): if not self.import_source or not isinstance(self.import_source, list):
self.logError(translate('SongsPlugin.PowerSongImport', 'No songs to import.'), self.log_error(translate('SongsPlugin.PowerSongImport', 'No songs to import.'),
translate('SongsPlugin.PowerSongImport', 'No %s files found.') % PS_string) translate('SongsPlugin.PowerSongImport', 'No %s files found.') % PS_string)
return return
self.import_wizard.progress_bar.setMaximum(len(self.import_source)) self.import_wizard.progress_bar.setMaximum(len(self.import_source))
for file in self.import_source: for file in self.import_source:
if self.stop_import_flag: if self.stop_import_flag:
return return
self.setDefaults() self.set_defaults()
parse_error = False parse_error = False
with open(file, 'rb') as song_data: with open(file, 'rb') as song_data:
while True: while True:
@ -119,7 +119,7 @@ class PowerSongImport(SongImport):
field = self._readString(song_data) field = self._readString(song_data)
except ValueError: except ValueError:
parse_error = True parse_error = True
self.logError(os.path.basename(file), str( self.log_error(os.path.basename(file), str(
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Unexpected byte value.')) % translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Unexpected byte value.')) %
PS_string) PS_string)
break break
@ -132,27 +132,27 @@ class PowerSongImport(SongImport):
found_copyright = True found_copyright = True
self._parseCopyrightCCLI(field) self._parseCopyrightCCLI(field)
elif label == 'PART': elif label == 'PART':
self.addVerse(field) self.add_verse(field)
if parse_error: if parse_error:
continue continue
# Check that file had TITLE field # Check that file had TITLE field
if not self.title: if not self.title:
self.logError(os.path.basename(file), str( self.log_error(os.path.basename(file), str(
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % PS_string) translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % PS_string)
continue continue
# Check that file had COPYRIGHTLINE label # Check that file had COPYRIGHTLINE label
if not found_copyright: if not found_copyright:
self.logError(self.title, str( self.log_error(self.title, str(
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" header.')) % translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" header.')) %
PS_string) PS_string)
continue continue
# Check that file had at least one verse # Check that file had at least one verse
if not self.verses: if not self.verses:
self.logError(self.title, str( self.log_error(self.title, str(
translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.'))) translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.')))
continue continue
if not self.finish(): if not self.finish():
self.logError(self.title) self.log_error(self.title)
def _readString(self, file_object): def _readString(self, file_object):
""" """
@ -211,8 +211,8 @@ class PowerSongImport(SongImport):
copyright = ccli_no copyright = ccli_no
ccli_no = '' ccli_no = ''
if copyright: if copyright:
self.addCopyright(copyright.rstrip('\n').replace('\n', ' ')) self.add_copyright(copyright.rstrip('\n').replace('\n', ' '))
if ccli_no: if ccli_no:
ccli_no = ccli_no.strip(' :') ccli_no = ccli_no.strip(' :')
if ccli_no.isdigit(): if ccli_no.isdigit():
self.ccliNumber = ccli_no self.ccli_number = ccli_no

View File

@ -108,7 +108,7 @@ class SofImport(OooImport):
except RuntimeException as exc: except RuntimeException as exc:
log.exception('Error processing file: %s', exc) log.exception('Error processing file: %s', exc)
if not self.finish(): if not self.finish():
self.logError(self.filepath) self.log_error(self.filepath)
def processParagraph(self, paragraph): def processParagraph(self, paragraph):
""" """
@ -173,17 +173,17 @@ class SofImport(OooImport):
self.skipToCloseBracket = True self.skipToCloseBracket = True
return return
if text.startswith('Copyright'): if text.startswith('Copyright'):
self.addCopyright(text) self.add_copyright(text)
return return
if text == '(Repeat)': if text == '(Repeat)':
self.finishVerse() self.finishVerse()
self.repeatVerse() self.repeat_verse()
return return
if self.title == '': if self.title == '':
if self.copyright == '': if self.copyright == '':
self.addSofAuthor(text) self.addSofAuthor(text)
else: else:
self.addCopyright(text) self.add_copyright(text)
return return
self.addVerseLine(text) self.addVerseLine(text)
@ -195,12 +195,12 @@ class SofImport(OooImport):
into line into line
""" """
text = textportion.getString() text = textportion.getString()
text = self.tidyText(text) text = self.tidy_text(text)
if text.strip() == '': if text.strip() == '':
return text return text
if textportion.CharWeight == BOLD: if textportion.CharWeight == BOLD:
boldtext = text.strip() boldtext = text.strip()
if boldtext.isdigit() and self.songNumber == '': if boldtext.isdigit() and self.song_number == '':
self.addSongNumber(boldtext) self.addSongNumber(boldtext)
return '' return ''
text = self.uncapText(text) text = self.uncapText(text)
@ -219,11 +219,11 @@ class SofImport(OooImport):
""" """
if self.song: if self.song:
self.finishVerse() self.finishVerse()
if not self.checkComplete(): if not self.check_complete():
return return
self.finish() self.finish()
self.song = True self.song = True
self.setDefaults() self.set_defaults()
self.skipToCloseBracket = False self.skipToCloseBracket = False
self.isChorus = False self.isChorus = False
self.italics = False self.italics = False
@ -234,7 +234,7 @@ class SofImport(OooImport):
Add a song number, store as alternate title. Also use the song Add a song number, store as alternate title. Also use the song
number to work out which songbook we're in number to work out which songbook we're in
""" """
self.songNumber = song_no self.song_number = song_no
self.alternateTitle = song_no + '.' self.alternateTitle = song_no + '.'
self.songBook_pub = 'Kingsway Publications' self.songBook_pub = 'Kingsway Publications'
if int(song_no) <= 640: if int(song_no) <= 640:
@ -299,7 +299,7 @@ class SofImport(OooImport):
splitat = None splitat = None
else: else:
versetag = 'V' versetag = 'V'
splitat = self.verseSplits(self.songNumber) splitat = self.verseSplits(self.song_number)
if splitat: if splitat:
ln = 0 ln = 0
verse = '' verse = ''
@ -322,9 +322,9 @@ class SofImport(OooImport):
self.isChorus = False self.isChorus = False
def addSofVerse(self, lyrics, tag): def addSofVerse(self, lyrics, tag):
self.addVerse(lyrics, tag) self.add_verse(lyrics, tag)
if not self.isChorus and 'C1' in self.verseOrderListGenerated: if not self.isChorus and 'C1' in self.verse_order_list_generated:
self.verseOrderListGenerated.append('C1') self.verse_order_list_generated.append('C1')
self.verseOrderListGenerated_useful = True self.verseOrderListGenerated_useful = True
def uncapText(self, text): def uncapText(self, text):

View File

@ -109,7 +109,7 @@ class SongBeamerImport(SongImport):
# TODO: check that it is a valid SongBeamer file # TODO: check that it is a valid SongBeamer file
if self.stop_import_flag: if self.stop_import_flag:
return return
self.setDefaults() self.set_defaults()
self.currentVerse = '' self.currentVerse = ''
self.currentVerseType = VerseType.tags[VerseType.Verse] self.currentVerseType = VerseType.tags[VerseType.Verse]
read_verses = False read_verses = False
@ -134,7 +134,7 @@ class SongBeamerImport(SongImport):
elif line.startswith('---'): elif line.startswith('---'):
if self.currentVerse: if self.currentVerse:
self.replaceHtmlTags() self.replaceHtmlTags()
self.addVerse(self.currentVerse, self.currentVerseType) self.add_verse(self.currentVerse, self.currentVerseType)
self.currentVerse = '' self.currentVerse = ''
self.currentVerseType = VerseType.tags[VerseType.Verse] self.currentVerseType = VerseType.tags[VerseType.Verse]
read_verses = True read_verses = True
@ -148,9 +148,9 @@ class SongBeamerImport(SongImport):
self.currentVerse += line + '\n' self.currentVerse += line + '\n'
if self.currentVerse: if self.currentVerse:
self.replaceHtmlTags() self.replaceHtmlTags()
self.addVerse(self.currentVerse, self.currentVerseType) self.add_verse(self.currentVerse, self.currentVerseType)
if not self.finish(): if not self.finish():
self.logError(import_file) self.log_error(import_file)
def replaceHtmlTags(self): def replaceHtmlTags(self):
""" """
@ -174,7 +174,7 @@ class SongBeamerImport(SongImport):
if not tag_val[0] or not tag_val[1]: if not tag_val[0] or not tag_val[1]:
return return
if tag_val[0] == '#(c)': if tag_val[0] == '#(c)':
self.addCopyright(tag_val[1]) self.add_copyright(tag_val[1])
elif tag_val[0] == '#AddCopyrightInfo': elif tag_val[0] == '#AddCopyrightInfo':
pass pass
elif tag_val[0] == '#Author': elif tag_val[0] == '#Author':
@ -186,7 +186,7 @@ class SongBeamerImport(SongImport):
elif tag_val[0] == '#Categories': elif tag_val[0] == '#Categories':
self.topics = tag_val[1].split(',') self.topics = tag_val[1].split(',')
elif tag_val[0] == '#CCLI': elif tag_val[0] == '#CCLI':
self.ccliNumber = tag_val[1] self.ccli_number = tag_val[1]
elif tag_val[0] == '#Chords': elif tag_val[0] == '#Chords':
pass pass
elif tag_val[0] == '#ChurchSongID': elif tag_val[0] == '#ChurchSongID':
@ -233,10 +233,10 @@ class SongBeamerImport(SongImport):
song_book_pub = tag_val[1] song_book_pub = tag_val[1]
elif tag_val[0] == '#Songbook' or tag_val[0] == '#SongBook': elif tag_val[0] == '#Songbook' or tag_val[0] == '#SongBook':
book_data = tag_val[1].split('/') book_data = tag_val[1].split('/')
self.songBookName = book_data[0].strip() self.song_book_name = book_data[0].strip()
if len(book_data) == 2: if len(book_data) == 2:
number = book_data[1].strip() number = book_data[1].strip()
self.songNumber = number if number.isdigit() else '' self.song_number = number if number.isdigit() else ''
elif tag_val[0] == '#Speed': elif tag_val[0] == '#Speed':
pass pass
elif tag_val[0] == 'Tempo': elif tag_val[0] == 'Tempo':

View File

@ -53,7 +53,7 @@ class SongImport(QtCore.QObject):
as necessary as necessary
""" """
@staticmethod @staticmethod
def isValidSource(import_source): def is_valid_source(import_source):
""" """
Override this method to validate the source prior to import. Override this method to validate the source prior to import.
""" """
@ -63,10 +63,8 @@ class SongImport(QtCore.QObject):
""" """
Initialise and create defaults for properties Initialise and create defaults for properties
``manager`` :param manager: An instance of a SongManager, through which all database access is performed.
An instance of a SongManager, through which all database access is :param kwargs:
performed.
""" """
self.manager = manager self.manager = manager
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
@ -82,56 +80,51 @@ class SongImport(QtCore.QObject):
self.import_wizard = None self.import_wizard = None
self.song = None self.song = None
self.stop_import_flag = False self.stop_import_flag = False
self.setDefaults() self.set_defaults()
Registry().register_function('openlp_stop_wizard', self.stop_import) Registry().register_function('openlp_stop_wizard', self.stop_import)
def setDefaults(self): def set_defaults(self):
""" """
Create defaults for properties - call this before each song Create defaults for properties - call this before each song
if importing many songs at once to ensure a clean beginning if importing many songs at once to ensure a clean beginning
""" """
self.title = '' self.title = ''
self.songNumber = '' self.song_number = ''
self.alternate_title = '' self.alternate_title = ''
self.copyright = '' self.copyright = ''
self.comments = '' self.comments = ''
self.themeName = '' self.theme_name = ''
self.ccliNumber = '' self.ccli_number = ''
self.authors = [] self.authors = []
self.topics = [] self.topics = []
self.mediaFiles = [] self.media_files = []
self.songBookName = '' self.song_book_name = ''
self.songBookPub = '' self.song_book_pub = ''
self.verseOrderListGeneratedUseful = False self.verse_order_list_generated_useful = False
self.verseOrderListGenerated = [] self.verse_order_list_generated = []
self.verseOrderList = [] self.verse_order_list = []
self.verses = [] self.verses = []
self.verseCounts = {} self.verse_counts = {}
self.copyrightString = translate('SongsPlugin.SongImport', 'copyright') self.copyright_string = translate('SongsPlugin.SongImport', 'copyright')
def logError(self, filepath, reason=SongStrings.SongIncomplete): def log_error(self, file_path, reason=SongStrings.SongIncomplete):
""" """
This should be called, when a song could not be imported. This should be called, when a song could not be imported.
``filepath`` :param file_path: This should be the file path if ``self.import_source`` is a list with different files. If it
This should be the file path if ``self.import_source`` is a list is not a list, but a single file (for instance a database), then this should be the song's title.
with different files. If it is not a list, but a single file (for :param reason: The reason why the import failed. The string should be as informative as possible.
instance a database), then this should be the song's title.
``reason``
The reason why the import failed. The string should be as
informative as possible.
""" """
self.setDefaults() self.set_defaults()
if self.import_wizard is None: if self.import_wizard is None:
return return
if self.import_wizard.error_report_text_edit.isHidden(): if self.import_wizard.error_report_text_edit.isHidden():
self.import_wizard.error_report_text_edit.setText(translate('SongsPlugin.SongImport', self.import_wizard.error_report_text_edit.setText(
'The following songs could not be imported:')) translate('SongsPlugin.SongImport', 'The following songs could not be imported:'))
self.import_wizard.error_report_text_edit.setVisible(True) self.import_wizard.error_report_text_edit.setVisible(True)
self.import_wizard.error_copy_to_button.setVisible(True) self.import_wizard.error_copy_to_button.setVisible(True)
self.import_wizard.error_save_to_button.setVisible(True) self.import_wizard.error_save_to_button.setVisible(True)
self.import_wizard.error_report_text_edit.append('- %s (%s)' % (filepath, reason)) self.import_wizard.error_report_text_edit.append('- %s (%s)' % (file_path, reason))
def stop_import(self): def stop_import(self):
""" """
@ -143,10 +136,9 @@ class SongImport(QtCore.QObject):
def register(self, import_wizard): def register(self, import_wizard):
self.import_wizard = import_wizard self.import_wizard = import_wizard
def tidyText(self, text): def tidy_text(self, text):
""" """
Get rid of some dodgy unicode and formatting characters we're not Get rid of some dodgy unicode and formatting characters we're not interested in. Some can be converted to ascii.
interested in. Some can be converted to ascii.
""" """
text = text.replace('\u2018', '\'') text = text.replace('\u2018', '\'')
text = text.replace('\u2019', '\'') text = text.replace('\u2019', '\'')
@ -161,21 +153,21 @@ class SongImport(QtCore.QObject):
text = re.sub(r' ?(\n{5}|\f)+ ?', '\f', text) text = re.sub(r' ?(\n{5}|\f)+ ?', '\f', text)
return text return text
def processSongText(self, text): def process_song_text(self, text):
verse_texts = text.split('\n\n') verse_texts = text.split('\n\n')
for verse_text in verse_texts: for verse_text in verse_texts:
if verse_text.strip() != '': if verse_text.strip() != '':
self.processVerseText(verse_text.strip()) self.process_verse_text(verse_text.strip())
def processVerseText(self, text): def process_verse_text(self, text):
lines = text.split('\n') lines = text.split('\n')
if text.lower().find(self.copyrightString) >= 0 or text.find(str(SongStrings.CopyrightSymbol)) >= 0: if text.lower().find(self.copyright_string) >= 0 or text.find(str(SongStrings.CopyrightSymbol)) >= 0:
copyright_found = False copyright_found = False
for line in lines: for line in lines:
if (copyright_found or line.lower().find(self.copyrightString) >= 0 or if (copyright_found or line.lower().find(self.copyright_string) >= 0 or
line.find(str(SongStrings.CopyrightSymbol)) >= 0): line.find(str(SongStrings.CopyrightSymbol)) >= 0):
copyright_found = True copyright_found = True
self.addCopyright(line) self.add_copyright(line)
else: else:
self.parse_author(line) self.parse_author(line)
return return
@ -184,9 +176,9 @@ class SongImport(QtCore.QObject):
return return
if not self.title: if not self.title:
self.title = lines[0] self.title = lines[0]
self.addVerse(text) self.add_verse(text)
def addCopyright(self, copyright): def add_copyright(self, copyright):
""" """
Build the copyright field Build the copyright field
""" """
@ -211,9 +203,9 @@ class SongImport(QtCore.QObject):
if author2.endswith('.'): if author2.endswith('.'):
author2 = author2[:-1] author2 = author2[:-1]
if author2: if author2:
self.addAuthor(author2) self.add_author(author2)
def addAuthor(self, author): def add_author(self, author):
""" """
Add an author to the list Add an author to the list
""" """
@ -221,15 +213,15 @@ class SongImport(QtCore.QObject):
return return
self.authors.append(author) self.authors.append(author)
def addMediaFile(self, filename, weight=0): def add_media_file(self, filename, weight=0):
""" """
Add a media file to the list Add a media file to the list
""" """
if filename in [x[0] for x in self.mediaFiles]: if filename in [x[0] for x in self.media_files]:
return return
self.mediaFiles.append((filename, weight)) self.media_files.append((filename, weight))
def addVerse(self, verse_text, verse_def='v', lang=None): def add_verse(self, verse_text, verse_def='v', lang=None):
""" """
Add a verse. This is the whole verse, lines split by \\n. It will also Add a verse. This is the whole verse, lines split by \\n. It will also
attempt to detect duplicates. In this case it will just add to the verse attempt to detect duplicates. In this case it will just add to the verse
@ -248,32 +240,32 @@ class SongImport(QtCore.QObject):
""" """
for (old_verse_def, old_verse, old_lang) in self.verses: for (old_verse_def, old_verse, old_lang) in self.verses:
if old_verse.strip() == verse_text.strip(): if old_verse.strip() == verse_text.strip():
self.verseOrderListGenerated.append(old_verse_def) self.verse_order_list_generated.append(old_verse_def)
self.verseOrderListGeneratedUseful = True self.verse_order_list_generated_useful = True
return return
if verse_def[0] in self.verseCounts: if verse_def[0] in self.verse_counts:
self.verseCounts[verse_def[0]] += 1 self.verse_counts[verse_def[0]] += 1
else: else:
self.verseCounts[verse_def[0]] = 1 self.verse_counts[verse_def[0]] = 1
if len(verse_def) == 1: if len(verse_def) == 1:
verse_def += str(self.verseCounts[verse_def[0]]) verse_def += str(self.verse_counts[verse_def[0]])
elif int(verse_def[1:]) > self.verseCounts[verse_def[0]]: elif int(verse_def[1:]) > self.verse_counts[verse_def[0]]:
self.verseCounts[verse_def[0]] = int(verse_def[1:]) self.verse_counts[verse_def[0]] = int(verse_def[1:])
self.verses.append([verse_def, verse_text.rstrip(), lang]) self.verses.append([verse_def, verse_text.rstrip(), lang])
# A verse_def refers to all verses with that name, adding it once adds every instance, so do not add if already # A verse_def refers to all verses with that name, adding it once adds every instance, so do not add if already
# used. # used.
if verse_def not in self.verseOrderListGenerated: if verse_def not in self.verse_order_list_generated:
self.verseOrderListGenerated.append(verse_def) self.verse_order_list_generated.append(verse_def)
def repeatVerse(self): def repeat_verse(self):
""" """
Repeat the previous verse in the verse order Repeat the previous verse in the verse order
""" """
if self.verseOrderListGenerated: if self.verse_order_list_generated:
self.verseOrderListGenerated.append(self.verseOrderListGenerated[-1]) self.verse_order_list_generated.append(self.verse_order_list_generated[-1])
self.verseOrderListGeneratedUseful = True self.verse_order_list_generated_useful = True
def checkComplete(self): def check_complete(self):
""" """
Check the mandatory fields are entered (i.e. title and a verse) Check the mandatory fields are entered (i.e. title and a verse)
Author not checked here, if no author then "Author unknown" is Author not checked here, if no author then "Author unknown" is
@ -288,8 +280,8 @@ class SongImport(QtCore.QObject):
""" """
All fields have been set to this song. Write the song to disk. All fields have been set to this song. Write the song to disk.
""" """
if not self.checkComplete(): if not self.check_complete():
self.setDefaults() self.set_defaults()
return False return False
log.info('committing song %s to database', self.title) log.info('committing song %s to database', self.title)
song = Song() song = Song()
@ -301,7 +293,7 @@ class SongImport(QtCore.QObject):
song.search_title = '' song.search_title = ''
song.search_lyrics = '' song.search_lyrics = ''
song.verse_order = '' song.verse_order = ''
song.song_number = self.songNumber song.song_number = self.song_number
verses_changed_to_other = {} verses_changed_to_other = {}
sxml = SongXML() sxml = SongXML()
other_count = 1 other_count = 1
@ -317,14 +309,14 @@ class SongImport(QtCore.QObject):
verse_def = new_verse_def verse_def = new_verse_def
sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang) sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)
song.lyrics = str(sxml.extract_xml(), 'utf-8') song.lyrics = str(sxml.extract_xml(), 'utf-8')
if not self.verseOrderList and self.verseOrderListGeneratedUseful: if not self.verse_order_list and self.verse_order_list_generated_useful:
self.verseOrderList = self.verseOrderListGenerated self.verse_order_list = self.verse_order_list_generated
self.verseOrderList = [verses_changed_to_other.get(v, v) for v in self.verseOrderList] self.verse_order_list = [verses_changed_to_other.get(v, v) for v in self.verse_order_list]
song.verse_order = ' '.join(self.verseOrderList) song.verse_order = ' '.join(self.verse_order_list)
song.copyright = self.copyright song.copyright = self.copyright
song.comments = self.comments song.comments = self.comments
song.theme_name = self.themeName song.theme_name = self.theme_name
song.ccli_number = self.ccliNumber song.ccli_number = self.ccli_number
for authortext in self.authors: for authortext in self.authors:
author = self.manager.get_object_filtered(Author, Author.display_name == authortext) author = self.manager.get_object_filtered(Author, Author.display_name == authortext)
if not author: if not author:
@ -332,10 +324,10 @@ class SongImport(QtCore.QObject):
last_name=authortext.split(' ')[-1], last_name=authortext.split(' ')[-1],
first_name=' '.join(authortext.split(' ')[:-1])) first_name=' '.join(authortext.split(' ')[:-1]))
song.authors.append(author) song.authors.append(author)
if self.songBookName: if self.song_book_name:
song_book = self.manager.get_object_filtered(Book, Book.name == self.songBookName) song_book = self.manager.get_object_filtered(Book, Book.name == self.song_book_name)
if song_book is None: if song_book is None:
song_book = Book.populate(name=self.songBookName, publisher=self.songBookPub) song_book = Book.populate(name=self.song_book_name, publisher=self.song_book_pub)
song.book = song_book song.book = song_book
for topictext in self.topics: for topictext in self.topics:
if not topictext: if not topictext:
@ -350,17 +342,17 @@ class SongImport(QtCore.QObject):
self.manager.save_object(song) self.manager.save_object(song)
# Now loop through the media files, copy them to the correct location, # Now loop through the media files, copy them to the correct location,
# and save the song again. # and save the song again.
for filename, weight in self.mediaFiles: for filename, weight in self.media_files:
media_file = self.manager.get_object_filtered(MediaFile, MediaFile.file_name == filename) media_file = self.manager.get_object_filtered(MediaFile, MediaFile.file_name == filename)
if not media_file: if not media_file:
if os.path.dirname(filename): if os.path.dirname(filename):
filename = self.copyMediaFile(song.id, filename) filename = self.copy_media_file(song.id, filename)
song.media_files.append(MediaFile.populate(file_name=filename, weight=weight)) song.media_files.append(MediaFile.populate(file_name=filename, weight=weight))
self.manager.save_object(song) self.manager.save_object(song)
self.setDefaults() self.set_defaults()
return True return True
def copyMediaFile(self, song_id, filename): def copy_media_file(self, song_id, filename):
""" """
This method copies the media file to the correct location and returns This method copies the media file to the correct location and returns
the new file location. the new file location.

View File

@ -100,7 +100,7 @@ class SongProImport(SongImport):
Process a section of the song, i.e. title, verse etc. Process a section of the song, i.e. title, verse etc.
""" """
if tag == 'T': if tag == 'T':
self.setDefaults() self.set_defaults()
if text: if text:
self.title = text self.title = text
return return
@ -118,29 +118,29 @@ class SongProImport(SongImport):
if tag == 'A': if tag == 'A':
self.parse_author(text) self.parse_author(text)
elif tag in ['B', 'C']: elif tag in ['B', 'C']:
self.addVerse(text, tag) self.add_verse(text, tag)
elif tag == 'D': elif tag == 'D':
self.addVerse(text, 'E') self.add_verse(text, 'E')
elif tag == 'G': elif tag == 'G':
self.topics.append(text) self.topics.append(text)
elif tag == 'M': elif tag == 'M':
matches = re.findall(r'\d+', text) matches = re.findall(r'\d+', text)
if matches: if matches:
self.songNumber = matches[-1] self.song_number = matches[-1]
self.songBookName = text[:text.rfind(self.songNumber)] self.song_book_name = text[:text.rfind(self.song_number)]
elif tag == 'N': elif tag == 'N':
self.comments = text self.comments = text
elif tag == 'O': elif tag == 'O':
for char in text: for char in text:
if char == 'C': if char == 'C':
self.verseOrderList.append('C1') self.verse_order_list.append('C1')
elif char == 'B': elif char == 'B':
self.verseOrderList.append('B1') self.verse_order_list.append('B1')
elif char == 'D': elif char == 'D':
self.verseOrderList.append('E1') self.verse_order_list.append('E1')
elif '1' <= char <= '7': elif '1' <= char <= '7':
self.verseOrderList.append('V' + char) self.verse_order_list.append('V' + char)
elif tag == 'R': elif tag == 'R':
self.addCopyright(text) self.add_copyright(text)
elif '1' <= tag <= '7': elif '1' <= tag <= '7':
self.addVerse(text, 'V' + tag[1:]) self.add_verse(text, 'V' + tag[1:])

View File

@ -145,15 +145,15 @@ class SongShowPlusImport(SongImport):
author = authorParts[1] + " " + authorParts[0] author = authorParts[1] + " " + authorParts[0]
self.parse_author(author) self.parse_author(author)
elif block_key == COPYRIGHT: elif block_key == COPYRIGHT:
self.addCopyright(self.decode(data)) self.add_copyright(self.decode(data))
elif block_key == CCLI_NO: elif block_key == CCLI_NO:
self.ccliNumber = int(data) self.ccli_number = int(data)
elif block_key == VERSE: elif block_key == VERSE:
self.addVerse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no)) self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no))
elif block_key == CHORUS: elif block_key == CHORUS:
self.addVerse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no)) self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no))
elif block_key == BRIDGE: elif block_key == BRIDGE:
self.addVerse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no)) self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no))
elif block_key == TOPIC: elif block_key == TOPIC:
self.topics.append(self.decode(data)) self.topics.append(self.decode(data))
elif block_key == COMMENTS: elif block_key == COMMENTS:
@ -165,19 +165,19 @@ class SongShowPlusImport(SongImport):
verse_tag = self.decode(verse_tag) verse_tag = self.decode(verse_tag)
self.ssp_verse_order_list.append(verse_tag) self.ssp_verse_order_list.append(verse_tag)
elif block_key == SONG_BOOK: elif block_key == SONG_BOOK:
self.songBookName = self.decode(data) self.song_book_name = self.decode(data)
elif block_key == SONG_NUMBER: elif block_key == SONG_NUMBER:
self.songNumber = ord(data) self.song_number = ord(data)
elif block_key == CUSTOM_VERSE: elif block_key == CUSTOM_VERSE:
verse_tag = self.to_openlp_verse_tag(verse_name) verse_tag = self.to_openlp_verse_tag(verse_name)
self.addVerse(self.decode(data), verse_tag) self.add_verse(self.decode(data), verse_tag)
else: else:
log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data)) log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data))
song_data.seek(next_block_starts) song_data.seek(next_block_starts)
self.verseOrderList = self.ssp_verse_order_list self.verse_order_list = self.ssp_verse_order_list
song_data.close() song_data.close()
if not self.finish(): if not self.finish():
self.logError(file) self.log_error(file)
def to_openlp_verse_tag(self, verse_name, ignore_unique=False): def to_openlp_verse_tag(self, verse_name, ignore_unique=False):
# Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have # Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have

View File

@ -75,18 +75,18 @@ class SundayPlusImport(SongImport):
""" """
Process the Sunday Plus file object. Process the Sunday Plus file object.
""" """
self.setDefaults() self.set_defaults()
if not self.parse(file.read()): if not self.parse(file.read()):
self.logError(file.name) self.log_error(file.name)
return return
if not self.title: if not self.title:
self.title = self.titleFromFilename(file.name) self.title = self.titleFromFilename(file.name)
if not self.finish(): if not self.finish():
self.logError(file.name) self.log_error(file.name)
def parse(self, data, cell=False): def parse(self, data, cell=False):
if len(data) == 0 or data[0:1] != '[' or data[-1] != ']': if len(data) == 0 or data[0:1] != '[' or data[-1] != ']':
self.logError('File is malformed') self.log_error('File is malformed')
return False return False
i = 1 i = 1
verse_type = VerseType.tags[VerseType.Verse] verse_type = VerseType.tags[VerseType.Verse]
@ -126,7 +126,7 @@ class SundayPlusImport(SongImport):
elif name == 'Author': elif name == 'Author':
author = self.decode(self.unescape(value)) author = self.decode(self.unescape(value))
if len(author): if len(author):
self.addAuthor(author) self.add_author(author)
elif name == 'Copyright': elif name == 'Copyright':
self.copyright = self.decode(self.unescape(value)) self.copyright = self.decode(self.unescape(value))
elif name[0:4] == 'CELL': elif name[0:4] == 'CELL':
@ -160,13 +160,13 @@ class SundayPlusImport(SongImport):
if line[:3].lower() == 'ccl': if line[:3].lower() == 'ccl':
m = re.search(r'[0-9]+', line) m = re.search(r'[0-9]+', line)
if m: if m:
self.ccliNumber = int(m.group(0)) self.ccli_number = int(m.group(0))
continue continue
elif line.lower() == 'public domain': elif line.lower() == 'public domain':
self.copyright = 'Public Domain' self.copyright = 'Public Domain'
continue continue
processed_lines.append(line) processed_lines.append(line)
self.addVerse('\n'.join(processed_lines).strip(), verse_type) self.add_verse('\n'.join(processed_lines).strip(), verse_type)
if end == -1: if end == -1:
break break
i = end + 1 i = end + 1

View File

@ -60,7 +60,7 @@ class WorshipCenterProImport(SongImport):
except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e:
log.warn('Unable to connect the WorshipCenter Pro database %s. %s', self.import_source, str(e)) log.warn('Unable to connect the WorshipCenter Pro database %s. %s', self.import_source, str(e))
# Unfortunately no specific exception type # Unfortunately no specific exception type
self.logError(self.import_source, self.log_error(self.import_source,
translate('SongsPlugin.WorshipCenterProImport', 'Unable to connect the WorshipCenter Pro database.')) translate('SongsPlugin.WorshipCenterProImport', 'Unable to connect the WorshipCenter Pro database.'))
return return
cursor = conn.cursor() cursor = conn.cursor()
@ -76,10 +76,10 @@ class WorshipCenterProImport(SongImport):
for song in songs: for song in songs:
if self.stop_import_flag: if self.stop_import_flag:
break break
self.setDefaults() self.set_defaults()
self.title = songs[song]['TITLE'] self.title = songs[song]['TITLE']
lyrics = songs[song]['LYRICS'].strip('&crlf;&crlf;') lyrics = songs[song]['LYRICS'].strip('&crlf;&crlf;')
for verse in lyrics.split('&crlf;&crlf;'): for verse in lyrics.split('&crlf;&crlf;'):
verse = verse.replace('&crlf;', '\n') verse = verse.replace('&crlf;', '\n')
self.addVerse(verse) self.add_verse(verse)
self.finish() self.finish()

View File

@ -110,10 +110,10 @@ class WowImport(SongImport):
for source in self.import_source: for source in self.import_source:
if self.stop_import_flag: if self.stop_import_flag:
return return
self.setDefaults() self.set_defaults()
song_data = open(source, 'rb') song_data = open(source, 'rb')
if song_data.read(19) != 'WoW File\nSong Words': if song_data.read(19) != 'WoW File\nSong Words':
self.logError(source, str(translate('SongsPlugin.WordsofWorshipSongImport', self.log_error(source, str(translate('SongsPlugin.WordsofWorshipSongImport',
('Invalid Words of Worship song file. Missing "Wow File\\nSong Words" header.')))) ('Invalid Words of Worship song file. Missing "Wow File\\nSong Words" header.'))))
continue continue
# Seek to byte which stores number of blocks in the song # Seek to byte which stores number of blocks in the song
@ -121,7 +121,7 @@ class WowImport(SongImport):
no_of_blocks = ord(song_data.read(1)) no_of_blocks = ord(song_data.read(1))
song_data.seek(66) song_data.seek(66)
if song_data.read(16) != 'CSongDoc::CBlock': if song_data.read(16) != 'CSongDoc::CBlock':
self.logError(source, str(translate('SongsPlugin.WordsofWorshipSongImport', self.log_error(source, str(translate('SongsPlugin.WordsofWorshipSongImport',
('Invalid Words of Worship song file. Missing "CSongDoc::CBlock" string.')))) ('Invalid Words of Worship song file. Missing "CSongDoc::CBlock" string.'))))
continue continue
# Seek to the beginning of the first block # Seek to the beginning of the first block
@ -141,7 +141,7 @@ class WowImport(SongImport):
# this is the last block! # this is the last block!
if block + 1 < no_of_blocks: if block + 1 < no_of_blocks:
song_data.seek(2, os.SEEK_CUR) song_data.seek(2, os.SEEK_CUR)
self.addVerse(block_text, block_type) self.add_verse(block_text, block_type)
# Now to extract the author # Now to extract the author
author_length = ord(song_data.read(1)) author_length = ord(song_data.read(1))
if author_length: if author_length:
@ -149,10 +149,10 @@ class WowImport(SongImport):
# Finally the copyright # Finally the copyright
copyright_length = ord(song_data.read(1)) copyright_length = ord(song_data.read(1))
if copyright_length: if copyright_length:
self.addCopyright(str(song_data.read(copyright_length), 'cp1252')) self.add_copyright(str(song_data.read(copyright_length), 'cp1252'))
file_name = os.path.split(source)[1] file_name = os.path.split(source)[1]
# Get the song title # Get the song title
self.title = file_name.rpartition('.')[0] self.title = file_name.rpartition('.')[0]
song_data.close() song_data.close()
if not self.finish(): if not self.finish():
self.logError(source) self.log_error(source)

View File

@ -89,7 +89,7 @@ class ZionWorxImport(SongImport):
try: try:
records = list(songs_reader) records = list(songs_reader)
except csv.Error as e: except csv.Error as e:
self.logError(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'), self.log_error(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'),
translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e)) translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e))
return return
num_records = len(records) num_records = len(records)
@ -98,20 +98,20 @@ class ZionWorxImport(SongImport):
for index, record in enumerate(records, 1): for index, record in enumerate(records, 1):
if self.stop_import_flag: if self.stop_import_flag:
return return
self.setDefaults() self.set_defaults()
try: try:
self.title = self._decode(record['Title1']) self.title = self._decode(record['Title1'])
if record['Title2']: if record['Title2']:
self.alternate_title = self._decode(record['Title2']) self.alternate_title = self._decode(record['Title2'])
self.parse_author(self._decode(record['Writer'])) self.parse_author(self._decode(record['Writer']))
self.addCopyright(self._decode(record['Copyright'])) self.add_copyright(self._decode(record['Copyright']))
lyrics = self._decode(record['Lyrics']) lyrics = self._decode(record['Lyrics'])
except UnicodeDecodeError as e: except UnicodeDecodeError as e:
self.logError(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index), self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index),
translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e) translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e)
continue continue
except TypeError as e: except TypeError as e:
self.logError(translate( self.log_error(translate(
'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), 'TypeError: %s' % e) 'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), 'TypeError: %s' % e)
return return
verse = '' verse = ''
@ -119,13 +119,13 @@ class ZionWorxImport(SongImport):
if line and not line.isspace(): if line and not line.isspace():
verse += line + '\n' verse += line + '\n'
elif verse: elif verse:
self.addVerse(verse) self.add_verse(verse)
verse = '' verse = ''
if verse: if verse:
self.addVerse(verse) self.add_verse(verse)
title = self.title title = self.title
if not self.finish(): if not self.finish():
self.logError(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index
+ (': "' + title + '"' if title else '')) + (': "' + title + '"' if title else ''))
def _decode(self, str): def _decode(self, str):

View File

@ -369,8 +369,8 @@ class TestEasyWorshipSongImport(TestCase):
importer = EasyWorshipSongImportLogger(mocked_manager) importer = EasyWorshipSongImportLogger(mocked_manager)
importer.import_wizard = mocked_import_wizard importer.import_wizard = mocked_import_wizard
importer.stop_import_flag = False importer.stop_import_flag = False
importer.addAuthor = mocked_add_author importer.add_author = mocked_add_author
importer.addVerse = mocked_add_verse importer.add_verse = mocked_add_verse
importer.title = mocked_title importer.title = mocked_title
importer.finish = mocked_finish importer.finish = mocked_finish
importer.topics = [] importer.topics = []
@ -394,11 +394,11 @@ class TestEasyWorshipSongImport(TestCase):
if song_copyright: if song_copyright:
self.assertEqual(importer.copyright, song_copyright) self.assertEqual(importer.copyright, song_copyright)
if ccli_number: if ccli_number:
self.assertEquals(importer.ccliNumber, ccli_number, 'ccliNumber for %s should be %s' self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s'
% (title, ccli_number)) % (title, ccli_number))
for verse_text, verse_tag in add_verse_calls: for verse_text, verse_tag in add_verse_calls:
mocked_add_verse.assert_any_call(verse_text, verse_tag) mocked_add_verse.assert_any_call(verse_text, verse_tag)
if verse_order_list: if verse_order_list:
self.assertEquals(importer.verseOrderList, verse_order_list, 'verseOrderList for %s should be %s' self.assertEquals(importer.verse_order_list, verse_order_list, 'verse_order_list for %s should be %s'
% (title, verse_order_list)) % (title, verse_order_list))
mocked_finish.assert_called_with() mocked_finish.assert_called_with()

View File

@ -169,7 +169,7 @@ class TestFoilPresenter(TestCase):
# WHEN: xml_to_song is called with a string without an xml encoding declaration # WHEN: xml_to_song is called with a string without an xml encoding declaration
foil_presenter_instance.xml_to_song('<foilpresenterfolie>') foil_presenter_instance.xml_to_song('<foilpresenterfolie>')
# THEN: the string shiuld have been left intact # THEN: the string should have been left intact
self.mocked_re.compile.sub.called_with('<foilpresenterfolie>') self.mocked_re.compile.sub.called_with('<foilpresenterfolie>')
def process_lyrics_no_verses_test(self): def process_lyrics_no_verses_test(self):
@ -188,7 +188,7 @@ class TestFoilPresenter(TestCase):
# WHEN: _process_lyrics is called # WHEN: _process_lyrics is called
result = foil_presenter_instance._process_lyrics(mock_foilpresenterfolie, mocked_song) result = foil_presenter_instance._process_lyrics(mock_foilpresenterfolie, mocked_song)
# THEN: _process_lyrics should return None and the song_import logError method should have been called once # THEN: _process_lyrics should return None and the song_import log_error method should have been called once
self.assertIsNone(result) self.assertIsNone(result)
self.mocked_song_import.logError.assert_called_once_with('Element Text', 'Translated String') self.mocked_song_import.log_error.assert_called_once_with('Element Text', 'Translated String')
self.process_lyrics_patcher.start() self.process_lyrics_patcher.start()

View File

@ -130,7 +130,7 @@ class TestSongBeamerImport(TestCase):
importer = SongBeamerImport(mocked_manager) importer = SongBeamerImport(mocked_manager)
importer.import_wizard = mocked_import_wizard importer.import_wizard = mocked_import_wizard
importer.stop_import_flag = False importer.stop_import_flag = False
importer.addVerse = mocked_add_verse importer.add_verse = mocked_add_verse
importer.finish = mocked_finish importer.finish = mocked_finish
# WHEN: Importing each file # WHEN: Importing each file
@ -147,9 +147,9 @@ class TestSongBeamerImport(TestCase):
for verse_text, verse_tag in add_verse_calls: for verse_text, verse_tag in add_verse_calls:
mocked_add_verse.assert_any_call(verse_text, verse_tag) mocked_add_verse.assert_any_call(verse_text, verse_tag)
if song_book_name: if song_book_name:
self.assertEquals(importer.songBookName, song_book_name, 'songBookName for %s should be "%s"' self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"'
% (song_file, song_book_name)) % (song_file, song_book_name))
if song_number: if song_number:
self.assertEquals(importer.songNumber, song_number, 'songNumber for %s should be %s' self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s'
% (song_file, song_number)) % (song_file, song_number))
mocked_finish.assert_called_with() mocked_finish.assert_called_with()

View File

@ -41,6 +41,7 @@ from tests.functional import patch, MagicMock
TEST_PATH = os.path.abspath( TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'songshowplussongs')) os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'songshowplussongs'))
class TestSongShowPlusFileImport(SongImportTestHelper): class TestSongShowPlusFileImport(SongImportTestHelper):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.importer_class_name = 'SongShowPlusImport' self.importer_class_name = 'SongShowPlusImport'

View File

@ -152,7 +152,7 @@ class TestWorshipCenterProSongImport(TestCase):
Test that exceptions raised by pyodbc are handled Test that exceptions raised by pyodbc are handled
""" """
# GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method, # 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. # a mocked "manager" and a mocked out log_error method.
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \
patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \ patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \
patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate:
@ -160,7 +160,7 @@ class TestWorshipCenterProSongImport(TestCase):
mocked_log_error = MagicMock() mocked_log_error = MagicMock()
mocked_translate.return_value = 'Translated Text' mocked_translate.return_value = 'Translated Text'
importer = WorshipCenterProImport(mocked_manager) importer = WorshipCenterProImport(mocked_manager)
importer.logError = mocked_log_error importer.log_error = mocked_log_error
importer.import_source = 'import_source' importer.import_source = 'import_source'
pyodbc_errors = [pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError] pyodbc_errors = [pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError]
mocked_pyodbc_connect.side_effect = pyodbc_errors mocked_pyodbc_connect.side_effect = pyodbc_errors
@ -169,7 +169,7 @@ class TestWorshipCenterProSongImport(TestCase):
for effect in pyodbc_errors: for effect in pyodbc_errors:
return_value = importer.doImport() return_value = importer.doImport()
# THEN: doImport should return None, and pyodbc, translate & logError are called with known calls # THEN: doImport should return None, and pyodbc, translate & log_error are called with known calls
self.assertIsNone(return_value, 'doImport should return None when pyodbc raises an exception.') self.assertIsNone(return_value, 'doImport should return None when pyodbc raises an exception.')
mocked_pyodbc_connect.assert_called_with( 'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source') mocked_pyodbc_connect.assert_called_with( 'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source')
mocked_translate.assert_called_with('SongsPlugin.WorshipCenterProImport', mocked_translate.assert_called_with('SongsPlugin.WorshipCenterProImport',
@ -181,7 +181,7 @@ class TestWorshipCenterProSongImport(TestCase):
Test that a simulated WorshipCenter Pro recordset is imported correctly Test that a simulated WorshipCenter Pro recordset is imported correctly
""" """
# GIVEN: A mocked out SongImport class, a mocked out pyodbc module with a simulated recordset, a mocked out # GIVEN: A mocked out SongImport class, a mocked out pyodbc module with a simulated recordset, a mocked out
# translate method, a mocked "manager", addVerse method & mocked_finish method. # translate method, a mocked "manager", add_verse method & mocked_finish method.
with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \
patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \
patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate:
@ -194,7 +194,7 @@ class TestWorshipCenterProSongImport(TestCase):
importer = WorshipCenterProImportLogger(mocked_manager) importer = WorshipCenterProImportLogger(mocked_manager)
importer.import_source = 'import_source' importer.import_source = 'import_source'
importer.import_wizard = mocked_import_wizard importer.import_wizard = mocked_import_wizard
importer.addVerse = mocked_add_verse importer.add_verse = mocked_add_verse
importer.stop_import_flag = False importer.stop_import_flag = False
importer.finish = mocked_finish importer.finish = mocked_finish
@ -202,7 +202,7 @@ class TestWorshipCenterProSongImport(TestCase):
return_value = importer.doImport() return_value = importer.doImport()
# THEN: doImport should return None, and pyodbc, import_wizard, importer.title and addVerse are called with # THEN: doImport should return None, and pyodbc, import_wizard, importer.title and add_verse are called with
# known calls # known calls
self.assertIsNone(return_value, 'doImport should return None when pyodbc raises an exception.') self.assertIsNone(return_value, 'doImport should return None when pyodbc raises an exception.')
mocked_pyodbc.connect.assert_called_with('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source') mocked_pyodbc.connect.assert_called_with('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source')
@ -220,4 +220,4 @@ class TestWorshipCenterProSongImport(TestCase):
for call in verse_calls: for call in verse_calls:
mocked_add_verse.assert_any_call(call) mocked_add_verse.assert_any_call(call)
self.assertEqual(mocked_add_verse.call_count, add_verse_call_count, self.assertEqual(mocked_add_verse.call_count, add_verse_call_count,
'Incorrect number of calls made to addVerse') 'Incorrect number of calls made to add_verse')

View File

@ -35,6 +35,7 @@ from unittest import TestCase
from tests.functional import patch, MagicMock from tests.functional import patch, MagicMock
class SongImportTestHelper(TestCase): class SongImportTestHelper(TestCase):
""" """
This class is designed to be a helper class to reduce repition when testing the import of song files. This class is designed to be a helper class to reduce repition when testing the import of song files.
@ -50,9 +51,9 @@ class SongImportTestHelper(TestCase):
Patch and set up the mocks required. Patch and set up the mocks required.
""" """
self.add_copyright_patcher = patch( self.add_copyright_patcher = patch(
'openlp.plugins.songs.lib.%s.%s.addCopyright' % (self.importer_module_name, self.importer_class_name)) 'openlp.plugins.songs.lib.%s.%s.add_copyright' % (self.importer_module_name, self.importer_class_name))
self.add_verse_patcher = patch( self.add_verse_patcher = patch(
'openlp.plugins.songs.lib.%s.%s.addVerse' % (self.importer_module_name, self.importer_class_name)) 'openlp.plugins.songs.lib.%s.%s.add_verse' % (self.importer_module_name, self.importer_class_name))
self.finish_patcher = patch( self.finish_patcher = patch(
'openlp.plugins.songs.lib.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) 'openlp.plugins.songs.lib.%s.%s.finish' % (self.importer_module_name, self.importer_class_name))
self.parse_author_patcher = patch( self.parse_author_patcher = patch(
@ -115,7 +116,7 @@ class SongImportTestHelper(TestCase):
if song_copyright: if song_copyright:
self.mocked_add_copyright.assert_called_with(song_copyright) self.mocked_add_copyright.assert_called_with(song_copyright)
if ccli_number: if ccli_number:
self.assertEquals(importer.ccliNumber, ccli_number, 'ccliNumber for %s should be %s' self.assertEquals(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s'
% (source_file_name, ccli_number)) % (source_file_name, ccli_number))
for verse_text, verse_tag in add_verse_calls: for verse_text, verse_tag in add_verse_calls:
self.mocked_add_verse.assert_any_call(verse_text, verse_tag) self.mocked_add_verse.assert_any_call(verse_text, verse_tag)
@ -125,13 +126,13 @@ class SongImportTestHelper(TestCase):
self.assertEquals(importer.comments, comments, 'comments for %s should be "%s"' self.assertEquals(importer.comments, comments, 'comments for %s should be "%s"'
% (source_file_name, comments)) % (source_file_name, comments))
if song_book_name: if song_book_name:
self.assertEquals(importer.songBookName, song_book_name, 'songBookName for %s should be "%s"' self.assertEquals(importer.song_book_name, song_book_name, 'song_book_name for %s should be "%s"'
% (source_file_name, song_book_name)) % (source_file_name, song_book_name))
if song_number: if song_number:
self.assertEquals(importer.songNumber, song_number, 'songNumber for %s should be %s' self.assertEquals(importer.song_number, song_number, 'song_number for %s should be %s'
% (source_file_name, song_number)) % (source_file_name, song_number))
if verse_order_list: if verse_order_list:
self.assertEquals(importer.verseOrderList, [], 'verseOrderList for %s should be %s' self.assertEquals(importer.verse_order_list, [], 'verse_order_list for %s should be %s'
% (source_file_name, verse_order_list)) % (source_file_name, verse_order_list))
self.mocked_finish.assert_called_with() self.mocked_finish.assert_called_with()