diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 7e573ae2e..36bfa24ef 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -82,11 +82,8 @@ def upgrade_db(url, upgrade): """ Upgrade a database. - ``url`` - The url of the database to upgrade. - - ``upgrade`` - The python module that contains the upgrade instructions. + :param url: The url of the database to upgrade. + :param upgrade: The python module that contains the upgrade instructions. """ session, metadata = init_db(url) @@ -99,7 +96,7 @@ def upgrade_db(url, upgrade): metadata_table = Table('metadata', metadata, Column('key', types.Unicode(64), primary_key=True), Column('value', types.UnicodeText(), default=None) - ) + ) metadata_table.create(checkfirst=True) mapper(Metadata, metadata_table) version_meta = session.query(Metadata).get('version') @@ -137,11 +134,8 @@ def delete_database(plugin_name, db_file_name=None): """ Remove a database file from the system. - ``plugin_name`` - The name of the plugin to remove the database for - - ``db_file_name`` - The database file name. Defaults to None resulting in the plugin_name being used. + :param plugin_name: The name of the plugin to remove the database for + :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used. """ db_file_path = None if db_file_name: @@ -175,17 +169,11 @@ class Manager(object): Runs the initialisation process that includes creating the connection to the database and the tables if they do not exist. - ``plugin_name`` - The name to setup paths and settings section names - - ``init_schema`` - The init_schema function for this database - - ``upgrade_schema`` - The upgrade_schema function for this database - - ``db_file_name`` - The file name to use for this database. Defaults to None resulting in the plugin_name being used. + :param plugin_name: The name to setup paths and settings section names + :param init_schema: The init_schema function for this database + :param db_file_name: The upgrade_schema function for this database + :param upgrade_mod: The file name to use for this database. Defaults to None resulting in the plugin_name + being used. """ settings = Settings() settings.beginGroup(plugin_name) @@ -208,7 +196,10 @@ class Manager(object): self.db_url += '?charset=%s' % urlquote(db_encoding) settings.endGroup() if upgrade_mod: - db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) + try: + db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) + except (SQLAlchemyError, DBAPIError): + log.exception('Error loading database: %s', self.db_url) if db_ver > up_ver: critical_error_message_box( translate('OpenLP.Manager', 'Database Error'), @@ -229,11 +220,8 @@ class Manager(object): """ Save an object to the database - ``object_instance`` - The object to save - - ``commit`` - Commit the session with this object + :param object_instance: The object to save + :param commit: Commit the session with this object """ for try_count in range(3): try: @@ -262,11 +250,8 @@ class Manager(object): """ Save a list of objects to the database - ``object_list`` - The list of objects to save - - ``commit`` - Commit the session with this object + :param object_list: The list of objects to save + :param commit: Commit the session with this object """ for try_count in range(3): try: @@ -295,11 +280,8 @@ class Manager(object): """ Return the details of an object - ``object_class`` - The type of object to return - - ``key`` - The unique reference or primary key for the instance to return + :param object_class: The type of object to return + :param key: The unique reference or primary key for the instance to return """ if not key: return object_class() @@ -319,11 +301,8 @@ class Manager(object): """ Returns an object matching specified criteria - ``object_class`` - The type of object to return - - ``filter_clause`` - The criteria to select the object by + :param object_class: The type of object to return + :param filter_clause: The criteria to select the object by """ for try_count in range(3): try: @@ -340,14 +319,9 @@ class Manager(object): """ Returns all the objects from the database - ``object_class`` - The type of objects to return - - ``filter_clause`` - The filter governing selection of objects to return. Defaults to None. - - ``order_by_ref`` - Any parameters to order the returned objects by. Defaults to None. + :param object_class: The type of objects to return + :param filter_clause: The filter governing selection of objects to return. Defaults to None. + :param order_by_ref: Any parameters to order the returned objects by. Defaults to None. """ query = self.session.query(object_class) if filter_clause is not None: @@ -371,11 +345,8 @@ class Manager(object): """ Returns a count of the number of objects in the database. - ``object_class`` - The type of objects to return. - - ``filter_clause`` - The filter governing selection of objects to return. Defaults to None. + :param object_class: The type of objects to return. + :param filter_clause: The filter governing selection of objects to return. Defaults to None. """ query = self.session.query(object_class) if filter_clause is not None: @@ -395,11 +366,8 @@ class Manager(object): """ Delete an object from the database - ``object_class`` - The type of object to delete - - ``key`` - The unique reference or primary key for the instance to be deleted + :param object_class: The type of object to delete + :param key: The unique reference or primary key for the instance to be deleted """ if key != 0: object_instance = self.get_object(object_class, key) @@ -432,11 +400,8 @@ class Manager(object): Delete all object records. This method should only be used for simple tables and **not** ones with relationships. The relationships are not deleted from the database and this will lead to database corruptions. - ``object_class`` - The type of object to delete - - ``filter_clause`` - The filter governing selection of objects to return. Defaults to None. + :param object_class: The type of object to delete + :param filter_clause: The filter governing selection of objects to return. Defaults to None. """ for try_count in range(3): try: diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 08ef29039..92a91aad4 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -116,20 +116,20 @@ class BiblePlugin(Plugin): if QtGui.QMessageBox.information(self.main_window, translate('OpenLP', 'Information'), translate('OpenLP', 'Bible format has changed.\nYou have to upgrade your existing Bibles.\n' - 'Should OpenLP upgrade now?'), + 'Should OpenLP upgrade now?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) == \ QtGui.QMessageBox.Yes: self.on_tools_upgrade_Item_triggered() def add_import_menu_item(self, import_menu): self.import_bible_item = create_action(import_menu, 'importBibleItem', - text=translate('BiblesPlugin', '&Bible'), visible=False, - triggers=self.on_bible_import_click) + text=translate('BiblesPlugin', '&Bible'), visible=False, + triggers=self.on_bible_import_click) import_menu.addAction(self.import_bible_item) def add_export_menu_Item(self, export_menu): self.export_bible_item = create_action(export_menu, 'exportBibleItem', - text=translate('BiblesPlugin', '&Bible'), visible=False) + text=translate('BiblesPlugin', '&Bible'), visible=False) export_menu.addAction(self.export_bible_item) def add_tools_menu_item(self, tools_menu): @@ -140,7 +140,8 @@ class BiblePlugin(Plugin): The actual **Tools** menu item, so that your actions can use it as their parent. """ log.debug('add tools menu') - self.tools_upgrade_item = create_action(tools_menu, 'toolsUpgradeItem', + self.tools_upgrade_item = create_action( + tools_menu, 'toolsUpgradeItem', text=translate('BiblesPlugin', '&Upgrade older Bibles'), statustip=translate('BiblesPlugin', 'Upgrade the Bible databases to the latest format.'), visible=False, triggers=self.on_tools_upgrade_Item_triggered) @@ -162,14 +163,16 @@ class BiblePlugin(Plugin): def about(self): about_text = translate('BiblesPlugin', 'Bible Plugin' - '
The Bible plugin provides the ability to display Bible ' - 'verses from different sources during the service.') + '
The Bible plugin provides the ability to display Bible ' + 'verses from different sources during the service.') return about_text def uses_theme(self, theme): """ Called to find out if the bible plugin is currently using a theme. Returns ``True`` if the theme is being used, otherwise returns ``False``. + + :param theme: The theme """ return str(self.settings_tab.bible_theme) == theme @@ -178,11 +181,8 @@ class BiblePlugin(Plugin): Rename the theme the bible plugin is using making the plugin use the new name. - ``old_theme`` - The name of the theme the plugin should stop using. Unused for this particular plugin. - - ``new_theme`` - The new name the plugin should now use. + :param old_theme: The name of the theme the plugin should stop using. Unused for this particular plugin. + :param new_theme: The new name the plugin should now use. """ self.settings_tab.bible_theme = new_theme self.settings_tab.save() @@ -207,8 +207,7 @@ class BiblePlugin(Plugin): 'new': translate('BiblesPlugin', 'Add a new Bible.'), 'edit': translate('BiblesPlugin', 'Edit the selected Bible.'), 'delete': translate('BiblesPlugin', 'Delete the selected Bible.'), - 'preview': translate('BiblesPlugin', - 'Preview the selected Bible.'), + 'preview': translate('BiblesPlugin', 'Preview the selected Bible.'), 'live': translate('BiblesPlugin', 'Send the selected Bible live.'), 'service': translate('BiblesPlugin', 'Add the selected Bible to the service.') } diff --git a/openlp/plugins/bibles/lib/__init__.py b/openlp/plugins/bibles/lib/__init__.py index b8c0c0ed9..39bee992f 100644 --- a/openlp/plugins/bibles/lib/__init__.py +++ b/openlp/plugins/bibles/lib/__init__.py @@ -182,9 +182,10 @@ def update_reference_separators(): """ Updates separators and matches for parsing and formating scripture references. """ - default_separators = translate('BiblesPlugin', - ':|v|V|verse|verses;;-|to;;,|and;;end Double-semicolon delimited separators for parsing references. ' - 'Consult the developers for further information.').split(';;') + default_separators = \ + translate('BiblesPlugin', + ':|v|V|verse|verses;;-|to;;,|and;;end Double-semicolon delimited separators for parsing references. ' + 'Consult the developers for further information.').split(';;') settings = Settings() settings.beginGroup('bibles') custom_separators = [ @@ -206,8 +207,7 @@ def update_reference_separators(): for character in '\\.^$*+?{}[]()': source_string = source_string.replace(character, '\\' + character) # add various unicode alternatives - source_string = source_string.replace('-', - '(?:[-\u00AD\u2010\u2011\u2012\u2014\u2014\u2212\uFE63\uFF0D])') + source_string = source_string.replace('-', '(?:[-\u00AD\u2010\u2011\u2012\u2014\u2014\u2212\uFE63\uFF0D])') source_string = source_string.replace(',', '(?:[,\u201A])') REFERENCE_SEPARATORS['sep_%s' % role] = '\s*(?:%s)\s*' % source_string REFERENCE_SEPARATORS['sep_%s_default' % role] = default_separators[index] @@ -227,8 +227,7 @@ def get_reference_separator(separator_type): """ Provides separators for parsing and formatting scripture references. - ``separator_type`` - The role and format of the separator. + :param separator_type: The role and format of the separator. """ if not REFERENCE_SEPARATORS: update_reference_separators() @@ -239,8 +238,7 @@ def get_reference_match(match_type): """ Provides matches for parsing scripture references strings. - ``match_type`` - The type of match is ``range_separator``, ``range`` or ``full``. + :param match_type: The type of match is ``range_separator``, ``range`` or ``full``. """ if not REFERENCE_MATCHES: update_reference_separators() @@ -252,19 +250,10 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False): This is the next generation über-awesome function that takes a person's typed in string and converts it to a list of references to be queried from the Bible database files. - ``reference`` - A string. The Bible reference to parse. - - ``bible`` - A object. The Bible database object. - - ``language_selection`` - An int. The language selection the user has choosen in settings section. - - ``book_ref_id`` - A string. The book reference id. - - Returns ``None`` or a reference list. + :param reference: A string. The Bible reference to parse. + :param bible: A object. The Bible database object. + :param language_selection: An int. The language selection the user has chosen in settings section. + :param book_ref_id: A string. The book reference id. The reference list is a list of tuples, with each tuple structured like this:: @@ -410,15 +399,9 @@ class SearchResults(object): """ Create the search result object. - ``book`` - The book of the Bible. - - ``chapter`` - The chapter of the book. - - ``verse_list`` - The list of verses for this reading. - + :param book: The book of the Bible. + :param chapter: The chapter of the book. + :param verse_list: The list of verses for this reading. """ self.book = book self.chapter = chapter diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index ac7a1ac72..8e5c50178 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -120,7 +120,7 @@ class BiblesTab(SettingsTab): self.end_separator_line_edit = QtGui.QLineEdit(self.scripture_reference_group_box) self.end_separator_line_edit.setObjectName('end_separator_line_edit') self.end_separator_line_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^0-9]*'), - self.end_separator_line_edit)) + self.end_separator_line_edit)) self.scripture_reference_layout.addWidget(self.end_separator_line_edit, 3, 1) self.left_layout.addWidget(self.scripture_reference_group_box) self.right_column.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) @@ -142,7 +142,7 @@ class BiblesTab(SettingsTab): self.new_chapters_check_box.stateChanged.connect(self.on_new_chapters_check_box_changed) self.display_style_combo_box.activated.connect(self.on_display_style_combo_box_changed) self.bible_theme_combo_box.activated.connect(self.on_bible_theme_combo_box_changed) - self.layout_style_combo_box.activated.connect(self.on_layout_style_combo_boxChanged) + self.layout_style_combo_box.activated.connect(self.on_layout_style_combo_box_changed) self.bible_second_check_box.stateChanged.connect(self.on_bible_second_check_box) self.verse_separator_check_box.clicked.connect(self.on_verse_separator_check_box_clicked) self.verse_separator_line_edit.textEdited.connect(self.on_verse_separator_line_edit_edited) @@ -170,15 +170,15 @@ class BiblesTab(SettingsTab): self.layout_style_combo_box.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine) self.layout_style_combo_box.setItemText(LayoutStyle.Continuous, UiStrings().Continuous) self.display_style_combo_box.setItemText(DisplayStyle.NoBrackets, - translate('BiblesPlugin.BiblesTab', 'No Brackets')) + translate('BiblesPlugin.BiblesTab', 'No Brackets')) self.display_style_combo_box.setItemText(DisplayStyle.Round, - translate('BiblesPlugin.BiblesTab', '( And )')) + translate('BiblesPlugin.BiblesTab', '( And )')) self.display_style_combo_box.setItemText(DisplayStyle.Curly, - translate('BiblesPlugin.BiblesTab', '{ And }')) + translate('BiblesPlugin.BiblesTab', '{ And }')) self.display_style_combo_box.setItemText(DisplayStyle.Square, - translate('BiblesPlugin.BiblesTab', '[ And ]')) + translate('BiblesPlugin.BiblesTab', '[ And ]')) self.change_note_label.setText(translate('BiblesPlugin.BiblesTab', - 'Note:\nChanges do not affect verses already in the service.')) + 'Note:\nChanges do not affect verses already in the service.')) self.bible_second_check_box.setText(translate('BiblesPlugin.BiblesTab', 'Display second Bible verses')) self.scripture_reference_group_box.setTitle(translate('BiblesPlugin.BiblesTab', 'Custom Scripture References')) self.verse_separator_check_box.setText(translate('BiblesPlugin.BiblesTab', 'Verse Separator:')) @@ -186,21 +186,21 @@ class BiblesTab(SettingsTab): self.list_separator_check_box.setText(translate('BiblesPlugin.BiblesTab', 'List Separator:')) self.end_separator_check_box.setText(translate('BiblesPlugin.BiblesTab', 'End Mark:')) tip_text = translate('BiblesPlugin.BiblesTab', - 'Multiple alternative verse separators may be defined.\nThey have to be separated by a vertical bar "|".' - '\nPlease clear this edit line to use the default value.') + 'Multiple alternative verse separators may be defined.\nThey have to be separated by a ' + 'vertical bar "|".\nPlease clear this edit line to use the default value.') self.verse_separator_line_edit.setToolTip(tip_text) self.range_separator_line_edit.setToolTip(tip_text) self.list_separator_line_edit.setToolTip(tip_text) self.end_separator_line_edit.setToolTip(tip_text) self.language_selection_group_box.setTitle(translate('BiblesPlugin.BiblesTab', 'Default Bible Language')) - self.language_selection_label.setText(translate('BiblesPlugin.BiblesTab', - 'Book name language in search field,\nsearch results and on display:')) - self.language_selection_combo_box.setItemText(LanguageSelection.Bible, - translate('BiblesPlugin.BiblesTab', 'Bible Language')) - self.language_selection_combo_box.setItemText(LanguageSelection.Application, - translate('BiblesPlugin.BiblesTab', 'Application Language')) - self.language_selection_combo_box.setItemText(LanguageSelection.English, - translate('BiblesPlugin.BiblesTab', 'English')) + self.language_selection_label.setText( + translate('BiblesPlugin.BiblesTab', 'Book name language in search field,\nsearch results and on display:')) + self.language_selection_combo_box.setItemText( + LanguageSelection.Bible, translate('BiblesPlugin.BiblesTab', 'Bible Language')) + self.language_selection_combo_box.setItemText( + LanguageSelection.Application, translate('BiblesPlugin.BiblesTab', 'Application Language')) + self.language_selection_combo_box.setItemText( + LanguageSelection.English, translate('BiblesPlugin.BiblesTab', 'English')) def on_bible_theme_combo_box_changed(self): self.bible_theme = self.bible_theme_combo_box.currentText() @@ -208,7 +208,7 @@ class BiblesTab(SettingsTab): def on_display_style_combo_box_changed(self): self.display_style = self.display_style_combo_box.currentIndex() - def on_layout_style_combo_boxChanged(self): + def on_layout_style_combo_box_changed(self): self.layout_style = self.layout_style_combo_box.currentIndex() def on_language_selection_combo_box_changed(self): @@ -238,11 +238,11 @@ class BiblesTab(SettingsTab): self.verse_separator_line_edit.setFocus() else: self.verse_separator_line_edit.setText(get_reference_separator('sep_v_default')) - self.verse_separator_line_edit.setPalette(self.getGreyTextPalette(not checked)) + self.verse_separator_line_edit.setPalette(self.get_grey_text_palette(not checked)) def on_verse_separator_line_edit_edited(self, text): self.verse_separator_check_box.setChecked(True) - self.verse_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.verse_separator_line_edit.setPalette(self.get_grey_text_palette(False)) def on_verse_separator_line_edit_finished(self): if self.verse_separator_line_edit.isModified(): @@ -250,18 +250,18 @@ class BiblesTab(SettingsTab): if text == get_reference_separator('sep_v_default') or not text.replace('|', ''): self.verse_separator_check_box.setChecked(False) self.verse_separator_line_edit.setText(get_reference_separator('sep_v_default')) - self.verse_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.verse_separator_line_edit.setPalette(self.get_grey_text_palette(True)) def on_range_separator_check_box_clicked(self, checked): if checked: self.range_separator_line_edit.setFocus() else: self.range_separator_line_edit.setText(get_reference_separator('sep_r_default')) - self.range_separator_line_edit.setPalette(self.getGreyTextPalette(not checked)) + self.range_separator_line_edit.setPalette(self.get_grey_text_palette(not checked)) def on_range_separator_line_edit_edited(self, text): self.range_separator_check_box.setChecked(True) - self.range_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.range_separator_line_edit.setPalette(self.get_grey_text_palette(False)) def on_range_separator_line_edit_finished(self): if self.range_separator_line_edit.isModified(): @@ -269,18 +269,18 @@ class BiblesTab(SettingsTab): if text == get_reference_separator('sep_r_default') or not text.replace('|', ''): self.range_separator_check_box.setChecked(False) self.range_separator_line_edit.setText(get_reference_separator('sep_r_default')) - self.range_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.range_separator_line_edit.setPalette(self.get_grey_text_palette(True)) def on_list_separator_check_box_clicked(self, checked): if checked: self.list_separator_line_edit.setFocus() else: self.list_separator_line_edit.setText(get_reference_separator('sep_l_default')) - self.list_separator_line_edit.setPalette(self.getGreyTextPalette(not checked)) + self.list_separator_line_edit.setPalette(self.get_grey_text_palette(not checked)) def on_list_separator_line_edit_edited(self, text): self.list_separator_check_box.setChecked(True) - self.list_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.list_separator_line_edit.setPalette(self.get_grey_text_palette(False)) def on_list_separator_line_edit_finished(self): if self.list_separator_line_edit.isModified(): @@ -288,18 +288,18 @@ class BiblesTab(SettingsTab): if text == get_reference_separator('sep_l_default') or not text.replace('|', ''): self.list_separator_check_box.setChecked(False) self.list_separator_line_edit.setText(get_reference_separator('sep_l_default')) - self.list_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.list_separator_line_edit.setPalette(self.get_grey_text_palette(True)) def on_end_separator_check_box_clicked(self, checked): if checked: self.end_separator_line_edit.setFocus() else: self.end_separator_line_edit.setText(get_reference_separator('sep_e_default')) - self.end_separator_line_edit.setPalette(self.getGreyTextPalette(not checked)) + self.end_separator_line_edit.setPalette(self.get_grey_text_palette(not checked)) def on_end_separator_line_edit_edited(self, text): self.end_separator_check_box.setChecked(True) - self.end_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.end_separator_line_edit.setPalette(self.get_grey_text_palette(False)) def on_end_separator_line_edit_finished(self): if self.end_separator_line_edit.isModified(): @@ -307,7 +307,7 @@ class BiblesTab(SettingsTab): if text == get_reference_separator('sep_e_default') or not text.replace('|', ''): self.end_separator_check_box.setChecked(False) self.end_separator_line_edit.setText(get_reference_separator('sep_e_default')) - self.end_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.end_separator_line_edit.setPalette(self.get_grey_text_palette(True)) def load(self): settings = Settings() @@ -327,38 +327,38 @@ class BiblesTab(SettingsTab): verse_separator = settings.value('verse separator') if (verse_separator.strip('|') == '') or (verse_separator == get_reference_separator('sep_v_default')): self.verse_separator_line_edit.setText(get_reference_separator('sep_v_default')) - self.verse_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.verse_separator_line_edit.setPalette(self.get_grey_text_palette(True)) self.verse_separator_check_box.setChecked(False) else: self.verse_separator_line_edit.setText(verse_separator) - self.verse_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.verse_separator_line_edit.setPalette(self.get_grey_text_palette(False)) self.verse_separator_check_box.setChecked(True) range_separator = settings.value('range separator') if (range_separator.strip('|') == '') or (range_separator == get_reference_separator('sep_r_default')): self.range_separator_line_edit.setText(get_reference_separator('sep_r_default')) - self.range_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.range_separator_line_edit.setPalette(self.get_grey_text_palette(True)) self.range_separator_check_box.setChecked(False) else: self.range_separator_line_edit.setText(range_separator) - self.range_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.range_separator_line_edit.setPalette(self.get_grey_text_palette(False)) self.range_separator_check_box.setChecked(True) list_separator = settings.value('list separator') if (list_separator.strip('|') == '') or (list_separator == get_reference_separator('sep_l_default')): self.list_separator_line_edit.setText(get_reference_separator('sep_l_default')) - self.list_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.list_separator_line_edit.setPalette(self.get_grey_text_palette(True)) self.list_separator_check_box.setChecked(False) else: self.list_separator_line_edit.setText(list_separator) - self.list_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.list_separator_line_edit.setPalette(self.get_grey_text_palette(False)) self.list_separator_check_box.setChecked(True) end_separator = settings.value('end separator') if (end_separator.strip('|') == '') or (end_separator == get_reference_separator('sep_e_default')): self.end_separator_line_edit.setText(get_reference_separator('sep_e_default')) - self.end_separator_line_edit.setPalette(self.getGreyTextPalette(True)) + self.end_separator_line_edit.setPalette(self.get_grey_text_palette(True)) self.end_separator_check_box.setChecked(False) else: self.end_separator_line_edit.setText(end_separator) - self.end_separator_line_edit.setPalette(self.getGreyTextPalette(False)) + self.end_separator_line_edit.setPalette(self.get_grey_text_palette(False)) self.end_separator_check_box.setChecked(True) self.language_selection = settings.value('book name language') self.language_selection_combo_box.setCurrentIndex(self.language_selection) @@ -402,7 +402,7 @@ class BiblesTab(SettingsTab): """ Called from ThemeManager when the Themes have changed. - ``theme_list`` + :param theme_list: The list of available themes:: [u'Bible Theme', u'Song Theme'] @@ -412,7 +412,7 @@ class BiblesTab(SettingsTab): self.bible_theme_combo_box.addItems(theme_list) find_and_set_in_combo_box(self.bible_theme_combo_box, self.bible_theme) - def getGreyTextPalette(self, greyed): + def get_grey_text_palette(self, greyed): """ Returns a QPalette with greyed out text as used for placeholderText. """ diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index d5dfcf2df..c7d37cb7b 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -80,8 +80,8 @@ class CSVBible(BibleDB): """ log.info(self.__class__.__name__) BibleDB.__init__(self, parent, **kwargs) - self.booksfile = kwargs['booksfile'] - self.versesfile = kwargs['versefile'] + self.books_file = kwargs['books_file'] + self.verses_file = kwargs['versefile'] def do_import(self, bible_name=None): """ @@ -99,8 +99,8 @@ class CSVBible(BibleDB): book_list = {} # Populate the Tables try: - details = get_file_encoding(self.booksfile) - books_file = open(self.booksfile, 'r') + details = get_file_encoding(self.books_file) + books_file = open(self.books_file, 'r') if not books_file.read(3) == '\xEF\xBB\xBF': # no BOM was found books_file.seek(0) @@ -109,10 +109,10 @@ class CSVBible(BibleDB): if self.stop_import_flag: break self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') % - str(line[2], details['encoding'])) + str(line[2], details['encoding'])) book_ref_id = self.get_book_ref_id_by_name(str(line[2], details['encoding']), 67, language_id) if not book_ref_id: - log.error('Importing books from "%s" failed' % self.booksfile) + log.error('Importing books from "%s" failed' % self.books_file) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) self.create_book(str(line[2], details['encoding']), book_ref_id, book_details['testament_id']) @@ -131,8 +131,8 @@ class CSVBible(BibleDB): verse_file = None try: book_ptr = None - details = get_file_encoding(self.versesfile) - verse_file = open(self.versesfile, 'rb') + details = get_file_encoding(self.verses_file) + verse_file = open(self.verses_file, 'rb') if not verse_file.read(3) == '\xEF\xBB\xBF': # no BOM was found verse_file.seek(0) @@ -147,8 +147,9 @@ class CSVBible(BibleDB): if book_ptr != line_book: book = self.get_book(line_book) book_ptr = book.name - self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', - 'Importing verses from %s... Importing verses from ...') % book.name) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.CSVBible', + 'Importing verses from %s... Importing verses from ...') % book.name) self.session.commit() try: verse_text = str(line[3], details['encoding']) @@ -169,6 +170,7 @@ class CSVBible(BibleDB): else: return success + def get_file_encoding(filename): """ Utility function to get the file encoding. diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 73ecb1eba..36b8a0bf2 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -48,6 +48,7 @@ log = logging.getLogger(__name__) RESERVED_CHARACTERS = '\\.^$*+?{}[]()' + class BibleMeta(BaseModel): """ Bible Meta Data @@ -79,23 +80,23 @@ def init_schema(url): session, metadata = init_db(url) meta_table = Table('metadata', metadata, - Column('key', types.Unicode(255), primary_key=True, index=True), - Column('value', types.Unicode(255)), + Column('key', types.Unicode(255), primary_key=True, index=True), + Column('value', types.Unicode(255)), ) book_table = Table('book', metadata, - Column('id', types.Integer, primary_key=True), - Column('book_reference_id', types.Integer, index=True), - Column('testament_reference_id', types.Integer), - Column('name', types.Unicode(50), index=True), + Column('id', types.Integer, primary_key=True), + Column('book_reference_id', types.Integer, index=True), + Column('testament_reference_id', types.Integer), + Column('name', types.Unicode(50), index=True), ) verse_table = Table('verse', metadata, - Column('id', types.Integer, primary_key=True, index=True), - Column('book_id', types.Integer, ForeignKey( - 'book.id'), index=True), - Column('chapter', types.Integer, index=True), - Column('verse', types.Integer, index=True), - Column('text', types.UnicodeText, index=True), + Column('id', types.Integer, primary_key=True, index=True), + Column('book_id', types.Integer, ForeignKey( + 'book.id'), index=True), + Column('chapter', types.Integer, index=True), + Column('verse', types.Integer, index=True), + Column('text', types.UnicodeText, index=True), ) try: @@ -105,8 +106,7 @@ def init_schema(url): try: class_mapper(Book) except UnmappedClassError: - mapper(Book, book_table, - properties={'verses': relation(Verse, backref='book')}) + mapper(Book, book_table, properties={'verses': relation(Verse, backref='book')}) try: class_mapper(Verse) except UnmappedClassError: @@ -118,9 +118,8 @@ def init_schema(url): class BibleDB(QtCore.QObject, Manager): """ - This class represents a database-bound Bible. It is used as a base class - for all the custom importers, so that the can implement their own import - methods, but benefit from the database methods in here via inheritance, + This class represents a database-bound Bible. It is used as a base class for all the custom importers, so that + the can implement their own import methods, but benefit from the database methods in here via inheritance, rather than depending on yet another object. """ log.info('BibleDB loaded') @@ -130,14 +129,13 @@ class BibleDB(QtCore.QObject, Manager): The constructor loads up the database and creates and initialises the tables if the database doesn't exist. - **Required keyword arguments:** + :param parent: + :param kwargs: + ``path`` + The path to the bible database file. - ``path`` - The path to the bible database file. - - ``name`` - The name of the database. This is also used as the file name for - SQLite databases. + ``name`` + The name of the database. This is also used as the file name for SQLite databases. """ log.info('BibleDB loaded') QtCore.QObject.__init__(self) @@ -179,13 +177,11 @@ class BibleDB(QtCore.QObject, Manager): def register(self, wizard): """ - This method basically just initialialises the database. It is called - from the Bible Manager when a Bible is imported. Descendant classes - may want to override this method to supply their own custom + This method basically just initialises the database. It is called from the Bible Manager when a Bible is + imported. Descendant classes may want to override this method to supply their own custom initialisation as well. - ``wizard`` - The actual Qt wizard form. + :param wizard: The actual Qt wizard form. """ self.wizard = wizard return self.name @@ -194,14 +190,9 @@ class BibleDB(QtCore.QObject, Manager): """ Add a book to the database. - ``name`` - The name of the book. - - ``bk_ref_id`` - The book_reference_id from bibles_resources.sqlite of the book. - - ``testament`` - *Defaults to 1.* The testament_reference_id from + :param name: The name of the book. + :param bk_ref_id: The book_reference_id from bibles_resources.sqlite of the book. + :param testament: *Defaults to 1.* The testament_reference_id from bibles_resources.sqlite of the testament this book belongs to. """ log.debug('BibleDB.create_book("%s", "%s")', name, bk_ref_id) @@ -213,8 +204,7 @@ class BibleDB(QtCore.QObject, Manager): """ Update a book in the database. - ``book`` - The book object + :param book: The book object """ log.debug('BibleDB.update_book("%s")', book.name) return self.save_object(book) @@ -223,31 +213,24 @@ class BibleDB(QtCore.QObject, Manager): """ Delete a book from the database. - ``db_book`` - The book object. + :param db_book: The book object. """ log.debug('BibleDB.delete_book("%s")', db_book.name) if self.delete_object(Book, db_book.id): return True return False - def create_chapter(self, book_id, chapter, textlist): + def create_chapter(self, book_id, chapter, text_list): """ Add a chapter and its verses to a book. - ``book_id`` - The id of the book being appended. - - ``chapter`` - The chapter number. - - ``textlist`` - A dict of the verses to be inserted. The key is the verse number, - and the value is the verse text. + :param book_id: The id of the book being appended. + :param chapter: The chapter number. + :param text_list: A dict of the verses to be inserted. The key is the verse number, and the value is the verse text. """ log.debug('BibleDBcreate_chapter("%s", "%s")', book_id, chapter) # Text list has book and chapter as first two elements of the array. - for verse_number, verse_text in textlist.items(): + for verse_number, verse_text in text_list.items(): verse = Verse.populate( book_id=book_id, chapter=chapter, @@ -261,17 +244,10 @@ class BibleDB(QtCore.QObject, Manager): """ Add a single verse to a chapter. - ``book_id`` - The id of the book being appended. - - ``chapter`` - The chapter number. - - ``verse`` - The verse number. - - ``text`` - The verse text. + :param book_id: The id of the book being appended. + :param chapter: The chapter number. + :param verse: The verse number. + :param text: The verse text. """ if not isinstance(text, str): details = chardet.detect(text) @@ -289,11 +265,8 @@ class BibleDB(QtCore.QObject, Manager): """ Utility method to save or update BibleMeta objects in a Bible database. - ``key`` - The key for this instance. - - ``value`` - The value for this instance. + :param key: The key for this instance. + :param value: The value for this instance. """ if not isinstance(value, str): value = str(value) @@ -309,8 +282,7 @@ class BibleDB(QtCore.QObject, Manager): """ Return a book object from the database. - ``book`` - The name of the book to return. + :param book: The name of the book to return. """ log.debug('BibleDB.get_book("%s")', book) return self.get_object_filtered(Book, Book.name.like(book + '%')) @@ -327,8 +299,7 @@ class BibleDB(QtCore.QObject, Manager): """ Return a book object from the database. - ``id`` - The reference id of the book to return. + :param id: The reference id of the book to return. """ log.debug('BibleDB.get_book_by_book_ref_id("%s")', id) return self.get_object_filtered(Book, Book.book_reference_id.like(id)) @@ -357,11 +328,8 @@ class BibleDB(QtCore.QObject, Manager): """ Return the id of a named book. - ``book`` - The name of the book, according to the selected language. - - ``language_selection`` - The language selection the user has chosen in the settings section of the Bible. + :param book: The name of the book, according to the selected language. + :param language_selection: The language selection the user has chosen in the settings section of the Bible. """ log.debug('get_book_ref_id_by_localised_name("%s", "%s")', book, language_selection) from openlp.plugins.bibles.lib import LanguageSelection, BibleStrings @@ -398,8 +366,7 @@ class BibleDB(QtCore.QObject, Manager): This is probably the most used function. It retrieves the list of verses based on the user's query. - ``reference_list`` - This is the list of references the media manager item wants. It is + :param reference_list: This is the list of references the media manager item wants. It is a list of tuples, with the following format:: (book_reference_id, chapter, start_verse, end_verse) @@ -410,6 +377,7 @@ class BibleDB(QtCore.QObject, Manager): list of ``Verse`` objects. For example:: [(u'35', 1, 1, 1), (u'35', 2, 2, 3)] + :param show_error: """ log.debug('BibleDB.get_verses("%s")', reference_list) verse_list = [] @@ -436,14 +404,14 @@ class BibleDB(QtCore.QObject, Manager): critical_error_message_box( translate('BiblesPlugin', 'No Book Found'), translate('BiblesPlugin', 'No matching book ' - 'could be found in this Bible. Check that you have spelled the name of the book correctly.')) + 'could be found in this Bible. Check that you have spelled the name of the book correctly.')) return verse_list def verse_search(self, text): """ Search for verses containing text ``text``. - ``text`` + :param text: The text to search for. If the text contains commas, it will be split apart and OR'd on the list of values. If the text just contains spaces, it will split apart and AND'd on the list of @@ -452,13 +420,11 @@ class BibleDB(QtCore.QObject, Manager): log.debug('BibleDB.verse_search("%s")', text) verses = self.session.query(Verse) if text.find(',') > -1: - keywords = \ - ['%%%s%%' % keyword.strip() for keyword in text.split(',')] + keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(',')] or_clause = [Verse.text.like(keyword) for keyword in keywords] verses = verses.filter(or_(*or_clause)) else: - keywords = \ - ['%%%s%%' % keyword.strip() for keyword in text.split(' ')] + keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(' ')] for keyword in keywords: verses = verses.filter(Verse.text.like(keyword)) verses = verses.all() @@ -468,8 +434,7 @@ class BibleDB(QtCore.QObject, Manager): """ Return the number of chapters in a book. - ``book`` - The book object to get the chapter count for. + :param book: The book object to get the chapter count for. """ log.debug('BibleDB.get_chapter_count("%s")', book.name) count = self.session.query(func.max(Verse.chapter)).join(Book).filter( @@ -482,11 +447,8 @@ class BibleDB(QtCore.QObject, Manager): """ Return the number of verses in a chapter. - ``book_ref_id`` - The book reference id. - - ``chapter`` - The chapter to get the verse count for. + :param book_ref_id: The book reference id. + :param chapter: The chapter to get the verse count for. """ log.debug('BibleDB.get_verse_count("%s", "%s")', book_ref_id, chapter) count = self.session.query(func.max(Verse.verse)).join(Book) \ @@ -499,12 +461,10 @@ class BibleDB(QtCore.QObject, Manager): def get_language(self, bible_name=None): """ - If no language is given it calls a dialog window where the user could - select the bible language. + If no language is given it calls a dialog window where the user could select the bible language. Return the language id of a bible. - ``book`` - The language the bible is. + :param bible_name: The language the bible is. """ log.debug('BibleDB.get_language()') from openlp.plugins.bibles.forms import LanguageForm @@ -521,8 +481,7 @@ class BibleDB(QtCore.QObject, Manager): def is_old_database(self): """ - Returns ``True`` if it is a bible database, which has been created - prior to 1.9.6. + Returns ``True`` if it is a bible database, which has been created prior to 1.9.6. """ try: self.session.query(Book).all() @@ -576,9 +535,9 @@ class BiblesResourcesDB(QtCore.QObject, Manager): Return the cursor object. Instantiate one if it doesn't exist yet. """ if BiblesResourcesDB.cursor is None: - filepath = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), - 'bibles', 'resources', 'bibles_resources.sqlite') - conn = sqlite3.connect(filepath) + file_path = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), + 'bibles', 'resources', 'bibles_resources.sqlite') + conn = sqlite3.connect(file_path) BiblesResourcesDB.cursor = conn.cursor() return BiblesResourcesDB.cursor @@ -603,8 +562,8 @@ class BiblesResourcesDB(QtCore.QObject, Manager): Return a list of all the books of the Bible. """ log.debug('BiblesResourcesDB.get_books()') - books = BiblesResourcesDB.run_sql('SELECT id, testament_id, name, ' - 'abbreviation, chapters FROM book_reference ORDER BY id') + books = BiblesResourcesDB.run_sql( + 'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference ORDER BY id') return [{ 'id': book[0], 'testament_id': book[1], @@ -618,24 +577,20 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return a book by name or abbreviation. - ``name`` - The name or abbreviation of the book. - - ``lower`` - True if the comparsion should be only lowercase + :param name: The name or abbreviation of the book. + :param lower: True if the comparsion should be only lowercase """ log.debug('BiblesResourcesDB.get_book("%s")', name) if not isinstance(name, str): name = str(name) if lower: - books = BiblesResourcesDB.run_sql('SELECT id, testament_id, name, ' - 'abbreviation, chapters FROM book_reference WHERE ' - 'LOWER(name) = ? OR LOWER(abbreviation) = ?', - (name.lower(), name.lower())) + books = BiblesResourcesDB.run_sql( + 'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference WHERE ' + 'LOWER(name) = ? OR LOWER(abbreviation) = ?', (name.lower(), name.lower())) else: - books = BiblesResourcesDB.run_sql('SELECT id, testament_id, name, ' - 'abbreviation, chapters FROM book_reference WHERE name = ?' - ' OR abbreviation = ?', (name, name)) + books = BiblesResourcesDB.run_sql( + 'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference WHERE name = ?' + ' OR abbreviation = ?', (name, name)) if books: return { 'id': books[0][0], @@ -652,16 +607,15 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return the books which include string. - ``string`` - The string to search for in the book names or abbreviations. + :param string: The string to search for in the book names or abbreviations. """ log.debug('BiblesResourcesDB.get_book_like("%s")', string) if not isinstance(string, str): name = str(string) - books = BiblesResourcesDB.run_sql('SELECT id, testament_id, name, ' - 'abbreviation, chapters FROM book_reference WHERE ' - 'LOWER(name) LIKE ? OR LOWER(abbreviation) LIKE ?', - ('%' + string.lower() + '%', '%' + string.lower() + '%')) + books = BiblesResourcesDB.run_sql( + 'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference WHERE ' + 'LOWER(name) LIKE ? OR LOWER(abbreviation) LIKE ?', + ('%' + string.lower() + '%', '%' + string.lower() + '%')) if books: return [{ 'id': book[0], @@ -678,14 +632,13 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return a book by id. - ``id`` - The id of the book. + :param id: The id of the book. """ log.debug('BiblesResourcesDB.get_book_by_id("%s")', id) if not isinstance(id, int): id = int(id) - books = BiblesResourcesDB.run_sql('SELECT id, testament_id, name, ' - 'abbreviation, chapters FROM book_reference WHERE id = ?', (id, )) + books = BiblesResourcesDB.run_sql( + 'SELECT id, testament_id, name, abbreviation, chapters FROM book_reference WHERE id = ?', (id, )) if books: return { 'id': books[0][0], @@ -702,16 +655,14 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return the chapter details for a specific chapter of a book. - ``book_ref_id`` - The id of a book. - - ``chapter`` - The chapter number. + :param book_ref_id: The id of a book. + :param chapter: The chapter number. """ log.debug('BiblesResourcesDB.get_chapter("%s", "%s")', book_ref_id, chapter) if not isinstance(chapter, int): chapter = int(chapter) - chapters = BiblesResourcesDB.run_sql('SELECT id, book_reference_id, ' + chapters = BiblesResourcesDB.run_sql( + 'SELECT id, book_reference_id, ' 'chapter, verse_count FROM chapters WHERE book_reference_id = ?', (book_ref_id,)) try: return { @@ -728,8 +679,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return the number of chapters in a book. - ``book_ref_id`` - The id of the book. + :param book_ref_id: The id of the book. """ log.debug('BiblesResourcesDB.get_chapter_count("%s")', book_ref_id) details = BiblesResourcesDB.get_book_by_id(book_ref_id) @@ -742,11 +692,8 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return the number of verses in a chapter. - ``book`` - The id of the book. - - ``chapter`` - The number of the chapter. + :param book_ref_id: The id of the book. + :param chapter: The number of the chapter. """ log.debug('BiblesResourcesDB.get_verse_count("%s", "%s")', book_ref_id, chapter) details = BiblesResourcesDB.get_chapter(book_ref_id, chapter) @@ -759,15 +706,14 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return a download_source_id by source. - ``name`` - The name or abbreviation of the book. + :param source: The name or abbreviation of the book. """ log.debug('BiblesResourcesDB.get_download_source("%s")', source) if not isinstance(source, str): source = str(source) source = source.title() - dl_source = BiblesResourcesDB.run_sql('SELECT id, source FROM ' - 'download_source WHERE source = ?', (source.lower(),)) + dl_source = BiblesResourcesDB.run_sql( + 'SELECT id, source FROM download_source WHERE source = ?', (source.lower(),)) if dl_source: return { 'id': dl_source[0][0], @@ -781,8 +727,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return the bibles a webbible provide for download. - ``source`` - The source of the webbible. + :param source: The source of the webbible. """ log.debug('BiblesResourcesDB.get_webbibles("%s")', source) if not isinstance(source, str): @@ -806,11 +751,8 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return the bibles a webbible provide for download. - ``abbreviation`` - The abbreviation of the webbible. - - ``source`` - The source of the webbible. + :param abbreviation: The abbreviation of the webbible. + :param source: The source of the webbible. """ log.debug('BiblesResourcesDB.get_webbibles("%s", "%s")', abbreviation, source) if not isinstance(abbreviation, str): @@ -818,8 +760,8 @@ class BiblesResourcesDB(QtCore.QObject, Manager): if not isinstance(source, str): source = str(source) source = BiblesResourcesDB.get_download_source(source) - bible = BiblesResourcesDB.run_sql('SELECT id, name, abbreviation, ' - 'language_id, download_source_id FROM webbibles WHERE ' + bible = BiblesResourcesDB.run_sql( + 'SELECT id, name, abbreviation, language_id, download_source_id FROM webbibles WHERE ' 'download_source_id = ? AND abbreviation = ?', (source['id'], abbreviation)) try: return { @@ -837,16 +779,14 @@ class BiblesResourcesDB(QtCore.QObject, Manager): """ Return a book_reference_id if the name matches. - ``name`` - The name to search the id. - - ``language_id`` - The language_id for which language should be searched + :param name: The name to search the id. + :param language_id: The language_id for which language should be searched """ log.debug('BiblesResourcesDB.get_alternative_book_name("%s", "%s")', name, language_id) if language_id: - books = BiblesResourcesDB.run_sql('SELECT book_reference_id, name ' - 'FROM alternative_book_names WHERE language_id = ? ORDER BY id', (language_id, )) + books = BiblesResourcesDB.run_sql( + 'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ? ORDER BY id', + (language_id, )) else: books = BiblesResourcesDB.run_sql('SELECT book_reference_id, name FROM alternative_book_names ORDER BY id') for book in books: @@ -857,17 +797,15 @@ class BiblesResourcesDB(QtCore.QObject, Manager): @staticmethod def get_language(name): """ - Return a dict containing the language id, name and code by name or - abbreviation. + Return a dict containing the language id, name and code by name or abbreviation. - ``name`` - The name or abbreviation of the language. + :param name: The name or abbreviation of the language. """ log.debug('BiblesResourcesDB.get_language("%s")', name) if not isinstance(name, str): name = str(name) - language = BiblesResourcesDB.run_sql('SELECT id, name, code FROM ' - 'language WHERE name = ? OR code = ?', (name, name.lower())) + language = BiblesResourcesDB.run_sql( + 'SELECT id, name, code FROM language WHERE name = ? OR code = ?', (name, name.lower())) if language: return { 'id': language[0][0], @@ -920,22 +858,20 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): def get_cursor(): """ Return the cursor object. Instantiate one if it doesn't exist yet. - If necessary loads up the database and creates the tables if the - database doesn't exist. + If necessary loads up the database and creates the tables if the database doesn't exist. """ if AlternativeBookNamesDB.cursor is None: - filepath = os.path.join( + file_path = os.path.join( AppLocation.get_directory(AppLocation.DataDir), 'bibles', 'alternative_book_names.sqlite') - if not os.path.exists(filepath): + if not os.path.exists(file_path): #create new DB, create table alternative_book_names - AlternativeBookNamesDB.conn = sqlite3.connect(filepath) - AlternativeBookNamesDB.conn.execute('CREATE TABLE ' - 'alternative_book_names(id INTEGER NOT NULL, ' - 'book_reference_id INTEGER, language_id INTEGER, name ' - 'VARCHAR(50), PRIMARY KEY (id))') + AlternativeBookNamesDB.conn = sqlite3.connect(file_path) + AlternativeBookNamesDB.conn.execute( + 'CREATE TABLE alternative_book_names(id INTEGER NOT NULL, ' + 'book_reference_id INTEGER, language_id INTEGER, name VARCHAR(50), PRIMARY KEY (id))') else: #use existing DB - AlternativeBookNamesDB.conn = sqlite3.connect(filepath) + AlternativeBookNamesDB.conn = sqlite3.connect(file_path) AlternativeBookNamesDB.cursor = AlternativeBookNamesDB.conn.cursor() return AlternativeBookNamesDB.cursor @@ -944,14 +880,9 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): """ Run an SQL query on the database, returning the results. - ``query`` - The actual SQL query to run. - - ``parameters`` - Any variable parameters to add to the query - - ``commit`` - If a commit statement is necessary this should be True. + :param query: The actual SQL query to run. + :param parameters: Any variable parameters to add to the query + :param commit: If a commit statement is necessary this should be True. """ cursor = AlternativeBookNamesDB.get_cursor() cursor.execute(query, parameters) @@ -964,19 +895,16 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): """ Return a book_reference_id if the name matches. - ``name`` - The name to search the id. - - ``language_id`` - The language_id for which language should be searched + :param name: The name to search the id. + :param language_id: The language_id for which language should be searched """ log.debug('AlternativeBookNamesDB.get_book_reference_id("%s", "%s")', name, language_id) if language_id: - books = AlternativeBookNamesDB.run_sql('SELECT book_reference_id, ' - 'name FROM alternative_book_names WHERE language_id = ?', (language_id, )) + books = AlternativeBookNamesDB.run_sql( + 'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ?', (language_id, )) else: - books = AlternativeBookNamesDB.run_sql('SELECT book_reference_id, ' - 'name FROM alternative_book_names') + books = AlternativeBookNamesDB.run_sql( + 'SELECT book_reference_id, name FROM alternative_book_names') for book in books: if book[1].lower() == name.lower(): return book[0] @@ -987,19 +915,14 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): """ Add an alternative book name to the database. - ``name`` - The name of the alternative book name. - - ``book_reference_id`` - The book_reference_id of the book. - - ``language_id`` - The language to which the alternative book name belong. + :param name: The name of the alternative book name. + :param book_reference_id: The book_reference_id of the book. + :param language_id: The language to which the alternative book name belong. """ - log.debug('AlternativeBookNamesDB.create_alternative_book_name("%s", ' - '"%s", "%s"', name, book_reference_id, language_id) - return AlternativeBookNamesDB.run_sql('INSERT INTO ' - 'alternative_book_names(book_reference_id, language_id, name) ' + log.debug('AlternativeBookNamesDB.create_alternative_book_name("%s", "%s", "%s")', + name, book_reference_id, language_id) + return AlternativeBookNamesDB.run_sql( + 'INSERT INTO alternative_book_names(book_reference_id, language_id, name) ' 'VALUES (?, ?, ?)', (book_reference_id, language_id, name), True) @@ -1012,8 +935,7 @@ class OldBibleDB(QtCore.QObject, Manager): def __init__(self, parent, **kwargs): """ - The constructor loads up the database and creates and initialises the - tables if the database doesn't exist. + The constructor loads up the database and creates and initialises the tables if the database doesn't exist. **Required keyword arguments:** @@ -1021,8 +943,7 @@ class OldBibleDB(QtCore.QObject, Manager): The path to the bible database file. ``name`` - The name of the database. This is also used as the file name for - SQLite databases. + The name of the database. This is also used as the file name for SQLite databases. """ log.info('OldBibleDB loaded') QtCore.QObject.__init__(self) @@ -1040,8 +961,8 @@ class OldBibleDB(QtCore.QObject, Manager): Return the cursor object. Instantiate one if it doesn't exist yet. """ if self.cursor is None: - filepath = os.path.join(self.path, self.file) - self.connection = sqlite3.connect(filepath) + file_path = os.path.join(self.path, self.file) + self.connection = sqlite3.connect(file_path) self.cursor = self.connection.cursor() return self.cursor @@ -1049,11 +970,8 @@ class OldBibleDB(QtCore.QObject, Manager): """ Run an SQL query on the database, returning the results. - ``query`` - The actual SQL query to run. - - ``parameters`` - Any variable parameters to add to the query. + :param query: The actual SQL query to run. + :param parameters: Any variable parameters to add to the query. """ cursor = self.get_cursor() cursor.execute(query, parameters) @@ -1092,9 +1010,9 @@ class OldBibleDB(QtCore.QObject, Manager): """ if not isinstance(name, str): name = str(name) - books = self.run_sql('SELECT id, testament_id, name, ' - 'abbreviation FROM book WHERE LOWER(name) = ? OR ' - 'LOWER(abbreviation) = ?', (name.lower(), name.lower())) + books = self.run_sql( + 'SELECT id, testament_id, name, abbreviation FROM book WHERE LOWER(name) = ? OR ' + 'LOWER(abbreviation) = ?', (name.lower(), name.lower())) if books: return { 'id': books[0][0], @@ -1122,8 +1040,8 @@ class OldBibleDB(QtCore.QObject, Manager): """ Returns the verses of the Bible. """ - verses = self.run_sql('SELECT book_id, chapter, verse, text FROM ' - 'verse WHERE book_id = ? ORDER BY id', (book_id, )) + verses = self.run_sql( + 'SELECT book_id, chapter, verse, text FROM verse WHERE book_id = ? ORDER BY id', (book_id, )) if verses: return [{ 'book_id': int(verse[0]), diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 7dc3a372c..5f3692527 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -74,14 +74,9 @@ class BGExtract(object): """ Remove a particular element from the BeautifulSoup tree. - ``parent`` - The element from which items need to be removed. - - ``tag`` - A string of the tab type, e.g. "div" - - ``class_`` - An HTML class attribute for further qualification. + :param parent: The element from which items need to be removed. + :param tag: A string of the tab type, e.g. "div" + :param class_: An HTML class attribute for further qualification. """ if class_: all_tags = parent.find_all(tag, class_) @@ -94,8 +89,7 @@ class BGExtract(object): """ Extract a verse (or part of a verse) from a tag. - ``tag`` - The BeautifulSoup Tag element with the stuff we want. + :param tag: The BeautifulSoup Tag element with the stuff we want. """ if isinstance(tag, NavigableString): return None, str(tag) @@ -122,8 +116,7 @@ class BGExtract(object): """ Remove all the rubbish from the HTML page. - ``tag`` - The base tag within which we want to remove stuff. + :param tag: The base tag within which we want to remove stuff. """ self._remove_elements(tag, 'sup', 'crossreference') self._remove_elements(tag, 'sup', 'footnote') @@ -137,8 +130,7 @@ class BGExtract(object): """ Extract all the verses from a pre-prepared list of HTML tags. - ``tags`` - A list of BeautifulSoup Tag elements. + :param tags: A list of BeautifulSoup Tag elements. """ verses = [] tags = tags[::-1] @@ -184,8 +176,7 @@ class BGExtract(object): Use the old style of parsing for those Bibles on BG who mysteriously have not been migrated to the new (still broken) HTML. - ``div`` - The parent div. + :param div: The parent div. """ verse_list = {} # Cater for inconsistent mark up in the first verse of a chapter. @@ -225,14 +216,9 @@ class BGExtract(object): """ Access and decode Bibles via the BibleGateway website. - ``version`` - The version of the Bible like 31 for New International version. - - ``book_name`` - Name of the Book. - - ``chapter`` - Chapter number. + :param version: The version of the Bible like 31 for New International version. + :param book_name: Name of the Book. + :param chapter: Chapter number. """ log.debug('BGExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) url_book_name = urllib.parse.quote(book_name.encode("utf-8")) @@ -259,10 +245,9 @@ class BGExtract(object): def get_books_from_http(self, version): """ - Load a list of all books a Bible contaions from BibleGateway website. + Load a list of all books a Bible contains from BibleGateway website. - ``version`` - The version of the Bible like NIV for New International Version + :param version: The version of the Bible like NIV for New International Version """ log.debug('BGExtract.get_books_from_http("%s")', version) url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '%s' % version}) @@ -328,14 +313,9 @@ class BSExtract(object): """ Access and decode bibles via Bibleserver mobile website - ``version`` - The version of the bible like NIV for New International Version - - ``book_name`` - Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung - - ``chapter`` - Chapter number + :param version: The version of the bible like NIV for New International Version + :param book_name: Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung + :param chapter: Chapter number """ log.debug('BSExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) url_version = urllib.parse.quote(version.encode("utf-8")) @@ -363,12 +343,11 @@ class BSExtract(object): """ Load a list of all books a Bible contains from Bibleserver mobile website. - ``version`` - The version of the Bible like NIV for New International Version + :param version: The version of the Bible like NIV for New International Version """ log.debug('BSExtract.get_books_from_http("%s")', version) url_version = urllib.parse.quote(version.encode("utf-8")) - chapter_url = 'http://m.bibleserver.com/overlay/selectBook?translation=%s' % (url_version) + chapter_url = 'http://m.bibleserver.com/overlay/selectBook?translation=%s' % url_version soup = get_soup_for_bible_ref(chapter_url) if not soup: return None @@ -408,14 +387,9 @@ class CWExtract(object): """ Access and decode bibles via the Crosswalk website - ``version`` - The version of the Bible like niv for New International Version - - ``book_name`` - Text name of in english e.g. 'gen' for Genesis - - ``chapter`` - Chapter number + :param version: The version of the Bible like niv for New International Version + :param book_name: Text name of in english e.g. 'gen' for Genesis + :param chapter: Chapter number """ log.debug('CWExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) url_book_name = book_name.replace(' ', '-') @@ -463,11 +437,10 @@ class CWExtract(object): """ Load a list of all books a Bible contain from the Crosswalk website. - ``version`` - The version of the bible like NIV for New International Version + :param version: The version of the bible like NIV for New International Version """ log.debug('CWExtract.get_books_from_http("%s")', version) - chapter_url = 'http://www.biblestudytools.com/%s/' % (version) + chapter_url = 'http://www.biblestudytools.com/%s/' % version soup = get_soup_for_bible_ref(chapter_url) if not soup: return None @@ -533,7 +506,8 @@ class HTTPBible(BibleDB): failure. """ self.wizard.progress_bar.setMaximum(68) - self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', 'Registering Bible and loading books...')) + self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', + 'Registering Bible and loading books...')) self.save_meta('download_source', self.download_source) self.save_meta('download_name', self.download_name) if self.proxy_server: @@ -552,8 +526,8 @@ class HTTPBible(BibleDB): handler = BSExtract(self.proxy_server) books = handler.get_books_from_http(self.download_name) if not books: - log.error('Importing books from %s - download name: "%s" '\ - 'failed' % (self.download_source, self.download_name)) + log.error('Importing books from %s - download name: "%s" failed' % + (self.download_source, self.download_name)) return False self.wizard.progress_bar.setMaximum(len(books) + 2) self.wizard.increment_progress_bar(translate( 'BiblesPlugin.HTTPBible', 'Registering Language...')) @@ -573,12 +547,12 @@ class HTTPBible(BibleDB): 'BiblesPlugin.HTTPBible', 'Importing %s...', 'Importing ...') % book) book_ref_id = self.get_book_ref_id_by_name(book, len(books), language_id) if not book_ref_id: - log.error('Importing books from %s - download name: "%s" '\ - 'failed' % (self.download_source, self.download_name)) + log.error('Importing books from %s - download name: "%s" failed' % + (self.download_source, self.download_name)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) log.debug('Book details: Name:%s; id:%s; testament_id:%s', - book, book_ref_id, book_details['testament_id']) + book, book_ref_id, book_details['testament_id']) self.create_book(book, book_ref_id, book_details['testament_id']) if self.stop_import_flag: return False @@ -612,7 +586,7 @@ class HTTPBible(BibleDB): critical_error_message_box( translate('BiblesPlugin', 'No Book Found'), translate('BiblesPlugin', 'No matching book could be found in this Bible. Check that you have ' - 'spelled the name of the book correctly.')) + 'spelled the name of the book correctly.')) return [] book = db_book.name if BibleDB.get_verse_count(self, book_id, reference[1]) == 0: @@ -658,8 +632,7 @@ class HTTPBible(BibleDB): """ Return the number of chapters in a particular book. - ``book`` - The book object to get the chapter count for. + :param book: The book object to get the chapter count for. """ log.debug('HTTPBible.get_chapter_count("%s")', book.name) return BiblesResourcesDB.get_chapter_count(book.book_reference_id) @@ -668,11 +641,8 @@ class HTTPBible(BibleDB): """ Return the number of verses for the specified chapter and book. - ``book`` - The name of the book. - - ``chapter`` - The chapter whose verses are being counted. + :param book_id: The name of the book. + :param chapter: The chapter whose verses are being counted. """ log.debug('HTTPBible.get_verse_count("%s", %s)', book_id, chapter) return BiblesResourcesDB.get_verse_count(book_id, chapter) @@ -696,18 +666,11 @@ def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, pre """ Gets a webpage and returns a parsed and optionally cleaned soup or None. - ``reference_url`` - The URL to obtain the soup from. - - ``header`` - An optional HTTP header to pass to the bible web server. - - ``pre_parse_regex`` - A regular expression to run on the webpage. Allows manipulation of the webpage before passing to BeautifulSoup - for parsing. - - ``pre_parse_substitute`` - The text to replace any matches to the regular expression with. + :param reference_url: The URL to obtain the soup from. + :param header: An optional HTTP header to pass to the bible web server. + :param pre_parse_regex: A regular expression to run on the webpage. Allows manipulation of the webpage before + passing to BeautifulSoup for parsing. + :param pre_parse_substitute: The text to replace any matches to the regular expression with. """ if not reference_url: return None @@ -742,9 +705,10 @@ def send_error_message(error_type): critical_error_message_box( translate('BiblesPlugin.HTTPBible', 'Download Error'), translate('BiblesPlugin.HTTPBible', 'There was a problem downloading your verse selection. Please check ' - 'your Internet connection, and if this error continues to occur please consider reporting a bug.')) + 'your Internet connection, and if this error continues to occur please consider reporting a bug' + '.')) elif error_type == 'parse': critical_error_message_box( translate('BiblesPlugin.HTTPBible', 'Parse Error'), translate('BiblesPlugin.HTTPBible', 'There was a problem extracting your verse selection. If this error ' - 'continues to occur please consider reporting a bug.')) + 'continues to occur please consider reporting a bug.')) diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 888677a8d..53bab5f6b 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -40,7 +40,6 @@ from .opensong import OpenSongBible from .osis import OSISBible - log = logging.getLogger(__name__) @@ -57,10 +56,9 @@ class BibleFormat(object): @staticmethod def get_class(format): """ - Return the appropriate imeplementation class. + Return the appropriate implementation class. - ``format`` - The Bible format. + :param format: The Bible format. """ if format == BibleFormat.OSIS: return OSISBible @@ -94,9 +92,8 @@ class BibleManager(object): def __init__(self, parent): """ - Finds all the bibles defined for the system and creates an interface - object for each bible containing connection information. Throws - Exception if no Bibles are found. + Finds all the bibles defined for the system and creates an interface object for each bible containing + connection information. Throws Exception if no Bibles are found. Init confirms the bible exists and stores the database path. """ @@ -114,9 +111,8 @@ class BibleManager(object): def reload_bibles(self): """ - Reloads the Bibles from the available Bible databases on disk. If a web - Bible is encountered, an instance of HTTPBible is loaded instead of the - BibleDB class. + Reloads the Bibles from the available Bible databases on disk. If a web Bible is encountered, an instance + of HTTPBible is loaded instead of the BibleDB class. """ log.debug('Reload bibles') files = AppLocation.get_files(self.settings_section, self.suffix) @@ -146,7 +142,7 @@ class BibleManager(object): download_name = self.db_cache[name].get_object(BibleMeta, 'download_name').value meta_proxy = self.db_cache[name].get_object(BibleMeta, 'proxy_server') web_bible = HTTPBible(self.parent, path=self.path, file=filename, download_source=source.value, - download_name=download_name) + download_name=download_name) if meta_proxy: web_bible.proxy_server = meta_proxy.value self.db_cache[name] = web_bible @@ -156,8 +152,7 @@ class BibleManager(object): """ Sets the reference to the dialog with the progress bar on it. - ``dialog`` - The reference to the import wizard. + :param wizard: The reference to the import wizard. """ self.import_wizard = wizard @@ -165,11 +160,8 @@ class BibleManager(object): """ Register a bible in the bible cache, and then import the verses. - ``type`` - What type of Bible, one of the ``BibleFormat`` values. - - ``**kwargs`` - Keyword arguments to send to the actual importer class. + :param type: What type of Bible, one of the ``BibleFormat`` values. + :param kwargs: Keyword arguments to send to the actual importer class. """ class_ = BibleFormat.get_class(type) kwargs['path'] = self.path @@ -182,8 +174,7 @@ class BibleManager(object): """ Delete a bible completely. - ``name`` - The name of the bible. + :param name: The name of the bible. """ log.debug('BibleManager.delete_bible("%s")', name) bible = self.db_cache[name] @@ -202,8 +193,7 @@ class BibleManager(object): """ Returns a list of Bible books, and the number of chapters in that book. - ``bible`` - Unicode. The Bible to get the list of books from. + :param bible: Unicode. The Bible to get the list of books from. """ log.debug('BibleManager.get_books("%s")', bible) return [ @@ -219,11 +209,8 @@ class BibleManager(object): """ Returns a book object by given id. - ``bible`` - Unicode. The Bible to get the list of books from. - - ``id`` - Unicode. The book_reference_id to get the book for. + :param bible: Unicode. The Bible to get the list of books from. + :param id: Unicode. The book_reference_id to get the book for. """ log.debug('BibleManager.get_book_by_id("%s", "%s")', bible, id) return self.db_cache[bible].get_book_by_book_ref_id(id) @@ -232,22 +219,17 @@ class BibleManager(object): """ Returns the number of Chapters for a given book. - ``bible`` - Unicode. The Bible to get the list of books from. - - ``book`` - The book object to get the chapter count for. + :param bible: Unicode. The Bible to get the list of books from. + :param book: The book object to get the chapter count for. """ log.debug('BibleManager.get_book_chapter_count ("%s", "%s")', bible, book.name) return self.db_cache[bible].get_chapter_count(book) def get_verse_count(self, bible, book, chapter): """ - Returns all the number of verses for a given - book and chapterMaxBibleBookVerses. + Returns all the number of verses for a given book and chapterMaxBibleBookVerses. """ - log.debug('BibleManager.get_verse_count("%s", "%s", %s)', - bible, book, chapter) + log.debug('BibleManager.get_verse_count("%s", "%s", %s)', bible, book, chapter) language_selection = self.get_language_selection(bible) book_ref_id = self.db_cache[bible].get_book_ref_id_by_localised_name(book, language_selection) return self.db_cache[bible].get_verse_count(book_ref_id, chapter) @@ -260,16 +242,14 @@ class BibleManager(object): log.debug('BibleManager.get_verse_count_by_book_ref_id("%s", "%s", "%s")', bible, book_ref_id, chapter) return self.db_cache[bible].get_verse_count(book_ref_id, chapter) - def get_verses(self, bible, versetext, book_ref_id=False, show_error=True): + def get_verses(self, bible, verse_text, book_ref_id=False, show_error=True): """ Parses a scripture reference, fetches the verses from the Bible specified, and returns a list of ``Verse`` objects. - ``bible`` - Unicode. The Bible to use. - - ``versetext`` - Unicode. The scripture reference. Valid scripture references are: + :param bible: Unicode. The Bible to use. + :param verse_text: + Unicode. The scripture reference. Valid scripture references are: - Genesis 1 - Genesis 1-2 @@ -279,55 +259,53 @@ class BibleManager(object): - Genesis 1:1-2:10 - Genesis 1:1-10,2:1-10 - ``book_ref_id`` - Unicode. The book referece id from the book in versetext. + :param book_ref_id: Unicode. The book reference id from the book in verse_text. For second bible this is necessary. + :param show_error: """ - log.debug('BibleManager.get_verses("%s", "%s")', bible, versetext) + log.debug('BibleManager.get_verses("%s", "%s")', bible, verse_text) if not bible: if show_error: self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'No Bibles Available'), - translate('BiblesPlugin.BibleManager', - 'There are no Bibles currently installed. Please use the ' - 'Import Wizard to install one or more Bibles.') - ) + translate('BiblesPlugin.BibleManager', 'There are no Bibles currently installed. Please use the ' + 'Import Wizard to install one or more Bibles.') + ) return None language_selection = self.get_language_selection(bible) - reflist = parse_reference(versetext, self.db_cache[bible], - language_selection, book_ref_id) - if reflist: - return self.db_cache[bible].get_verses(reflist, show_error) + ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id) + if ref_list: + return self.db_cache[bible].get_verses(ref_list, show_error) else: if show_error: - reference_seperators = { + reference_separators = { 'verse': get_reference_separator('sep_v_display'), 'range': get_reference_separator('sep_r_display'), 'list': get_reference_separator('sep_l_display')} self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'), translate('BiblesPlugin.BibleManager', 'Your scripture reference is either not supported by ' - 'OpenLP or is invalid. Please make sure your reference ' - 'conforms to one of the following patterns or consult the manual:\n\n' - 'Book Chapter\n' - 'Book Chapter%(range)sChapter\n' - 'Book Chapter%(verse)sVerse%(range)sVerse\n' - 'Book Chapter%(verse)sVerse%(range)sVerse%(list)sVerse' - '%(range)sVerse\n' - 'Book Chapter%(verse)sVerse%(range)sVerse%(list)sChapter' - '%(verse)sVerse%(range)sVerse\n' - 'Book Chapter%(verse)sVerse%(range)sChapter%(verse)sVerse', - 'Please pay attention to the appended "s" of the wildcards ' - 'and refrain from translating the words inside the names in the brackets.') % reference_seperators - ) + 'OpenLP or is invalid. Please make sure your reference ' + 'conforms to one of the following patterns or consult the manual:\n\n' + 'Book Chapter\n' + 'Book Chapter%(range)sChapter\n' + 'Book Chapter%(verse)sVerse%(range)sVerse\n' + 'Book Chapter%(verse)sVerse%(range)sVerse%(list)sVerse' + '%(range)sVerse\n' + 'Book Chapter%(verse)sVerse%(range)sVerse%(list)sChapter' + '%(verse)sVerse%(range)sVerse\n' + 'Book Chapter%(verse)sVerse%(range)sChapter%(verse)sVerse', + 'Please pay attention to the appended "s" of the wildcards ' + 'and refrain from translating the words inside the names in the brackets.') + % reference_separators + ) return None def get_language_selection(self, bible): """ Returns the language selection of a bible. - ``bible`` - Unicode. The Bible to get the language selection from. + :param bible: Unicode. The Bible to get the language selection from. """ log.debug('BibleManager.get_language_selection("%s")', bible) language_selection = self.get_meta_data(bible, 'book_name_language') @@ -347,34 +325,29 @@ class BibleManager(object): """ Does a verse search for the given bible and text. - ``bible`` - The bible to search in (unicode). - - ``second_bible`` - The second bible (unicode). We do not search in this bible. - - ``text`` - The text to search for (unicode). + :param bible: The bible to search in (unicode). + :param second_bible: The second bible (unicode). We do not search in this bible. + :param text: The text to search for (unicode). """ log.debug('BibleManager.verse_search("%s", "%s")', bible, text) if not bible: self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'No Bibles Available'), translate('BiblesPlugin.BibleManager', - 'There are no Bibles currently installed. Please use the Import Wizard to install one or more' - ' Bibles.') - ) + 'There are no Bibles currently installed. Please use the Import Wizard to install one or ' + 'more Bibles.') + ) return None # Check if the bible or second_bible is a web bible. - webbible = self.db_cache[bible].get_object(BibleMeta, 'download_source') - second_webbible = '' + web_bible = self.db_cache[bible].get_object(BibleMeta, 'download_source') + second_web_bible = '' if second_bible: - second_webbible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source') - if webbible or second_webbible: + second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source') + if web_bible or second_web_bible: self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used'), translate('BiblesPlugin.BibleManager', 'Text Search is not available with Web Bibles.') - ) + ) return None if text: return self.db_cache[bible].verse_search(text) @@ -382,23 +355,20 @@ class BibleManager(object): self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'), translate('BiblesPlugin.BibleManager', 'You did not enter a search keyword.\nYou can separate ' - 'different keywords by a space to search for all of your keywords and you can separate ' - 'them by a comma to search for one of them.') - ) + 'different keywords by a space to search for all of your keywords and you can separate ' + 'them by a comma to search for one of them.') + ) return None - def save_meta_data(self, bible, version, copyright, permissions, - book_name_language=None): + def save_meta_data(self, bible, version, copyright, permissions, book_name_language=None): """ Saves the bibles meta data. """ - log.debug('save_meta data %s, %s, %s, %s', - bible, version, copyright, permissions) + log.debug('save_meta data %s, %s, %s, %s', bible, version, copyright, permissions) self.db_cache[bible].save_meta('name', version) self.db_cache[bible].save_meta('copyright', copyright) self.db_cache[bible].save_meta('permissions', permissions) - self.db_cache[bible].save_meta('book_name_language', - book_name_language) + self.db_cache[bible].save_meta('book_name_language', book_name_language) def get_meta_data(self, bible, key): """ diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 1817ac240..0bdd8aae6 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -86,19 +86,19 @@ class BibleMediaItem(MediaManagerItem): if not bitem.flags() & QtCore.Qt.ItemIsSelectable: # The item is the "No Search Results" item. self.list_view.clear() - self.displayResults(bible, second_bible) + self.display_results(bible, second_bible) return else: item_second_bible = self._decode_qt_object(bitem, 'second_bible') if item_second_bible and second_bible or not item_second_bible and not second_bible: - self.displayResults(bible, second_bible) + self.display_results(bible, second_bible) elif critical_error_message_box( message=translate('BiblesPlugin.MediaItem', - 'You cannot combine single and dual Bible verse search results. ' - 'Do you want to delete your search results and start a new search?'), - parent=self, question=True) == QtGui.QMessageBox.Yes: + 'You cannot combine single and dual Bible verse search results. ' + 'Do you want to delete your search results and start a new search?'), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.list_view.clear() - self.displayResults(bible, second_bible) + self.display_results(bible, second_bible) def _decode_qt_object(self, bitem, key): reference = bitem.data(QtCore.Qt.UserRole) @@ -116,8 +116,8 @@ class BibleMediaItem(MediaManagerItem): self.has_delete_icon = True self.add_to_service_item = False - def addSearchTab(self, prefix, name): - self.searchTabBar.addTab(name) + def add_search_tab(self, prefix, name): + self.search_tab_bar.addTab(name) tab = QtGui.QWidget() tab.setObjectName(prefix + 'Tab') tab.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) @@ -126,15 +126,12 @@ class BibleMediaItem(MediaManagerItem): setattr(self, prefix + 'Tab', tab) setattr(self, prefix + 'Layout', layout) - def addSearchFields(self, prefix, name): + def add_search_fields(self, prefix, name): """ Creates and adds generic search tab. - ``prefix`` - The prefix of the tab, this is either ``quick`` or ``advanced``. - - ``name`` - The translated string to display. + :param prefix: The prefix of the tab, this is either ``quick`` or ``advanced``. + :param name: The translated string to display. """ if prefix == 'quick': idx = 2 @@ -142,124 +139,126 @@ class BibleMediaItem(MediaManagerItem): idx = 5 tab = getattr(self, prefix + 'Tab') layout = getattr(self, prefix + 'Layout') - versionLabel = QtGui.QLabel(tab) - versionLabel.setObjectName(prefix + 'VersionLabel') - layout.addWidget(versionLabel, idx, 0, QtCore.Qt.AlignRight) - versionComboBox = create_horizontal_adjusting_combo_box(tab, prefix + 'VersionComboBox') - versionLabel.setBuddy(versionComboBox) - layout.addWidget(versionComboBox, idx, 1, 1, 2) - secondLabel = QtGui.QLabel(tab) - secondLabel.setObjectName(prefix + 'SecondLabel') - layout.addWidget(secondLabel, idx + 1, 0, QtCore.Qt.AlignRight) - secondComboBox = create_horizontal_adjusting_combo_box(tab, prefix + 'SecondComboBox') - versionLabel.setBuddy(secondComboBox) - layout.addWidget(secondComboBox, idx + 1, 1, 1, 2) - styleLabel = QtGui.QLabel(tab) - styleLabel.setObjectName(prefix + 'StyleLabel') - layout.addWidget(styleLabel, idx + 2, 0, QtCore.Qt.AlignRight) - styleComboBox = create_horizontal_adjusting_combo_box(tab, prefix + 'StyleComboBox') - styleComboBox.addItems(['', '', '']) - layout.addWidget(styleComboBox, idx + 2, 1, 1, 2) + version_label = QtGui.QLabel(tab) + version_label.setObjectName(prefix + 'VersionLabel') + layout.addWidget(version_label, idx, 0, QtCore.Qt.AlignRight) + version_combo_box = create_horizontal_adjusting_combo_box(tab, prefix + 'VersionComboBox') + version_label.setBuddy(version_combo_box) + layout.addWidget(version_combo_box, idx, 1, 1, 2) + second_label = QtGui.QLabel(tab) + second_label.setObjectName(prefix + 'SecondLabel') + layout.addWidget(second_label, idx + 1, 0, QtCore.Qt.AlignRight) + second_combo_box = create_horizontal_adjusting_combo_box(tab, prefix + 'SecondComboBox') + version_label.setBuddy(second_combo_box) + layout.addWidget(second_combo_box, idx + 1, 1, 1, 2) + style_label = QtGui.QLabel(tab) + style_label.setObjectName(prefix + 'StyleLabel') + layout.addWidget(style_label, idx + 2, 0, QtCore.Qt.AlignRight) + style_combo_box = create_horizontal_adjusting_combo_box(tab, prefix + 'StyleComboBox') + style_combo_box.addItems(['', '', '']) + layout.addWidget(style_combo_box, idx + 2, 1, 1, 2) search_button_layout = QtGui.QHBoxLayout() search_button_layout.setObjectName(prefix + 'search_button_layout') search_button_layout.addStretch() - lockButton = QtGui.QToolButton(tab) - lockButton.setIcon(self.unlock_icon) - lockButton.setCheckable(True) - lockButton.setObjectName(prefix + 'LockButton') - search_button_layout.addWidget(lockButton) - searchButton = QtGui.QPushButton(tab) - searchButton.setObjectName(prefix + 'SearchButton') - search_button_layout.addWidget(searchButton) + lock_button = QtGui.QToolButton(tab) + lock_button.setIcon(self.unlock_icon) + lock_button.setCheckable(True) + lock_button.setObjectName(prefix + 'LockButton') + search_button_layout.addWidget(lock_button) + search_button = QtGui.QPushButton(tab) + search_button.setObjectName(prefix + 'SearchButton') + search_button_layout.addWidget(search_button) layout.addLayout(search_button_layout, idx + 3, 1, 1, 2) self.page_layout.addWidget(tab) tab.setVisible(False) - lockButton.toggled.connect(self.onLockButtonToggled) - setattr(self, prefix + 'VersionLabel', versionLabel) - setattr(self, prefix + 'VersionComboBox', versionComboBox) - setattr(self, prefix + 'SecondLabel', secondLabel) - setattr(self, prefix + 'SecondComboBox', secondComboBox) - setattr(self, prefix + 'StyleLabel', styleLabel) - setattr(self, prefix + 'StyleComboBox', styleComboBox) - setattr(self, prefix + 'LockButton', lockButton) + lock_button.toggled.connect(self.on_lock_button_toggled) + setattr(self, prefix + 'VersionLabel', version_label) + setattr(self, prefix + 'VersionComboBox', version_combo_box) + setattr(self, prefix + 'SecondLabel', second_label) + setattr(self, prefix + 'SecondComboBox', second_combo_box) + setattr(self, prefix + 'StyleLabel', style_label) + setattr(self, prefix + 'StyleComboBox', style_combo_box) + setattr(self, prefix + 'LockButton', lock_button) setattr(self, prefix + 'SearchButtonLayout', search_button_layout) - setattr(self, prefix + 'SearchButton', searchButton) + setattr(self, prefix + 'SearchButton', search_button) def add_end_header_bar(self): - self.searchTabBar = QtGui.QTabBar(self) - self.searchTabBar.setExpanding(False) - self.searchTabBar.setObjectName('searchTabBar') - self.page_layout.addWidget(self.searchTabBar) + self.search_tab_bar = QtGui.QTabBar(self) + self.search_tab_bar.setExpanding(False) + self.search_tab_bar.setObjectName('search_tab_bar') + self.page_layout.addWidget(self.search_tab_bar) # Add the Quick Search tab. - self.addSearchTab('quick', translate('BiblesPlugin.MediaItem', 'Quick')) - self.quickSearchLabel = QtGui.QLabel(self.quickTab) - self.quickSearchLabel.setObjectName('quickSearchLabel') - self.quickLayout.addWidget(self.quickSearchLabel, 0, 0, QtCore.Qt.AlignRight) - self.quickSearchEdit = SearchEdit(self.quickTab) - self.quickSearchEdit.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Fixed) - self.quickSearchEdit.setObjectName('quickSearchEdit') - self.quickSearchLabel.setBuddy(self.quickSearchEdit) - self.quickLayout.addWidget(self.quickSearchEdit, 0, 1, 1, 2) - self.addSearchFields('quick', translate('BiblesPlugin.MediaItem', 'Quick')) + self.add_search_tab('quick', translate('BiblesPlugin.MediaItem', 'Quick')) + self.quick_search_label = QtGui.QLabel(self.quickTab) + self.quick_search_label.setObjectName('quick_search_label') + self.quickLayout.addWidget(self.quick_search_label, 0, 0, QtCore.Qt.AlignRight) + self.quick_search_edit = SearchEdit(self.quickTab) + self.quick_search_edit.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Fixed) + self.quick_search_edit.setObjectName('quick_search_edit') + self.quick_search_label.setBuddy(self.quick_search_edit) + self.quickLayout.addWidget(self.quick_search_edit, 0, 1, 1, 2) + self.add_search_fields('quick', translate('BiblesPlugin.MediaItem', 'Quick')) self.quickTab.setVisible(True) # Add the Advanced Search tab. - self.addSearchTab('advanced', UiStrings().Advanced) - self.advancedBookLabel = QtGui.QLabel(self.advancedTab) - self.advancedBookLabel.setObjectName('advancedBookLabel') - self.advancedLayout.addWidget(self.advancedBookLabel, 0, 0, QtCore.Qt.AlignRight) - self.advancedBookComboBox = create_horizontal_adjusting_combo_box(self.advancedTab, 'advancedBookComboBox') - self.advancedBookLabel.setBuddy(self.advancedBookComboBox) - self.advancedLayout.addWidget(self.advancedBookComboBox, 0, 1, 1, 2) - self.advancedChapterLabel = QtGui.QLabel(self.advancedTab) - self.advancedChapterLabel.setObjectName('advancedChapterLabel') - self.advancedLayout.addWidget(self.advancedChapterLabel, 1, 1, 1, 2) - self.advancedVerseLabel = QtGui.QLabel(self.advancedTab) - self.advancedVerseLabel.setObjectName('advancedVerseLabel') - self.advancedLayout.addWidget(self.advancedVerseLabel, 1, 2) - self.advancedFromLabel = QtGui.QLabel(self.advancedTab) - self.advancedFromLabel.setObjectName('advancedFromLabel') - self.advancedLayout.addWidget(self.advancedFromLabel, 3, 0, QtCore.Qt.AlignRight) - self.advancedFromChapter = QtGui.QComboBox(self.advancedTab) - self.advancedFromChapter.setObjectName('advancedFromChapter') - self.advancedLayout.addWidget(self.advancedFromChapter, 3, 1) - self.advancedFromVerse = QtGui.QComboBox(self.advancedTab) - self.advancedFromVerse.setObjectName('advancedFromVerse') - self.advancedLayout.addWidget(self.advancedFromVerse, 3, 2) - self.advancedToLabel = QtGui.QLabel(self.advancedTab) - self.advancedToLabel.setObjectName('advancedToLabel') - self.advancedLayout.addWidget(self.advancedToLabel, 4, 0, QtCore.Qt.AlignRight) - self.advancedToChapter = QtGui.QComboBox(self.advancedTab) - self.advancedToChapter.setObjectName('advancedToChapter') - self.advancedLayout.addWidget(self.advancedToChapter, 4, 1) - self.advancedToVerse = QtGui.QComboBox(self.advancedTab) - self.advancedToVerse.setObjectName('advancedToVerse') - self.advancedLayout.addWidget(self.advancedToVerse, 4, 2) - self.addSearchFields('advanced', UiStrings().Advanced) + self.add_search_tab('advanced', UiStrings().Advanced) + self.advanced_book_label = QtGui.QLabel(self.advancedTab) + self.advanced_book_label.setObjectName('advanced_book_label') + self.advancedLayout.addWidget(self.advanced_book_label, 0, 0, QtCore.Qt.AlignRight) + self.advanced_book_combo_box = create_horizontal_adjusting_combo_box(self.advancedTab, + 'advanced_book_combo_box') + self.advanced_book_label.setBuddy(self.advanced_book_combo_box) + self.advancedLayout.addWidget(self.advanced_book_combo_box, 0, 1, 1, 2) + self.advanced_chapter_label = QtGui.QLabel(self.advancedTab) + self.advanced_chapter_label.setObjectName('advanced_chapter_label') + self.advancedLayout.addWidget(self.advanced_chapter_label, 1, 1, 1, 2) + self.advanced_verse_label = QtGui.QLabel(self.advancedTab) + self.advanced_verse_label.setObjectName('advanced_verse_label') + self.advancedLayout.addWidget(self.advanced_verse_label, 1, 2) + self.advanced_from_label = QtGui.QLabel(self.advancedTab) + self.advanced_from_label.setObjectName('advanced_from_label') + self.advancedLayout.addWidget(self.advanced_from_label, 3, 0, QtCore.Qt.AlignRight) + self.advanced_from_chapter = QtGui.QComboBox(self.advancedTab) + self.advanced_from_chapter.setObjectName('advanced_from_chapter') + self.advancedLayout.addWidget(self.advanced_from_chapter, 3, 1) + self.advanced_from_verse = QtGui.QComboBox(self.advancedTab) + self.advanced_from_verse.setObjectName('advanced_from_verse') + self.advancedLayout.addWidget(self.advanced_from_verse, 3, 2) + self.advanced_to_label = QtGui.QLabel(self.advancedTab) + self.advanced_to_label.setObjectName('advanced_to_label') + self.advancedLayout.addWidget(self.advanced_to_label, 4, 0, QtCore.Qt.AlignRight) + self.advanced_to_chapter = QtGui.QComboBox(self.advancedTab) + self.advanced_to_chapter.setObjectName('advanced_to_chapter') + self.advancedLayout.addWidget(self.advanced_to_chapter, 4, 1) + self.advanced_to_verse = QtGui.QComboBox(self.advancedTab) + self.advanced_to_verse.setObjectName('advanced_to_verse') + self.advancedLayout.addWidget(self.advanced_to_verse, 4, 2) + self.add_search_fields('advanced', UiStrings().Advanced) # Combo Boxes - self.quickVersionComboBox.activated.connect(self.updateAutoCompleter) - self.quickSecondComboBox.activated.connect(self.updateAutoCompleter) - self.advancedVersionComboBox.activated.connect(self.onAdvancedVersionComboBox) - self.advancedSecondComboBox.activated.connect(self.onAdvancedSecondComboBox) - self.advancedBookComboBox.activated.connect(self.onAdvancedBookComboBox) - self.advancedFromChapter.activated.connect(self.onAdvancedFromChapter) - self.advancedFromVerse.activated.connect(self.onAdvancedFromVerse) - self.advancedToChapter.activated.connect(self.onAdvancedToChapter) - QtCore.QObject.connect(self.quickSearchEdit, QtCore.SIGNAL('searchTypeChanged(int)'), self.updateAutoCompleter) - self.quickVersionComboBox.activated.connect(self.updateAutoCompleter) - self.quickStyleComboBox.activated.connect(self.onQuickStyleComboBoxChanged) - self.advancedStyleComboBox.activated.connect(self.onAdvancedStyleComboBoxChanged) + self.quickVersionComboBox.activated.connect(self.update_auto_completer) + self.quickSecondComboBox.activated.connect(self.update_auto_completer) + self.advancedVersionComboBox.activated.connect(self.on_advanced_version_combo_box) + self.advancedSecondComboBox.activated.connect(self.on_advanced_second_combo_box) + self.advanced_book_combo_box.activated.connect(self.on_advanced_book_combo_box) + self.advanced_from_chapter.activated.connect(self.on_advanced_from_chapter) + self.advanced_from_verse.activated.connect(self.on_advanced_from_verse) + self.advanced_to_chapter.activated.connect(self.on_advanced_to_chapter) + QtCore.QObject.connect(self.quick_search_edit, QtCore.SIGNAL('searchTypeChanged(int)'), + self.update_auto_completer) + self.quickVersionComboBox.activated.connect(self.update_auto_completer) + self.quickStyleComboBox.activated.connect(self.on_quick_style_combo_box_changed) + self.advancedStyleComboBox.activated.connect(self.on_advanced_style_combo_box_changed) # Buttons - self.advancedSearchButton.clicked.connect(self.onAdvancedSearchButton) - self.quickSearchButton.clicked.connect(self.onQuickSearchButton) + self.advancedSearchButton.clicked.connect(self.on_advanced_search_button) + self.quickSearchButton.clicked.connect(self.on_quick_search_button) # Other stuff - self.quickSearchEdit.returnPressed.connect(self.onQuickSearchButton) - self.searchTabBar.currentChanged.connect(self.onSearchTabBarCurrentChanged) + self.quick_search_edit.returnPressed.connect(self.on_quick_search_button) + self.search_tab_bar.currentChanged.connect(self.on_search_tab_bar_current_changed) def on_focus(self): if self.quickTab.isVisible(): - self.quickSearchEdit.setFocus() + self.quick_search_edit.setFocus() else: - self.advancedBookComboBox.setFocus() + self.advanced_book_combo_box.setFocus() def config_update(self): log.debug('config_update') @@ -278,7 +277,7 @@ class BibleMediaItem(MediaManagerItem): def retranslateUi(self): log.debug('retranslateUi') - self.quickSearchLabel.setText(translate('BiblesPlugin.MediaItem', 'Find:')) + self.quick_search_label.setText(translate('BiblesPlugin.MediaItem', 'Find:')) self.quickVersionLabel.setText('%s:' % UiStrings().Version) self.quickSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:')) self.quickStyleLabel.setText(UiStrings().LayoutStyle) @@ -286,13 +285,13 @@ class BibleMediaItem(MediaManagerItem): self.quickStyleComboBox.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine) self.quickStyleComboBox.setItemText(LayoutStyle.Continuous, UiStrings().Continuous) self.quickLockButton.setToolTip(translate('BiblesPlugin.MediaItem', - 'Toggle to keep or clear the previous results.')) + 'Toggle to keep or clear the previous results.')) self.quickSearchButton.setText(UiStrings().Search) - self.advancedBookLabel.setText(translate('BiblesPlugin.MediaItem', 'Book:')) - self.advancedChapterLabel.setText(translate('BiblesPlugin.MediaItem', 'Chapter:')) - self.advancedVerseLabel.setText(translate('BiblesPlugin.MediaItem', 'Verse:')) - self.advancedFromLabel.setText(translate('BiblesPlugin.MediaItem', 'From:')) - self.advancedToLabel.setText(translate('BiblesPlugin.MediaItem', 'To:')) + self.advanced_book_label.setText(translate('BiblesPlugin.MediaItem', 'Book:')) + self.advanced_chapter_label.setText(translate('BiblesPlugin.MediaItem', 'Chapter:')) + self.advanced_verse_label.setText(translate('BiblesPlugin.MediaItem', 'Verse:')) + self.advanced_from_label.setText(translate('BiblesPlugin.MediaItem', 'From:')) + self.advanced_to_label.setText(translate('BiblesPlugin.MediaItem', 'To:')) self.advancedVersionLabel.setText('%s:' % UiStrings().Version) self.advancedSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:')) self.advancedStyleLabel.setText(UiStrings().LayoutStyle) @@ -300,14 +299,14 @@ class BibleMediaItem(MediaManagerItem): self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine) self.advancedStyleComboBox.setItemText(LayoutStyle.Continuous, UiStrings().Continuous) self.advancedLockButton.setToolTip(translate('BiblesPlugin.MediaItem', - 'Toggle to keep or clear the previous results.')) + 'Toggle to keep or clear the previous results.')) self.advancedSearchButton.setText(UiStrings().Search) def initialise(self): log.debug('bible manager initialise') self.plugin.manager.media = self - self.loadBibles() - self.quickSearchEdit.set_search_types([ + self.load_bibles() + self.quick_search_edit.set_search_types([ (BibleSearch.Reference, ':/bibles/bibles_search_reference.png', translate('BiblesPlugin.MediaItem', 'Scripture Reference'), translate('BiblesPlugin.MediaItem', 'Search Scripture Reference...')), @@ -315,11 +314,11 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'Text Search'), translate('BiblesPlugin.MediaItem', 'Search Text...')) ]) - self.quickSearchEdit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) + self.quick_search_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) self.config_update() log.debug('bible manager initialise complete') - def loadBibles(self): + def load_bibles(self): log.debug('Loading Bibles') self.quickVersionComboBox.clear() self.quickSecondComboBox.clear() @@ -340,80 +339,73 @@ class BibleMediaItem(MediaManagerItem): bible = Settings().value(self.settings_section + '/advanced bible') if bible in bibles: find_and_set_in_combo_box(self.advancedVersionComboBox, bible) - self.initialiseAdvancedBible(str(bible)) + self.initialise_advanced_bible(str(bible)) elif bibles: - self.initialiseAdvancedBible(bibles[0]) + self.initialise_advanced_bible(bibles[0]) bible = Settings().value(self.settings_section + '/quick bible') find_and_set_in_combo_box(self.quickVersionComboBox, bible) def reload_bibles(self, process=False): log.debug('Reloading Bibles') self.plugin.manager.reload_bibles() - self.loadBibles() + self.load_bibles() # If called from first time wizard re-run, process any new bibles. if process: self.plugin.app_startup() - self.updateAutoCompleter() + self.update_auto_completer() - def initialiseAdvancedBible(self, bible, last_book_id=None): + def initialise_advanced_bible(self, bible, last_book_id=None): """ - This initialises the given bible, which means that its book names and - their chapter numbers is added to the combo boxes on the - 'Advanced Search' Tab. This is not of any importance of the - 'Quick Search' Tab. + This initialises the given bible, which means that its book names and their chapter numbers is added to the + combo boxes on the 'Advanced Search' Tab. This is not of any importance of the 'Quick Search' Tab. - ``bible`` - The bible to initialise (unicode). - - ``last_book_id`` - The "book reference id" of the book which is choosen at the moment. + :param bible: The bible to initialise (unicode). + :param last_book_id: The "book reference id" of the book which is chosen at the moment. (int) """ - log.debug('initialiseAdvancedBible %s, %s', bible, last_book_id) + log.debug('initialise_advanced_bible %s, %s', bible, last_book_id) book_data = self.plugin.manager.get_books(bible) - secondbible = self.advancedSecondComboBox.currentText() - if secondbible != '': - secondbook_data = self.plugin.manager.get_books(secondbible) + second_bible = self.advancedSecondComboBox.currentText() + if second_bible != '': + second_book_data = self.plugin.manager.get_books(second_bible) book_data_temp = [] for book in book_data: - for secondbook in secondbook_data: - if book['book_reference_id'] == \ - secondbook['book_reference_id']: + for second_book in second_book_data: + if book['book_reference_id'] == second_book['book_reference_id']: book_data_temp.append(book) book_data = book_data_temp - self.advancedBookComboBox.clear() + self.advanced_book_combo_box.clear() first = True initialise_chapter_verse = False language_selection = self.plugin.manager.get_language_selection(bible) book_names = BibleStrings().BookNames for book in book_data: - row = self.advancedBookComboBox.count() + row = self.advanced_book_combo_box.count() if language_selection == LanguageSelection.Bible: - self.advancedBookComboBox.addItem(book['name']) + self.advanced_book_combo_box.addItem(book['name']) elif language_selection == LanguageSelection.Application: data = BiblesResourcesDB.get_book_by_id(book['book_reference_id']) - self.advancedBookComboBox.addItem(book_names[data['abbreviation']]) + self.advanced_book_combo_box.addItem(book_names[data['abbreviation']]) elif language_selection == LanguageSelection.English: data = BiblesResourcesDB.get_book_by_id(book['book_reference_id']) - self.advancedBookComboBox.addItem(data['name']) - self.advancedBookComboBox.setItemData(row, book['book_reference_id']) + self.advanced_book_combo_box.addItem(data['name']) + self.advanced_book_combo_box.setItemData(row, book['book_reference_id']) if first: first = False first_book = book initialise_chapter_verse = True if last_book_id and last_book_id == int(book['book_reference_id']): - index = self.advancedBookComboBox.findData(book['book_reference_id']) + index = self.advanced_book_combo_box.findData(book['book_reference_id']) if index == -1: # Not Found. index = 0 - self.advancedBookComboBox.setCurrentIndex(index) + self.advanced_book_combo_box.setCurrentIndex(index) initialise_chapter_verse = False if initialise_chapter_verse: - self.initialiseChapterVerse(bible, first_book['name'], - first_book['book_reference_id']) + self.initialise_chapter_verse(bible, first_book['name'], first_book['book_reference_id']) - def initialiseChapterVerse(self, bible, book, book_ref_id): - log.debug('initialiseChapterVerse %s, %s, %s', bible, book, book_ref_id) + def initialise_chapter_verse(self, bible, book, book_ref_id): + log.debug('initialise_chapter_verse %s, %s, %s', bible, book, book_ref_id) book = self.plugin.manager.get_book_by_id(bible, book_ref_id) self.chapter_count = self.plugin.manager.get_chapter_count(bible, book) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1) @@ -422,36 +414,36 @@ class BibleMediaItem(MediaManagerItem): critical_error_message_box(message=translate('BiblesPlugin.MediaItem', 'Bible not fully loaded.')) else: self.advancedSearchButton.setEnabled(True) - self.adjustComboBox(1, self.chapter_count, self.advancedFromChapter) - self.adjustComboBox(1, self.chapter_count, self.advancedToChapter) - self.adjustComboBox(1, verse_count, self.advancedFromVerse) - self.adjustComboBox(1, verse_count, self.advancedToVerse) + self.adjust_combo_box(1, self.chapter_count, self.advanced_from_chapter) + self.adjust_combo_box(1, self.chapter_count, self.advanced_to_chapter) + self.adjust_combo_box(1, verse_count, self.advanced_from_verse) + self.adjust_combo_box(1, verse_count, self.advanced_to_verse) - def updateAutoCompleter(self): + def update_auto_completer(self): """ This updates the bible book completion list for the search field. The completion depends on the bible. It is only updated when we are doing a reference search, otherwise the auto completion list is removed. """ - log.debug('updateAutoCompleter') + log.debug('update_auto_completer') # Save the current search type to the configuration. - Settings().setValue('%s/last search type' % self.settings_section, self.quickSearchEdit.current_search_type()) + Settings().setValue('%s/last search type' % self.settings_section, self.quick_search_edit.current_search_type()) # Save the current bible to the configuration. Settings().setValue(self.settings_section + '/quick bible', self.quickVersionComboBox.currentText()) books = [] # We have to do a 'Reference Search'. - if self.quickSearchEdit.current_search_type() == BibleSearch.Reference: + if self.quick_search_edit.current_search_type() == BibleSearch.Reference: bibles = self.plugin.manager.get_bibles() bible = self.quickVersionComboBox.currentText() if bible: book_data = bibles[bible].get_books() - secondbible = self.quickSecondComboBox.currentText() - if secondbible != '': - secondbook_data = bibles[secondbible].get_books() + second_bible = self.quickSecondComboBox.currentText() + if second_bible != '': + second_book_data = bibles[second_bible].get_books() book_data_temp = [] for book in book_data: - for secondbook in secondbook_data: - if book.book_reference_id == secondbook.book_reference_id: + for second_book in second_book_data: + if book.book_reference_id == second_book.book_reference_id: book_data_temp.append(book) book_data = book_data_temp language_selection = self.plugin.manager.get_language_selection(bible) @@ -467,7 +459,7 @@ class BibleMediaItem(MediaManagerItem): data = BiblesResourcesDB.get_book_by_id(book.book_reference_id) books.append(data['name'] + ' ') books.sort(key=get_locale_key) - set_case_insensitive_completer(books, self.quickSearchEdit) + set_case_insensitive_completer(books, self.quick_search_edit) def on_import_click(self): if not hasattr(self, 'import_wizard'): @@ -482,9 +474,9 @@ class BibleMediaItem(MediaManagerItem): elif self.advancedTab.isVisible(): bible = self.advancedVersionComboBox.currentText() if bible: - self.editBibleForm = EditBibleForm(self, self.main_window, self.plugin.manager) - self.editBibleForm.loadBible(bible) - if self.editBibleForm.exec_(): + self.edit_bible_form = EditBibleForm(self, self.main_window, self.plugin.manager) + self.edit_bible_form.loadBible(bible) + if self.edit_bible_form.exec_(): self.reload_bibles() def on_delete_click(self): @@ -493,117 +485,113 @@ class BibleMediaItem(MediaManagerItem): elif self.advancedTab.isVisible(): bible = self.advancedVersionComboBox.currentText() if bible: - if QtGui.QMessageBox.question(self, UiStrings().ConfirmDelete, - translate('BiblesPlugin.MediaItem', 'Are you sure you want to completely delete "%s" Bible from ' - 'OpenLP?\n\nYou will need to re-import this Bible to use it again.') % bible, + if QtGui.QMessageBox.question( + self, UiStrings().ConfirmDelete, + translate('BiblesPlugin.MediaItem', 'Are you sure you want to completely delete "%s" Bible from ' + 'OpenLP?\n\nYou will need to re-import this Bible to use it again.') % bible, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), - QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No: + QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No: return self.plugin.manager.delete_bible(bible) self.reload_bibles() - def onSearchTabBarCurrentChanged(self, index): + def on_search_tab_bar_current_changed(self, index): if index == 0: self.advancedTab.setVisible(False) self.quickTab.setVisible(True) - self.quickSearchEdit.setFocus() + self.quick_search_edit.setFocus() else: self.quickTab.setVisible(False) self.advancedTab.setVisible(True) - self.advancedBookComboBox.setFocus() + self.advanced_book_combo_box.setFocus() - def onLockButtonToggled(self, checked): + def on_lock_button_toggled(self, checked): if checked: self.sender().setIcon(self.lock_icon) else: self.sender().setIcon(self.unlock_icon) - def onQuickStyleComboBoxChanged(self): + def on_quick_style_combo_box_changed(self): self.settings.layout_style = self.quickStyleComboBox.currentIndex() self.advancedStyleComboBox.setCurrentIndex(self.settings.layout_style) self.settings.layout_style_combo_box.setCurrentIndex(self.settings.layout_style) Settings().setValue(self.settings_section + '/verse layout style', self.settings.layout_style) - def onAdvancedStyleComboBoxChanged(self): + def on_advanced_style_combo_box_changed(self): self.settings.layout_style = self.advancedStyleComboBox.currentIndex() self.quickStyleComboBox.setCurrentIndex(self.settings.layout_style) self.settings.layout_style_combo_box.setCurrentIndex(self.settings.layout_style) Settings().setValue(self.settings_section + '/verse layout style', self.settings.layout_style) - def onAdvancedVersionComboBox(self): + def on_advanced_version_combo_box(self): Settings().setValue(self.settings_section + '/advanced bible', self.advancedVersionComboBox.currentText()) - self.initialiseAdvancedBible(self.advancedVersionComboBox.currentText(), - self.advancedBookComboBox.itemData(int(self.advancedBookComboBox.currentIndex()))) - - def onAdvancedSecondComboBox(self): - self.initialiseAdvancedBible(self.advancedVersionComboBox.currentText(), - self.advancedBookComboBox.itemData(int(self.advancedBookComboBox.currentIndex()))) - - def onAdvancedBookComboBox(self): - item = int(self.advancedBookComboBox.currentIndex()) - self.initialiseChapterVerse( + self.initialise_advanced_bible( self.advancedVersionComboBox.currentText(), - self.advancedBookComboBox.currentText(), - self.advancedBookComboBox.itemData(item)) + self.advanced_book_combo_box.itemData(int(self.advanced_book_combo_box.currentIndex()))) - def onAdvancedFromVerse(self): - chapter_from = int(self.advancedFromChapter.currentText()) - chapter_to = int(self.advancedToChapter.currentText()) + def on_advanced_second_combo_box(self): + self.initialise_advanced_bible( + self.advancedVersionComboBox.currentText(), + self.advanced_book_combo_box.itemData(int(self.advanced_book_combo_box.currentIndex()))) + + def on_advanced_book_combo_box(self): + item = int(self.advanced_book_combo_box.currentIndex()) + self.initialise_chapter_verse( + self.advancedVersionComboBox.currentText(), + self.advanced_book_combo_box.currentText(), + self.advanced_book_combo_box.itemData(item)) + + def on_advanced_from_verse(self): + chapter_from = int(self.advanced_from_chapter.currentText()) + chapter_to = int(self.advanced_to_chapter.currentText()) if chapter_from == chapter_to: bible = self.advancedVersionComboBox.currentText() - book_ref_id = self.advancedBookComboBox.itemData(int(self.advancedBookComboBox.currentIndex())) - verse_from = int(self.advancedFromVerse.currentText()) + book_ref_id = self.advanced_book_combo_box.itemData(int(self.advanced_book_combo_box.currentIndex())) + verse_from = int(self.advanced_from_verse.currentText()) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, chapter_to) - self.adjustComboBox(verse_from, verse_count, self.advancedToVerse, True) + self.adjust_combo_box(verse_from, verse_count, self.advanced_to_verse, True) - def onAdvancedToChapter(self): + def on_advanced_to_chapter(self): bible = self.advancedVersionComboBox.currentText() - book_ref_id = self.advancedBookComboBox.itemData(int(self.advancedBookComboBox.currentIndex())) - chapter_from = int(self.advancedFromChapter.currentText()) - chapter_to = int(self.advancedToChapter.currentText()) - verse_from = int(self.advancedFromVerse.currentText()) - verse_to = int(self.advancedToVerse.currentText()) + book_ref_id = self.advanced_book_combo_box.itemData(int(self.advanced_book_combo_box.currentIndex())) + chapter_from = int(self.advanced_from_chapter.currentText()) + chapter_to = int(self.advanced_to_chapter.currentText()) + verse_from = int(self.advanced_from_verse.currentText()) + verse_to = int(self.advanced_to_verse.currentText()) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, chapter_to) if chapter_from == chapter_to and verse_from > verse_to: - self.adjustComboBox(verse_from, verse_count, self.advancedToVerse) + self.adjust_combo_box(verse_from, verse_count, self.advanced_to_verse) else: - self.adjustComboBox(1, verse_count, self.advancedToVerse) + self.adjust_combo_box(1, verse_count, self.advanced_to_verse) - def onAdvancedFromChapter(self): + def on_advanced_from_chapter(self): bible = self.advancedVersionComboBox.currentText() - book_ref_id = self.advancedBookComboBox.itemData( - int(self.advancedBookComboBox.currentIndex())) - chapter_from = int(self.advancedFromChapter.currentText()) - chapter_to = int(self.advancedToChapter.currentText()) + book_ref_id = self.advanced_book_combo_box.itemData( + int(self.advanced_book_combo_box.currentIndex())) + chapter_from = int(self.advanced_from_chapter.currentText()) + chapter_to = int(self.advanced_to_chapter.currentText()) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, chapter_from) - self.adjustComboBox(1, verse_count, self.advancedFromVerse) + self.adjust_combo_box(1, verse_count, self.advanced_from_verse) if chapter_from > chapter_to: - self.adjustComboBox(1, verse_count, self.advancedToVerse) - self.adjustComboBox(chapter_from, self.chapter_count, self.advancedToChapter) + self.adjust_combo_box(1, verse_count, self.advanced_to_verse) + self.adjust_combo_box(chapter_from, self.chapter_count, self.advanced_to_chapter) elif chapter_from == chapter_to: - self.adjustComboBox(chapter_from, self.chapter_count, self.advancedToChapter) - self.adjustComboBox(1, verse_count, self.advancedToVerse, True) + self.adjust_combo_box(chapter_from, self.chapter_count, self.advanced_to_chapter) + self.adjust_combo_box(1, verse_count, self.advanced_to_verse, True) else: - self.adjustComboBox(chapter_from, self.chapter_count, self.advancedToChapter, True) + self.adjust_combo_box(chapter_from, self.chapter_count, self.advanced_to_chapter, True) - def adjustComboBox(self, range_from, range_to, combo, restore=False): + def adjust_combo_box(self, range_from, range_to, combo, restore=False): """ Adjusts the given como box to the given values. - ``range_from`` - The first number of the range (int). - - ``range_to`` - The last number of the range (int). - - ``combo`` - The combo box itself (QComboBox). - - ``restore`` - If True, then the combo's currentText will be restored after + :param range_from: The first number of the range (int). + :param range_to: The last number of the range (int). + :param combo: The combo box itself (QComboBox). + :param restore: If True, then the combo's currentText will be restored after adjusting (if possible). """ - log.debug('adjustComboBox %s, %s, %s', combo, range_from, range_to) + log.debug('adjust_combo_box %s, %s, %s', combo, range_from, range_to) if restore: old_text = combo.currentText() combo.clear() @@ -611,7 +599,7 @@ class BibleMediaItem(MediaManagerItem): if restore and combo.findText(old_text) != -1: combo.setCurrentIndex(combo.findText(old_text)) - def onAdvancedSearchButton(self): + def on_advanced_search_button(self): """ Does an advanced search and saves the search results. """ @@ -620,32 +608,32 @@ class BibleMediaItem(MediaManagerItem): self.application.process_events() bible = self.advancedVersionComboBox.currentText() second_bible = self.advancedSecondComboBox.currentText() - book = self.advancedBookComboBox.currentText() - book_ref_id = self.advancedBookComboBox.itemData(int(self.advancedBookComboBox.currentIndex())) - chapter_from = self.advancedFromChapter.currentText() - chapter_to = self.advancedToChapter.currentText() - verse_from = self.advancedFromVerse.currentText() - verse_to = self.advancedToVerse.currentText() + book = self.advanced_book_combo_box.currentText() + book_ref_id = self.advanced_book_combo_box.itemData(int(self.advanced_book_combo_box.currentIndex())) + chapter_from = self.advanced_from_chapter.currentText() + chapter_to = self.advanced_to_chapter.currentText() + verse_from = self.advanced_from_verse.currentText() + verse_to = self.advanced_to_verse.currentText() verse_separator = get_reference_separator('sep_v_display') range_separator = get_reference_separator('sep_r_display') verse_range = chapter_from + verse_separator + verse_from + range_separator + chapter_to + \ verse_separator + verse_to - versetext = '%s %s' % (book, verse_range) + verse_text = '%s %s' % (book, verse_range) self.application.set_busy_cursor() - self.search_results = self.plugin.manager.get_verses(bible, versetext, book_ref_id) + self.search_results = self.plugin.manager.get_verses(bible, verse_text, book_ref_id) if second_bible: - self.second_search_results = self.plugin.manager.get_verses(second_bible, versetext, book_ref_id) + self.second_search_results = self.plugin.manager.get_verses(second_bible, verse_text, book_ref_id) if not self.advancedLockButton.isChecked(): self.list_view.clear() if self.list_view.count() != 0: self.__check_second_bible(bible, second_bible) elif self.search_results: - self.displayResults(bible, second_bible) + self.display_results(bible, second_bible) self.advancedSearchButton.setEnabled(True) self.check_search_result() self.application.set_normal_cursor() - def onQuickSearchButton(self): + def on_quick_search_button(self): """ Does a quick search and saves the search results. Quick search can either be "Reference Search" or "Text Search". @@ -655,13 +643,13 @@ class BibleMediaItem(MediaManagerItem): self.application.process_events() bible = self.quickVersionComboBox.currentText() second_bible = self.quickSecondComboBox.currentText() - text = self.quickSearchEdit.text() - if self.quickSearchEdit.current_search_type() == BibleSearch.Reference: + text = self.quick_search_edit.text() + if self.quick_search_edit.current_search_type() == BibleSearch.Reference: # We are doing a 'Reference Search'. self.search_results = self.plugin.manager.get_verses(bible, text) if second_bible and self.search_results: - self.second_search_results = self.plugin.manager.get_verses(second_bible, text, - self.search_results[0].book.book_reference_id) + self.second_search_results = \ + self.plugin.manager.get_verses(second_bible, text, self.search_results[0].book.book_reference_id) else: # We are doing a 'Text Search'. self.application.set_busy_cursor() @@ -681,13 +669,13 @@ class BibleMediaItem(MediaManagerItem): count += 1 continue new_search_results.append(verse) - text.append((verse.book.book_reference_id, verse.chapter, - verse.verse, verse.verse)) + text.append((verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse)) if passage_not_found: - QtGui.QMessageBox.information(self, translate('BiblesPlugin.MediaItem', 'Information'), + QtGui.QMessageBox.information( + self, translate('BiblesPlugin.MediaItem', 'Information'), translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses ' - 'that are in the main Bible. Only verses found in both Bibles will be shown. %d verses ' - 'have not been included in the results.') % count, + 'that are in the main Bible. Only verses found in both Bibles will be shown. %d ' + 'verses have not been included in the results.') % count, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok)) self.search_results = new_search_results self.second_search_results = bibles[second_bible].get_verses(text) @@ -696,24 +684,24 @@ class BibleMediaItem(MediaManagerItem): if self.list_view.count() != 0 and self.search_results: self.__check_second_bible(bible, second_bible) elif self.search_results: - self.displayResults(bible, second_bible) + self.display_results(bible, second_bible) self.quickSearchButton.setEnabled(True) self.check_search_result() self.application.set_normal_cursor() - def displayResults(self, bible, second_bible=''): + def display_results(self, bible, second_bible=''): """ Displays the search results in the media manager. All data needed for further action is saved for/in each row. """ - items = self.buildDisplayResults(bible, second_bible, self.search_results) + items = self.build_display_results(bible, second_bible, self.search_results) for bible_verse in items: self.list_view.addItem(bible_verse) self.list_view.selectAll() self.search_results = {} self.second_search_results = {} - def buildDisplayResults(self, bible, second_bible, search_results): + def build_display_results(self, bible, second_bible, search_results): """ Displays the search results in the media manager. All data needed for further action is saved for/in each row. @@ -764,7 +752,7 @@ class BibleMediaItem(MediaManagerItem): log.exception('The second_search_results does not have as many verses as the search_results.') break bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version, - second_version) + second_version) else: bible_text = '%s %d%s%d (%s)' % (book, verse.chapter, verse_separator, verse.verse, version) bible_verse = QtGui.QListWidgetItem(bible_text) @@ -772,11 +760,16 @@ class BibleMediaItem(MediaManagerItem): items.append(bible_verse) return items - def generate_slide_data(self, service_item, item=None, xmlVersion=False, - remote=False, context=ServiceItemContext.Service): + def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, + context=ServiceItemContext.Service): """ - Generates and formats the slides for the service item as well as the - service item's title. + Generate the slide data. Needs to be implemented by the plugin. + + :param service_item: The service item to be built on + :param item: The Song item to be used + :param xml_version: The xml version (not used) + :param remote: Triggered from remote + :param context: Why is it being generated """ log.debug('generating slide data') if item: @@ -806,7 +799,7 @@ class BibleMediaItem(MediaManagerItem): second_permissions = self._decode_qt_object(bitem, 'second_permissions') second_text = self._decode_qt_object(bitem, 'second_text') verses.add(book, chapter, verse, version, copyright, permissions) - verse_text = self.formatVerse(old_chapter, chapter, verse) + verse_text = self.format_verse(old_chapter, chapter, verse) if second_bible: bible_text = '%s%s\n\n%s %s' % (verse_text, text, verse_text, second_text) raw_slides.append(bible_text.rstrip()) @@ -825,8 +818,8 @@ class BibleMediaItem(MediaManagerItem): bible_text = bible_text.strip(' ') if not old_item: start_item = bitem - elif self.checkTitle(bitem, old_item): - raw_title.append(self.formatTitle(start_item, old_item)) + elif self.check_title(bitem, old_item): + raw_title.append(self.format_title(start_item, old_item)) start_item = bitem old_item = bitem old_chapter = chapter @@ -835,7 +828,7 @@ class BibleMediaItem(MediaManagerItem): if second_bible: verses.add_version(second_version, second_copyright, second_permissions) service_item.raw_footer.append(verses.format_versions()) - raw_title.append(self.formatTitle(start_item, bitem)) + raw_title.append(self.format_title(start_item, bitem)) # If there are no more items we check whether we have to add bible_text. if bible_text: raw_slides.append(bible_text.lstrip()) @@ -858,17 +851,14 @@ class BibleMediaItem(MediaManagerItem): service_item.add_from_text(slide) return True - def formatTitle(self, start_bitem, old_bitem): + def format_title(self, start_bitem, old_bitem): """ This method is called, when we have to change the title, because we are at the end of a verse range. E. g. if we want to add Genesis 1:1-6 as well as Daniel 2:14. - ``start_item`` - The first item of a range. - - ``old_item`` - The last item of a range. + :param start_bitem: The first item of a range. + :param old_bitem: The last item of a range. """ verse_separator = get_reference_separator('sep_v_display') range_separator = get_reference_separator('sep_r_display') @@ -893,17 +883,15 @@ class BibleMediaItem(MediaManagerItem): range_separator + old_chapter + verse_separator + old_verse return '%s %s (%s)' % (start_book, verse_range, bibles) - def checkTitle(self, bitem, old_bitem): + def check_title(self, bitem, old_bitem): """ This method checks if we are at the end of an verse range. If that is the case, we return True, otherwise False. E. g. if we added + Genesis 1:1-6, but the next verse is Daniel 2:14, we return True. - ``item`` - The item we are dealing with at the moment. - - ``old_item`` - The item we were previously dealing with. + :param bitem: The item we are dealing with at the moment. + :param old_bitem: The item we were previously dealing with. """ # Get all the necessary meta data. book = self._decode_qt_object(bitem, 'book') @@ -930,22 +918,18 @@ class BibleMediaItem(MediaManagerItem): return True return False - def formatVerse(self, old_chapter, chapter, verse): + def format_verse(self, old_chapter, chapter, verse): """ Formats and returns the text, each verse starts with, for the given chapter and verse. The text is either surrounded by round, square, + curly brackets or no brackets at all. For example:: u'{su}1:1{/su}' - ``old_chapter`` - The previous verse's chapter number (int). - - ``chapter`` - The chapter number (int). - - ``verse`` - The verse number (int). + :param old_chapter: The previous verse's chapter number (int). + :param chapter: The chapter number (int). + :param verse: The verse number (int). """ verse_separator = get_reference_separator('sep_v_display') if not self.settings.is_verse_number_visible: @@ -969,16 +953,15 @@ class BibleMediaItem(MediaManagerItem): bible = self.quickVersionComboBox.currentText() search_results = self.plugin.manager.get_verses(bible, string, False, showError) if search_results: - versetext = ' '.join([verse.text for verse in search_results]) - return [[string, versetext]] + verse_text = ' '.join([verse.text for verse in search_results]) + return [[string, verse_text]] return [] def create_item_from_id(self, item_id): """ Create a media item from an item id. """ - item = QtGui.QListWidgetItem() bible = self.quickVersionComboBox.currentText() search_results = self.plugin.manager.get_verses(bible, item_id, False) - items = self.buildDisplayResults(bible, '', search_results) + items = self.build_display_results(bible, '', search_results) return items diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index 03ed322e7..a522c1c57 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -55,8 +55,7 @@ class OpenSongBible(BibleDB): """ Recursively get all text in an objectify element and its child elements. - ``element`` - An objectify element to get the text from + :param element: An objectify element to get the text from """ verse_text = '' if element.text: @@ -122,14 +121,16 @@ class OpenSongBible(BibleDB): else: verse_number += 1 self.create_verse(db_book.id, chapter_number, verse_number, self.get_text(verse)) - self.wizard.increment_progress_bar(translate('BiblesPlugin.Opensong', 'Importing %s %s...', - 'Importing ...')) % (db_book.name, chapter_number) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.Opensong', 'Importing %s %s...', + 'Importing ...')) % (db_book.name, chapter_number) self.session.commit() self.application.process_events() except etree.XMLSyntaxError as inst: - critical_error_message_box(message=translate('BiblesPlugin.OpenSongImport', - 'Incorrect Bible file type supplied. OpenSong Bibles may be ' - 'compressed. You must decompress them before import.')) + critical_error_message_box( + message=translate('BiblesPlugin.OpenSongImport', + 'Incorrect Bible file type supplied. OpenSong Bibles may be ' + 'compressed. You must decompress them before import.')) log.exception(inst) success = False except (IOError, AttributeError): diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index b606e9fc0..4f85bef1a 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -84,8 +84,8 @@ class OSISBible(BibleDB): success = True last_chapter = 0 match_count = 0 - self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', - 'Detecting encoding (this may take a few minutes)...')) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.OsisImport', 'Detecting encoding (this may take a few minutes)...')) try: detect_file = open(self.filename, 'r') details = chardet.detect(detect_file.read(1048576)) @@ -101,7 +101,7 @@ class OSISBible(BibleDB): osis = codecs.open(self.filename, 'r', details['encoding']) repl = replacement language_id = False - # Decide if the bible propably contains only NT or AT and NT or + # Decide if the bible probably contains only NT or AT and NT or # AT, NT and Apocrypha if lines_in_file < 11500: book_count = 27 @@ -154,10 +154,11 @@ class OSISBible(BibleDB): if last_chapter != chapter: if last_chapter != 0: self.session.commit() - self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', 'Importing %s %s...', - 'Importing ...') % (book_details['name'], chapter)) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.OsisImport', 'Importing %s %s...', + 'Importing ...') % (book_details['name'], chapter)) last_chapter = chapter - # All of this rigmarol below is because the mod2osis tool from the Sword library embeds XML in the + # All of this rigmarole below is because the mod2osis tool from the Sword library embeds XML in the # OSIS but neglects to enclose the verse text (with XML) in <[CDATA[ ]]> tags. verse_text = self.note_regex.sub('', verse_text) verse_text = self.title_regex.sub('', verse_text) diff --git a/openlp/plugins/bibles/lib/versereferencelist.py b/openlp/plugins/bibles/lib/versereferencelist.py index 1cd0fa3cb..1d3877d1d 100644 --- a/openlp/plugins/bibles/lib/versereferencelist.py +++ b/openlp/plugins/bibles/lib/versereferencelist.py @@ -42,18 +42,15 @@ class VerseReferenceList(object): def add(self, book, chapter, verse, version, copyright, permission): self.add_version(version, copyright, permission) if not self.verse_list or self.verse_list[self.current_index]['book'] != book: - self.verse_list.append({'version': version, 'book': book, - 'chapter': chapter, 'start': verse, 'end': verse}) + self.verse_list.append({'version': version, 'book': book, 'chapter': chapter, 'start': verse, 'end': verse}) self.current_index += 1 elif self.verse_list[self.current_index]['chapter'] != chapter: - self.verse_list.append({'version': version, 'book': book, - 'chapter': chapter, 'start': verse, 'end': verse}) + self.verse_list.append({'version': version, 'book': book, 'chapter': chapter, 'start': verse, 'end': verse}) self.current_index += 1 elif (self.verse_list[self.current_index]['end'] + 1) == verse: self.verse_list[self.current_index]['end'] = verse else: - self.verse_list.append({'version': version, 'book': book, - 'chapter': chapter, 'start': verse, 'end': verse}) + self.verse_list.append({'version': version, 'book': book, 'chapter': chapter, 'start': verse, 'end': verse}) self.current_index += 1 def add_version(self, version, copyright, permission): diff --git a/openlp/plugins/images/forms/addgroupform.py b/openlp/plugins/images/forms/addgroupform.py index f13293cc3..d5f26f308 100644 --- a/openlp/plugins/images/forms/addgroupform.py +++ b/openlp/plugins/images/forms/addgroupform.py @@ -49,14 +49,9 @@ class AddGroupForm(QtGui.QDialog, Ui_AddGroupDialog): """ Show the form. - ``clear`` - Set to False if the text input box should not be cleared when showing the dialog (default: True). - - ``show_top_level_group`` - Set to True when "-- Top level group --" should be showed as first item (default: False). - - ``selected_group`` - The ID of the group that should be selected by default when showing the dialog. + :param clear: Set to False if the text input box should not be cleared when showing the dialog (default: True). + :param show_top_level_group: Set to True when "-- Top level group --" should be showed as first item (default: False). + :param selected_group: The ID of the group that should be selected by default when showing the dialog. """ if clear: self.name_edit.clear() @@ -76,7 +71,7 @@ class AddGroupForm(QtGui.QDialog, Ui_AddGroupDialog): """ if not self.name_edit.text(): critical_error_message_box(message=translate('ImagePlugin.AddGroupForm', - 'You need to type in a group name.')) + 'You need to type in a group name.')) self.name_edit.setFocus() return False else: diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index e9fba423c..c03059815 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -57,16 +57,16 @@ class ImagePlugin(Plugin): def about(self): about_text = translate('ImagePlugin', 'Image Plugin' - '
The image plugin provides displaying of images.
One ' - 'of the distinguishing features of this plugin is the ability to ' - 'group a number of images together in the service manager, making ' - 'the displaying of multiple images easier. This plugin can also ' - 'make use of OpenLP\'s "timed looping" feature to create a slide ' - 'show that runs automatically. In addition to this, images from ' - 'the plugin can be used to override the current theme\'s ' - 'background, which renders text-based items like songs with the ' - 'selected image as a background instead of the background ' - 'provided by the theme.') + '
The image plugin provides displaying of images.
One ' + 'of the distinguishing features of this plugin is the ability to ' + 'group a number of images together in the service manager, making ' + 'the displaying of multiple images easier. This plugin can also ' + 'make use of OpenLP\'s "timed looping" feature to create a slide ' + 'show that runs automatically. In addition to this, images from ' + 'the plugin can be used to override the current theme\'s ' + 'background, which renders text-based items like songs with the ' + 'selected image as a background instead of the background ' + 'provided by the theme.') return about_text def app_startup(self): diff --git a/openlp/plugins/images/lib/db.py b/openlp/plugins/images/lib/db.py index 2862409d5..69bc70982 100644 --- a/openlp/plugins/images/lib/db.py +++ b/openlp/plugins/images/lib/db.py @@ -80,17 +80,17 @@ def init_schema(url): # Definition of the "image_groups" table image_groups_table = Table('image_groups', metadata, - Column('id', types.Integer(), primary_key=True), - Column('parent_id', types.Integer()), - Column('group_name', types.Unicode(128)) - ) + Column('id', types.Integer(), primary_key=True), + Column('parent_id', types.Integer()), + Column('group_name', types.Unicode(128)) + ) # Definition of the "image_filenames" table image_filenames_table = Table('image_filenames', metadata, - Column('id', types.Integer(), primary_key=True), - Column('group_id', types.Integer(), ForeignKey('image_groups.id'), default=None), - Column('filename', types.Unicode(255), nullable=False) - ) + Column('id', types.Integer(), primary_key=True), + Column('group_id', types.Integer(), ForeignKey('image_groups.id'), default=None), + Column('filename', types.Unicode(255), nullable=False) + ) mapper(ImageGroups, image_groups_table) mapper(ImageFilenames, image_filenames_table) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 26ed887ad..5b88bfb36 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -76,8 +76,8 @@ class ImageMediaItem(MediaManagerItem): self.on_new_prompt = translate('ImagePlugin.MediaItem', 'Select Image(s)') file_formats = get_images_filter() self.on_new_file_masks = '%s;;%s (*.*) (*)' % (file_formats, UiStrings().AllFiles) - self.addGroupAction.setText(UiStrings().AddGroup) - self.addGroupAction.setToolTip(UiStrings().AddGroup) + self.add_group_action.setText(UiStrings().AddGroup) + self.add_group_action.setToolTip(UiStrings().AddGroup) self.replace_action.setText(UiStrings().ReplaceBG) self.replace_action.setToolTip(UiStrings().ReplaceLiveBG) self.reset_action.setText(UiStrings().ResetBG) @@ -120,31 +120,36 @@ class ImageMediaItem(MediaManagerItem): # define and add the context menu self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) if self.has_edit_icon: - create_widget_action(self.list_view, + create_widget_action( + self.list_view, text=self.plugin.get_string(StringContent.Edit)['title'], icon=':/general/general_edit.png', triggers=self.on_edit_click) create_widget_action(self.list_view, separator=True) if self.has_delete_icon: - create_widget_action(self.list_view, + create_widget_action( + self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()), text=self.plugin.get_string(StringContent.Delete)['title'], icon=':/general/general_delete.png', can_shortcuts=True, triggers=self.on_delete_click) create_widget_action(self.list_view, separator=True) - create_widget_action(self.list_view, + create_widget_action( + self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()), text=self.plugin.get_string(StringContent.Preview)['title'], icon=':/general/general_preview.png', can_shortcuts=True, triggers=self.on_preview_click) - create_widget_action(self.list_view, + create_widget_action( + self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()), text=self.plugin.get_string(StringContent.Live)['title'], icon=':/general/general_live.png', can_shortcuts=True, triggers=self.on_live_click) - create_widget_action(self.list_view, + create_widget_action( + self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()), can_shortcuts=True, text=self.plugin.get_string(StringContent.Service)['title'], @@ -152,7 +157,8 @@ class ImageMediaItem(MediaManagerItem): triggers=self.on_add_click) if self.add_to_service_item: create_widget_action(self.list_view, separator=True) - create_widget_action(self.list_view, + create_widget_action( + self.list_view, text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), icon=':/general/general_add.png', triggers=self.on_add_edit_click) @@ -170,9 +176,11 @@ class ImageMediaItem(MediaManagerItem): Add custom actions to the context menu. """ create_widget_action(self.list_view, separator=True) - create_widget_action(self.list_view, + create_widget_action( + self.list_view, text=UiStrings().AddGroup, icon=':/images/image_new_group.png', triggers=self.on_add_group_click) - create_widget_action(self.list_view, + create_widget_action( + self.list_view, text=self.plugin.get_string(StringContent.Load)['tooltip'], icon=':/general/general_open.png', triggers=self.on_file_click) @@ -180,24 +188,26 @@ class ImageMediaItem(MediaManagerItem): """ Add custom buttons to the start of the toolbar. """ - self.addGroupAction = self.toolbar.add_toolbar_action('addGroupAction', - icon=':/images/image_new_group.png', triggers=self.on_add_group_click) + self.add_group_action = self.toolbar.add_toolbar_action('add_group_action', + icon=':/images/image_new_group.png', + triggers=self.on_add_group_click) def add_end_header_bar(self): """ Add custom buttons to the end of the toolbar """ self.replace_action = self.toolbar.add_toolbar_action('replace_action', - icon=':/slides/slide_blank.png', triggers=self.on_replace_click) + icon=':/slides/slide_blank.png', + triggers=self.on_replace_click) self.reset_action = self.toolbar.add_toolbar_action('reset_action', - icon=':/system/system_close.png', visible=False, triggers=self.on_reset_click) + icon=':/system/system_close.png', + visible=False, triggers=self.on_reset_click) def recursively_delete_group(self, image_group): """ Recursively deletes a group and all groups and images in it. - ``image_group`` - The ImageGroups instance of the group that will be deleted. + :param image_group: The ImageGroups instance of the group that will be deleted. """ images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id) for image in images: @@ -215,7 +225,7 @@ class ImageMediaItem(MediaManagerItem): # Turn off auto preview triggers. self.list_view.blockSignals(True) if check_item_selected(self.list_view, translate('ImagePlugin.MediaItem', - 'You must select an image or group to delete.')): + 'You must select an image or group to delete.')): item_list = self.list_view.selectedItems() self.application.set_busy_cursor() self.main_window.display_progress_bar(len(item_list)) @@ -230,12 +240,14 @@ class ImageMediaItem(MediaManagerItem): row_item.parent().removeChild(row_item) self.manager.delete_object(ImageFilenames, row_item.data(0, QtCore.Qt.UserRole).id) elif isinstance(item_data, ImageGroups): - if QtGui.QMessageBox.question(self.list_view.parent(), + if QtGui.QMessageBox.question( + self.list_view.parent(), translate('ImagePlugin.MediaItem', 'Remove group'), translate('ImagePlugin.MediaItem', - 'Are you sure you want to remove "%s" and everything in it?') % item_data.group_name, + 'Are you sure you want to remove "%s" and everything in it?') % + item_data.group_name, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | - QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes: + QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes: self.recursively_delete_group(item_data) self.manager.delete_object(ImageGroups, row_item.data(0, QtCore.Qt.UserRole).id) if item_data.parent_id == 0: @@ -253,11 +265,8 @@ class ImageMediaItem(MediaManagerItem): """ Recursively add subgroups to the given parent group in a QTreeWidget. - ``group_list`` - The List object that contains all QTreeWidgetItems. - - ``parent_group_id`` - The ID of the group that will be added recursively. + :param group_list: The List object that contains all QTreeWidgetItems. + :param parent_group_id: The ID of the group that will be added recursively. """ image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id) image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name)) @@ -278,14 +287,10 @@ class ImageMediaItem(MediaManagerItem): """ Recursively add groups to the combobox in the 'Add group' dialog. - ``combobox`` - The QComboBox to add the options to. - - ``parent_group_id`` - The ID of the group that will be added. - - ``prefix`` - A string containing the prefix that will be added in front of the groupname for each level of the tree. + :param combobox: The QComboBox to add the options to. + :param parent_group_id: The ID of the group that will be added. + :param prefix: A string containing the prefix that will be added in front of the groupname for each level of + the tree. """ if parent_group_id == 0: combobox.clear() @@ -300,11 +305,8 @@ class ImageMediaItem(MediaManagerItem): """ Expand groups in the widget recursively. - ``group_id`` - The ID of the group that will be expanded. - - ``root_item`` - This option is only used for recursion purposes. + :param group_id: The ID of the group that will be expanded. + :param root_item: This option is only used for recursion purposes. """ return_value = False if root_item is None: @@ -323,14 +325,9 @@ class ImageMediaItem(MediaManagerItem): """ Replace the list of images and groups in the interface. - ``images`` - A List of ImageFilenames objects that will be used to reload the mediamanager list. - - ``initial_load`` - When set to False, the busy cursor and progressbar will be shown while loading images. - - ``open_group`` - ImageGroups object of the group that must be expanded after reloading the list in the interface. + :param images: A List of Image Filenames objects that will be used to reload the mediamanager list. + :param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images. + :param open_group: ImageGroups object of the group that must be expanded after reloading the list in the interface. """ if not initial_load: self.application.set_busy_cursor() @@ -375,11 +372,8 @@ class ImageMediaItem(MediaManagerItem): Process a list for files either from the File Dialog or from Drag and Drop. This method is overloaded from MediaManagerItem. - ``files`` - A List of strings containing the filenames of the files to be loaded - - ``target_group`` - The QTreeWidgetItem of the group that will be the parent of the added files + :param files: A List of strings containing the filenames of the files to be loaded + :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files """ self.application.set_normal_cursor() self.load_list(files, target_group) @@ -390,14 +384,9 @@ class ImageMediaItem(MediaManagerItem): """ Add new images to the database. This method is called when adding images using the Add button or DnD. - ``images`` - A List of strings containing the filenames of the files to be loaded - - ``target_group`` - The QTreeWidgetItem of the group that will be the parent of the added files - - ``initial_load`` - When set to False, the busy cursor and progressbar will be shown while loading images + :param images: A List of strings containing the filenames of the files to be loaded + :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files + :param initial_load: When set to False, the busy cursor and progressbar will be shown while loading images """ parent_group = None if target_group is None: @@ -464,30 +453,25 @@ class ImageMediaItem(MediaManagerItem): # Save the new images in the database self.save_new_images_list(images, group_id=parent_group.id, reload_list=False) self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), - initial_load=initial_load, open_group=parent_group) + initial_load=initial_load, open_group=parent_group) self.application.set_normal_cursor() def save_new_images_list(self, images_list, group_id=0, reload_list=True): """ Convert a list of image filenames to ImageFilenames objects and save them in the database. - ``images_list`` - A List of strings containing image filenames - - ``group_id`` - The ID of the group to save the images in - - ``reload_list`` - This boolean is set to True when the list in the interface should be reloaded after saving the new images + :param images_list: A List of strings containing image filenames + :param group_id: The ID of the group to save the images in + :param reload_list: This boolean is set to True when the list in the interface should be reloaded after saving the new images """ for filename in images_list: if not isinstance(filename, str): continue log.debug('Adding new image: %s', filename) - imageFile = ImageFilenames() - imageFile.group_id = group_id - imageFile.filename = str(filename) - self.manager.save_object(imageFile) + image_file = ImageFilenames() + image_file.group_id = group_id + image_file.filename = str(filename) + self.manager.save_object(image_file) self.main_window.increment_progress_bar() if reload_list and images_list: self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename)) @@ -496,8 +480,7 @@ class ImageMediaItem(MediaManagerItem): """ Handle drag-and-drop moving of images within the media manager - ``target`` - This contains the QTreeWidget that is the target of the DnD action + :param target: This contains the QTreeWidget that is the target of the DnD action """ items_to_move = self.list_view.selectedItems() # Determine group to move images to @@ -538,10 +521,16 @@ class ImageMediaItem(MediaManagerItem): image_items.sort(key=lambda item: get_locale_key(item.text(0))) target_group.addChildren(image_items) - def generate_slide_data(self, service_item, item=None, xml_version=False, - remote=False, context=ServiceItemContext.Service): + def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, + context=ServiceItemContext.Service): """ Generate the slide data. Needs to be implemented by the plugin. + + :param service_item: The service item to be built on + :param item: The Song item to be used + :param xml_version: The xml version (not used) + :param remote: Triggered from remote + :param context: Why is it being generated """ background = QtGui.QColor(Settings().value(self.settings_section + '/background color')) if item: @@ -561,40 +550,41 @@ class ImageMediaItem(MediaManagerItem): service_item.add_capability(ItemCapabilities.CanAppend) # force a nonexistent theme service_item.theme = -1 - missing_items_filenames = [] - images_filenames = [] + missing_items_file_names = [] + images_file_names = [] # Expand groups to images for bitem in items: if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None: for index in range(0, bitem.childCount()): if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames): - images_filenames.append(bitem.child(index).data(0, QtCore.Qt.UserRole).filename) + images_file_names.append(bitem.child(index).data(0, QtCore.Qt.UserRole).filename) elif isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames): - images_filenames.append(bitem.data(0, QtCore.Qt.UserRole).filename) + images_file_names.append(bitem.data(0, QtCore.Qt.UserRole).filename) # Don't try to display empty groups - if not images_filenames: + if not images_file_names: return False # Find missing files - for filename in images_filenames: + for filename in images_file_names: if not os.path.exists(filename): - missing_items_filenames.append(filename) + missing_items_file_names.append(filename) # We cannot continue, as all images do not exist. - if not images_filenames: + if not images_file_names: if not remote: critical_error_message_box( translate('ImagePlugin.MediaItem', 'Missing Image(s)'), - translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s') % - '\n'.join(missing_items_filenames)) + translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s') + % '\n'.join(missing_items_file_names)) return False # We have missing as well as existing images. We ask what to do. - elif missing_items_filenames and QtGui.QMessageBox.question(self, - translate('ImagePlugin.MediaItem', 'Missing Image(s)'), - translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n' - 'Do you want to add the other images anyway?') % '\n'.join(missing_items_filenames), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: + elif missing_items_file_names and QtGui.QMessageBox.question( + self, translate('ImagePlugin.MediaItem', 'Missing Image(s)'), + translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n' + 'Do you want to add the other images anyway?') % '\n'.join(missing_items_file_names), + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == \ + QtGui.QMessageBox.No: return False # Continue with the existing images. - for filename in images_filenames: + for filename in images_file_names: name = os.path.split(filename)[1] service_item.add_from_image(filename, name, background) return True @@ -603,8 +593,7 @@ class ImageMediaItem(MediaManagerItem): """ Returns *True* if the given Group already exists in the database, otherwise *False*. - ``new_group`` - The ImageGroups object that contains the name of the group that will be checked + :param new_group: The ImageGroups object that contains the name of the group that will be checked """ groups = self.manager.get_all_objects(ImageGroups, ImageGroups.group_name == new_group.group_name) if groups: @@ -633,8 +622,8 @@ class ImageMediaItem(MediaManagerItem): group_name=self.add_group_form.name_edit.text()) if not self.check_group_exists(new_group): if self.manager.save_object(new_group): - self.load_full_list(self.manager.get_all_objects(ImageFilenames, - order_by_ref=ImageFilenames.filename)) + self.load_full_list(self.manager.get_all_objects( + ImageFilenames, order_by_ref=ImageFilenames.filename)) self.expand_group(new_group.id) self.fill_groups_combobox(self.choose_group_form.group_combobox) self.fill_groups_combobox(self.add_group_form.parent_group_combobox) @@ -659,9 +648,10 @@ class ImageMediaItem(MediaManagerItem): def on_replace_click(self): """ - Called to replace Live backgound with the image selected. + Called to replace Live background with the image selected. """ - if check_item_selected(self.list_view, + if check_item_selected( + self.list_view, translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')): background = QtGui.QColor(Settings().value(self.settings_section + '/background color')) bitem = self.list_view.selectedItems()[0] @@ -673,24 +663,24 @@ class ImageMediaItem(MediaManagerItem): if self.live_controller.display.direct_image(filename, background): self.reset_action.setVisible(True) else: - critical_error_message_box(UiStrings().LiveBGError, + critical_error_message_box( + UiStrings().LiveBGError, translate('ImagePlugin.MediaItem', 'There was no display item to amend.')) else: - critical_error_message_box(UiStrings().LiveBGError, + critical_error_message_box( + UiStrings().LiveBGError, translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' - 'the image file "%s" no longer exists.') % filename) + 'the image file "%s" no longer exists.') % filename) def search(self, string, show_error=True): """ Perform a search on the image file names. - ``string`` - The glob to search for - - ``show_error`` - Unused. + :param string: The glob to search for + :param show_error: Unused. """ - files = self.manager.get_all_objects(ImageFilenames, filter_clause=ImageFilenames.filename.contains(string), + files = self.manager.get_all_objects( + ImageFilenames, filter_clause=ImageFilenames.filename.contains(string), order_by_ref=ImageFilenames.filename) results = [] for file_object in files: diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 644b573b9..5e1412a39 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -131,6 +131,11 @@ class MediaMediaItem(MediaManagerItem): self.display_type_combo_box.currentIndexChanged.connect(self.override_player_changed) def override_player_changed(self, index): + """ + The Player has been overridden + + :param index: Index + """ player = get_media_players()[0] if index == 0: set_media_players(player) @@ -178,9 +183,15 @@ class MediaMediaItem(MediaManagerItem): 'the media file "%s" no longer exists.') % filename) def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, - context=ServiceItemContext.Live): + context=ServiceItemContext.Service): """ Generate the slide data. Needs to be implemented by the plugin. + + :param service_item: The service item to be built on + :param item: The Song item to be used + :param xml_version: The xml version (not used) + :param remote: Triggered from remote + :param context: Why is it being generated """ if item is None: item = self.list_view.currentItem() @@ -269,6 +280,12 @@ class MediaMediaItem(MediaManagerItem): def load_list(self, media, target_group=None): # Sort the media by its filename considering language specific characters. + """ + Load the media list + + :param media: The media + :param target_group: + """ media.sort(key=lambda file_name: get_locale_key(os.path.split(str(file_name))[1])) for track in media: track_info = QtCore.QFileInfo(track) diff --git a/openlp/plugins/media/lib/mediatab.py b/openlp/plugins/media/lib/mediatab.py index 2fd01026f..051d937c9 100644 --- a/openlp/plugins/media/lib/mediatab.py +++ b/openlp/plugins/media/lib/mediatab.py @@ -33,14 +33,6 @@ from openlp.core.common import Settings, UiStrings, translate from openlp.core.lib import SettingsTab -class MediaQ_check_box(QtGui.QCheckBox): - """ - MediaQ_check_box adds an extra property, playerName to the Q_check_box class. - """ - def setPlayerName(self, name): - self.playerName = name - - class MediaTab(SettingsTab): """ MediaTab is the Media settings tab in the settings dialog. diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 56141a6ea..0ec0940a7 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -66,7 +66,7 @@ class MediaPlugin(Plugin): def about(self): about_text = translate('MediaPlugin', 'Media Plugin' - '
The media plugin provides playback of audio and video.') + '
The media plugin provides playback of audio and video.') return about_text def set_plugin_text_strings(self): diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index a80dc2a81..356a6cceb 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -52,6 +52,7 @@ else: import uno from com.sun.star.beans import PropertyValue from com.sun.star.task import ErrorCodeIOException + uno_available = True except ImportError: uno_available = False @@ -183,9 +184,9 @@ class ImpressController(PresentationController): docs = desktop.getComponents() cnt = 0 if docs.hasElements(): - list = docs.createEnumeration() - while list.hasMoreElements(): - doc = list.nextElement() + list_elements = docs.createEnumeration() + while list_elements.hasMoreElements(): + doc = list_elements.nextElement() if doc.getImplementationName() != 'com.sun.star.comp.framework.BackingComp': cnt += 1 if cnt > 0: @@ -203,7 +204,7 @@ class ImpressDocument(PresentationDocument): Class which holds information and controls a single presentation. """ - def __init__(self, controller, presentation): + def __init__ (self, controller, presentation): """ Constructor, store information about the file and initialise. """ @@ -225,10 +226,10 @@ class ImpressDocument(PresentationDocument): if desktop is None: self.controller.start_process() desktop = self.controller.get_com_desktop() - url = 'file:///' + self.filepath.replace('\\', '/').replace(':', '|').replace(' ', '%20') + url = 'file:///' + self.file_path.replace('\\', '/').replace(':', '|').replace(' ', '%20') else: desktop = self.controller.get_uno_desktop() - url = uno.systemPathToFileUrl(self.filepath) + url = uno.systemPathToFileUrl(self.file_path) if desktop is None: return False self.desktop = desktop @@ -352,7 +353,7 @@ class ImpressDocument(PresentationDocument): log.debug('unblank screen OpenOffice') return self.control.resume() - def blank_screen(self): + def blank_screen (self): """ Blanks the screen. """ @@ -409,11 +410,13 @@ class ImpressDocument(PresentationDocument): """ return self.document.getDrawPages().getCount() - def goto_slide(self, slideno): + def goto_slide(self, slide_no): """ Go to a specific slide (from 1). + + :param slide_no: The slide the text is required for, starting at 1 """ - self.control.gotoSlideIndex(slideno-1) + self.control.gotoSlideIndex(slide_no - 1) def next_step(self): """ @@ -435,8 +438,7 @@ class ImpressDocument(PresentationDocument): """ Returns the text on the slide. - ``slide_no`` - The slide the text is required for, starting at 1 + :param slide_no: The slide the text is required for, starting at 1 """ return self.__get_text_from_page(slide_no) @@ -444,8 +446,7 @@ class ImpressDocument(PresentationDocument): """ Returns the text in the slide notes. - ``slide_no`` - The slide the notes are required for, starting at 1 + :param slide_no: The slide the notes are required for, starting at 1 """ return self.__get_text_from_page(slide_no, True) @@ -453,8 +454,8 @@ class ImpressDocument(PresentationDocument): """ Return any text extracted from the presentation page. - ``notes`` - A boolean. If set the method searches the notes of the slide. + :param slide_no: The slide the notes are required for, starting at 1 + :param notes: A boolean. If set the method searches the notes of the slide. """ text = '' pages = self.document.getDrawPages() diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 931a01bfd..1894cbf1f 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -183,7 +183,7 @@ class PresentationMediaItem(MediaManagerItem): translate('PresentationPlugin.MediaItem', 'A presentation with that filename already exists.')) continue - controller_name = self.findControllerByType(filename) + controller_name = self.find_controller_by_type(filename) if controller_name: controller = self.controllers[controller_name] doc = controller.add_document(file) @@ -240,11 +240,16 @@ class PresentationMediaItem(MediaManagerItem): self.list_view.takeItem(row) Settings().setValue(self.settings_section + '/presentations files', self.get_file_list()) - def generate_slide_data(self, service_item, item=None, xml_version=False, - remote=False, context=ServiceItemContext.Service, presentation_file=None): + def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, + context=ServiceItemContext.Service, presentation_file=None): """ - Load the relevant information for displaying the presentation in the slidecontroller. In the case of - powerpoints, an image for each slide. + Generate the slide data. Needs to be implemented by the plugin. + + :param service_item: The service item to be built on + :param item: The Song item to be used + :param xml_version: The xml version (not used) + :param remote: Triggered from remote + :param context: Why is it being generated """ if item: items = [item] @@ -272,7 +277,7 @@ class PresentationMediaItem(MediaManagerItem): (path, name) = os.path.split(filename) service_item.title = name if os.path.exists(filename): - processor = self.findControllerByType(filename) + processor = self.find_controller_by_type(filename) if not processor: return False controller = self.controllers[processor] @@ -282,13 +287,13 @@ class PresentationMediaItem(MediaManagerItem): os.path.join(doc.get_temp_folder(), 'mainslide001.png')): doc.load_presentation() i = 1 - imagefile = 'mainslide%03d.png' % i - image = os.path.join(doc.get_temp_folder(), imagefile) + image_file = 'mainslide%03d.png' % i + image = os.path.join(doc.get_temp_folder(), image_file) while os.path.isfile(image): service_item.add_from_image(image, name) i += 1 - imagefile = 'mainslide%03d.png' % i - image = os.path.join(doc.get_temp_folder(), imagefile) + image_file = 'mainslide%03d.png' % i + image = os.path.join(doc.get_temp_folder(), image_file) doc.close_presentation() return True else: @@ -307,7 +312,7 @@ class PresentationMediaItem(MediaManagerItem): service_item.title = name if os.path.exists(filename): if service_item.processor == self.automatic: - service_item.processor = self.findControllerByType(filename) + service_item.processor = self.find_controller_by_type(filename) if not service_item.processor: return False controller = self.controllers[service_item.processor] @@ -340,11 +345,13 @@ class PresentationMediaItem(MediaManagerItem): 'The presentation %s no longer exists.') % filename) return False - def findControllerByType(self, filename): + def find_controller_by_type(self, filename): """ Determine the default application controller to use for the selected file type. This is used if "Automatic" is set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension. If none found, then look for a controller which "also supports" it instead. + + :param filename: The file name """ file_type = os.path.splitext(filename)[1][1:] if not file_type: @@ -360,6 +367,13 @@ class PresentationMediaItem(MediaManagerItem): return None def search(self, string, show_error): + """ + Search in files + + :param string: name to be found + :param show_error: not used + :return: + """ files = Settings().value(self.settings_section + '/presentations files') results = [] string = string.lower() diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index d734add72..724282eb4 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -71,7 +71,7 @@ class Controller(object): return self.doc.slidenumber = slide_no self.hide_mode = hide_mode - log.debug('add_handler, slidenumber: %d' % slide_no) + log.debug('add_handler, slide_number: %d' % slide_no) if self.is_live: if hide_mode == HideMode.Screen: Registry().execute('live_display_hide', HideMode.Screen) @@ -342,7 +342,7 @@ class MessageListener(object): # so handler & processor is set to None, and we skip adding the handler. self.handler = None if self.handler == self.media_item.automatic: - self.handler = self.media_item.findControllerByType(file) + self.handler = self.media_item.find_controller_by_type(file) if not self.handler: return if is_live: @@ -359,6 +359,8 @@ class MessageListener(object): def slide(self, message): """ React to the message to move to a specific slide. + + :param message: The message {1} is_live {2} slide """ is_live = message[1] slide = message[2] @@ -370,6 +372,8 @@ class MessageListener(object): def first(self, message): """ React to the message to move to the first slide. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: @@ -380,6 +384,8 @@ class MessageListener(object): def last(self, message): """ React to the message to move to the last slide. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: @@ -390,6 +396,8 @@ class MessageListener(object): def next(self, message): """ React to the message to move to the next animation/slide. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: @@ -400,6 +408,8 @@ class MessageListener(object): def previous(self, message): """ React to the message to move to the previous animation/slide. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: @@ -410,6 +420,8 @@ class MessageListener(object): def shutdown(self, message): """ React to message to shutdown the presentation. I.e. end the show and close the file. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: @@ -420,6 +432,8 @@ class MessageListener(object): def hide(self, message): """ React to the message to show the desktop. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: @@ -428,6 +442,8 @@ class MessageListener(object): def blank(self, message): """ React to the message to blank the display. + + :param message: The message {1} is_live {2} slide """ is_live = message[1] hide_mode = message[2] @@ -437,6 +453,8 @@ class MessageListener(object): def unblank(self, message): """ React to the message to unblank the display. + + :param message: The message {1} is_live """ is_live = message[1] if is_live: diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index 534106f52..2dade90a1 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -113,7 +113,7 @@ class PdfController(PresentationController): self.gsbin = '' self.also_supports = [] # Use the user defined program if given - if (Settings().value('presentations/enable_pdf_program')): + if Settings().value('presentations/enable_pdf_program'): pdf_program = Settings().value('presentations/pdf_program') program_type = self.check_binary(pdf_program) if program_type == 'gs': @@ -197,7 +197,7 @@ class PdfDocument(PresentationDocument): runlog = [] try: runlog = check_output([self.controller.gsbin, '-dNOPAUSE', '-dNODISPLAY', '-dBATCH', - '-sFile=' + self.filepath, gs_resolution_script]) + '-sFile=' + self.file_path, gs_resolution_script]) except CalledProcessError as e: log.debug(' '.join(e.cmd)) log.debug(e.output) @@ -246,13 +246,13 @@ class PdfDocument(PresentationDocument): os.makedirs(self.get_temp_folder()) if self.controller.mudrawbin: runlog = check_output([self.controller.mudrawbin, '-w', str(size.right()), '-h', str(size.bottom()), - '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.filepath]) + '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path]) elif self.controller.gsbin: resolution = self.gs_get_resolution(size) runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m', '-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), - self.filepath]) + self.file_path]) created_files = sorted(os.listdir(self.get_temp_folder())) for fn in created_files: if os.path.isfile(os.path.join(self.get_temp_folder(), fn)): diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 29fea458f..d6447adce 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -112,6 +112,9 @@ class PowerpointDocument(PresentationDocument): def __init__(self, controller, presentation): """ Constructor, store information about the file and initialise. + + :param controller: + :param presentation: """ log.debug('Init Presentation Powerpoint') super(PowerpointDocument, self).__init__(controller, presentation) @@ -126,7 +129,7 @@ class PowerpointDocument(PresentationDocument): if not self.controller.process or not self.controller.process.Visible: self.controller.start_process() try: - self.controller.process.Presentations.Open(self.filepath, False, False, True) + self.controller.process.Presentations.Open(self.file_path, False, False, True) except pywintypes.com_error: log.debug('PPT open failed') return False @@ -275,12 +278,14 @@ class PowerpointDocument(PresentationDocument): log.debug('get_slide_count') return self.presentation.Slides.Count - def goto_slide(self, slideno): + def goto_slide(self, slide_no): """ Moves to a specific slide in the presentation. + + :param slide_no: The slide the text is required for, starting at 1 """ log.debug('goto_slide') - self.presentation.SlideShowWindow.View.GotoSlide(slideno) + self.presentation.SlideShowWindow.View.GotoSlide(slide_no) def next_step(self): """ @@ -302,8 +307,7 @@ class PowerpointDocument(PresentationDocument): """ Returns the text on the slide. - ``slide_no`` - The slide the text is required for, starting at 1. + :param slide_no: The slide the text is required for, starting at 1 """ return _get_text_from_shapes(self.presentation.Slides(slide_no).Shapes) @@ -311,8 +315,7 @@ class PowerpointDocument(PresentationDocument): """ Returns the text on the slide. - ``slide_no`` - The slide the notes are required for, starting at 1. + :param slide_no: The slide the text is required for, starting at 1 """ return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes) @@ -321,8 +324,7 @@ def _get_text_from_shapes(shapes): """ Returns any text extracted from the shapes on a presentation slide. - ``shapes`` - A set of shapes to search for text. + :param shapes: A set of shapes to search for text. """ text = '' for index in range(shapes.Count): diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index 91f7f1a2d..46195478d 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -124,7 +124,7 @@ class PptviewDocument(PresentationDocument): temp_folder = self.get_temp_folder() size = ScreenList().current['size'] rect = RECT(size.x(), size.y(), size.right(), size.bottom()) - file_path = os.path.normpath(self.filepath) + file_path = os.path.normpath(self.file_path) preview_path = os.path.join(temp_folder, 'slide') # Ensure that the paths are null terminated file_path = file_path.encode('utf-16-le') + b'\0' @@ -228,11 +228,13 @@ class PptviewDocument(PresentationDocument): """ return self.controller.process.GetSlideCount(self.ppt_id) - def goto_slide(self, slideno): + def goto_slide(self, slide_no): """ Moves to a specific slide in the presentation. + + :param slide_no: The slide the text is required for, starting at 1 """ - self.controller.process.GotoSlide(self.ppt_id, slideno) + self.controller.process.GotoSlide(self.ppt_id, slide_no) def next_step(self): """ diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index ade3d4d4b..9615d812c 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -103,8 +103,8 @@ class PresentationDocument(object): """ Run some initial setup. This method is separate from __init__ in order to mock it out in tests. """ - self.slidenumber = 0 - self.filepath = name + self.slide_number = 0 + self.file_path = name check_directory_exists(self.get_thumbnail_folder()) def load_presentation(self): @@ -131,7 +131,7 @@ class PresentationDocument(object): """ Return just the filename of the presentation, without the directory """ - return os.path.split(self.filepath)[1] + return os.path.split(self.file_path)[1] def get_thumbnail_folder(self): """ @@ -149,10 +149,10 @@ class PresentationDocument(object): """ Returns ``True`` if the thumbnail images exist and are more recent than the powerpoint file. """ - lastimage = self.get_thumbnail_path(self.get_slide_count(), True) - if not (lastimage and os.path.isfile(lastimage)): + last_image = self.get_thumbnail_path(self.get_slide_count(), True) + if not (last_image and os.path.isfile(last_image)): return False - return validate_thumb(self.filepath, lastimage) + return validate_thumb(self.file_path, last_image) def close_presentation(self): """ @@ -253,8 +253,7 @@ class PresentationDocument(object): ``slide_no`` The slide an image is required for, starting at 1 """ - path = os.path.join(self.get_thumbnail_folder(), - self.controller.thumbnail_prefix + str(slide_no) + '.png') + path = os.path.join(self.get_thumbnail_folder(), self.controller.thumbnail_prefix + str(slide_no) + '.png') if os.path.isfile(path) or not check_exists: return path else: @@ -268,21 +267,20 @@ class PresentationDocument(object): return if not hide_mode: current = self.get_slide_number() - if current == self.slidenumber: + if current == self.slide_number: return - self.slidenumber = current + self.slide_number = current if is_live: prefix = 'live' else: prefix = 'preview' - Registry().execute('slidecontroller_%s_change' % prefix, self.slidenumber - 1) + Registry().execute('slidecontroller_%s_change' % prefix, self.slide_number - 1) def get_slide_text(self, slide_no): """ Returns the text on the slide - ``slide_no`` - The slide the text is required for, starting at 1 + :param slide_no: The slide the text is required for, starting at 1 """ return '' @@ -290,8 +288,7 @@ class PresentationDocument(object): """ Returns the text on the slide - ``slide_no`` - The slide the notes are required for, starting at 1 + :param slide_no: The slide the text is required for, starting at 1 """ return '' @@ -350,6 +347,7 @@ class PresentationController(object): def __init__(self, plugin=None, name='PresentationController', document_class=PresentationDocument): """ This is the constructor for the presentationcontroller object. This provides an easy way for descendent plugins + to populate common data. This method *must* be overridden, like so:: class MyPresentationController(PresentationController): @@ -357,11 +355,9 @@ class PresentationController(object): PresentationController.__init( self, plugin, u'My Presenter App') - ``plugin`` - Defaults to *None*. The presentationplugin object - - ``name`` - Name of the application, to appear in the application + :param plugin: Defaults to *None*. The presentationplugin object + :param name: Name of the application, to appear in the application + :param document_class: """ self.supports = [] self.also_supports = [] diff --git a/openlp/plugins/remotes/html/jquery.mobile.js b/openlp/plugins/remotes/html/jquery.mobile.js index c12426c0a..cb2e72be0 100644 --- a/openlp/plugins/remotes/html/jquery.mobile.js +++ b/openlp/plugins/remotes/html/jquery.mobile.js @@ -2485,7 +2485,7 @@ $.mobile.transitionFallbacks = {}; return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' ); }, - //return the substring of a filepath before the sub-page key, for making a server request + //return the substring of a file_path before the sub-page key, for making a server request getFilePath: function( path ) { var splitkey = '&' + $.mobile.subPageUrlKey; return path && path.split( splitkey )[0].split( dialogHashKey )[0]; diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index c2d9a3110..4521ea1e4 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -201,7 +201,7 @@ class SongImportForm(OpenLPWizard): def validateCurrentPage(self): """ 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: return True @@ -217,7 +217,7 @@ class SongImportForm(OpenLPWizard): import_source = self.format_widgets[this_format]['file_path_edit'].text() error_title = (UiStrings().IFSs if select_mode == SongFormatSelect.SingleFile else UiStrings().IFdSs) 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) focus_button.setFocus() return False @@ -334,7 +334,7 @@ class SongImportForm(OpenLPWizard): def perform_wizard(self): """ - Perform the actual import. This method pulls in the correct importer class, and then runs the ``doImport`` + Perform the actual import. This method pulls in the correct importer class, and then runs the ``do_import`` method of the importer to do the actual importing. """ source_format = self.current_format @@ -349,7 +349,7 @@ class SongImportForm(OpenLPWizard): importer = self.plugin.import_songs( source_format, filenames=self.get_list_of_files(self.format_widgets[source_format]['file_list_widget'])) - importer.doImport() + importer.do_import() self.progress_label.setText(WizardStrings.FinishedImport) def on_error_copy_to_button_clicked(self): diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 45dfc5460..1c9141b16 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -389,7 +389,6 @@ def clean_song(manager, song): song.lyrics = str(song.lyrics, encoding='utf8') verses = SongXML().get_verses(song.lyrics) song.search_lyrics = ' '.join([clean_string(verse[1]) for verse in verses]) - # The song does not have any author, add one. if not song.authors: name = SongStrings.AuthorUnknown diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/cclifileimport.py index 252b9e4b5..54779a194 100644 --- a/openlp/plugins/songs/lib/cclifileimport.py +++ b/openlp/plugins/songs/lib/cclifileimport.py @@ -38,26 +38,23 @@ from .songimport import SongImport log = logging.getLogger(__name__) + class CCLIFileImport(SongImport): """ - The :class:`CCLIFileImport` class provides OpenLP with the ability to import - CCLI SongSelect song files in both .txt and .usr formats. See - ``_ for more details. + The :class:`CCLIFileImport` class provides OpenLP with the ability to import CCLI SongSelect song files in + both .txt and .usr formats. See ``_ for more details. """ def __init__(self, manager, **kwargs): """ Initialise the import. - ``manager`` - The song manager for the running OpenLP installation. - - ``filenames`` - The files to be imported. + :param manager: The song manager for the running OpenLP installation. + :param kwargs: The files to be imported. """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Import either a ``.usr`` or a ``.txt`` SongSelect file. """ @@ -85,27 +82,24 @@ class CCLIFileImport(SongImport): ext = os.path.splitext(filename)[1] if ext.lower() == '.usr': log.info('SongSelect .usr format file found: %s', filename) - if not self.doImportUsrFile(lines): - self.logError(filename) + if not self.do_import_usr_file(lines): + self.log_error(filename) elif ext.lower() == '.txt': log.info('SongSelect .txt format file found: %s', filename) - if not self.doImportTxtFile(lines): - self.logError(filename) + if not self.do_import_txt_file(lines): + self.log_error(filename) else: - self.logError(filename, + self.log_error(filename, translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid extension.')) log.info('Extension %s is not valid', filename) if self.stop_import_flag: return - def doImportUsrFile(self, textList): + def do_import_usr_file(self, text_list): """ The :func:`doImport_usr_file` method provides OpenLP with the ability to import CCLI SongSelect songs in *USR* file format. - ``textList`` - An array of strings containing the usr file content. - **SongSelect .usr file format** ``[File]`` @@ -155,17 +149,18 @@ class CCLIFileImport(SongImport): *Fields* description e.g. *Words=Above all powers....* [/n = CR, /n/t = CRLF] + :param text_list: An array of strings containing the usr file content. """ - log.debug('USR file text: %s', textList) + log.debug('USR file text: %s', text_list) song_author = '' song_topics = '' - for line in textList: + for line in text_list: if line.startswith('[S '): ccli, line = line.split(']', 1) if ccli.startswith('[S A'): - self.ccliNumber = ccli[4:].strip() + self.ccli_number = ccli[4:].strip() else: - self.ccliNumber = ccli[3:].strip() + self.ccli_number = ccli[3:].strip() if line.startswith('Title='): self.title = line[6:].strip() elif line.startswith('Author='): @@ -176,7 +171,7 @@ class CCLIFileImport(SongImport): song_topics = line[7:].strip().replace(' | ', '/t') elif line.startswith('Fields='): # Fields contain single line indicating verse, chorus, etc, - # /t delimited, same as with words field. store seperately + # /t delimited, same as with words field. store separately # and process at end. song_fields = line[7:].strip() elif line.startswith('Words='): @@ -213,7 +208,7 @@ class CCLIFileImport(SongImport): verse_type = VerseType.tags[VerseType.Other] verse_text = verse_lines[1] if verse_text: - self.addVerse(verse_text, verse_type) + self.add_verse(verse_text, verse_type) check_first_verse_line = False # Handle multiple authors author_list = song_author.split('/') @@ -223,17 +218,16 @@ class CCLIFileImport(SongImport): separated = author.split(',') if len(separated) > 1: 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')] return self.finish() - def doImportTxtFile(self, textList): + def do_import_txt_file(self, text_list): """ The :func:`doImport_txt_file` method provides OpenLP with the ability to import CCLI SongSelect songs in *TXT* file format. - ``textList`` - An array of strings containing the txt file content. + :param text_list: An array of strings containing the txt file content. SongSelect .txt file format:: @@ -259,20 +253,20 @@ class CCLIFileImport(SongImport): # e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14 """ - log.debug('TXT file text: %s', textList) + log.debug('TXT file text: %s', text_list) line_number = 0 check_first_verse_line = False verse_text = '' song_author = '' verse_start = False - for line in textList: + for line in text_list: clean_line = line.strip() if not clean_line: if line_number == 0: continue elif verse_start: if verse_text: - self.addVerse(verse_text, verse_type) + self.add_verse(verse_text, verse_type) verse_text = '' verse_start = False else: @@ -286,7 +280,7 @@ class CCLIFileImport(SongImport): if clean_line.startswith('CCLI'): line_number += 1 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: # We have the verse descriptor verse_desc_parts = clean_line.split(' ') @@ -348,5 +342,5 @@ class CCLIFileImport(SongImport): author_list = song_author.split('|') # Clean spaces before and after author names. for author_name in author_list: - self.addAuthor(author_name.strip()) + self.add_author(author_name.strip()) return self.finish() diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index c1c29e146..4f5712012 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -87,6 +87,7 @@ class Topic(BaseModel): """ pass + def init_schema(url): """ Setup the songs database connection and initialise the database schema. @@ -183,8 +184,7 @@ def init_schema(url): # Definition of the "media_files" table media_files_table = Table('media_files', metadata, Column('id', types.Integer(), primary_key=True), - Column('song_id', types.Integer(), ForeignKey('songs.id'), - default=None), + Column('song_id', types.Integer(), ForeignKey('songs.id'), default=None), Column('file_name', types.Unicode(255), nullable=False), Column('type', types.Unicode(64), nullable=False, default='audio'), Column('weight', types.Integer(), default=0) @@ -200,8 +200,7 @@ def init_schema(url): # Definition of the "songs" table songs_table = Table('songs', metadata, Column('id', types.Integer(), primary_key=True), - Column('song_book_id', types.Integer(), - ForeignKey('song_books.id'), default=None), + Column('song_book_id', types.Integer(), ForeignKey('song_books.id'), default=None), Column('title', types.Unicode(255), nullable=False), Column('alternate_title', types.Unicode(255)), Column('lyrics', types.UnicodeText, nullable=False), @@ -214,8 +213,7 @@ def init_schema(url): Column('search_title', types.Unicode(255), index=True, nullable=False), Column('search_lyrics', types.UnicodeText, nullable=False), Column('create_date', types.DateTime(), default=func.now()), - Column('last_modified', types.DateTime(), default=func.now(), - onupdate=func.now()), + Column('last_modified', types.DateTime(), default=func.now(), onupdate=func.now()), Column('temporary', types.Boolean(), default=False) ) @@ -227,18 +225,14 @@ def init_schema(url): # Definition of the "authors_songs" table authors_songs_table = Table('authors_songs', metadata, - Column('author_id', types.Integer(), - ForeignKey('authors.id'), primary_key=True), - Column('song_id', types.Integer(), - ForeignKey('songs.id'), primary_key=True) + Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True), + Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True) ) # Definition of the "songs_topics" table songs_topics_table = Table('songs_topics', metadata, - Column('song_id', types.Integer(), - ForeignKey('songs.id'), primary_key=True), - Column('topic_id', types.Integer(), - ForeignKey('topics.id'), primary_key=True) + Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True), + Column('topic_id', types.Integer(), ForeignKey('topics.id'), primary_key=True) ) mapper(Author, authors_table) @@ -246,13 +240,10 @@ def init_schema(url): mapper(MediaFile, media_files_table) mapper(Song, songs_table, properties={ - 'authors': relation(Author, backref='songs', - secondary=authors_songs_table, lazy=False), + 'authors': relation(Author, backref='songs', secondary=authors_songs_table, lazy=False), 'book': relation(Book, backref='songs'), - 'media_files': relation(MediaFile, backref='songs', - order_by=media_files_table.c.weight), - 'topics': relation(Topic, backref='songs', - secondary=songs_topics_table) + 'media_files': relation(MediaFile, backref='songs', order_by=media_files_table.c.weight), + 'topics': relation(Topic, backref='songs', secondary=songs_topics_table) }) mapper(Topic, topics_table) diff --git a/openlp/plugins/songs/lib/dreambeamimport.py b/openlp/plugins/songs/lib/dreambeamimport.py index 62f9728c9..18da6d8e3 100644 --- a/openlp/plugins/songs/lib/dreambeamimport.py +++ b/openlp/plugins/songs/lib/dreambeamimport.py @@ -40,6 +40,7 @@ from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) + class DreamBeamImport(SongImport): """ The :class:`DreamBeamImport` class provides the ability to import song files from @@ -83,7 +84,7 @@ class DreamBeamImport(SongImport): * \*.xml """ - def doImport(self): + def do_import(self): """ Receive a single file or a list of files to import. """ @@ -92,18 +93,19 @@ class DreamBeamImport(SongImport): for file in self.import_source: if self.stop_import_flag: return - self.setDefaults() + self.set_defaults() parser = etree.XMLParser(remove_blank_text=True) try: parsed_file = etree.parse(open(file, 'r'), parser) except etree.XMLSyntaxError: log.exception('XML syntax error in file %s' % file) - self.logError(file, SongStrings.XMLSyntaxError) + self.log_error(file, SongStrings.XMLSyntaxError) continue xml = etree.tostring(parsed_file).decode() song_xml = objectify.fromstring(xml) if song_xml.tag != 'DreamSong': - self.logError(file, + self.log_error( + file, translate('SongsPlugin.DreamBeamImport', 'Invalid DreamBeam song file. Missing DreamSong tag.')) continue if hasattr(song_xml, 'Version'): @@ -121,15 +123,15 @@ class DreamBeamImport(SongImport): verse_type = lyrics_item.get('Type') verse_number = lyrics_item.get('Number') 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'): - self.songBookName = str(song_xml.Collection.text) + self.song_book_name = str(song_xml.Collection.text) 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'): - for LyricsSequenceItem in (song_xml.Sequence.iterchildren()): - self.verseOrderList.append("%s%s" % (LyricsSequenceItem.get('Type')[:1], - LyricsSequenceItem.get('Number'))) + for lyrics_sequence_item in (song_xml.Sequence.iterchildren()): + self.verse_order_list.append("%s%s" % (lyrics_sequence_item.get('Type')[:1], + lyrics_sequence_item.get('Number'))) if hasattr(song_xml, 'Notes'): self.comments = str(song_xml.Notes.text) else: @@ -138,15 +140,15 @@ class DreamBeamImport(SongImport): if hasattr(song_xml.Text1, 'Text'): self.lyrics = str(song_xml.Text1.Text.text) for verse in self.lyrics.split('\n\n\n'): - self.addVerse(verse) + self.add_verse(verse) if hasattr(song_xml.Text2, 'Text'): author_copyright = song_xml.Text2.Text.text if author_copyright: author_copyright = str(author_copyright) if author_copyright.find( str(SongStrings.CopyrightSymbol)) >= 0: - self.addCopyright(author_copyright) + self.add_copyright(author_copyright) else: self.parse_author(author_copyright) if not self.finish(): - self.logError(file) + self.log_error(file) diff --git a/openlp/plugins/songs/lib/easyslidesimport.py b/openlp/plugins/songs/lib/easyslidesimport.py index 83333aab0..628d64880 100644 --- a/openlp/plugins/songs/lib/easyslidesimport.py +++ b/openlp/plugins/songs/lib/easyslidesimport.py @@ -37,6 +37,7 @@ from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) + class EasySlidesImport(SongImport): """ Import songs exported from EasySlides @@ -50,7 +51,7 @@ class EasySlidesImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): log.info('Importing EasySlides XML file %s', self.import_source) parser = etree.XMLParser(remove_blank_text=True) parsed_file = etree.parse(self.import_source, parser) @@ -60,18 +61,18 @@ class EasySlidesImport(SongImport): for song in song_xml.Item: if self.stop_import_flag: return - self._parseSong(song) + self._parse_song(song) - def _parseSong(self, song): + def _parse_song(self, song): self._success = True self._add_unicode_attribute('title', song.Title1, True) if hasattr(song, 'Title2'): - self._add_unicode_attribute('alternateTitle', song.Title2) + self._add_unicode_attribute('alternate_title', song.Title2) if hasattr(song, 'SongNumber'): - self._add_unicode_attribute('songNumber', song.SongNumber) - if self.songNumber == '0': - self.songNumber = '' - self._addAuthors(song) + self._add_unicode_attribute('song_number', song.SongNumber) + if self.song_number == '0': + self.song_number = '' + self._add_authors(song) if hasattr(song, 'Copyright'): self._add_copyright(song.Copyright) if hasattr(song, 'LicenceAdmin1'): @@ -79,13 +80,13 @@ class EasySlidesImport(SongImport): if hasattr(song, 'LicenceAdmin2'): self._add_copyright(song.LicenceAdmin2) if hasattr(song, 'BookReference'): - self._add_unicode_attribute('songBookName', song.BookReference) - self._parseAndAddLyrics(song) + self._add_unicode_attribute('song_book_name', song.BookReference) + self._parse_and_add_lyrics(song) if self._success: if not self.finish(): - self.logError(song.Title1 if song.Title1 else '') + self.log_error(song.Title1 if song.Title1 else '') else: - self.setDefaults() + self.set_defaults() def _add_unicode_attribute(self, self_attribute, import_attribute, mandatory=False): """ @@ -94,14 +95,9 @@ class EasySlidesImport(SongImport): present _success is set to False so the importer can react appropriately. - ``self_attribute`` - The attribute in the song model to populate. - - ``import_attribute`` - The imported value to convert to unicode and save to the song. - - ``mandatory`` - Signals that this attribute must exist in a valid song. + :param self_attribute: The attribute in the song model to populate. + :param import_attribute: The imported value to convert to unicode and save to the song. + :param mandatory: Signals that this attribute must exist in a valid song. """ try: setattr(self, self_attribute, str(import_attribute).strip()) @@ -113,7 +109,7 @@ class EasySlidesImport(SongImport): if mandatory: self._success = False - def _addAuthors(self, song): + def _add_authors(self, song): try: authors = str(song.Writer).split(',') self.authors = [author.strip() for author in authors if author.strip()] @@ -125,21 +121,24 @@ class EasySlidesImport(SongImport): def _add_copyright(self, element): """ - Add a piece of copyright to the total copyright information for the - song. + Add a piece of copyright to the total copyright information for the song. - ``element`` - The imported variable to get the data from. + :param element: The imported variable to get the data from. """ try: - self.addCopyright(str(element).strip()) + self.add_copyright(str(element).strip()) except UnicodeDecodeError: log.exception('Unicode error on decoding copyright: %s' % element) self._success = False except AttributeError: pass - def _parseAndAddLyrics(self, song): + def _parse_and_add_lyrics(self, song): + """ + Process the song lyrics + + :param song: The song details + """ try: lyrics = str(song.Contents).strip() except UnicodeDecodeError: @@ -151,29 +150,29 @@ class EasySlidesImport(SongImport): lines = lyrics.split('\n') # we go over all lines first, to determine information, # which tells us how to parse verses later - regionlines = {} - separatorlines = 0 + region_lines = {} + separator_lines = 0 for line in lines: line = line.strip() if not line: continue elif line[1:7] == 'region': # this is region separator, probably [region 2] - region = self._extractRegion(line) - regionlines[region] = 1 + regionlines.get(region, 0) + region = self._extract_region(line) + region_lines[region] = 1 + region_lines.get(region, 0) elif line[0] == '[': - separatorlines += 1 + separator_lines += 1 # if the song has separators - separators = (separatorlines > 0) + separators = (separator_lines > 0) # the number of different regions in song - 1 - if len(regionlines) > 1: + if len(region_lines) > 1: log.info('EasySlidesImport: the file contained a song named "%s"' - 'with more than two regions, but only two regions are tested, encountered regions were: %s', - self.title, ','.join(list(regionlines.keys()))) + 'with more than two regions, but only two regions are tested, encountered regions were: %s', + self.title, ','.join(list(region_lines.keys()))) # if the song has regions - regions = (len(regionlines) > 0) + regions = (len(region_lines) > 0) # if the regions are inside verses - regionsInVerses = (regions and regionlines[list(regionlines.keys())[0]] > 1) + regions_in_verses = (regions and region_lines[list(region_lines.keys())[0]] > 1) MarkTypes = { 'CHORUS': VerseType.tags[VerseType.Chorus], 'VERSE': VerseType.tags[VerseType.Verse], @@ -185,21 +184,20 @@ class EasySlidesImport(SongImport): verses = {} # list as [region, versetype, versenum, instance] our_verse_order = [] - defaultregion = '1' - reg = defaultregion + default_region = '1' + reg = default_region verses[reg] = {} # instance differentiates occurrences of same verse tag vt = 'V' vn = '1' inst = 1 - for line in lines: line = line.strip() if not line: if separators: # separators are used, so empty line means slide break # inside verse - if self._listHas(verses, [reg, vt, vn, inst]): + if self._list_has(verses, [reg, vt, vn, inst]): inst += 1 else: # separators are not used, so empty line starts a new verse @@ -207,9 +205,9 @@ class EasySlidesImport(SongImport): vn = len(verses[reg].get(vt, {})) + 1 inst = 1 elif line[0:7] == '[region': - reg = self._extractRegion(line) + reg = self._extract_region(line) verses.setdefault(reg, {}) - if not regionsInVerses: + if not regions_in_verses: vt = 'V' vn = '1' inst = 1 @@ -224,10 +222,10 @@ class EasySlidesImport(SongImport): marker = match.group(1).strip() vn = match.group(2) vt = MarkTypes.get(marker, 'O') if marker else 'V' - if regionsInVerses: - region = defaultregion + if regions_in_verses: + region = default_region inst = 1 - if self._listHas(verses, [reg, vt, vn, inst]): + if self._list_has(verses, [reg, vt, vn, inst]): inst = len(verses[reg][vt][vn]) + 1 else: if not [reg, vt, vn, inst] in our_verse_order: @@ -235,21 +233,19 @@ class EasySlidesImport(SongImport): verses[reg].setdefault(vt, {}) verses[reg][vt].setdefault(vn, {}) 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 - versetags = [] # we use our_verse_order to ensure, we insert lyrics in the same order # as these appeared originally in the file for [reg, vt, vn, inst] in our_verse_order: - if self._listHas(verses, [reg, vt, vn, inst]): + if self._list_has(verses, [reg, vt, vn, inst]): # this is false, but needs user input lang = None versetag = '%s%s' % (vt, vn) versetags.append(versetag) lines = '\n'.join(verses[reg][vt][vn][inst]) self.verses.append([versetag, lines, lang]) - SeqTypes = { 'p': 'P1', 'q': 'P2', @@ -271,25 +267,37 @@ class EasySlidesImport(SongImport): else: continue if tag in versetags: - self.verseOrderList.append(tag) + self.verse_order_list.append(tag) else: - log.info('Got order item %s, which is not in versetags, dropping item from presentation order', - tag) + log.info('Got order item %s, which is not in versetags, dropping item from presentation order', tag) except UnicodeDecodeError: log.exception('Unicode decode error while decoding Sequence') self._success = False except AttributeError: pass - def _listHas(self, lst, subitems): - for subitem in subitems: - if subitem in lst: - lst = lst[subitem] + def _list_has(self, lst, sub_items): + """ + See if the list has sub items + + :param lst: The list to check + :param sub_items: sub item list + :return: + """ + for sub_item in sub_items: + if sub_item in lst: + lst = lst[sub_item] else: return False return True - def _extractRegion(self, line): + def _extract_region(self, line): # this was true already: line[0:7] == u'[region': + """ + Extract the region from text + + :param line: The line of text + :return: + """ right_bracket = line.find(']') return line[7:right_bracket].strip() diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index cbae52142..9e3ae566e 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -75,7 +75,12 @@ class EasyWorshipSongImport(SongImport): def __init__(self, manager, **kwargs): SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): + """ + Import the songs + + :return: + """ # Open the DB and MB files if they exist import_source_mb = self.import_source.replace('.DB', '.MB') if not os.path.isfile(self.import_source) or not os.path.isfile(import_source_mb): @@ -84,12 +89,12 @@ class EasyWorshipSongImport(SongImport): if db_size < 0x800: return db_file = open(self.import_source, 'rb') - self.memoFile = open(import_source_mb, 'rb') + self.memo_file = open(import_source_mb, 'rb') # Don't accept files that are clearly not paradox files record_size, header_size, block_size, first_block, num_fields = struct.unpack(' 4: db_file.close() - self.memoFile.close() + self.memo_file.close() return # Take a stab at how text is encoded self.encoding = 'cp1252' @@ -124,20 +129,20 @@ class EasyWorshipSongImport(SongImport): db_file.seek(4 + (num_fields * 4) + 261, os.SEEK_CUR) field_names = db_file.read(header_size - db_file.tell()).split(b'\0', num_fields) field_names.pop() - field_descs = [] + field_descriptions = [] for i, field_name in enumerate(field_names): field_type, field_size = struct.unpack_from('BB', field_info, i * 2) - field_descs.append(FieldDescEntry(field_name, field_type, field_size)) - self.setRecordStruct(field_descs) + field_descriptions.append(FieldDescEntry(field_name, field_type, field_size)) + self.set_record_struct(field_descriptions) # Pick out the field description indexes we will need try: success = True - fi_title = self.findField(b'Title') - fi_author = self.findField(b'Author') - fi_copy = self.findField(b'Copyright') - fi_admin = self.findField(b'Administrator') - fi_words = self.findField(b'Words') - fi_ccli = self.findField(b'Song Number') + fi_title = self.find_field(b'Title') + fi_author = self.find_field(b'Author') + fi_copy = self.find_field(b'Copyright') + fi_admin = self.find_field(b'Administrator') + fi_words = self.find_field(b'Words') + fi_ccli = self.find_field(b'Song Number') except IndexError: # This is the wrong table success = False @@ -162,15 +167,15 @@ class EasyWorshipSongImport(SongImport): if self.stop_import_flag: break raw_record = db_file.read(record_size) - self.fields = self.recordStruct.unpack(raw_record) - self.setDefaults() - self.title = self.getField(fi_title).decode() + self.fields = self.record_structure.unpack(raw_record) + self.set_defaults() + self.title = self.get_field(fi_title).decode() # Get remaining fields. - copy = self.getField(fi_copy) - admin = self.getField(fi_admin) - ccli = self.getField(fi_ccli) - authors = self.getField(fi_author) - words = self.getField(fi_words) + copy = self.get_field(fi_copy) + admin = self.get_field(fi_admin) + ccli = self.get_field(fi_ccli) + authors = self.get_field(fi_author) + words = self.get_field(fi_words) # Set the SongImport object members. if copy: self.copyright = copy.decode() @@ -180,7 +185,7 @@ class EasyWorshipSongImport(SongImport): self.copyright += translate('SongsPlugin.EasyWorshipSongImport', 'Administered by %s') % admin.decode() if ccli: - self.ccliNumber = ccli.decode() + self.ccli_number = ccli.decode() if authors: # Split up the authors author_list = authors.split(b'/') @@ -189,7 +194,7 @@ class EasyWorshipSongImport(SongImport): if len(author_list) < 2: author_list = authors.split(b',') for author_name in author_list: - self.addAuthor(author_name.decode().strip()) + self.add_author(author_name.decode().strip()) if words: # Format the lyrics result = strip_rtf(words.decode(), self.encoding) @@ -227,24 +232,35 @@ class EasyWorshipSongImport(SongImport): if not number_found: verse_type += '1' 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: 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: break if not self.finish(): - self.logError(self.import_source) + self.log_error(self.import_source) db_file.close() - self.memoFile.close() + self.memo_file.close() - def findField(self, field_name): - return [i for i, x in enumerate(self.fieldDescs) if x.name == field_name][0] + def find_field(self, field_name): + """ + Find a field in the descriptions - def setRecordStruct(self, field_descs): + :param field_name: field to find + :return: + """ + return [i for i, x in enumerate(self.field_descriptions) if x.name == field_name][0] + + def set_record_struct(self, field_descriptions): + """ + Save the record structure + + :param field_descriptions: An array of field descriptions + """ # Begin with empty field struct list fsl = ['>'] - for field_desc in field_descs: + for field_desc in field_descriptions: if field_desc.field_type == FieldType.String: fsl.append('%ds' % field_desc.size) elif field_desc.field_type == FieldType.Int16: @@ -261,12 +277,18 @@ class EasyWorshipSongImport(SongImport): fsl.append('Q') else: fsl.append('%ds' % field_desc.size) - self.recordStruct = struct.Struct(''.join(fsl)) - self.fieldDescs = field_descs + self.record_structure = struct.Struct(''.join(fsl)) + self.field_descriptions = field_descriptions - def getField(self, field_desc_index): + def get_field(self, field_desc_index): + """ + Extract the field + + :param field_desc_index: Field index value + :return: + """ field = self.fields[field_desc_index] - field_desc = self.fieldDescs[field_desc_index] + field_desc = self.field_descriptions[field_desc_index] # Return None in case of 'blank' entries if isinstance(field, bytes): if not field.rstrip(b'\0'): @@ -281,23 +303,23 @@ class EasyWorshipSongImport(SongImport): elif field_desc.field_type == FieldType.Int32: return field ^ 0x80000000 elif field_desc.field_type == FieldType.Logical: - return (field ^ 0x80 == 1) + return field ^ 0x80 == 1 elif field_desc.field_type == FieldType.Memo or field_desc.field_type == FieldType.Blob: block_start, blob_size = struct.unpack_from(' 63: return b'' - self.memoFile.seek(11 + (5 * sub_block), os.SEEK_CUR) - sub_block_start, = struct.unpack('B', self.memoFile.read(1)) - self.memoFile.seek(block_start + (sub_block_start * 16)) + self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) + sub_block_start, = struct.unpack('B', self.memo_file.read(1)) + self.memo_file.seek(block_start + (sub_block_start * 16)) else: return b'' - return self.memoFile.read(blob_size) + return self.memo_file.read(blob_size) else: return 0 diff --git a/openlp/plugins/songs/lib/foilpresenterimport.py b/openlp/plugins/songs/lib/foilpresenterimport.py index 785151698..5c88cc6a3 100644 --- a/openlp/plugins/songs/lib/foilpresenterimport.py +++ b/openlp/plugins/songs/lib/foilpresenterimport.py @@ -106,6 +106,7 @@ from openlp.plugins.songs.lib.xml import SongXML log = logging.getLogger(__name__) + class FoilPresenterImport(SongImport): """ This provides the Foilpresenter import. @@ -116,9 +117,9 @@ class FoilPresenterImport(SongImport): """ log.debug('initialise FoilPresenterImport') SongImport.__init__(self, manager, **kwargs) - self.FoilPresenter = FoilPresenter(self.manager, self) + self.foil_presenter = FoilPresenter(self.manager, self) - def doImport(self): + def do_import(self): """ Imports the songs. """ @@ -131,9 +132,9 @@ class FoilPresenterImport(SongImport): try: parsed_file = etree.parse(file_path, parser) xml = etree.tostring(parsed_file).decode() - self.FoilPresenter.xml_to_song(xml) + self.foil_presenter.xml_to_song(xml) 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) @@ -245,8 +246,7 @@ class FoilPresenter(object): """ This returns the text of an element as unicode string. - ``element`` - The element. + :param element: The element """ if element is not None: return str(element) @@ -256,11 +256,8 @@ class FoilPresenter(object): """ Adds the authors specified in the XML to the song. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ authors = [] try: @@ -324,8 +321,7 @@ class FoilPresenter(object): break author_temp = [] for author in strings: - temp = re.split(',(?=\D{2})|(?<=\D),|\/(?=\D{3,})|(?<=\D);', - author) + temp = re.split(',(?=\D{2})|(?<=\D),|\/(?=\D{3,})|(?<=\D);', author) for tempx in temp: author_temp.append(tempx) for author in author_temp: @@ -349,7 +345,7 @@ class FoilPresenter(object): if author is None: # We need to create a new author, as the author does not exist. author = Author.populate(display_name=display_name, last_name=display_name.split(' ')[-1], - first_name=' '.join(display_name.split(' ')[:-1])) + first_name=' '.join(display_name.split(' ')[:-1])) self.manager.save_object(author) song.authors.append(author) @@ -357,11 +353,8 @@ class FoilPresenter(object): """ Adds the CCLI number to the song. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ try: song.ccli_number = self._child(foilpresenterfolie.ccliid) @@ -372,11 +365,8 @@ class FoilPresenter(object): """ Joins the comments specified in the XML and add it to the song. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ try: song.comments = self._child(foilpresenterfolie.notiz) @@ -387,11 +377,8 @@ class FoilPresenter(object): """ Adds the copyright to the song. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ try: song.copyright = self._child(foilpresenterfolie.copyright.text_) @@ -402,11 +389,8 @@ class FoilPresenter(object): """ Processes the verses and search_lyrics for the song. - ``foilpresenterfolie`` - The foilpresenterfolie object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The foilpresenterfolie object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ sxml = SongXML() temp_verse_order = {} @@ -423,9 +407,9 @@ class FoilPresenter(object): VerseType.tags[VerseType.PreChorus]: 1 } if not hasattr(foilpresenterfolie.strophen, 'strophe'): - self.importer.logError(self._child(foilpresenterfolie.titel), - str(translate('SongsPlugin.FoilPresenterSongImport', - 'Invalid Foilpresenter song file. No verses found.'))) + self.importer.log_error(self._child(foilpresenterfolie.titel), + str(translate('SongsPlugin.FoilPresenterSongImport', + 'Invalid Foilpresenter song file. No verses found.'))) self.save_song = False return for strophe in foilpresenterfolie.strophen.strophe: @@ -478,10 +462,8 @@ class FoilPresenter(object): verse_number = str(int(verse_number) + 1) verse_type_index = VerseType.from_tag(verse_type[0]) verse_type = VerseType.tags[verse_type_index] - temp_verse_order[verse_sortnr] = ''.join((verse_type[0], - verse_number)) - temp_verse_order_backup.append(''.join((verse_type[0], - verse_number))) + temp_verse_order[verse_sortnr] = ''.join((verse_type[0], verse_number)) + temp_verse_order_backup.append(''.join((verse_type[0], verse_number))) sxml.add_verse_to_lyrics(verse_type, verse_number, text) song.lyrics = str(sxml.extract_xml(), 'utf-8') # Process verse order @@ -506,11 +488,8 @@ class FoilPresenter(object): """ Adds the song book and song number specified in the XML to the song. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ song.song_book_id = 0 song.song_number = '' @@ -518,8 +497,7 @@ class FoilPresenter(object): for bucheintrag in foilpresenterfolie.buch.bucheintrag: book_name = self._child(bucheintrag.name) if book_name: - book = self.manager.get_object_filtered(Book, - Book.name == book_name) + book = self.manager.get_object_filtered(Book, Book.name == book_name) if book is None: # We need to create a book, because it does not exist. book = Book.populate(name=book_name, publisher='') @@ -539,11 +517,8 @@ class FoilPresenter(object): """ Processes the titles specified in the song's XML. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ try: for title_string in foilpresenterfolie.titel.titelstring: @@ -561,18 +536,14 @@ class FoilPresenter(object): """ Adds the topics to the song. - ``foilpresenterfolie`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param foilpresenterfolie: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ try: for name in foilpresenterfolie.kategorien.name: topic_text = self._child(name) if topic_text: - topic = self.manager.get_object_filtered(Topic, - Topic.name == topic_text) + topic = self.manager.get_object_filtered(Topic, Topic.name == topic_text) if topic is None: # We need to create a topic, because it does not exist. topic = Topic.populate(name=topic_text) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 37a147ba9..0d05d1fd3 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -82,6 +82,7 @@ if os.name == 'nt': except ImportError: log.exception('Error importing %s', 'WorshipCenterProImport') + class SongFormatSelect(object): """ This is a special enumeration class listing available file selection modes. @@ -99,47 +100,47 @@ class SongFormat(object): Required attributes for each song format: - ``u'class'`` + ``'class'`` Import class, e.g. ``OpenLyricsImport`` - ``u'name'`` - Name of the format, e.g. ``u'OpenLyrics'`` + ``'name'`` + Name of the format, e.g. ``'OpenLyrics'`` - ``u'prefix'`` - Prefix for Qt objects. Use mixedCase, e.g. ``u'openLyrics'`` + ``'prefix'`` + Prefix for Qt objects. Use mixedCase, e.g. ``'open_lyrics'`` See ``SongImportForm.add_file_select_item()`` Optional attributes for each song format: - ``u'canDisable'`` + ``'canDisable'`` Whether song format importer is disablable. - If ``True``, then ``u'disabledLabelText'`` must also be defined. + If ``True``, then ``'disabledLabelText'`` must also be defined. - ``u'availability'`` + ``'availability'`` Whether song format importer is available. - ``u'selectMode'`` + ``'selectMode'`` Whether format accepts single file, multiple files, or single folder (as per ``SongFormatSelect`` options). - ``u'filter'`` + ``'filter'`` File extension filter for ``QFileDialog``. Optional/custom text Strings for ``SongImportForm`` widgets: - ``u'comboBoxText'`` - Combo box selector (default value is the format's ``u'name'``). + ``'comboBoxText'`` + Combo box selector (default value is the format's ``'name'``). - ``u'disabledLabelText'`` + ``'disabledLabelText'`` Required for disablable song formats. - ``u'getFilesTitle'`` - Title for ``QFileDialog`` (default includes the format's ``u'name'``). + ``'getFilesTitle'`` + Title for ``QFileDialog`` (default includes the format's ``'name'``). - ``u'invalidSourceMsg'`` - Message displayed if ``isValidSource()`` returns ``False``. + ``'invalidSourceMsg'`` + Message displayed if ``is_valid_source()`` returns ``False``. - ``u'descriptionText'`` + ``'descriptionText'`` Short description (1-2 lines) about the song format. """ # Song formats (ordered alphabetically after Generic) @@ -184,7 +185,7 @@ class SongFormat(object): OpenLyrics: { 'class': OpenLyricsImport, 'name': 'OpenLyrics', - 'prefix': 'openLyrics', + 'prefix': 'open_lyrics', 'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2.0 Exported Song') }, @@ -200,8 +201,8 @@ class SongFormat(object): 'prefix': 'generic', 'canDisable': True, 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', - 'The generic document/presentation importer has been disabled ' - 'because OpenLP cannot access OpenOffice or LibreOffice.'), + 'The generic document/presentation importer has been disabled ' + 'because OpenLP cannot access OpenOffice or LibreOffice.'), 'getFilesTitle': translate('SongsPlugin.ImportWizardForm', 'Select Document/Presentation Files') }, CCLI: { @@ -241,13 +242,12 @@ class SongFormat(object): 'prefix': 'mediaShout', 'canDisable': True, 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', - 'MediaShout Database'), + 'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'MediaShout Database'), 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', - 'The MediaShout 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.') + 'The MediaShout 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.') }, OpenSong: { 'class': OpenSongImport, @@ -259,15 +259,14 @@ class SongFormat(object): 'name': 'PowerSong 1.0', 'prefix': 'powerSong', 'selectMode': SongFormatSelect.SingleFolder, - 'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', - 'You need to specify a valid PowerSong 1.0 database folder.') + 'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', 'You need to specify a valid PowerSong 1.0 ' + 'database folder.') }, SongBeamer: { 'class': SongBeamerImport, 'name': 'SongBeamer', 'prefix': 'songBeamer', - 'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', - 'SongBeamer Files') + 'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files') }, SongPro: { 'class': SongProImport, @@ -277,7 +276,7 @@ class SongFormat(object): 'filter': '%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', 'SongPro Text Files'), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'SongPro (Export File)'), 'descriptionText': translate('SongsPlugin.ImportWizardForm', - 'In SongPro, export your songs using the File -> Export menu') + 'In SongPro, export your songs using the File -> Export menu') }, SongShowPlus: { 'class': SongShowPlusImport, @@ -291,8 +290,8 @@ class SongFormat(object): 'canDisable': True, 'filter': '%s (*.rtf)' % translate('SongsPlugin.ImportWizardForm', 'Songs Of Fellowship Song Files'), 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', - 'The Songs of Fellowship importer has been disabled because ' - 'OpenLP cannot access OpenOffice or LibreOffice.') + 'The Songs of Fellowship importer has been disabled because ' + 'OpenLP cannot access OpenOffice or LibreOffice.') }, SundayPlus: { 'class': SundayPlusImport, @@ -304,8 +303,7 @@ class SongFormat(object): 'class': WowImport, 'name': 'Words of Worship', 'prefix': 'wordsOfWorship', - 'filter': '%s (*.wsg *.wow-song)' % - translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') + 'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') }, WorshipCenterPro: { 'name': 'WorshipCenter Pro', @@ -314,8 +312,9 @@ class SongFormat(object): 'selectMode': SongFormatSelect.SingleFile, 'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'WorshipCenter Pro Song Files'), '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.') + '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: { 'class': ZionWorxImport, @@ -324,9 +323,9 @@ class SongFormat(object): 'selectMode': SongFormatSelect.SingleFile, 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'ZionWorx (CSV)'), 'descriptionText': translate('SongsPlugin.ImportWizardForm', - 'First convert your ZionWorx database to a CSV text file, as ' - 'explained in the User Manual.') + 'First convert your ZionWorx database to a CSV text file, as ' + 'explained in the User Manual.') } } diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 0f7c17693..27571c0ca 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -36,8 +36,8 @@ from PyQt4 import QtCore, QtGui from sqlalchemy.sql import or_ from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate -from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \ - check_item_selected, create_separated_list +from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, check_item_selected, \ + create_separated_list from openlp.core.lib.ui import create_widget_action from openlp.plugins.songs.forms.editsongform import EditSongForm from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm @@ -97,21 +97,21 @@ class SongMediaItem(MediaManagerItem): def add_end_header_bar(self): self.toolbar.addSeparator() ## Song Maintenance Button ## - self.maintenanceAction = self.toolbar.add_toolbar_action('maintenanceAction', - icon=':/songs/song_maintenance.png', - triggers=self.on_song_maintenance_click) + self.maintenance_action = self.toolbar.add_toolbar_action('maintenance_action', + icon=':/songs/song_maintenance.png', + triggers=self.on_song_maintenance_click) self.add_search_to_toolbar() # Signals and slots Registry().register_function('songs_load_list', self.on_song_list_load) Registry().register_function('songs_preview', self.on_preview_click) QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL('cleared()'), self.on_clear_text_button_click) - QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL('searchTypeChanged(int)'), - self.on_search_text_button_clicked) + QtCore.QObject.connect( + self.search_text_edit, QtCore.SIGNAL('searchTypeChanged(int)'), self.on_search_text_button_clicked) def add_custom_context_actions(self): create_widget_action(self.list_view, separator=True) - create_widget_action(self.list_view, - text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=':/general/general_clone.png', + create_widget_action( + self.list_view, text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=':/general/general_clone.png', triggers=self.on_clone_click) def on_focus(self): @@ -123,15 +123,15 @@ class SongMediaItem(MediaManagerItem): """ log.debug('config_updated') self.search_as_you_type = Settings().value(self.settings_section + '/search as type') - self.updateServiceOnEdit = Settings().value(self.settings_section + '/update service on edit') - self.addSongFromService = Settings().value(self.settings_section + '/add song from service',) + self.update_service_on_edit = Settings().value(self.settings_section + '/update service on edit') + self.add_song_from_service = Settings().value(self.settings_section + '/add song from service',) def retranslateUi(self): self.search_text_label.setText('%s:' % UiStrings().Search) self.search_text_button.setText(UiStrings().Search) - self.maintenanceAction.setText(SongStrings.SongMaintenance) - self.maintenanceAction.setToolTip(translate('SongsPlugin.MediaItem', - 'Maintain the lists of authors, topics and books.')) + self.maintenance_action.setText(SongStrings.SongMaintenance) + self.maintenance_action.setToolTip(translate('SongsPlugin.MediaItem', + 'Maintain the lists of authors, topics and books.')) def initialise(self): """ @@ -139,7 +139,7 @@ class SongMediaItem(MediaManagerItem): """ self.song_maintenance_form = SongMaintenanceForm(self.plugin.manager, self) self.edit_song_form = EditSongForm(self, self.main_window, self.plugin.manager) - self.openLyrics = OpenLyrics(self.plugin.manager) + self.open_lyrics = OpenLyrics(self.plugin.manager) self.search_text_edit.set_search_types([ (SongSearch.Entire, ':/songs/song_search_all.png', translate('SongsPlugin.MediaItem', 'Entire Song'), @@ -154,8 +154,7 @@ class SongMediaItem(MediaManagerItem): translate('SongsPlugin.MediaItem', 'Search Authors...')), (SongSearch.Books, ':/songs/song_book_edit.png', SongStrings.SongBooks, translate('SongsPlugin.MediaItem', 'Search Song Books...')), - (SongSearch.Themes, ':/slides/slide_theme.png', - UiStrings().Themes, UiStrings().SearchThemes) + (SongSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes) ]) self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) self.config_update() @@ -172,64 +171,65 @@ class SongMediaItem(MediaManagerItem): self.display_results_song(search_results) elif search_type == SongSearch.Titles: log.debug('Titles Search') - search_results = self.plugin.manager.get_all_objects(Song, - Song.search_title.like('%' + clean_string(search_keywords) + '%')) + search_string = '%' + clean_string(search_keywords) + '%' + search_results = self.plugin.manager.get_all_objects(Song, Song.search_title.like(search_string)) self.display_results_song(search_results) elif search_type == SongSearch.Lyrics: log.debug('Lyrics Search') - search_results = self.plugin.manager.get_all_objects(Song, - Song.search_lyrics.like('%' + clean_string(search_keywords) + '%')) + search_string = '%' + clean_string(search_keywords) + '%' + search_results = self.plugin.manager.get_all_objects(Song, Song.search_lyrics.like(search_string)) self.display_results_song(search_results) elif search_type == SongSearch.Authors: log.debug('Authors Search') - search_results = self.plugin.manager.get_all_objects(Author, - Author.display_name.like('%' + search_keywords + '%'), Author.display_name.asc()) + search_string = '%' + search_keywords + '%' + search_results = self.plugin.manager.get_all_objects( + Author, Author.display_name.like(search_string), Author.display_name.asc()) self.display_results_author(search_results) elif search_type == SongSearch.Books: log.debug('Books Search') - search_results = self.plugin.manager.get_all_objects(Book, - Book.name.like('%' + search_keywords + '%'), Book.name.asc()) + search_string = '%' + search_keywords + '%' + search_results = self.plugin.manager.get_all_objects(Book, Book.name.like(search_string), Book.name.asc()) song_number = False if not search_results: search_keywords = search_keywords.rpartition(' ') + search_string = '%' + search_keywords + '%' search_results = self.plugin.manager.get_all_objects(Book, - Book.name.like('%' + search_keywords[0] + '%'), Book.name.asc()) + Book.name.like(search_string), Book.name.asc()) song_number = re.sub(r'[^0-9]', '', search_keywords[2]) self.display_results_book(search_results, song_number) elif search_type == SongSearch.Themes: log.debug('Theme Search') - search_results = self.plugin.manager.get_all_objects(Song, - Song.theme_name.like('%' + search_keywords + '%')) + search_string = '%' + search_keywords + '%' + search_results = self.plugin.manager.get_all_objects(Song, Song.theme_name.like(search_string)) self.display_results_song(search_results) self.check_search_result() def search_entire(self, search_keywords): - return self.plugin.manager.get_all_objects(Song, - or_(Song.search_title.like('%' + clean_string(search_keywords) + '%'), - Song.search_lyrics.like('%' + clean_string(search_keywords) + '%'), - Song.comments.like('%' + search_keywords.lower() + '%'))) + search_string = '%' + clean_string(search_keywords) + '%' + return self.plugin.manager.get_all_objects( + Song, or_(Song.search_title.like(search_string), Song.search_lyrics.like(search_string), + Song.comments.like(search_string))) def on_song_list_load(self): """ - Handle the exit from the edit dialog and trigger remote updates - of songs + Handle the exit from the edit dialog and trigger remote updates of songs """ log.debug('on_song_list_load - start') # Called to redisplay the song list screen edit from a search or from the exit of the Song edit dialog. If # remote editing is active Trigger it and clean up so it will not update again. Push edits to the service # manager to update items - if self.edit_item and self.updateServiceOnEdit and not self.remote_triggered: + if self.edit_item and self.update_service_on_edit and not self.remote_triggered: item = self.build_service_item(self.edit_item) self.service_manager.replace_service_item(item) self.on_search_text_button_clicked() log.debug('on_song_list_load - finished') - def display_results_song(self, searchresults): + def display_results_song(self, search_results): log.debug('display results Song') self.save_auto_select_id() self.list_view.clear() - searchresults.sort(key=lambda song: song.sort_key) - for song in searchresults: + search_results.sort(key=lambda song: song.sort_key) + for song in search_results: # Do not display temporary songs if song.temporary: continue @@ -244,10 +244,10 @@ class SongMediaItem(MediaManagerItem): self.list_view.setCurrentItem(song_name) self.auto_select_id = -1 - def display_results_author(self, searchresults): + def display_results_author(self, search_results): log.debug('display results Author') self.list_view.clear() - for author in searchresults: + for author in search_results: for song in author.songs: # Do not display temporary songs if song.temporary: @@ -257,12 +257,11 @@ class SongMediaItem(MediaManagerItem): song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) - def display_results_book(self, searchresults, song_number=False): + def display_results_book(self, search_results, song_number=False): log.debug('display results Book') self.list_view.clear() - for book in searchresults: - songs = sorted(book.songs, key=lambda song: - int(re.match(r'[0-9]+', '0' + song.song_number).group())) + for book in search_results: + songs = sorted(book.songs, key=lambda song: int(re.match(r'[0-9]+', '0' + song.song_number).group())) for song in songs: # Do not display temporary songs if song.temporary: @@ -305,9 +304,9 @@ class SongMediaItem(MediaManagerItem): Registry().execute('songs_load_list') def on_export_click(self): - if not hasattr(self, 'exportWizard'): - self.exportWizard = SongExportForm(self, self.plugin) - self.exportWizard.exec_() + if not hasattr(self, 'export_wizard'): + self.export_wizard = SongExportForm(self, self.plugin) + self.export_wizard.exec_() def on_new_click(self): log.debug('on_new_click') @@ -362,10 +361,10 @@ class SongMediaItem(MediaManagerItem): """ if check_item_selected(self.list_view, UiStrings().SelectDelete): items = self.list_view.selectedIndexes() - if QtGui.QMessageBox.question(self, - UiStrings().ConfirmDelete, + if QtGui.QMessageBox.question( + self, UiStrings().ConfirmDelete, translate('SongsPlugin.MediaItem', 'Are you sure you want to delete the %n selected song(s)?', '', - QtCore.QCoreApplication.CodecForTr, len(items)), + QtCore.QCoreApplication.CodecForTr, len(items)), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No: return @@ -388,17 +387,23 @@ class SongMediaItem(MediaManagerItem): self.edit_item = self.list_view.currentItem() item_id = self.edit_item.data(QtCore.Qt.UserRole) old_song = self.plugin.manager.get_object(Song, item_id) - song_xml = self.openLyrics.song_to_xml(old_song) - new_song = self.openLyrics.xml_to_song(song_xml) - new_song.title = '%s <%s>' % (new_song.title, - translate('SongsPlugin.MediaItem', 'copy', 'For song cloning')) + song_xml = self.open_lyrics.song_to_xml(old_song) + new_song = self.open_lyrics.xml_to_song(song_xml) + new_song.title = '%s <%s>' % \ + (new_song.title, translate('SongsPlugin.MediaItem', 'copy', 'For song cloning')) self.plugin.manager.save_object(new_song) self.on_song_list_load() - def generate_slide_data(self, service_item, item=None, xmlVersion=False, - remote=False, context=ServiceItemContext.Service): + def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, + context=ServiceItemContext.Service): """ Generate the slide data. Needs to be implemented by the plugin. + + :param service_item: The service item to be built on + :param item: The Song item to be used + :param xml_version: The xml version (not used) + :param remote: Triggered from remote + :param context: Why is it being generated """ log.debug('generate_slide_data: %s, %s, %s' % (service_item, item, self.remote_song)) item_id = self._get_id_of_item_to_generate(item, self.remote_song) @@ -411,50 +416,45 @@ class SongMediaItem(MediaManagerItem): song = self.plugin.manager.get_object(Song, item_id) service_item.theme = song.theme_name service_item.edit_id = item_id - if song.lyrics.startswith(' 1: - verse_index = VerseType.from_translated_string(verse_tag) - if verse_index is None: - verse_index = VerseType.from_string(verse_tag, None) + verse_list = SongXML().get_verses(song.lyrics) + # no verse list or only 1 space (in error) + verse_tags_translated = False + if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None: + verse_tags_translated = True + if not song.verse_order.strip(): + for verse in verse_list: + # We cannot use from_loose_input() here, because database is supposed to contain English lowercase + # singlechar tags. + verse_tag = verse[0]['type'] + verse_index = None + if len(verse_tag) > 1: + verse_index = VerseType.from_translated_string(verse_tag) if verse_index is None: - verse_index = VerseType.from_tag(verse_tag) - verse_tag = VerseType.translated_tags[verse_index].upper() - verse_def = '%s%s' % (verse_tag, verse[0]['label']) - service_item.add_from_text(str(verse[1]), verse_def) - else: - # Loop through the verse list and expand the song accordingly. - for order in song.verse_order.lower().split(): - if not order: - break - for verse in verse_list: - if verse[0]['type'][0].lower() == order[0] and (verse[0]['label'].lower() == order[1:] or \ - not order[1:]): - if verse_tags_translated: - verse_index = VerseType.from_translated_tag(verse[0]['type']) - else: - verse_index = VerseType.from_tag(verse[0]['type']) - verse_tag = VerseType.translated_tags[verse_index] - verse_def = '%s%s' % (verse_tag, verse[0]['label']) - service_item.add_from_text(verse[1], verse_def) + verse_index = VerseType.from_string(verse_tag, None) + if verse_index is None: + verse_index = VerseType.from_tag(verse_tag) + verse_tag = VerseType.translated_tags[verse_index].upper() + verse_def = '%s%s' % (verse_tag, verse[0]['label']) + service_item.add_from_text(str(verse[1]), verse_def) else: - verses = song.lyrics.split('\n\n') - for slide in verses: - service_item.add_from_text(str(slide)) + # Loop through the verse list and expand the song accordingly. + for order in song.verse_order.lower().split(): + if not order: + break + for verse in verse_list: + if verse[0]['type'][0].lower() == \ + order[0] and (verse[0]['label'].lower() == order[1:] or not order[1:]): + if verse_tags_translated: + verse_index = VerseType.from_translated_tag(verse[0]['type']) + else: + verse_index = VerseType.from_tag(verse[0]['type']) + verse_tag = VerseType.translated_tags[verse_index] + verse_def = '%s%s' % (verse_tag, verse[0]['label']) + service_item.add_from_text(verse[1], verse_def) service_item.title = song.title author_list = self.generate_footer(service_item, song) service_item.data_string = {'title': song.search_title, 'authors': ', '.join(author_list)} - service_item.xml_version = self.openLyrics.song_to_xml(song) + service_item.xml_version = self.open_lyrics.song_to_xml(song) # Add the audio file to the service item. if song.media_files: service_item.add_capability(ItemCapabilities.HasBackgroundAudio) @@ -466,11 +466,8 @@ class SongMediaItem(MediaManagerItem): Generates the song footer based on a song and adds details to a service item. author_list is only required for initial song generation. - ``item`` - The service item to be amended - - ``song`` - The song to be used to generate the footer + :param item: The service item to be amended + :param song: The song to be used to generate the footer """ author_list = [str(author.display_name) for author in song.authors] item.audit = [ @@ -481,8 +478,8 @@ class SongMediaItem(MediaManagerItem): item.raw_footer.append(create_separated_list(author_list)) item.raw_footer.append(song.copyright) if Settings().value('core/ccli number'): - item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') + - Settings().value('core/ccli number')) + item.raw_footer.append(translate('SongsPlugin.MediaItem', + 'CCLI License: ') + Settings().value('core/ccli number')) return author_list def service_load(self, item): @@ -500,8 +497,8 @@ class SongMediaItem(MediaManagerItem): Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(' ', item.data_string['title'].strip()) + '@').strip().lower(), Song.search_title.asc()) else: - search_results = self.plugin.manager.get_all_objects(Song, - Song.search_title == item.data_string['title'], Song.search_title.asc()) + search_results = self.plugin.manager.get_all_objects( + Song, Song.search_title == item.data_string['title'], Song.search_title.asc()) edit_id = 0 add_song = True if search_results: @@ -521,16 +518,16 @@ class SongMediaItem(MediaManagerItem): # If there's any backing tracks, copy them over. if item.background_audio: self._update_background_audio(song, item) - if add_song and self.addSongFromService: - song = self.openLyrics.xml_to_song(item.xml_version) + if add_song and self.add_song_from_service: + song = self.open_lyrics.xml_to_song(item.xml_version) # If there's any backing tracks, copy them over. if item.background_audio: self._update_background_audio(song, item) - editId = song.id + edit_id = song.id self.on_search_text_button_clicked() - elif add_song and not self.addSongFromService: + elif add_song and not self.add_song_from_service: # Make sure we temporary import formatting tags. - song = self.openLyrics.xml_to_song(item.xml_version, True) + song = self.open_lyrics.xml_to_song(item.xml_version, True) # If there's any backing tracks, copy them over. if item.background_audio: self._update_background_audio(song, item) @@ -540,9 +537,11 @@ class SongMediaItem(MediaManagerItem): self.generate_footer(item, song) return item - def search(self, string, showError): + def search(self, string, show_error): """ Search for some songs + :param string: The string to show + :param show_error: Is this an error? """ search_results = self.search_entire(string) return [[song.id, song.title] for song in search_results] diff --git a/openlp/plugins/songs/lib/mediashoutimport.py b/openlp/plugins/songs/lib/mediashoutimport.py index 40f99d255..99850e950 100644 --- a/openlp/plugins/songs/lib/mediashoutimport.py +++ b/openlp/plugins/songs/lib/mediashoutimport.py @@ -37,6 +37,7 @@ from openlp.plugins.songs.lib.songimport import SongImport VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E'] + class MediaShoutImport(SongImport): """ The :class:`MediaShoutImport` class provides the ability to import the @@ -48,61 +49,57 @@ class MediaShoutImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Receive a single file to import. """ try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};' - 'DBQ=%s;PWD=6NOZ4eHK7k' % self.import_source) + conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s;PWD=6NOZ4eHK7k' % + self.import_source) except: # Unfortunately no specific exception type - self.logError(self.import_source, - translate('SongsPlugin.MediaShoutImport', 'Unable to open the MediaShout database.')) + self.log_error(self.import_source, translate('SongsPlugin.MediaShoutImport', + 'Unable to open the MediaShout database.')) return cursor = conn.cursor() - cursor.execute('SELECT Record, Title, Author, Copyright, ' - 'SongID, CCLI, Notes FROM Songs ORDER BY Title') + cursor.execute('SELECT Record, Title, Author, Copyright, SongID, CCLI, Notes FROM Songs ORDER BY Title') songs = cursor.fetchall() self.import_wizard.progress_bar.setMaximum(len(songs)) for song in songs: if self.stop_import_flag: break - cursor.execute('SELECT Type, Number, Text FROM Verses ' - 'WHERE Record = %s ORDER BY Type, Number' % song.Record) + cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = %s ORDER BY Type, Number' + % song.Record) verses = cursor.fetchall() - cursor.execute('SELECT Type, Number, POrder FROM PlayOrder ' - 'WHERE Record = %s ORDER BY POrder' % song.Record) + cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = %s ORDER BY POrder' % song.Record) verse_order = cursor.fetchall() - cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ' - 'ON SongThemes.ThemeId = Themes.ThemeId ' - 'WHERE SongThemes.Record = %s' % song.Record) + cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId ' + 'WHERE SongThemes.Record = %s' % song.Record) topics = cursor.fetchall() - cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ' - 'ON SongGroups.GroupId = Groups.GroupId ' - 'WHERE SongGroups.Record = %s' % song.Record) + cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ON SongGroups.GroupId = Groups.GroupId ' + 'WHERE SongGroups.Record = %s' % song.Record) topics += cursor.fetchall() - self.processSong(song, verses, verse_order, topics) + self.process_song(song, verses, verse_order, topics) - def processSong(self, song, verses, verse_order, topics): + def process_song(self, song, verses, verse_order, topics): """ Create the song, i.e. title, verse etc. """ - self.setDefaults() + self.set_defaults() self.title = song.Title self.parse_author(song.Author) - self.addCopyright(song.Copyright) + self.add_copyright(song.Copyright) self.comments = song.Notes for topic in topics: self.topics.append(topic.Name) if '-' in song.SongID: - self.songBookName, self.songNumber = song.SongID.split('-', 1) + self.song_book_name, self.song_number = song.SongID.split('-', 1) else: - self.songBookName = song.SongID + self.song_book_name = song.SongID for verse in verses: 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: 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() diff --git a/openlp/plugins/songs/lib/olpimport.py b/openlp/plugins/songs/lib/olpimport.py index 147434c59..0dae2d5d0 100644 --- a/openlp/plugins/songs/lib/olpimport.py +++ b/openlp/plugins/songs/lib/olpimport.py @@ -45,6 +45,7 @@ from .songimport import SongImport log = logging.getLogger(__name__) + class OpenLPSongImport(SongImport): """ The :class:`OpenLPSongImport` class provides OpenLP with the ability to @@ -54,20 +55,17 @@ class OpenLPSongImport(SongImport): """ Initialise the import. - ``manager`` - The song manager for the running OpenLP installation. - - ``source_db`` - The database providing the data to import. + :param manager: The song manager for the running OpenLP installation. + :param kwargs: The database providing the data to import. """ SongImport.__init__(self, manager, **kwargs) - self.sourceSession = None + self.source_session = None - def doImport(self, progressDialog=None): + def do_import(self, progress_dialog=None): """ Run the import for an OpenLP version 2 song database. - ``progressDialog`` + ``progress_dialog`` The QProgressDialog used when importing songs from the FRW. """ @@ -77,28 +75,24 @@ class OpenLPSongImport(SongImport): """ pass - class OldBook(BaseModel): """ Book model """ pass - class OldMediaFile(BaseModel): """ MediaFile model """ pass - class OldSong(BaseModel): """ Song model """ pass - class OldTopic(BaseModel): """ Topic model @@ -107,15 +101,15 @@ class OpenLPSongImport(SongImport): # Check the file type if not self.import_source.endswith('.sqlite'): - self.logError(self.import_source, - translate('SongsPlugin.OpenLPSongImport', 'Not a valid OpenLP 2.0 song database.')) + self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport', + 'Not a valid OpenLP 2.0 song database.')) return self.import_source = 'sqlite:///%s' % self.import_source # Load the db file engine = create_engine(self.import_source) source_meta = MetaData() source_meta.reflect(engine) - self.sourceSession = scoped_session(sessionmaker(bind=engine)) + self.source_session = scoped_session(sessionmaker(bind=engine)) if 'media_files' in list(source_meta.tables.keys()): has_media_files = True else: @@ -143,14 +137,13 @@ class OpenLPSongImport(SongImport): } if has_media_files: if isinstance(source_media_files_songs_table, Table): - song_props['media_files'] = relation(OldMediaFile, - backref='songs', - secondary=source_media_files_songs_table) + song_props['media_files'] = relation(OldMediaFile, backref='songs', + secondary=source_media_files_songs_table) else: - song_props['media_files'] = relation(OldMediaFile, - backref='songs', - foreign_keys=[source_media_files_table.c.song_id], - primaryjoin=source_songs_table.c.id == source_media_files_table.c.song_id) + song_props['media_files'] = \ + relation(OldMediaFile, backref='songs', + foreign_keys=[source_media_files_table.c.song_id], + primaryjoin=source_songs_table.c.id == source_media_files_table.c.song_id) try: class_mapper(OldAuthor) except UnmappedClassError: @@ -168,7 +161,7 @@ class OpenLPSongImport(SongImport): except UnmappedClassError: mapper(OldTopic, source_topics_table) - source_songs = self.sourceSession.query(OldSong).all() + source_songs = self.source_session.query(OldSong).all() if self.import_wizard: self.import_wizard.progress_bar.setMaximum(len(source_songs)) for song in source_songs: @@ -212,17 +205,17 @@ class OpenLPSongImport(SongImport): if has_media_files: if song.media_files: for media_file in song.media_files: - existing_media_file = self.manager.get_object_filtered(MediaFile, - MediaFile.file_name == media_file.file_name) + existing_media_file = self.manager.get_object_filtered( + MediaFile, MediaFile.file_name == media_file.file_name) if existing_media_file: new_song.media_files.append(existing_media_file) else: new_song.media_files.append(MediaFile.populate(file_name=media_file.file_name)) clean_song(self.manager, new_song) self.manager.save_object(new_song) - if progressDialog: - progressDialog.setValue(progressDialog.value() + 1) - progressDialog.setLabelText(WizardStrings.ImportingType % new_song.title) + if progress_dialog: + progress_dialog.setValue(progress_dialog.value() + 1) + progress_dialog.setLabelText(WizardStrings.ImportingType % new_song.title) else: self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % new_song.title) if self.stop_import_flag: diff --git a/openlp/plugins/songs/lib/oooimport.py b/openlp/plugins/songs/lib/oooimport.py index 81335247c..0e388b54f 100644 --- a/openlp/plugins/songs/lib/oooimport.py +++ b/openlp/plugins/songs/lib/oooimport.py @@ -58,20 +58,19 @@ class OooImport(SongImport): """ def __init__(self, manager, **kwargs): """ - Initialise the class. Requires a songmanager class which is passed - to SongImport for writing song to disk + Initialise the class. Requires a songmanager class which is passed to SongImport for writing song to disk """ SongImport.__init__(self, manager, **kwargs) self.document = None - self.processStarted = False + self.process_started = False - def doImport(self): + def do_import(self): if not isinstance(self.import_source, list): return try: - self.startOoo() + self.start_ooo() except NoConnectException as exc: - self.logError( + self.log_error( self.import_source[0], translate('SongsPlugin.SongImport', 'Cannot access OpenOffice or LibreOffice')) log.error(exc) @@ -82,34 +81,34 @@ class OooImport(SongImport): break filename = str(filename) if os.path.isfile(filename): - self.openOooFile(filename) + self.open_ooo_file(filename) if self.document: - self.processOooDocument() - self.closeOooFile() + self.process_ooo_document() + self.close_ooo_file() else: - self.logError(self.filepath, translate('SongsPlugin.SongImport', 'Unable to open file')) + self.log_error(self.file_path, translate('SongsPlugin.SongImport', 'Unable to open file')) else: - self.logError(self.filepath, translate('SongsPlugin.SongImport', 'File not found')) - self.closeOoo() + self.log_error(self.file_path, translate('SongsPlugin.SongImport', 'File not found')) + self.close_ooo() - def processOooDocument(self): + def process_ooo_document(self): """ Handle the import process for OpenOffice files. This method facilitates allowing subclasses to handle specific types of OpenOffice files. """ if self.document.supportsService("com.sun.star.presentation.PresentationDocument"): - self.processPres() + self.process_presentation() if self.document.supportsService("com.sun.star.text.TextDocument"): - self.processDoc() + self.process_doc() - def startOoo(self): + def start_ooo(self): """ Start OpenOffice.org process TODO: The presentation/Impress plugin may already have it running """ if os.name == 'nt': - self.startOooProcess() - self.desktop = self.oooManager.createInstance('com.sun.star.frame.Desktop') + self.start_ooo_process() + self.desktop = self.ooo_manager.createInstance('com.sun.star.frame.Desktop') else: context = uno.getComponentContext() resolver = context.ServiceManager.createInstanceWithContext('com.sun.star.bridge.UnoUrlResolver', context) @@ -121,7 +120,7 @@ class OooImport(SongImport): except NoConnectException: time.sleep(0.1) log.exception("Failed to resolve uno connection") - self.startOooProcess() + self.start_ooo_process() loop += 1 else: manager = uno_instance.ServiceManager @@ -129,60 +128,62 @@ class OooImport(SongImport): return raise Exception('Unable to start LibreOffice') - def startOooProcess(self): + def start_ooo_process(self): + """ + Start the OO Process + """ try: if os.name == 'nt': - self.oooManager = Dispatch('com.sun.star.ServiceManager') - self.oooManager._FlagAsMethod('Bridge_GetStruct') - self.oooManager._FlagAsMethod('Bridge_GetValueObject') + self.ooo_manager = Dispatch('com.sun.star.ServiceManager') + self.ooo_manager._FlagAsMethod('Bridge_GetStruct') + self.ooo_manager._FlagAsMethod('Bridge_GetValueObject') else: cmd = get_uno_command() process = QtCore.QProcess() process.startDetached(cmd) - self.processStarted = True + self.process_started = True except: - log.exception("startOooProcess failed") + log.exception("start_ooo_process failed") - def openOooFile(self, filepath): + def open_ooo_file(self, file_path): """ Open the passed file in OpenOffice.org Impress """ - self.filepath = filepath + self.file_path = file_path if os.name == 'nt': - url = filepath.replace('\\', '/') + url = file_path.replace('\\', '/') url = url.replace(':', '|').replace(' ', '%20') url = 'file:///' + url else: - url = uno.systemPathToFileUrl(filepath) + url = uno.systemPathToFileUrl(file_path) properties = [] properties = tuple(properties) try: - self.document = self.desktop.loadComponentFromURL(url, '_blank', - 0, properties) + self.document = self.desktop.loadComponentFromURL(url, '_blank', 0, properties) if not self.document.supportsService("com.sun.star.presentation.PresentationDocument") and not \ self.document.supportsService("com.sun.star.text.TextDocument"): - self.closeOooFile() + self.close_ooo_file() else: - self.import_wizard.increment_progress_bar('Processing file ' + filepath, 0) + self.import_wizard.increment_progress_bar('Processing file ' + file_path, 0) except AttributeError: - log.exception("openOooFile failed: %s", url) + log.exception("open_ooo_file failed: %s", url) return - def closeOooFile(self): + def close_ooo_file(self): """ Close file. """ self.document.close(True) self.document = None - def closeOoo(self): + def close_ooo(self): """ Close OOo. But only if we started it and not on windows """ - if self.processStarted: + if self.process_started: self.desktop.terminate() - def processPres(self): + def process_presentation(self): """ Process the file """ @@ -194,47 +195,52 @@ class OooImport(SongImport): self.import_wizard.increment_progress_bar('Import cancelled', 0) return slide = slides.getByIndex(slide_no) - slidetext = '' + slide_text = '' for idx in range(slide.getCount()): shape = slide.getByIndex(idx) if shape.supportsService("com.sun.star.drawing.Text"): if shape.getString().strip() != '': - slidetext += shape.getString().strip() + '\n\n' - if slidetext.strip() == '': - slidetext = '\f' - text += slidetext - self.processSongsText(text) + slide_text += shape.getString().strip() + '\n\n' + if slide_text.strip() == '': + slide_text = '\f' + text += slide_text + self.process_songs_text(text) return - def processDoc(self): + def process_doc(self): """ Process the doc file, a paragraph at a time """ text = '' paragraphs = self.document.getText().createEnumeration() while paragraphs.hasMoreElements(): - paratext = '' + para_text = '' paragraph = paragraphs.nextElement() if paragraph.supportsService("com.sun.star.text.Paragraph"): - textportions = paragraph.createEnumeration() - while textportions.hasMoreElements(): - textportion = textportions.nextElement() - if textportion.BreakType in (PAGE_BEFORE, PAGE_BOTH): - paratext += '\f' - paratext += textportion.getString() - if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH): - paratext += '\f' - text += paratext + '\n' - self.processSongsText(text) + text_portions = paragraph.createEnumeration() + while text_portions.hasMoreElements(): + text_portion = text_portions.nextElement() + if text_portion.BreakType in (PAGE_BEFORE, PAGE_BOTH): + para_text += '\f' + para_text += text_portion.getString() + if text_portion.BreakType in (PAGE_AFTER, PAGE_BOTH): + para_text += '\f' + text += para_text + '\n' + self.process_songs_text(text) - def processSongsText(self, text): - songtexts = self.tidyText(text).split('\f') - self.setDefaults() - for songtext in songtexts: - if songtext.strip(): - self.processSongText(songtext.strip()) - if self.checkComplete(): + def process_songs_text(self, text): + """ + Process the songs text + + :param text: The text. + """ + song_texts = self.tidy_text(text).split('\f') + self.set_defaults() + for song_text in song_texts: + if song_text.strip(): + self.process_song_text(song_text.strip()) + if self.check_complete(): self.finish() - self.setDefaults() - if self.checkComplete(): + self.set_defaults() + if self.check_complete(): self.finish() diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 8cdd804e1..ff4c475f3 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -27,8 +27,8 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`openlyricsexport` module provides the functionality for exporting -songs from the database to the OpenLyrics format. +The :mod:`openlyricsexport` module provides the functionality for exporting songs from the database to the OpenLyrics +format. """ import logging import os @@ -62,15 +62,15 @@ class OpenLyricsExport(object): Export the songs. """ log.debug('started OpenLyricsExport') - openLyrics = OpenLyrics(self.manager) + open_lyrics = OpenLyrics(self.manager) self.parent.progress_bar.setMaximum(len(self.songs)) for song in self.songs: self.application.process_events() if self.parent.stop_export_flag: return False self.parent.increment_progress_bar(translate('SongsPlugin.OpenLyricsExport', 'Exporting "%s"...') % - song.title) - xml = openLyrics.song_to_xml(song) + song.title) + xml = open_lyrics.song_to_xml(song) tree = etree.ElementTree(etree.fromstring(xml.encode())) filename = '%s (%s)' % (song.title, ', '.join([author.display_name for author in song.authors])) filename = clean_filename(filename) @@ -78,8 +78,8 @@ class OpenLyricsExport(object): filename = '%s.xml' % filename[0:250 - len(self.save_path)] # Pass a file object, because lxml does not cope with some special # characters in the path (see lp:757673 and lp:744337). - tree.write(open(os.path.join(self.save_path, filename), 'wb'), - encoding='utf-8', xml_declaration=True, pretty_print=True) + tree.write(open(os.path.join(self.save_path, filename), 'wb'), encoding='utf-8', xml_declaration=True, + pretty_print=True) return True def _get_application(self): diff --git a/openlp/plugins/songs/lib/openlyricsimport.py b/openlp/plugins/songs/lib/openlyricsimport.py index f52c0dc53..675c0d98a 100644 --- a/openlp/plugins/songs/lib/openlyricsimport.py +++ b/openlp/plugins/songs/lib/openlyricsimport.py @@ -54,9 +54,9 @@ class OpenLyricsImport(SongImport): """ log.debug('initialise OpenLyricsImport') SongImport.__init__(self, manager, **kwargs) - self.openLyrics = OpenLyrics(self.manager) + self.open_lyrics = OpenLyrics(self.manager) - def doImport(self): + def do_import(self): """ Imports the songs. """ @@ -71,11 +71,11 @@ class OpenLyricsImport(SongImport): # special characters in the path (see lp:757673 and lp:744337). parsed_file = etree.parse(open(file_path, 'r'), parser) xml = etree.tostring(parsed_file).decode() - self.openLyrics.xml_to_song(xml) + self.open_lyrics.xml_to_song(xml) except etree.XMLSyntaxError: 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: - log.exception('OpenLyricsException %d in file %s: %s' - % (exception.type, file_path, exception.log_message)) - self.logError(file_path, exception.display_message) + log.exception('OpenLyricsException %d in file %s: %s' % + (exception.type, file_path, exception.log_message)) + self.log_error(file_path, exception.display_message) diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py index 646595722..bee0989a0 100644 --- a/openlp/plugins/songs/lib/opensongimport.py +++ b/openlp/plugins/songs/lib/opensongimport.py @@ -109,34 +109,34 @@ class OpenSongImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) for filename in self.import_source: if self.stop_import_flag: return song_file = open(filename) - self.doImportFile(song_file) + self.do_import_file(song_file) song_file.close() - def doImportFile(self, file): + def do_import_file(self, file): """ Process the OpenSong file - pass in a file-like object, not a file path. """ - self.setDefaults() + self.set_defaults() try: tree = objectify.parse(file) except (Error, LxmlError): - self.logError(file.name, SongStrings.XMLSyntaxError) + self.log_error(file.name, SongStrings.XMLSyntaxError) log.exception('Error parsing XML') return root = tree.getroot() if root.tag != 'song': - self.logError(file.name, str( - translate('SongsPlugin.OpenSongImport', ('Invalid OpenSong song file. Missing song tag.')))) + self.log_error(file.name, str( + translate('SongsPlugin.OpenSongImport', 'Invalid OpenSong song file. Missing song tag.'))) return fields = dir(root) decode = { - 'copyright': self.addCopyright, + 'copyright': self.add_copyright, 'ccli': 'ccli_number', 'author': self.parse_author, 'title': 'title', @@ -207,7 +207,7 @@ class OpenSongImport(SongImport): verses[verse_tag][verse_num][inst] = [] our_verse_order.append([verse_tag, verse_num, inst]) # 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('|', '\n') this_line = this_line.strip() @@ -218,15 +218,15 @@ class OpenSongImport(SongImport): for (verse_tag, verse_num, inst) in our_verse_order: lines = '\n'.join(verses[verse_tag][verse_num][inst]) length = 0 - while(length < len(verse_num) and verse_num[length].isnumeric()): + while length < len(verse_num) and verse_num[length].isnumeric(): length += 1 verse_def = '%s%s' % (verse_tag, verse_num[:length]) verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \ if verse_def in verse_joints else lines for verse_def, lines in verse_joints.items(): - self.addVerse(lines, verse_def) + self.add_verse(lines, verse_def) if not self.verses: - self.addVerse('') + self.add_verse('') # figure out the presentation order, if present if 'presentation' in fields and root.presentation: order = str(root.presentation) @@ -246,9 +246,9 @@ class OpenSongImport(SongImport): verse_num = '1' verse_def = '%s%s' % (verse_tag, verse_num) if verse_num in verses.get(verse_tag, {}): - self.verseOrderList.append(verse_def) + self.verse_order_list.append(verse_def) else: - log.info('Got order %s but not in verse tags, dropping' - 'this item from presentation order', verse_def) + log.info('Got order %s but not in verse tags, dropping this item from presentation order', + verse_def) if not self.finish(): - self.logError(file.name) + self.log_error(file.name) diff --git a/openlp/plugins/songs/lib/powersongimport.py b/openlp/plugins/songs/lib/powersongimport.py index 2b65729a8..7c5b9e02e 100644 --- a/openlp/plugins/songs/lib/powersongimport.py +++ b/openlp/plugins/songs/lib/powersongimport.py @@ -39,6 +39,7 @@ from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) + class PowerSongImport(SongImport): """ The :class:`PowerSongImport` class provides the ability to import song files @@ -73,7 +74,7 @@ class PowerSongImport(SongImport): * .song """ @staticmethod - def isValidSource(import_source): + def is_valid_source(import_source): """ Checks if source is a PowerSong 1.0 folder: * is a directory @@ -85,12 +86,12 @@ class PowerSongImport(SongImport): return True return False - def doImport(self): + def do_import(self): """ Receive either a list of files or a folder (unicode) to import. """ from .importer import SongFormat - PS_string = SongFormat.get(SongFormat.PowerSong, 'name') + ps_string = SongFormat.get(SongFormat.PowerSong, 'name') if isinstance(self.import_source, str): if os.path.isdir(self.import_source): dir = self.import_source @@ -101,27 +102,27 @@ class PowerSongImport(SongImport): else: self.import_source = '' if not self.import_source or not isinstance(self.import_source, list): - self.logError(translate('SongsPlugin.PowerSongImport', 'No songs to import.'), - translate('SongsPlugin.PowerSongImport', 'No %s files found.') % PS_string) + self.log_error(translate('SongsPlugin.PowerSongImport', 'No songs to import.'), + translate('SongsPlugin.PowerSongImport', 'No %s files found.') % ps_string) return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) for file in self.import_source: if self.stop_import_flag: return - self.setDefaults() + self.set_defaults() parse_error = False with open(file, 'rb') as song_data: while True: try: - label = self._readString(song_data) + label = self._read_string(song_data) if not label: break - field = self._readString(song_data) + field = self._read_string(song_data) except ValueError: 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.')) % - PS_string) + ps_string) break else: if label == 'TITLE': @@ -130,38 +131,38 @@ class PowerSongImport(SongImport): self.parse_author(field) elif label == 'COPYRIGHTLINE': found_copyright = True - self._parseCopyrightCCLI(field) + self._parse_copyright_cCCLI(field) elif label == 'PART': - self.addVerse(field) + self.add_verse(field) if parse_error: continue # Check that file had TITLE field if not self.title: - self.logError(os.path.basename(file), str( - translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % PS_string) + self.log_error(os.path.basename(file), str( + translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % ps_string) continue # Check that file had COPYRIGHTLINE label if not found_copyright: - self.logError(self.title, str( + self.log_error(self.title, str( translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" header.')) % - PS_string) + ps_string) continue # Check that file had at least one verse if not self.verses: - self.logError(self.title, str( + self.log_error(self.title, str( translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.'))) continue if not self.finish(): - self.logError(self.title) + self.log_error(self.title) - def _readString(self, file_object): + def _read_string(self, file_object): """ Reads in next variable-length string. """ - string_len = self._read7BitEncodedInteger(file_object) + string_len = self._read_7_bit_encoded_integer(file_object) return str(file_object.read(string_len), 'utf-8', 'ignore') - def _read7BitEncodedInteger(self, file_object): + def _read_7_bit_encoded_integer(self, file_object): """ Reads in a 32-bit integer in compressed 7-bit format. @@ -179,7 +180,7 @@ class PowerSongImport(SongImport): # Check for corrupted stream (since max 5 bytes per 32-bit integer) if i == 5: raise ValueError - byte = self._readByte(file_object) + byte = self._read_byte(file_object) # Strip high bit and shift left val += (byte & 0x7f) << shift shift += 7 @@ -189,7 +190,7 @@ class PowerSongImport(SongImport): i += 1 return val - def _readByte(self, file_object): + def _read_byte(self, file_object): """ Reads in next byte as an unsigned integer @@ -202,7 +203,7 @@ class PowerSongImport(SongImport): else: return ord(byte_str) - def _parseCopyrightCCLI(self, field): + def _parse_copyright_cCCLI(self, field): """ Look for CCLI song number, and get copyright """ @@ -211,8 +212,8 @@ class PowerSongImport(SongImport): copyright = ccli_no ccli_no = '' if copyright: - self.addCopyright(copyright.rstrip('\n').replace('\n', ' ')) + self.add_copyright(copyright.rstrip('\n').replace('\n', ' ')) if ccli_no: ccli_no = ccli_no.strip(' :') if ccli_no.isdigit(): - self.ccliNumber = ccli_no + self.ccli_number = ccli_no diff --git a/openlp/plugins/songs/lib/sofimport.py b/openlp/plugins/songs/lib/sofimport.py index 18bf0d49c..a41472201 100644 --- a/openlp/plugins/songs/lib/sofimport.py +++ b/openlp/plugins/songs/lib/sofimport.py @@ -61,6 +61,7 @@ try: except ImportError: ITALIC = 2 + class SofImport(OooImport): """ Import songs provided on disks with the Songs of Fellowship music books @@ -68,8 +69,8 @@ class SofImport(OooImport): Use OpenOffice.org Writer for processing the rtf file - The three books are not only inconsistant with each other, they are - inconsistant in themselves too with their formatting. Not only this, but + The three books are not only inconsistent with each other, they are + inconsistent in themselves too with their formatting. Not only this, but the 1+2 book does not space out verses correctly. This script attempts to sort it out, but doesn't get it 100% right. But better than having to type them all out! @@ -85,18 +86,18 @@ class SofImport(OooImport): OooImport.__init__(self, manager, **kwargs) self.song = False - def processOooDocument(self): + def process_ooo_document(self): """ Handle the import process for SoF files. """ - self.processSofFile() + self.process_sof_file() - def processSofFile(self): + def process_sof_file(self): """ Process the RTF file, a paragraph at a time """ - self.blankLines = 0 - self.newSong() + self.blank_lines = 0 + self.new_song() try: paragraphs = self.document.getText().createEnumeration() while paragraphs.hasMoreElements(): @@ -104,65 +105,68 @@ class SofImport(OooImport): return paragraph = paragraphs.nextElement() if paragraph.supportsService("com.sun.star.text.Paragraph"): - self.processParagraph(paragraph) + self.process_paragraph(paragraph) except RuntimeException as exc: log.exception('Error processing file: %s', exc) if not self.finish(): - self.logError(self.filepath) + self.log_error(self.file_path) - def processParagraph(self, paragraph): + def process_paragraph(self, paragraph): """ Process a paragraph. - In the first book, a paragraph is a single line. In the latter ones - they may contain multiple lines. - Each paragraph contains textportions. Each textportion has it's own - styling, e.g. italics, bold etc. + In the first book, a paragraph is a single line. In the latter ones they may contain multiple lines. + Each paragraph contains textportions. Each textportion has it's own styling, e.g. italics, bold etc. Also check for page breaks, which indicates a new song in books 1+2. - In later books, there may not be line breaks, so check for 3 or more - newlines + In later books, there may not be line breaks, so check for 3 or more newlines + + :param paragraph: The paragraph text """ text = '' - textportions = paragraph.createEnumeration() - while textportions.hasMoreElements(): - textportion = textportions.nextElement() - if textportion.BreakType in (PAGE_BEFORE, PAGE_BOTH): - self.processParagraphText(text) - self.newSong() + text_portions = paragraph.createEnumeration() + while text_portions.hasMoreElements(): + text_portion = text_portions.nextElement() + if text_portion.BreakType in (PAGE_BEFORE, PAGE_BOTH): + self.process_paragraph_text(text) + self.new_song() text = '' - text += self.processTextPortion(textportion) - if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH): - self.processParagraphText(text) - self.newSong() + text += self.process_text_portion(text_portion) + if text_portion.BreakType in (PAGE_AFTER, PAGE_BOTH): + self.process_paragraph_text(text) + self.new_song() text = '' - self.processParagraphText(text) + self.process_paragraph_text(text) - def processParagraphText(self, text): + def process_paragraph_text(self, text): """ Split the paragraph text into multiple lines and process + + :param text: The text """ for line in text.split('\n'): - self.processParagraphLine(line) - if self.blankLines > 2: - self.newSong() + self.process_paragraph_line(line) + if self.blank_lines > 2: + self.new_song() - def processParagraphLine(self, text): + def process_paragraph_line(self, text): """ Process a single line. Throw away that text which isn't relevant, i.e. stuff that appears at the end of the song. Anything that is OK, append to the current verse + + :param text: The text """ text = text.strip() if text == '': - self.blankLines += 1 - if self.blankLines > 1: + self.blank_lines += 1 + if self.blank_lines > 1: return if self.title != '': - self.finishVerse() + self.finish_verse() return - self.blankLines = 0 - if self.skipToCloseBracket: + self.blank_lines = 0 + if self.skip_to_close_bracket: if text.endswith(')'): - self.skipToCloseBracket = False + self.skip_to_close_bracket = False return if text.startswith('CCL Licence'): self.italics = False @@ -170,90 +174,93 @@ class SofImport(OooImport): if text == 'A Songs of Fellowship Worship Resource': return if text.startswith('(NB.') or text.startswith('(Regrettably') or text.startswith('(From'): - self.skipToCloseBracket = True + self.skip_to_close_bracket = True return if text.startswith('Copyright'): - self.addCopyright(text) + self.add_copyright(text) return if text == '(Repeat)': - self.finishVerse() - self.repeatVerse() + self.finish_verse() + self.repeat_verse() return if self.title == '': if self.copyright == '': - self.addSofAuthor(text) + self.add_sof_author(text) else: - self.addCopyright(text) + self.add_copyright(text) return - self.addVerseLine(text) + self.add_verse_line(text) - def processTextPortion(self, textportion): + def process_text_portion(self, text_portion): """ - Process a text portion. Here we just get the text and detect if - it's bold or italics. If it's bold then its a song number or song title. - Song titles are in all capitals, so we must bring the capitalization - into line + Process a text portion. Here we just get the text and detect if it's bold or italics. If it's bold then its a + song number or song title. + Song titles are in all capitals, so we must bring the capitalization into line + + :param text_portion: A Piece of text """ - text = textportion.getString() - text = self.tidyText(text) + text = text_portion.getString() + text = self.tidy_text(text) if text.strip() == '': return text - if textportion.CharWeight == BOLD: - boldtext = text.strip() - if boldtext.isdigit() and self.songNumber == '': - self.addSongNumber(boldtext) + if text_portion.CharWeight == BOLD: + bold_text = text.strip() + if bold_text.isdigit() and self.song_number == '': + self.add_song_number(bold_text) return '' - text = self.uncapText(text) + text = self.uncap_text(text) if self.title == '': - self.addTitle(text) + self.add_title(text) return text if text.strip().startswith('('): return text - self.italics = (textportion.CharPosture == ITALIC) + self.italics = (text_portion.CharPosture == ITALIC) return text - def newSong(self): + def new_song(self): """ A change of song. Store the old, create a new ... but only if the last song was complete. If not, stick with it """ if self.song: - self.finishVerse() - if not self.checkComplete(): + self.finish_verse() + if not self.check_complete(): return self.finish() self.song = True - self.setDefaults() - self.skipToCloseBracket = False - self.isChorus = False + self.set_defaults() + self.skip_to_close_bracket = False + self.is_chorus = False self.italics = False - self.currentVerse = '' + self.current__verse = '' - def addSongNumber(self, song_no): + def add_song_number(self, song_no): """ - Add a song number, store as alternate title. Also use the song - number to work out which songbook we're in + Add a song number, store as alternate title. Also use the song number to work out which songbook we're in + + :param song_no: The Song number """ - self.songNumber = song_no - self.alternateTitle = song_no + '.' - self.songBook_pub = 'Kingsway Publications' + self.song_number = song_no + self.alternate_title = song_no + '.' + self.song_book_pub = 'Kingsway Publications' if int(song_no) <= 640: - self.songBook = 'Songs of Fellowship 1' + self.song_book = 'Songs of Fellowship 1' elif int(song_no) <= 1150: - self.songBook = 'Songs of Fellowship 2' + self.song_book = 'Songs of Fellowship 2' elif int(song_no) <= 1690: - self.songBook = 'Songs of Fellowship 3' + self.song_book = 'Songs of Fellowship 3' elif int(song_no) <= 2200: - self.songBook = 'Songs of Fellowship 4' + self.song_book = 'Songs of Fellowship 4' elif int(song_no) <= 2710: - self.songBook = 'Songs of Fellowship 5' + self.song_book = 'Songs of Fellowship 5' else: - self.songBook = 'Songs of Fellowship Other' + self.song_book = 'Songs of Fellowship Other' - def addTitle(self, text): + def add_title(self, text): """ - Add the title to the song. Strip some leading/trailing punctuation that - we don't want in a title + Add the title to the song. Strip some leading/trailing punctuation that we don't want in a title + + :param text: Title text """ title = text.strip() if title.startswith('\''): @@ -263,50 +270,50 @@ class SofImport(OooImport): self.title = title self.import_wizard.increment_progress_bar('Processing song ' + title, 0) - def addSofAuthor(self, text): + def add_sof_author(self, text): """ - Add the author. OpenLP stores them individually so split by 'and', '&' - and comma. - However need to check for "Mr and Mrs Smith" and turn it to - "Mr Smith" and "Mrs Smith". + Add the author. OpenLP stores them individually so split by 'and', '&' and comma. + However need to check for "Mr and Mrs Smith" and turn it to "Mr Smith" and "Mrs Smith". + + :param text: Author text """ text = text.replace(' and ', ' & ') self.parse_author(text) - def addVerseLine(self, text): + def add_verse_line(self, text): """ - Add a line to the current verse. If the formatting has changed and - we're beyond the second line of first verse, then this indicates - a change of verse. Italics are a chorus - """ - if self.italics != self.isChorus and ((len(self.verses) > 0) or - (self.currentVerse.count('\n') > 1)): - self.finishVerse() - if self.italics: - self.isChorus = True - self.currentVerse += text + '\n' + Add a line to the current verse. If the formatting has changed and we're beyond the second line of first verse, + then this indicates a change of verse. Italics are a chorus - def finishVerse(self): + :param text: The verse text """ - Verse is finished, store it. Note in book 1+2, some songs are formatted - incorrectly. Here we try and split songs with missing line breaks into - the correct number of verses. + if self.italics != self.is_chorus and ((len(self.verses) > 0) or + (self.current__verse.count('\n') > 1)): + self.finish_verse() + if self.italics: + self.is_chorus = True + self.current__verse += text + '\n' + + def finish_verse(self): """ - if self.currentVerse.strip() == '': + Verse is finished, store it. Note in book 1+2, some songs are formatted incorrectly. Here we try and split + songs with missing line breaks into the correct number of verses. + """ + if self.current__verse.strip() == '': return - if self.isChorus: + if self.is_chorus: versetag = 'C' splitat = None else: versetag = 'V' - splitat = self.verseSplits(self.songNumber) + splitat = self.verse_splits(self.song_number) if splitat: ln = 0 verse = '' - for line in self.currentVerse.split('\n'): + for line in self.current__verse.split('\n'): ln += 1 if line == '' or ln > splitat: - self.addSofVerse(verse, versetag) + self.add_sof_verse(verse, versetag) ln = 0 if line: verse = line + '\n' @@ -315,19 +322,19 @@ class SofImport(OooImport): else: verse += line + '\n' if verse: - self.addSofVerse(verse, versetag) + self.add_sof_verse(verse, versetag) else: - self.addSofVerse(self.currentVerse, versetag) - self.currentVerse = '' - self.isChorus = False + self.add_sof_verse(self.current__verse, versetag) + self.current__verse = '' + self.is_chorus = False - def addSofVerse(self, lyrics, tag): - self.addVerse(lyrics, tag) - if not self.isChorus and 'C1' in self.verseOrderListGenerated: - self.verseOrderListGenerated.append('C1') - self.verseOrderListGenerated_useful = True + def add_sof_verse(self, lyrics, tag): + self.add_verse(lyrics, tag) + if not self.is_chorus and 'C1' in self.verse_order_list_generated: + self.verse_order_list_generated.append('C1') + self.verse_order_list_generated_useful = True - def uncapText(self, text): + def uncap_text(self, text): """ Words in the title are in all capitals, so we lowercase them. However some of these words, e.g. referring to God need a leading @@ -336,28 +343,26 @@ class SofImport(OooImport): There is a complicated word "One", which is sometimes lower and sometimes upper depending on context. Never mind, keep it lower. """ - textarr = re.split('(\W+)', text) - textarr[0] = textarr[0].capitalize() - for i in range(1, len(textarr)): + text_arr = re.split('(\W+)', text) + text_arr[0] = text_arr[0].capitalize() + for i in range(1, len(text_arr)): # Do not translate these. Fixed strings in SOF song file - if textarr[i] in ('JESUS', 'CHRIST', 'KING', 'ALMIGHTY', - 'REDEEMER', 'SHEPHERD', 'SON', 'GOD', 'LORD', 'FATHER', - 'HOLY', 'SPIRIT', 'LAMB', 'YOU', 'YOUR', 'I', 'I\'VE', - 'I\'M', 'I\'LL', 'SAVIOUR', 'O', 'YOU\'RE', 'HE', 'HIS', - 'HIM', 'ZION', 'EMMANUEL', 'MAJESTY', 'JESUS\'', 'JIREH', - 'JUDAH', 'LION', 'LORD\'S', 'ABRAHAM', 'GOD\'S', - 'FATHER\'S', 'ELIJAH' 'MARTHA', 'CHRISTMAS', 'ALPHA', - 'OMEGA'): - textarr[i] = textarr[i].capitalize() + if text_arr[i] in ('JESUS', 'CHRIST', 'KING', 'ALMIGHTY', 'REDEEMER', 'SHEPHERD', 'SON', 'GOD', 'LORD', + 'FATHER', 'HOLY', 'SPIRIT', 'LAMB', 'YOU', 'YOUR', 'I', 'I\'VE', 'I\'M', 'I\'LL', + 'SAVIOUR', 'O', 'YOU\'RE', 'HE', 'HIS', 'HIM', 'ZION', 'EMMANUEL', 'MAJESTY', 'JESUS\'', + 'JIREH', 'JUDAH', 'LION', 'LORD\'S', 'ABRAHAM', 'GOD\'S', 'FATHER\'S', 'ELIJAH' 'MARTHA', + 'CHRISTMAS', 'ALPHA', 'OMEGA'): + text_arr[i] = text_arr[i].capitalize() else: - textarr[i] = textarr[i].lower() - text = ''.join(textarr) + text_arr[i] = text_arr[i].lower() + text = ''.join(text_arr) return text - def verseSplits(self, song_number): + def verse_splits(self, song_number): """ - Because someone at Kingsway forgot to check the 1+2 RTF file, - some verses were not formatted correctly. + Because someone at Kingsway forgot to check the 1+2 RTF file, some verses were not formatted correctly. + + :param song_number: The Song number """ if song_number == 11: return 8 diff --git a/openlp/plugins/songs/lib/songbeamerimport.py b/openlp/plugins/songs/lib/songbeamerimport.py index 4f3cc250f..4de763554 100644 --- a/openlp/plugins/songs/lib/songbeamerimport.py +++ b/openlp/plugins/songs/lib/songbeamerimport.py @@ -40,6 +40,7 @@ from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) + class SongBeamerTypes(object): MarkTypes = { 'Refrain': VerseType.tags[VerseType.Chorus], @@ -98,7 +99,7 @@ class SongBeamerImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Receive a single file or a list of files to import. """ @@ -109,9 +110,9 @@ class SongBeamerImport(SongImport): # TODO: check that it is a valid SongBeamer file if self.stop_import_flag: return - self.setDefaults() - self.currentVerse = '' - self.currentVerseType = VerseType.tags[VerseType.Verse] + self.set_defaults() + self.current_verse = '' + self.current_verse_type = VerseType.tags[VerseType.Verse] read_verses = False file_name = os.path.split(import_file)[1] if os.path.isfile(import_file): @@ -132,39 +133,38 @@ class SongBeamerImport(SongImport): if line.startswith('#') and not read_verses: self.parseTags(line) elif line.startswith('---'): - if self.currentVerse: - self.replaceHtmlTags() - self.addVerse(self.currentVerse, self.currentVerseType) - self.currentVerse = '' - self.currentVerseType = VerseType.tags[VerseType.Verse] + if self.current_verse: + self.replace_html_tags() + self.add_verse(self.current_verse, self.current_verse_type) + self.current_verse = '' + self.current_verse_type = VerseType.tags[VerseType.Verse] read_verses = True verse_start = True elif read_verses: if verse_start: verse_start = False - if not self.checkVerseMarks(line): - self.currentVerse = line + '\n' + if not self.check_verse_marks(line): + self.current_verse = line + '\n' else: - self.currentVerse += line + '\n' - if self.currentVerse: - self.replaceHtmlTags() - self.addVerse(self.currentVerse, self.currentVerseType) + self.current_verse += line + '\n' + if self.current_verse: + self.replace_html_tags() + self.add_verse(self.current_verse, self.current_verse_type) if not self.finish(): - self.logError(import_file) + self.log_error(import_file) - def replaceHtmlTags(self): + def replace_html_tags(self): """ This can be called to replace SongBeamer's specific (html) tags with OpenLP's specific (html) tags. """ for pair in SongBeamerImport.HTML_TAG_PAIRS: - self.currentVerse = pair[0].sub(pair[1], self.currentVerse) + self.current_verse = pair[0].sub(pair[1], self.current_verse) def parseTags(self, line): """ Parses a meta data line. - ``line`` - The line in the file. It should consist of a tag and a value for this tag (unicode):: + :param line: The line in the file. It should consist of a tag and a value for this tag (unicode):: u'#Title=Nearer my God to Thee' """ @@ -174,7 +174,7 @@ class SongBeamerImport(SongImport): if not tag_val[0] or not tag_val[1]: return if tag_val[0] == '#(c)': - self.addCopyright(tag_val[1]) + self.add_copyright(tag_val[1]) elif tag_val[0] == '#AddCopyrightInfo': pass elif tag_val[0] == '#Author': @@ -186,7 +186,7 @@ class SongBeamerImport(SongImport): elif tag_val[0] == '#Categories': self.topics = tag_val[1].split(',') elif tag_val[0] == '#CCLI': - self.ccliNumber = tag_val[1] + self.ccli_number = tag_val[1] elif tag_val[0] == '#Chords': pass elif tag_val[0] == '#ChurchSongID': @@ -233,10 +233,10 @@ class SongBeamerImport(SongImport): song_book_pub = tag_val[1] elif tag_val[0] == '#Songbook' or tag_val[0] == '#SongBook': 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: 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': pass elif tag_val[0] == 'Tempo': @@ -267,20 +267,19 @@ class SongBeamerImport(SongImport): # TODO: add the verse order. pass - def checkVerseMarks(self, line): + def check_verse_marks(self, line): """ Check and add the verse's MarkType. Returns ``True`` if the given linE contains a correct verse mark otherwise ``False``. - ``line`` - The line to check for marks (unicode). + :param line: The line to check for marks (unicode). """ marks = line.split(' ') if len(marks) <= 2 and marks[0] in SongBeamerTypes.MarkTypes: - self.currentVerseType = SongBeamerTypes.MarkTypes[marks[0]] + self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]] if len(marks) == 2: # If we have a digit, we append it to current_verse_type. if marks[1].isdigit(): - self.currentVerseType += marks[1] + self.current_verse_type += marks[1] return True return False diff --git a/openlp/plugins/songs/lib/songcompare.py b/openlp/plugins/songs/lib/songcompare.py index 0fbc4530b..99a04beb2 100644 --- a/openlp/plugins/songs/lib/songcompare.py +++ b/openlp/plugins/songs/lib/songcompare.py @@ -56,11 +56,8 @@ def songs_probably_equal(song1, song2): """ Calculate and return whether two songs are probably equal. - ``song1`` - The first song to compare. - - ``song2`` - The second song to compare. + :param song1: The first song to compare. + :param song2: The second song to compare. """ if len(song1.search_lyrics) < len(song2.search_lyrics): small = song1.search_lyrics @@ -96,8 +93,7 @@ def _op_length(opcode): """ Return the length of a given difference. - ``opcode`` - The difference. + :param opcode: The difference. """ return max(opcode[2] - opcode[1], opcode[4] - opcode[3]) @@ -107,33 +103,28 @@ def _remove_typos(diff): Remove typos from a diff set. A typo is a small difference (min_fragment_size). - ``diff`` - The diff set to remove the typos from. + :param diff: The diff set to remove the typos from. """ # Remove typo at beginning of the string. if len(diff) >= 2: - if diff[0][0] != "equal" and _op_length(diff[0]) <= MAX_TYPO_SIZE and \ - _op_length(diff[1]) >= MIN_FRAGMENT_SIZE: - del diff[0] + if diff[0][0] != "equal" and _op_length(diff[0]) <= MAX_TYPO_SIZE and _op_length(diff[1]) >= MIN_FRAGMENT_SIZE: + del diff[0] # Remove typos in the middle of the string. if len(diff) >= 3: for index in range(len(diff) - 3, -1, -1): - if _op_length(diff[index]) >= MIN_FRAGMENT_SIZE and \ - diff[index + 1][0] != "equal" and _op_length(diff[index + 1]) <= MAX_TYPO_SIZE and \ - _op_length(diff[index + 2]) >= MIN_FRAGMENT_SIZE: - del diff[index + 1] + if _op_length(diff[index]) >= MIN_FRAGMENT_SIZE and diff[index + 1][0] != "equal" and \ + _op_length(diff[index + 1]) <= MAX_TYPO_SIZE and _op_length(diff[index + 2]) >= MIN_FRAGMENT_SIZE: + del diff[index + 1] # Remove typo at the end of the string. if len(diff) >= 2: - if _op_length(diff[-2]) >= MIN_FRAGMENT_SIZE and \ - diff[-1][0] != "equal" and _op_length(diff[-1]) <= MAX_TYPO_SIZE: - del diff[-1] + if _op_length(diff[-2]) >= MIN_FRAGMENT_SIZE and diff[-1][0] != "equal" \ + and _op_length(diff[-1]) <= MAX_TYPO_SIZE: + del diff[-1] # Merge the bordering equal passages that occured by removing differences. for index in range(len(diff) - 2, -1, -1): if diff[index][0] == "equal" and _op_length(diff[index]) >= MIN_FRAGMENT_SIZE and \ - diff[index + 1][0] == "equal" and _op_length(diff[index + 1]) >= MIN_FRAGMENT_SIZE: - diff[index] = ("equal", diff[index][1], diff[index + 1][2], diff[index][3], - diff[index + 1][4]) - del diff[index + 1] - + diff[index + 1][0] == "equal" and _op_length(diff[index + 1]) >= MIN_FRAGMENT_SIZE: + diff[index] = ("equal", diff[index][1], diff[index + 1][2], diff[index][3], diff[index + 1][4]) + del diff[index + 1] return diff diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index d6333e353..bb56f3498 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -53,7 +53,7 @@ class SongImport(QtCore.QObject): as necessary """ @staticmethod - def isValidSource(import_source): + def is_valid_source(import_source): """ Override this method to validate the source prior to import. """ @@ -63,10 +63,8 @@ class SongImport(QtCore.QObject): """ Initialise and create defaults for properties - ``manager`` - An instance of a SongManager, through which all database access is - performed. - + :param manager: An instance of a SongManager, through which all database access is performed. + :param kwargs: """ self.manager = manager QtCore.QObject.__init__(self) @@ -82,56 +80,51 @@ class SongImport(QtCore.QObject): self.import_wizard = None self.song = None self.stop_import_flag = False - self.setDefaults() + self.set_defaults() 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 if importing many songs at once to ensure a clean beginning """ self.title = '' - self.songNumber = '' + self.song_number = '' self.alternate_title = '' self.copyright = '' self.comments = '' - self.themeName = '' - self.ccliNumber = '' + self.theme_name = '' + self.ccli_number = '' self.authors = [] self.topics = [] - self.mediaFiles = [] - self.songBookName = '' - self.songBookPub = '' - self.verseOrderListGeneratedUseful = False - self.verseOrderListGenerated = [] - self.verseOrderList = [] + self.media_files = [] + self.song_book_name = '' + self.song_book_pub = '' + self.verse_order_list_generated_useful = False + self.verse_order_list_generated = [] + self.verse_order_list = [] self.verses = [] - self.verseCounts = {} - self.copyrightString = translate('SongsPlugin.SongImport', 'copyright') + self.verse_counts = {} + 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. - ``filepath`` - This should be the file path if ``self.import_source`` is a list - with different files. If it is not a list, but a single file (for - 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. + :param file_path: This should be the file path if ``self.import_source`` is a list with different files. If it + is not a list, but a single file (for instance a database), then this should be the song's title. + :param 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: return if self.import_wizard.error_report_text_edit.isHidden(): - self.import_wizard.error_report_text_edit.setText(translate('SongsPlugin.SongImport', - 'The following songs could not be imported:')) + self.import_wizard.error_report_text_edit.setText( + translate('SongsPlugin.SongImport', 'The following songs could not be imported:')) self.import_wizard.error_report_text_edit.setVisible(True) self.import_wizard.error_copy_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): """ @@ -143,10 +136,9 @@ class SongImport(QtCore.QObject): def register(self, 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 - interested in. Some can be converted to ascii. + Get rid of some dodgy unicode and formatting characters we're not interested in. Some can be converted to ascii. """ text = text.replace('\u2018', '\'') text = text.replace('\u2019', '\'') @@ -161,21 +153,31 @@ class SongImport(QtCore.QObject): text = re.sub(r' ?(\n{5}|\f)+ ?', '\f', text) return text - def processSongText(self, text): + def process_song_text(self, text): + """ + Process the song text from import + + :param text: Some text + """ verse_texts = text.split('\n\n') for verse_text in verse_texts: 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): + """ + Process the song verse text from import + + :param text: Some text + """ 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 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): copyright_found = True - self.addCopyright(line) + self.add_copyright(line) else: self.parse_author(line) return @@ -184,9 +186,9 @@ class SongImport(QtCore.QObject): return if not self.title: self.title = lines[0] - self.addVerse(text) + self.add_verse(text) - def addCopyright(self, copyright): + def add_copyright(self, copyright): """ Build the copyright field """ @@ -198,9 +200,8 @@ class SongImport(QtCore.QObject): def parse_author(self, text): """ - Add the author. OpenLP stores them individually so split by 'and', '&' - and comma. However need to check for 'Mr and Mrs Smith' and turn it to - 'Mr Smith' and 'Mrs Smith'. + Add the author. OpenLP stores them individually so split by 'and', '&' and comma. However need to check + for 'Mr and Mrs Smith' and turn it to 'Mr Smith' and 'Mrs Smith'. """ for author in text.split(','): authors = author.split('&') @@ -211,9 +212,9 @@ class SongImport(QtCore.QObject): if author2.endswith('.'): author2 = author2[:-1] if author2: - self.addAuthor(author2) + self.add_author(author2) - def addAuthor(self, author): + def add_author(self, author): """ Add an author to the list """ @@ -221,63 +222,56 @@ class SongImport(QtCore.QObject): return 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 """ - if filename in [x[0] for x in self.mediaFiles]: + if filename in [x[0] for x in self.media_files]: 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 attempt to detect duplicates. In this case it will just add to the verse order. - ``verse_text`` - The text of the verse. - - ``verse_def`` - The verse tag can be v1/c1/b etc, or 'v' and 'c' (will count the + :param verse_text: The text of the verse. + :param verse_def: The verse tag can be v1/c1/b etc, or 'v' and 'c' (will count the verses/choruses itself) or None, where it will assume verse. - - ``lang`` - The language code (ISO-639) of the verse, for example *en* or *de*. - + :param lang: The language code (ISO-639) of the verse, for example *en* or *de*. """ for (old_verse_def, old_verse, old_lang) in self.verses: if old_verse.strip() == verse_text.strip(): - self.verseOrderListGenerated.append(old_verse_def) - self.verseOrderListGeneratedUseful = True + self.verse_order_list_generated.append(old_verse_def) + self.verse_order_list_generated_useful = True return - if verse_def[0] in self.verseCounts: - self.verseCounts[verse_def[0]] += 1 + if verse_def[0] in self.verse_counts: + self.verse_counts[verse_def[0]] += 1 else: - self.verseCounts[verse_def[0]] = 1 + self.verse_counts[verse_def[0]] = 1 if len(verse_def) == 1: - verse_def += str(self.verseCounts[verse_def[0]]) - elif int(verse_def[1:]) > self.verseCounts[verse_def[0]]: - self.verseCounts[verse_def[0]] = int(verse_def[1:]) + verse_def += str(self.verse_counts[verse_def[0]]) + elif int(verse_def[1:]) > self.verse_counts[verse_def[0]]: + self.verse_counts[verse_def[0]] = int(verse_def[1:]) 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 # used. - if verse_def not in self.verseOrderListGenerated: - self.verseOrderListGenerated.append(verse_def) + if verse_def not in self.verse_order_list_generated: + self.verse_order_list_generated.append(verse_def) - def repeatVerse(self): + def repeat_verse(self): """ Repeat the previous verse in the verse order """ - if self.verseOrderListGenerated: - self.verseOrderListGenerated.append(self.verseOrderListGenerated[-1]) - self.verseOrderListGeneratedUseful = True + if self.verse_order_list_generated: + self.verse_order_list_generated.append(self.verse_order_list_generated[-1]) + 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) - Author not checked here, if no author then "Author unknown" is - automatically added + Author not checked here, if no author then "Author unknown" is automatically added """ if not self.title or not self.verses: return False @@ -288,8 +282,8 @@ class SongImport(QtCore.QObject): """ All fields have been set to this song. Write the song to disk. """ - if not self.checkComplete(): - self.setDefaults() + if not self.check_complete(): + self.set_defaults() return False log.info('committing song %s to database', self.title) song = Song() @@ -301,7 +295,7 @@ class SongImport(QtCore.QObject): song.search_title = '' song.search_lyrics = '' song.verse_order = '' - song.song_number = self.songNumber + song.song_number = self.song_number verses_changed_to_other = {} sxml = SongXML() other_count = 1 @@ -317,32 +311,32 @@ class SongImport(QtCore.QObject): verse_def = new_verse_def sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang) song.lyrics = str(sxml.extract_xml(), 'utf-8') - if not self.verseOrderList and self.verseOrderListGeneratedUseful: - self.verseOrderList = self.verseOrderListGenerated - self.verseOrderList = [verses_changed_to_other.get(v, v) for v in self.verseOrderList] - song.verse_order = ' '.join(self.verseOrderList) + if not self.verse_order_list and self.verse_order_list_generated_useful: + self.verse_order_list = self.verse_order_list_generated + self.verse_order_list = [verses_changed_to_other.get(v, v) for v in self.verse_order_list] + song.verse_order = ' '.join(self.verse_order_list) song.copyright = self.copyright song.comments = self.comments - song.theme_name = self.themeName - song.ccli_number = self.ccliNumber - for authortext in self.authors: - author = self.manager.get_object_filtered(Author, Author.display_name == authortext) + song.theme_name = self.theme_name + song.ccli_number = self.ccli_number + for author_text in self.authors: + author = self.manager.get_object_filtered(Author, Author.display_name == author_text) if not author: - author = Author.populate(display_name=authortext, - last_name=authortext.split(' ')[-1], - first_name=' '.join(authortext.split(' ')[:-1])) + author = Author.populate(display_name=author_text, + last_name=author_text.split(' ')[-1], + first_name=' '.join(author_text.split(' ')[:-1])) song.authors.append(author) - if self.songBookName: - song_book = self.manager.get_object_filtered(Book, Book.name == self.songBookName) + if self.song_book_name: + song_book = self.manager.get_object_filtered(Book, Book.name == self.song_book_name) 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 - for topictext in self.topics: - if not topictext: + for topic_text in self.topics: + if not topic_text: continue - topic = self.manager.get_object_filtered(Topic, Topic.name == topictext) + topic = self.manager.get_object_filtered(Topic, Topic.name == topic_text) if topic is None: - topic = Topic.populate(name=topictext) + topic = Topic.populate(name=topic_text) song.topics.append(topic) # We need to save the song now, before adding the media files, so that # we know where to save the media files to. @@ -350,29 +344,29 @@ class SongImport(QtCore.QObject): self.manager.save_object(song) # Now loop through the media files, copy them to the correct location, # 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) if not media_file: 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)) self.manager.save_object(song) - self.setDefaults() + self.set_defaults() 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 the new file location. - ``filename`` - The file to copy. + :param song_id: + :param filename: The file to copy. """ if not hasattr(self, 'save_path'): self.save_path = os.path.join(AppLocation.get_section_data_path(self.import_wizard.plugin.name), - 'audio', str(song_id)) + 'audio', str(song_id)) check_directory_exists(self.save_path) if not filename.startswith(self.save_path): - oldfile, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1]) - shutil.copyfile(oldfile, filename) + old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1]) + shutil.copyfile(old_file, filename) return filename diff --git a/openlp/plugins/songs/lib/songproimport.py b/openlp/plugins/songs/lib/songproimport.py index de707b495..86411a499 100644 --- a/openlp/plugins/songs/lib/songproimport.py +++ b/openlp/plugins/songs/lib/songproimport.py @@ -74,7 +74,7 @@ class SongProImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Receive a single file or a list of files to import. """ @@ -89,18 +89,18 @@ class SongProImport(SongImport): file_line = str(file_line, 'cp1252') file_text = file_line.rstrip() if file_text and file_text[0] == '#': - self.processSection(tag, text.rstrip()) + self.process_section(tag, text.rstrip()) tag = file_text[1:] text = '' else: text += file_line - def processSection(self, tag, text): + def process_section(self, tag, text): """ Process a section of the song, i.e. title, verse etc. """ if tag == 'T': - self.setDefaults() + self.set_defaults() if text: self.title = text return @@ -118,29 +118,29 @@ class SongProImport(SongImport): if tag == 'A': self.parse_author(text) elif tag in ['B', 'C']: - self.addVerse(text, tag) + self.add_verse(text, tag) elif tag == 'D': - self.addVerse(text, 'E') + self.add_verse(text, 'E') elif tag == 'G': self.topics.append(text) elif tag == 'M': matches = re.findall(r'\d+', text) if matches: - self.songNumber = matches[-1] - self.songBookName = text[:text.rfind(self.songNumber)] + self.song_number = matches[-1] + self.song_book_name = text[:text.rfind(self.song_number)] elif tag == 'N': self.comments = text elif tag == 'O': for char in text: if char == 'C': - self.verseOrderList.append('C1') + self.verse_order_list.append('C1') elif char == 'B': - self.verseOrderList.append('B1') + self.verse_order_list.append('B1') elif char == 'D': - self.verseOrderList.append('E1') + self.verse_order_list.append('E1') elif '1' <= char <= '7': - self.verseOrderList.append('V' + char) + self.verse_order_list.append('V' + char) elif tag == 'R': - self.addCopyright(text) + self.add_copyright(text) elif '1' <= tag <= '7': - self.addVerse(text, 'V' + tag[1:]) + self.add_verse(text, 'V' + tag[1:]) diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py index 1d333e38e..50a8698c3 100644 --- a/openlp/plugins/songs/lib/songshowplusimport.py +++ b/openlp/plugins/songs/lib/songshowplusimport.py @@ -94,7 +94,7 @@ class SongShowPlusImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Receive a single file or a list of files to import. """ @@ -141,19 +141,19 @@ class SongShowPlusImport(SongImport): authors = self.decode(data).split(" / ") for author in authors: if author.find(",") !=-1: - authorParts = author.split(", ") - author = authorParts[1] + " " + authorParts[0] + author_parts = author.split(", ") + author = author_parts[1] + " " + author_parts[0] self.parse_author(author) elif block_key == COPYRIGHT: - self.addCopyright(self.decode(data)) + self.add_copyright(self.decode(data)) elif block_key == CCLI_NO: - self.ccliNumber = int(data) + self.ccli_number = int(data) 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: - 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: - 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: self.topics.append(self.decode(data)) elif block_key == COMMENTS: @@ -165,21 +165,28 @@ class SongShowPlusImport(SongImport): verse_tag = self.decode(verse_tag) self.ssp_verse_order_list.append(verse_tag) elif block_key == SONG_BOOK: - self.songBookName = self.decode(data) + self.song_book_name = self.decode(data) elif block_key == SONG_NUMBER: - self.songNumber = ord(data) + self.song_number = ord(data) elif block_key == CUSTOM_VERSE: 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: log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data)) 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() if not self.finish(): - self.logError(file) + self.log_error(file) def to_openlp_verse_tag(self, verse_name, ignore_unique=False): + """ + Handle OpenLP verse tags + + :param verse_name: The verse name + :param ignore_unique: Ignore if unique + :return: The verse tags and verse number concatenated + """ # Have we got any digits? If so, verse number is everything from the digits to the end (OpenLP does not have # concept of part verses, so just ignore any non integers on the end (including floats)) match = re.match(r'(\D*)(\d+)', verse_name) diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index bf17af028..bf74a4e7c 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -71,10 +71,10 @@ class SongsTab(SettingsTab): self.mode_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Songs Mode')) self.search_as_type_check_box.setText(translate('SongsPlugin.SongsTab', 'Enable search as you type')) self.tool_bar_active_check_box.setText(translate('SongsPlugin.SongsTab', - 'Display verses on live tool bar')) + 'Display verses on live tool bar')) self.update_on_edit_check_box.setText(translate('SongsPlugin.SongsTab', 'Update service from song edit')) self.add_from_service_check_box.setText(translate('SongsPlugin.SongsTab', - 'Import missing songs from service files')) + 'Import missing songs from service files')) def on_search_as_type_check_box_changed(self, check_state): self.song_search = (check_state == QtCore.Qt.Checked) diff --git a/openlp/plugins/songs/lib/sundayplusimport.py b/openlp/plugins/songs/lib/sundayplusimport.py index f45c952a2..f63d625c5 100644 --- a/openlp/plugins/songs/lib/sundayplusimport.py +++ b/openlp/plugins/songs/lib/sundayplusimport.py @@ -48,6 +48,7 @@ HOTKEY_TO_VERSE_TYPE = { '+': 'b', 'Z': 'o'} + class SundayPlusImport(SongImport): """ Import Sunday Plus songs @@ -62,31 +63,38 @@ class SundayPlusImport(SongImport): SongImport.__init__(self, manager, **kwargs) self.encoding = 'us-ascii' - def doImport(self): + def do_import(self): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) for filename in self.import_source: if self.stop_import_flag: return song_file = open(filename) - self.doImportFile(song_file) + self.do_import_file(song_file) song_file.close() - def doImportFile(self, file): + def do_import_file(self, file): """ Process the Sunday Plus file object. """ - self.setDefaults() + self.set_defaults() if not self.parse(file.read()): - self.logError(file.name) + self.log_error(file.name) return if not self.title: - self.title = self.titleFromFilename(file.name) + self.title = self.title_from_filename(file.name) if not self.finish(): - self.logError(file.name) + self.log_error(file.name) def parse(self, data, cell=False): + """ + Process the records + + :param data: The data to be processed + :param cell: ? + :return: + """ if len(data) == 0 or data[0:1] != '[' or data[-1] != ']': - self.logError('File is malformed') + self.log_error('File is malformed') return False i = 1 verse_type = VerseType.tags[VerseType.Verse] @@ -126,7 +134,7 @@ class SundayPlusImport(SongImport): elif name == 'Author': author = self.decode(self.unescape(value)) if len(author): - self.addAuthor(author) + self.add_author(author) elif name == 'Copyright': self.copyright = self.decode(self.unescape(value)) elif name[0:4] == 'CELL': @@ -160,20 +168,26 @@ class SundayPlusImport(SongImport): if line[:3].lower() == 'ccl': m = re.search(r'[0-9]+', line) if m: - self.ccliNumber = int(m.group(0)) + self.ccli_number = int(m.group(0)) continue elif line.lower() == 'public domain': self.copyright = 'Public Domain' continue 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: break i = end + 1 i += 1 return True - def titleFromFilename(self, filename): + def title_from_filename(self, filename): + """ + Extract the title from the filename + + :param filename: File name + :return: + """ title = os.path.split(filename)[1] if title.endswith('.ptf'): title = title[:-4] diff --git a/openlp/plugins/songs/lib/worshipcenterproimport.py b/openlp/plugins/songs/lib/worshipcenterproimport.py index 12119d950..80b1b5fe3 100644 --- a/openlp/plugins/songs/lib/worshipcenterproimport.py +++ b/openlp/plugins/songs/lib/worshipcenterproimport.py @@ -51,7 +51,7 @@ class WorshipCenterProImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Receive a single file to import. """ @@ -60,7 +60,7 @@ class WorshipCenterProImport(SongImport): 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)) # 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.')) return cursor = conn.cursor() @@ -76,10 +76,10 @@ class WorshipCenterProImport(SongImport): for song in songs: if self.stop_import_flag: break - self.setDefaults() + self.set_defaults() self.title = songs[song]['TITLE'] lyrics = songs[song]['LYRICS'].strip('&crlf;&crlf;') for verse in lyrics.split('&crlf;&crlf;'): verse = verse.replace('&crlf;', '\n') - self.addVerse(verse) + self.add_verse(verse) self.finish() diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/wowimport.py index 85347b97d..c92b0ee2a 100644 --- a/openlp/plugins/songs/lib/wowimport.py +++ b/openlp/plugins/songs/lib/wowimport.py @@ -40,6 +40,7 @@ BLOCK_TYPES = ('V', 'C', 'B') log = logging.getLogger(__name__) + class WowImport(SongImport): """ The :class:`WowImport` class provides the ability to import song files from @@ -101,7 +102,7 @@ class WowImport(SongImport): """ SongImport.__init__(self, manager, **kwargs) - def doImport(self): + def do_import(self): """ Receive a single file or a list of files to import. """ @@ -110,38 +111,42 @@ class WowImport(SongImport): for source in self.import_source: if self.stop_import_flag: return - self.setDefaults() + self.set_defaults() song_data = open(source, 'rb') if song_data.read(19) != 'WoW File\nSong Words': - self.logError(source, str(translate('SongsPlugin.WordsofWorshipSongImport', - ('Invalid Words of Worship song file. Missing "Wow File\\nSong Words" header.')))) + self.log_error(source, + str(translate('SongsPlugin.WordsofWorshipSongImport', + 'Invalid Words of Worship song file. Missing "Wow File\\nSong ' + 'Words" header.'))) continue # Seek to byte which stores number of blocks in the song song_data.seek(56) no_of_blocks = ord(song_data.read(1)) song_data.seek(66) if song_data.read(16) != 'CSongDoc::CBlock': - self.logError(source, str(translate('SongsPlugin.WordsofWorshipSongImport', - ('Invalid Words of Worship song file. Missing "CSongDoc::CBlock" string.')))) + self.log_error(source, + str(translate('SongsPlugin.WordsofWorshipSongImport', + 'Invalid Words of Worship song file. Missing "CSongDoc::CBlock" ' + 'string.'))) continue # Seek to the beginning of the first block song_data.seek(82) for block in range(no_of_blocks): - self.linesToRead = ord(song_data.read(4)[:1]) + self.lines_to_read = ord(song_data.read(4)[:1]) block_text = '' - while self.linesToRead: - self.lineText = str(song_data.read(ord(song_data.read(1))), 'cp1252') + while self.lines_to_read: + self.line_text = str(song_data.read(ord(song_data.read(1))), 'cp1252') song_data.seek(1, os.SEEK_CUR) if block_text: block_text += '\n' - block_text += self.lineText - self.linesToRead -= 1 + block_text += self.line_text + self.lines_to_read -= 1 block_type = BLOCK_TYPES[ord(song_data.read(4)[:1])] # Blocks are separated by 2 bytes, skip them, but not if # this is the last block! if block + 1 < no_of_blocks: 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 author_length = ord(song_data.read(1)) if author_length: @@ -149,10 +154,10 @@ class WowImport(SongImport): # Finally the copyright copyright_length = ord(song_data.read(1)) 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] # Get the song title self.title = file_name.rpartition('.')[0] song_data.close() if not self.finish(): - self.logError(source) + self.log_error(source) diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index 30b7a4df8..95ae4fc33 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -97,21 +97,13 @@ class SongXML(object): """ Add a verse to the ```` tag. - ``type`` - A string denoting the type of verse. Possible values are *v*, *c*, *b*, *p*, *i*, *e* and *o*. Any other - type is **not** allowed, this also includes translated types. - - ``number`` - An integer denoting the number of the item, for example: verse 1. - - ``content`` - The actual text of the verse to be stored. - - ``lang`` - The verse's language code (ISO-639). This is not required, but should be added if available. + :param type: A string denoting the type of verse. Possible values are *v*, *c*, *b*, *p*, *i*, *e* and *o*. + Any other type is **not** allowed, this also includes translated types. + :param number: An integer denoting the number of the item, for example: verse 1. + :param content: The actual text of the verse to be stored. + :param lang: The verse's language code (ISO-639). This is not required, but should be added if available. """ - verse = etree.Element('verse', type=str(type), - label=str(number)) + verse = etree.Element('verse', type=str(type), label=str(number)) if lang: verse.set('lang', lang) verse.text = etree.CDATA(content) @@ -121,16 +113,13 @@ class SongXML(object): """ Extract our newly created XML song. """ - return etree.tostring(self.song_xml, encoding='UTF-8', - xml_declaration=True) + return etree.tostring(self.song_xml, encoding='UTF-8', xml_declaration=True) def get_verses(self, xml): """ Iterates through the verses in the XML and returns a list of verses and their attributes. - ``xml`` - The XML of the song to be parsed. - + :param xml: The XML of the song to be parsed. The returned list has the following format:: [[{'type': 'v', 'label': '1'}, u"optional slide split 1[---]optional slide split 2"], @@ -351,8 +340,7 @@ class OpenLyrics(object): The first unicode string are the start tags (for the next slide). The second unicode string are the end tags. - ``text`` - The text to test. The text must **not** contain html tags, only OpenLP formatting tags are allowed:: + :param text: The text to test. The text must **not** contain html tags, only OpenLP formatting tags are allowed:: {st}{r}Text text text """ @@ -378,12 +366,9 @@ class OpenLyrics(object): Create and save a song from OpenLyrics format xml to the database. Since we also export XML from external sources (e. g. OpenLyrics import), we cannot ensure, that it completely conforms to the OpenLyrics standard. - ``xml`` - The XML to parse (unicode). - - ``parse_and_temporary_save`` - Switch to skip processing the whole song and storing the songs in the database with a temporary flag. - Defaults to ``False``. + :param xml: The XML to parse (unicode). + :param parse_and_temporary_save: Switch to skip processing the whole song and storing the songs in the database + with a temporary flag. Defaults to ``False``. """ # No xml get out of here. if not xml: @@ -418,6 +403,15 @@ class OpenLyrics(object): return song def _add_text_to_element(self, tag, parent, text=None, label=None): + """ + Build an element + + :param tag: A Tag + :param parent: Its parent + :param text: Some text to be added + :param label: And a label + :return: + """ if label: element = etree.Element(tag, name=str(label)) else: @@ -430,6 +424,9 @@ class OpenLyrics(object): def _add_tag_to_formatting(self, tag_name, tags_element): """ Add new formatting tag to the element ```` if the tag is not present yet. + + :param tag_name: The tag_name + :param tags_element: Some tag elements """ available_tags = FormattingTags.get_html_tags() start_tag = '{%s}' % tag_name @@ -477,16 +474,16 @@ class OpenLyrics(object): def _extract_xml(self, xml): """ Extract our newly created XML song. + + :param xml: The XML """ - return etree.tostring(xml, encoding='UTF-8', - xml_declaration=True) + return etree.tostring(xml, encoding='UTF-8', xml_declaration=True) def _text(self, element): """ This returns the text of an element as unicode string. - ``element`` - The element. + :param element: The element. """ if element.text is not None: return str(element.text) @@ -496,11 +493,8 @@ class OpenLyrics(object): """ Adds the authors specified in the XML to the song. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object """ authors = [] if hasattr(properties, 'authors'): @@ -509,24 +503,20 @@ class OpenLyrics(object): if display_name: authors.append(display_name) for display_name in authors: - author = self.manager.get_object_filtered(Author, - Author.display_name == display_name) + author = self.manager.get_object_filtered(Author, Author.display_name == display_name) if author is None: # We need to create a new author, as the author does not exist. author = Author.populate(display_name=display_name, - last_name=display_name.split(' ')[-1], - first_name=' '.join(display_name.split(' ')[:-1])) + last_name=display_name.split(' ')[-1], + first_name=' '.join(display_name.split(' ')[:-1])) song.authors.append(author) def _process_cclinumber(self, properties, song): """ Adds the CCLI number to the song. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ if hasattr(properties, 'ccliNo'): song.ccli_number = self._text(properties.ccliNo) @@ -535,11 +525,8 @@ class OpenLyrics(object): """ Joins the comments specified in the XML and add it to the song. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ if hasattr(properties, 'comments'): comments_list = [] @@ -553,11 +540,8 @@ class OpenLyrics(object): """ Adds the copyright to the song. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ if hasattr(properties, 'copyright'): song.copyright = self._text(properties.copyright) @@ -566,6 +550,9 @@ class OpenLyrics(object): """ Process the formatting tags from the song and either add missing tags temporary or permanently to the formatting tag list. + + :param song_xml: The song XML + :param temporary: Is the song temporary? """ if not hasattr(song_xml, 'format'): return @@ -603,11 +590,9 @@ class OpenLyrics(object): Converts the xml text with mixed content to OpenLP representation. Chords are skipped and formatting tags are converted. - ``element`` - The property object (lxml.etree.Element). - - ``newlines`` - The switch to enable/disable processing of line breaks
. The
is used since OpenLyrics 0.8. + :param element: The property object (lxml.etree.Element). + :param newlines: The switch to enable/disable processing of line breaks
. The
is used since + OpenLyrics 0.8. """ text = '' use_endtag = True @@ -655,8 +640,8 @@ class OpenLyrics(object): """ Converts lyrics lines to OpenLP representation. - ``lines`` - The lines object (lxml.objectify.ObjectifiedElement). + :param lines: The lines object (lxml.objectify.ObjectifiedElement). + :param version: """ text = '' # Convert lxml.objectify to lxml.etree representation. @@ -682,14 +667,9 @@ class OpenLyrics(object): """ Processes the verses and search_lyrics for the song. - ``properties`` - The properties object (lxml.objectify.ObjectifiedElement). - - ``song_xml`` - The objectified song (lxml.objectify.ObjectifiedElement). - - ``song_obj`` - The song object. + :param properties: The properties object (lxml.objectify.ObjectifiedElement). + :param song_xml: The objectified song (lxml.objectify.ObjectifiedElement). + :param song_obj: The song object. """ sxml = SongXML() verses = {} @@ -698,12 +678,12 @@ class OpenLyrics(object): lyrics = song_xml.lyrics except AttributeError: raise OpenLyricsError(OpenLyricsError.LyricsError, ' tag is missing.', - translate('OpenLP.OpenLyricsImportError', ' tag is missing.')) + translate('OpenLP.OpenLyricsImportError', ' tag is missing.')) try: verse_list = lyrics.verse except AttributeError: raise OpenLyricsError(OpenLyricsError.VerseError, ' tag is missing.', - translate('OpenLP.OpenLyricsImportError', ' tag is missing.')) + translate('OpenLP.OpenLyricsImportError', ' tag is missing.')) # Loop over the "verse" elements. for verse in verse_list: text = '' @@ -712,8 +692,7 @@ class OpenLyrics(object): if text: text += '\n' # Append text from "lines" element to verse text. - text += self._process_verse_lines(lines, - version=song_xml.get('version')) + text += self._process_verse_lines(lines, version=song_xml.get('version')) # Add an optional split to the verse text. if lines.get('break') is not None: text += '\n[---]' @@ -749,11 +728,8 @@ class OpenLyrics(object): """ Adds the song book and song number specified in the XML to the song. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ song.song_book_id = None song.song_number = '' @@ -775,11 +751,8 @@ class OpenLyrics(object): """ Processes the titles specified in the song's XML. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ for title in properties.titles.title: if not song.title: @@ -792,11 +765,8 @@ class OpenLyrics(object): """ Adds the topics to the song. - ``properties`` - The property object (lxml.objectify.ObjectifiedElement). - - ``song`` - The song object. + :param properties: The property object (lxml.objectify.ObjectifiedElement). + :param song: The song object. """ if hasattr(properties, 'themes'): for topic_text in properties.themes.theme: diff --git a/openlp/plugins/songs/lib/zionworximport.py b/openlp/plugins/songs/lib/zionworximport.py index f8f31ac35..ab6bcb27d 100644 --- a/openlp/plugins/songs/lib/zionworximport.py +++ b/openlp/plugins/songs/lib/zionworximport.py @@ -41,6 +41,7 @@ log = logging.getLogger(__name__) # Used to strip control chars (except 10=LF, 13=CR) CONTROL_CHARS_MAP = dict.fromkeys(list(range(10)) + [11, 12] + list(range(14,32)) + [127]) + class ZionWorxImport(SongImport): """ The :class:`ZionWorxImport` class provides the ability to import songs @@ -78,19 +79,19 @@ class ZionWorxImport(SongImport): * Note: This is the default format of the Python ``csv`` module. """ - def doImport(self): + def do_import(self): """ Receive a CSV file (from a ZionWorx database dump) to import. """ with open(self.import_source, 'rb') as songs_file: field_names = ['SongNum', 'Title1', 'Title2', 'Lyrics', 'Writer', 'Copyright', 'Keywords', - 'DefaultStyle'] + 'DefaultStyle'] songs_reader = csv.DictReader(songs_file, field_names) try: records = list(songs_reader) except csv.Error as e: - self.logError(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'), - translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e)) + self.log_error(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'), + translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e)) return num_records = len(records) log.info('%s records found in CSV file' % num_records) @@ -98,20 +99,20 @@ class ZionWorxImport(SongImport): for index, record in enumerate(records, 1): if self.stop_import_flag: return - self.setDefaults() + self.set_defaults() try: self.title = self._decode(record['Title1']) if record['Title2']: self.alternate_title = self._decode(record['Title2']) 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']) except UnicodeDecodeError as e: - self.logError(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index), - translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e) + self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index), + translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e) continue except TypeError as e: - self.logError(translate( + self.log_error(translate( 'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), 'TypeError: %s' % e) return verse = '' @@ -119,19 +120,18 @@ class ZionWorxImport(SongImport): if line and not line.isspace(): verse += line + '\n' elif verse: - self.addVerse(verse) + self.add_verse(verse) verse = '' if verse: - self.addVerse(verse) + self.add_verse(verse) title = self.title if not self.finish(): - self.logError(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index - + (': "' + title + '"' if title else '')) + self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index + + (': "' + title + '"' if title else '')) def _decode(self, str): """ - Decodes CSV input to unicode, stripping all control characters (except - new lines). + Decodes CSV input to unicode, stripping all control characters (except new lines). """ # This encoding choice seems OK. ZionWorx has no option for setting the # encoding for its songs, so we assume encoding is always the same. diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 00bb72b9a..32d3ddbe6 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -314,7 +314,7 @@ class SongsPlugin(Plugin): self.application.process_events() for db in song_dbs: importer = OpenLPSongImport(self.manager, filename=db) - importer.doImport(progress) + importer.do_import(progress) self.application.process_events() progress.setValue(song_count) self.media_item.on_search_text_button_clicked() diff --git a/tests/functional/openlp_plugins/bibles/__init__.py b/tests/functional/openlp_plugins/bibles/__init__.py index c60847dc0..1f4f74a33 100644 --- a/tests/functional/openlp_plugins/bibles/__init__.py +++ b/tests/functional/openlp_plugins/bibles/__init__.py @@ -1,3 +1,28 @@ -""" -Tests for the Bibles plugin -""" +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### \ No newline at end of file diff --git a/tests/functional/openlp_plugins/bibles/test_lib.py b/tests/functional/openlp_plugins/bibles/test_lib.py index 0c8bb8211..9b3e79591 100644 --- a/tests/functional/openlp_plugins/bibles/test_lib.py +++ b/tests/functional/openlp_plugins/bibles/test_lib.py @@ -85,3 +85,5 @@ class TestLib(TestCase): # THEN: It should be False self.assertFalse(has_verse_list, 'The SearchResults object should have a verse list') + + diff --git a/tests/functional/openlp_plugins/bibles/test_versereferencelist.py b/tests/functional/openlp_plugins/bibles/test_versereferencelist.py index a7481ac57..8b7c3f786 100644 --- a/tests/functional/openlp_plugins/bibles/test_versereferencelist.py +++ b/tests/functional/openlp_plugins/bibles/test_versereferencelist.py @@ -83,7 +83,7 @@ class TestVerseReferenceList(TestCase): # THEN: The current index should be 0 and the end pointer of the entry should be '2' self.assertEqual(reference_list.current_index, 0, 'The current index should be 0') self.assertEqual(reference_list.verse_list[0]['end'], next_verse, - 'The end in first entry should be %u' % next_verse) + 'The end in first entry should be %u' % next_verse) def add_another_verse_test(self): """ @@ -124,8 +124,8 @@ class TestVerseReferenceList(TestCase): # THEN: the data will be appended to the list self.assertEqual(len(reference_list.version_list), 1, 'The version data should be appended') self.assertEqual(reference_list.version_list[0], - {'version': version, 'copyright': copyright_, 'permission': permission}, - 'The version data should be appended') + {'version': version, 'copyright': copyright_, 'permission': permission}, + 'The version data should be appended') def add_existing_version_test(self): """ diff --git a/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py b/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py index d22372377..5f25c4d3a 100644 --- a/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py @@ -118,7 +118,7 @@ class TestPptviewDocument(TestCase): self.mock_os.path.isdir.return_value = True self.mock_controller.process.OpenPPT.return_value = 0 instance = PptviewDocument(self.mock_controller, self.mock_presentation) - instance.filepath = 'test\path.ppt' + instance.file_path = 'test\path.ppt' if os.name == 'nt': result = instance.load_presentation() @@ -138,7 +138,7 @@ class TestPptviewDocument(TestCase): self.mock_os.path.isdir.return_value = False self.mock_controller.process.OpenPPT.return_value = -1 instance = PptviewDocument(self.mock_controller, self.mock_presentation) - instance.filepath = 'test\path.ppt' + instance.file_path = 'test\path.ppt' if os.name == 'nt': result = instance.load_presentation() diff --git a/tests/functional/openlp_plugins/songs/test_ewimport.py b/tests/functional/openlp_plugins/songs/test_ewimport.py index 2dc265a52..a22519bec 100644 --- a/tests/functional/openlp_plugins/songs/test_ewimport.py +++ b/tests/functional/openlp_plugins/songs/test_ewimport.py @@ -154,13 +154,13 @@ class TestEasyWorshipSongImport(TestCase): def find_field_exists_test(self): """ - Test finding an existing field in a given list using the :mod:`findField` + Test finding an existing field in a given list using the :mod:`find_field` """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions. with patch('openlp.plugins.songs.lib.ewimport.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager) - importer.fieldDescs = TEST_FIELD_DESCS + importer.field_descriptions = TEST_FIELD_DESCS # WHEN: Called with a field name that exists existing_fields = ['Title', 'Text Percentage Bottom', 'RecID', 'Default Background', 'Words', @@ -168,28 +168,28 @@ class TestEasyWorshipSongImport(TestCase): for field_name in existing_fields: # THEN: The item corresponding the index returned should have the same name attribute - self.assertEquals(importer.fieldDescs[importer.findField(field_name)].name, field_name) + self.assertEquals(importer.field_descriptions[importer.find_field(field_name)].name, field_name) def find_non_existing_field_test(self): """ - Test finding an non-existing field in a given list using the :mod:`findField` + Test finding an non-existing field in a given list using the :mod:`find_field` """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions with patch('openlp.plugins.songs.lib.ewimport.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager) - importer.fieldDescs = TEST_FIELD_DESCS + importer.field_descriptions = TEST_FIELD_DESCS # WHEN: Called with a field name that does not exist non_existing_fields = ['BK Gradient Shading', 'BK Gradient Variant', 'Favorite', 'Copyright'] for field_name in non_existing_fields: # THEN: The importer object should not be None - self.assertRaises(IndexError, importer.findField, field_name) + self.assertRaises(IndexError, importer.find_field, field_name) def set_record_struct_test(self): """ - Test the :mod:`setRecordStruct` module + Test the :mod:`set_record_struct` module """ # GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of # field descriptions @@ -198,17 +198,17 @@ class TestEasyWorshipSongImport(TestCase): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager) - # WHEN: setRecordStruct is called with a list of field descriptions - return_value = importer.setRecordStruct(TEST_FIELD_DESCS) + # WHEN: set_record_struct is called with a list of field descriptions + return_value = importer.set_record_struct(TEST_FIELD_DESCS) - # THEN: setRecordStruct should return None and Struct should be called with a value representing + # THEN: set_record_struct should return None and Struct should be called with a value representing # the list of field descriptions - self.assertIsNone(return_value, 'setRecordStruct should return None') + self.assertIsNone(return_value, 'set_record_struct should return None') mocked_struct.Struct.assert_called_with('>50sHIB250s250s10sQ') def get_field_test(self): """ - Test the :mod:`getField` module + Test the :mod:`get_field` module """ # GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results with patch('openlp.plugins.songs.lib.ewimport.SongImport'): @@ -216,20 +216,20 @@ class TestEasyWorshipSongImport(TestCase): importer = EasyWorshipSongImport(mocked_manager) importer.encoding = TEST_DATA_ENCODING importer.fields = TEST_FIELDS - importer.fieldDescs = TEST_FIELD_DESCS + importer.field_descriptions = TEST_FIELD_DESCS field_results = [(0, b'A Heart Like Thine'), (1, 100), (2, 102), (3, True), (6, None), (7, None)] # WHEN: Called with test data for field_index, result in field_results: - return_value = importer.getField(field_index) + return_value = importer.get_field(field_index) - # THEN: getField should return the known results + # THEN: get_field should return the known results self.assertEquals(return_value, result, - 'getField should return "%s" when called with "%s"' % (result, TEST_FIELDS[field_index])) + 'get_field should return "%s" when called with "%s"' % (result, TEST_FIELDS[field_index])) def get_memo_field_test(self): """ - Test the :mod:`getField` module + Test the :mod:`get_field` module """ for test_results in GET_MEMO_FIELD_TEST_RESULTS: # GIVEN: A mocked out SongImport class, a mocked out "manager", a mocked out memo_file and an encoding @@ -237,20 +237,20 @@ class TestEasyWorshipSongImport(TestCase): mocked_manager = MagicMock() mocked_memo_file = MagicMock() importer = EasyWorshipSongImport(mocked_manager) - importer.memoFile = mocked_memo_file + importer.memo_file = mocked_memo_file importer.encoding = TEST_DATA_ENCODING # WHEN: Supplied with test fields and test field descriptions importer.fields = TEST_FIELDS - importer.fieldDescs = TEST_FIELD_DESCS + importer.field_descriptions = TEST_FIELD_DESCS field_index = test_results[0] mocked_memo_file.read.return_value = test_results[1] get_field_result = test_results[2]['return'] get_field_read_calls = test_results[2]['read'] get_field_seek_calls = test_results[2]['seek'] - # THEN: getField should return the appropriate value with the appropriate mocked objects being called - self.assertEquals(importer.getField(field_index), get_field_result) + # THEN: get_field should return the appropriate value with the appropriate mocked objects being called + self.assertEquals(importer.get_field(field_index), get_field_result) for call in get_field_read_calls: mocked_memo_file.read.assert_any_call(call) for call in get_field_seek_calls: @@ -261,7 +261,7 @@ class TestEasyWorshipSongImport(TestCase): def do_import_source_test(self): """ - Test the :mod:`doImport` module opens the correct files + Test the :mod:`do_import` module opens the correct files """ # GIVEN: A mocked out SongImport class, a mocked out "manager" with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ @@ -273,14 +273,14 @@ class TestEasyWorshipSongImport(TestCase): # WHEN: Supplied with an import source importer.import_source = 'Songs.DB' - # THEN: doImport should return None having called os.path.isfile - self.assertIsNone(importer.doImport(), 'doImport should return None') + # THEN: do_import should return None having called os.path.isfile + self.assertIsNone(importer.do_import(), 'do_import should return None') mocked_os_path.isfile.assert_any_call('Songs.DB') mocked_os_path.isfile.assert_any_call('Songs.MB') def do_import_database_validity_test(self): """ - Test the :mod:`doImport` module handles invalid database files correctly + Test the :mod:`do_import` module handles invalid database files correctly """ # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager" with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ @@ -293,13 +293,13 @@ class TestEasyWorshipSongImport(TestCase): # WHEN: DB file size is less than 0x800 mocked_os_path.getsize.return_value = 0x7FF - # THEN: doImport should return None having called os.path.isfile - self.assertIsNone(importer.doImport(), 'doImport should return None when db_size is less than 0x800') + # THEN: do_import should return None having called os.path.isfile + self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800') mocked_os_path.getsize.assert_any_call('Songs.DB') def do_import_memo_validty_test(self): """ - Test the :mod:`doImport` module handles invalid memo files correctly + Test the :mod:`do_import` module handles invalid memo files correctly """ # GIVEN: A mocked out SongImport class, a mocked out "manager" with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ @@ -316,9 +316,9 @@ class TestEasyWorshipSongImport(TestCase): struct_unpack_return_values = [(0, 0x700, 2, 0, 0), (0, 0x800, 0, 0, 0), (0, 0x800, 5, 0, 0)] mocked_struct.unpack.side_effect = struct_unpack_return_values - # THEN: doImport should return None having called closed the open files db and memo files. + # THEN: do_import should return None having called closed the open files db and memo files. for effect in struct_unpack_return_values: - self.assertIsNone(importer.doImport(), 'doImport should return None when db_size is less than 0x800') + self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800') self.assertEqual(mocked_open().close.call_count, 2, 'The open db and memo files should have been closed') mocked_open().close.reset_mock() @@ -326,7 +326,7 @@ class TestEasyWorshipSongImport(TestCase): def code_page_to_encoding_test(self): """ - Test the :mod:`doImport` converts the code page to the encoding correctly + Test the :mod:`do_import` converts the code page to the encoding correctly """ # GIVEN: A mocked out SongImport class, a mocked out "manager" with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ @@ -345,8 +345,8 @@ class TestEasyWorshipSongImport(TestCase): mocked_struct.unpack.side_effect = struct_unpack_return_values mocked_retrieve_windows_encoding.return_value = False - # THEN: doImport should return None having called retrieve_windows_encoding with the correct encoding. - self.assertIsNone(importer.doImport(), 'doImport should return None when db_size is less than 0x800') + # THEN: do_import should return None having called retrieve_windows_encoding with the correct encoding. + self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800') mocked_retrieve_windows_encoding.assert_call(encoding) def file_import_test(self): @@ -369,8 +369,8 @@ class TestEasyWorshipSongImport(TestCase): importer = EasyWorshipSongImportLogger(mocked_manager) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = False - importer.addAuthor = mocked_add_author - importer.addVerse = mocked_add_verse + importer.add_author = mocked_add_author + importer.add_verse = mocked_add_verse importer.title = mocked_title importer.finish = mocked_finish importer.topics = [] @@ -378,9 +378,9 @@ class TestEasyWorshipSongImport(TestCase): # WHEN: Importing each file importer.import_source = os.path.join(TEST_PATH, 'Songs.DB') - # THEN: doImport should return none, the song data should be as expected, and finish should have been + # THEN: do_import should return none, the song data should be as expected, and finish should have been # called. - self.assertIsNone(importer.doImport(), 'doImport should return None when it has completed') + self.assertIsNone(importer.do_import(), 'do_import should return None when it has completed') for song_data in SONG_TEST_DATA: title = song_data['title'] author_calls = song_data['authors'] @@ -394,11 +394,11 @@ class TestEasyWorshipSongImport(TestCase): if song_copyright: self.assertEqual(importer.copyright, song_copyright) 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)) for verse_text, verse_tag in add_verse_calls: mocked_add_verse.assert_any_call(verse_text, verse_tag) 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)) mocked_finish.assert_called_with() diff --git a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py index e40ceffff..fbd339cf3 100644 --- a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py @@ -116,17 +116,17 @@ class TestFoilPresenter(TestCase): def create_foil_presenter_test(self): """ - Test creating an instance of the FoilPresenter class + Test creating an instance of the foil_presenter class """ # GIVEN: A mocked out "manager" and "SongImport" instance mocked_manager = MagicMock() mocked_song_import = MagicMock() - # WHEN: An FoilPresenter instance is created + # WHEN: An foil_presenter instance is created foil_presenter_instance = FoilPresenter(mocked_manager, mocked_song_import) # THEN: The instance should not be None - self.assertIsNotNone(foil_presenter_instance, 'FoilPresenter instance should not be none') + self.assertIsNotNone(foil_presenter_instance, 'foil_presenter instance should not be none') def no_xml_test(self): """ @@ -169,7 +169,7 @@ class TestFoilPresenter(TestCase): # WHEN: xml_to_song is called with a string without an xml encoding declaration foil_presenter_instance.xml_to_song('') - # THEN: the string shiuld have been left intact + # THEN: the string should have been left intact self.mocked_re.compile.sub.called_with('') def process_lyrics_no_verses_test(self): @@ -188,7 +188,7 @@ class TestFoilPresenter(TestCase): # WHEN: _process_lyrics is called 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.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() diff --git a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py index ba976a179..72901eb47 100644 --- a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py +++ b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py @@ -73,7 +73,7 @@ class TestSongBeamerImport(TestCase): def invalid_import_source_test(self): """ - Test SongBeamerImport.doImport handles different invalid import_source values + Test SongBeamerImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): @@ -87,14 +87,14 @@ class TestSongBeamerImport(TestCase): for source in ['not a list', 0]: importer.import_source = source - # THEN: doImport should return none and the progress bar maximum should not be set. - self.assertIsNone(importer.doImport(), 'doImport should return None when import_source is not a list') + # THEN: do_import should return none and the progress bar maximum should not be set. + self.assertIsNone(importer.do_import(), 'do_import should return None when import_source is not a list') self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False, 'setMaxium on import_wizard.progress_bar should not have been called') def valid_import_source_test(self): """ - Test SongBeamerImport.doImport handles different invalid import_source values + Test SongBeamerImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): @@ -107,10 +107,10 @@ class TestSongBeamerImport(TestCase): # WHEN: Import source is a list importer.import_source = ['List', 'of', 'files'] - # THEN: doImport should return none and the progress bar setMaximum should be called with the length of + # THEN: do_import should return none and the progress bar setMaximum should be called with the length of # import_source. - self.assertIsNone(importer.doImport(), - 'doImport should return None when import_source is a list and stop_import_flag is True') + self.assertIsNone(importer.do_import(), + 'do_import should return None when import_source is a list and stop_import_flag is True') mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source)) def file_import_test(self): @@ -130,7 +130,7 @@ class TestSongBeamerImport(TestCase): importer = SongBeamerImport(mocked_manager) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = False - importer.addVerse = mocked_add_verse + importer.add_verse = mocked_add_verse importer.finish = mocked_finish # WHEN: Importing each file @@ -140,16 +140,16 @@ class TestSongBeamerImport(TestCase): song_book_name = SONG_TEST_DATA[song_file]['song_book_name'] song_number = SONG_TEST_DATA[song_file]['song_number'] - # THEN: doImport should return none, the song data should be as expected, and finish should have been + # THEN: do_import should return none, the song data should be as expected, and finish should have been # called. - self.assertIsNone(importer.doImport(), 'doImport should return None when it has completed') + self.assertIsNone(importer.do_import(), 'do_import should return None when it has completed') self.assertEquals(importer.title, title, 'title for %s should be "%s"' % (song_file, title)) for verse_text, verse_tag in add_verse_calls: mocked_add_verse.assert_any_call(verse_text, verse_tag) 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)) 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)) mocked_finish.assert_called_with() diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index 6d909c2a9..5c945efb3 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -43,6 +43,7 @@ TEST_PATH = os.path.abspath( class TestSongShowPlusFileImport(SongImportTestHelper): + def __init__(self, *args, **kwargs): self.importer_class_name = 'SongShowPlusImport' self.importer_module_name = 'songshowplusimport' @@ -78,7 +79,7 @@ class TestSongShowPlusImport(TestCase): def invalid_import_source_test(self): """ - Test SongShowPlusImport.doImport handles different invalid import_source values + Test SongShowPlusImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): @@ -92,14 +93,14 @@ class TestSongShowPlusImport(TestCase): for source in ['not a list', 0]: importer.import_source = source - # THEN: doImport should return none and the progress bar maximum should not be set. - self.assertIsNone(importer.doImport(), 'doImport should return None when import_source is not a list') + # THEN: do_import should return none and the progress bar maximum should not be set. + self.assertIsNone(importer.do_import(), 'do_import should return None when import_source is not a list') self.assertEquals(mocked_import_wizard.progress_bar.setMaximum.called, False, 'setMaximum on import_wizard.progress_bar should not have been called') def valid_import_source_test(self): """ - Test SongShowPlusImport.doImport handles different invalid import_source values + Test SongShowPlusImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): @@ -112,10 +113,10 @@ class TestSongShowPlusImport(TestCase): # WHEN: Import source is a list importer.import_source = ['List', 'of', 'files'] - # THEN: doImport should return none and the progress bar setMaximum should be called with the length of + # THEN: do_import should return none and the progress bar setMaximum should be called with the length of # import_source. - self.assertIsNone(importer.doImport(), - 'doImport should return None when import_source is a list and stop_import_flag is True') + self.assertIsNone(importer.do_import(), + 'do_import should return None when import_source is a list and stop_import_flag is True') mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source)) def to_openlp_verse_tag_test(self): diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index 8e0b10667..630fb572e 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -152,7 +152,7 @@ class TestWorshipCenterProSongImport(TestCase): 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. + # a mocked "manager" and a mocked out log_error method. 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.translate') as mocked_translate: @@ -160,17 +160,17 @@ class TestWorshipCenterProSongImport(TestCase): mocked_log_error = MagicMock() mocked_translate.return_value = 'Translated Text' importer = WorshipCenterProImport(mocked_manager) - importer.logError = mocked_log_error + importer.log_error = mocked_log_error importer.import_source = 'import_source' pyodbc_errors = [pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError] mocked_pyodbc_connect.side_effect = pyodbc_errors - # WHEN: Calling the doImport method + # WHEN: Calling the do_import method for effect in pyodbc_errors: - return_value = importer.doImport() + return_value = importer.do_import() - # THEN: doImport should return None, and pyodbc, translate & logError are called with known calls - self.assertIsNone(return_value, 'doImport should return None when pyodbc raises an exception.') + # THEN: do_import should return None, and pyodbc, translate & log_error are called with known calls + self.assertIsNone(return_value, 'do_import should return None when pyodbc raises an exception.') mocked_pyodbc_connect.assert_called_with( 'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=import_source') mocked_translate.assert_called_with('SongsPlugin.WorshipCenterProImport', 'Unable to connect the WorshipCenter Pro database.') @@ -181,7 +181,7 @@ class TestWorshipCenterProSongImport(TestCase): 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 - # 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'), \ patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: @@ -194,17 +194,17 @@ class TestWorshipCenterProSongImport(TestCase): importer = WorshipCenterProImportLogger(mocked_manager) importer.import_source = 'import_source' importer.import_wizard = mocked_import_wizard - importer.addVerse = mocked_add_verse + importer.add_verse = mocked_add_verse importer.stop_import_flag = False importer.finish = mocked_finish - # WHEN: Calling the doImport method - return_value = importer.doImport() + # WHEN: Calling the do_import method + return_value = importer.do_import() - # THEN: doImport should return None, and pyodbc, import_wizard, importer.title and addVerse are called with + # THEN: do_import should return None, and pyodbc, import_wizard, importer.title and add_verse are called with # known calls - self.assertIsNone(return_value, 'doImport should return None when pyodbc raises an exception.') + self.assertIsNone(return_value, 'do_import 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().cursor.assert_any_call() mocked_pyodbc.connect().cursor().execute.assert_called_with('SELECT ID, Field, Value FROM __SONGDATA') @@ -220,4 +220,4 @@ class TestWorshipCenterProSongImport(TestCase): for call in verse_calls: mocked_add_verse.assert_any_call(call) 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') diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index af99bab6a..2ffecb11a 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -51,9 +51,9 @@ class SongImportTestHelper(TestCase): Patch and set up the mocks required. """ 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( - '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( 'openlp.plugins.songs.lib.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) self.parse_author_patcher = patch( @@ -107,16 +107,16 @@ class SongImportTestHelper(TestCase): topics = self._get_data(result_data, 'topics') verse_order_list = self._get_data(result_data, 'verse_order_list') - # THEN: doImport should return none, the song data should be as expected, and finish should have been + # THEN: do_import should return none, the song data should be as expected, and finish should have been # called. - self.assertIsNone(importer.doImport(), 'doImport should return None when it has completed') + self.assertIsNone(importer.do_import(), 'do_import should return None when it has completed') self.assertEquals(importer.title, title, 'title for %s should be "%s"' % (source_file_name, title)) for author in author_calls: self.mocked_parse_author.assert_any_call(author) if song_copyright: self.mocked_add_copyright.assert_called_with(song_copyright) 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)) for verse_text, verse_tag in add_verse_calls: self.mocked_add_verse.assert_any_call(verse_text, verse_tag) @@ -126,13 +126,13 @@ class SongImportTestHelper(TestCase): self.assertEquals(importer.comments, comments, 'comments for %s should be "%s"' % (source_file_name, comments)) 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)) 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)) 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)) self.mocked_finish.assert_called_with() diff --git a/tests/interfaces/openlp_plugins/bibles/__init__.py b/tests/interfaces/openlp_plugins/bibles/__init__.py index f87606f07..6b241e7fc 100644 --- a/tests/interfaces/openlp_plugins/bibles/__init__.py +++ b/tests/interfaces/openlp_plugins/bibles/__init__.py @@ -1 +1,28 @@ -__author__ = 'tim' +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_http.py b/tests/interfaces/openlp_plugins/bibles/test_lib_http.py index 386900a9b..9f90df64e 100644 --- a/tests/interfaces/openlp_plugins/bibles/test_lib_http.py +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_http.py @@ -1,3 +1,31 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### """ Package to test the openlp.plugin.bible.lib.https package. """ diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py b/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py new file mode 100644 index 000000000..b00bbee00 --- /dev/null +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### +""" +Functional tests to test the Bible Manager class and related methods. +""" +from unittest import TestCase + +from openlp.core.common import Registry, Settings +from openlp.plugins.bibles.lib import BibleManager, LanguageSelection +from tests.interfaces import MagicMock, patch + +from tests.utils.constants import TEST_RESOURCES_PATH +from tests.helpers.testmixin import TestMixin + + +class TestBibleManager(TestCase, TestMixin): + + def setUp(self): + """ + Set up the environment for testing bible queries with 1 Timothy 3 + """ + self.build_settings() + Registry.create() + Registry().register('service_list', MagicMock()) + Registry().register('application', MagicMock()) + bible_settings = { + 'bibles/proxy name': '', + 'bibles/db type': 'sqlite', + 'bibles/book name language': LanguageSelection.Bible, + 'bibles/verse separator': '', + 'bibles/range separator': '', + 'bibles/list separator': '', + 'bibles/end separator': '', + } + Settings().extend_default_settings(bible_settings) + with patch('openlp.core.common.applocation.Settings') as mocked_class, \ + patch('openlp.core.common.AppLocation.get_section_data_path') as mocked_get_section_data_path, \ + patch('openlp.core.common.AppLocation.get_files') as mocked_get_files: + # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_files() + mocked_settings = mocked_class.return_value + mocked_settings.contains.return_value = False + mocked_get_files.return_value = ["tests.sqlite"] + mocked_get_section_data_path.return_value = TEST_RESOURCES_PATH + "/bibles" + self.manager = BibleManager(MagicMock()) + + def tearDown(self): + """ + Delete all the C++ objects at the end so that we don't have a segfault + """ + self.destroy_settings() + + def get_books_test(self): + """ + Test the get_books method + """ + # GIVEN given a bible in the bible manager + # WHEN asking for the books of the bible + books = self.manager.get_books('tests') + # THEN a list of books should be returned + self.assertEqual(66, len(books), 'There should be 66 books in the bible') + + def get_book_by_id_test(self): + """ + Test the get_book_by_id method + """ + # GIVEN given a bible in the bible manager + # WHEN asking for the book of the bible + book = self.manager.get_book_by_id('tests', 54) + # THEN a book should be returned + self.assertEqual('1 Timothy', book.name, '1 Timothy should have been returned from the bible') + + def get_chapter_count_test(self): + """ + Test the get_chapter_count method + """ + # GIVEN given a bible in the bible manager + # WHEN asking for the chapters in a book of the bible + book = self.manager.get_book_by_id('tests', 54) + chapter = self.manager.get_chapter_count('tests', book) + # THEN the chapter count should be returned + self.assertEqual(6, chapter, '1 Timothy should have 6 chapters returned from the bible') + + def get_verse_count_by_book_ref_id_test(self): + """ + Test the get_verse_count_by_book_ref_id method + """ + # GIVEN given a bible in the bible manager + # WHEN asking for the number of verses in a book of the bible + verses = self.manager.get_verse_count_by_book_ref_id('tests', 54, 3) + # THEN the chapter count should be returned + self.assertEqual(16, verses, '1 Timothy v3 should have 16 verses returned from the bible') + diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py b/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py new file mode 100644 index 000000000..811d048db --- /dev/null +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### +""" +This module contains tests for the lib submodule of the Bibles plugin. +""" +from unittest import TestCase +from tests.interfaces import MagicMock, patch + +from openlp.core.common import Registry, Settings +from openlp.plugins.bibles.lib import BibleManager, parse_reference, LanguageSelection + +from tests.utils.constants import TEST_RESOURCES_PATH +from tests.helpers.testmixin import TestMixin + + +class TestBibleManager(TestCase, TestMixin): + + def setUp(self): + """ + Set up the environment for testing bible parse reference + """ + self.build_settings() + Registry.create() + Registry().register('service_list', MagicMock()) + Registry().register('application', MagicMock()) + bible_settings = { + 'bibles/proxy name': '', + 'bibles/db type': 'sqlite', + 'bibles/book name language': LanguageSelection.Bible, + 'bibles/verse separator': '', + 'bibles/range separator': '', + 'bibles/list separator': '', + 'bibles/end separator': '', + } + Settings().extend_default_settings(bible_settings) + with patch('openlp.core.common.applocation.Settings') as mocked_class, \ + patch('openlp.core.common.AppLocation.get_section_data_path') as mocked_get_section_data_path, \ + patch('openlp.core.common.AppLocation.get_files') as mocked_get_files: + # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_files() + mocked_settings = mocked_class.return_value + mocked_settings.contains.return_value = False + mocked_get_files.return_value = ["tests.sqlite"] + mocked_get_section_data_path.return_value = TEST_RESOURCES_PATH + "/bibles" + self.manager = BibleManager(MagicMock()) + + def tearDown(self): + """ + Delete all the C++ objects at the end so that we don't have a segfault + """ + self.destroy_settings() + + def parse_reference_one_test(self): + """ + Test the parse_reference method with 1 Timothy 1 + """ + # GIVEN given a bible in the bible manager + # WHEN asking to parse the bible reference + results = parse_reference('1 Timothy 1', self.manager.db_cache['tests'], MagicMock(), 54) + # THEN a verse array should be returned + self.assertEquals([(54, 1, 1, -1)], results , "The bible verses should matches the expected results") + + def parse_reference_two_test(self): + """ + Test the parse_reference method with 1 Timothy 1:1-2 + """ + # GIVEN given a bible in the bible manager + # WHEN asking to parse the bible reference + results = parse_reference('1 Timothy 1:1-2', self.manager.db_cache['tests'], MagicMock(), 54) + # THEN a verse array should be returned + self.assertEquals([(54, 1, 1, 2)], results , "The bible verses should matches the expected results") + + def parse_reference_three_test(self): + """ + Test the parse_reference method with 1 Timothy 1:1-2 + """ + # GIVEN given a bible in the bible manager + # WHEN asking to parse the bible reference + results = parse_reference('1 Timothy 1:1-2:1', self.manager.db_cache['tests'], MagicMock(), 54) + # THEN a verse array should be returned + self.assertEquals([(54,1,1,-1),(54,2,1,1)], results , "The bible verses should matches the expected results") \ No newline at end of file diff --git a/tests/interfaces/openlp_plugins/custom/__init__.py b/tests/interfaces/openlp_plugins/custom/__init__.py index e69de29bb..6b241e7fc 100644 --- a/tests/interfaces/openlp_plugins/custom/__init__.py +++ b/tests/interfaces/openlp_plugins/custom/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### diff --git a/tests/interfaces/openlp_plugins/custom/forms/test_customform.py b/tests/interfaces/openlp_plugins/custom/forms/test_customform.py index e98778926..e5fffabc0 100644 --- a/tests/interfaces/openlp_plugins/custom/forms/test_customform.py +++ b/tests/interfaces/openlp_plugins/custom/forms/test_customform.py @@ -1,3 +1,31 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 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 # +############################################################################### """ Module to test the EditCustomForm. """ diff --git a/tests/resources/bibles/tests.sqlite b/tests/resources/bibles/tests.sqlite new file mode 100644 index 000000000..b6af457d7 Binary files /dev/null and b/tests/resources/bibles/tests.sqlite differ