Merge lp:~tomasgroth/openlp/pysword-import into lp:openlp

Proposed by Tomas Groth
Status: Merged
Merged at revision: 2652
Proposed branch: lp:~tomasgroth/openlp/pysword-import
Merge into: lp:openlp
Diff against target: 615 lines (+412/-7)
7 files modified
openlp/core/ui/lib/wizard.py (+2/-1)
openlp/plugins/bibles/forms/bibleimportform.py (+176/-3)
openlp/plugins/bibles/lib/manager.py (+8/-1)
openlp/plugins/bibles/lib/sword.py (+100/-0)
scripts/check_dependencies.py (+1/-0)
tests/functional/openlp_plugins/bibles/test_swordimport.py (+109/-0)
tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py (+16/-2)
To merge this branch: bzr merge lp:~tomasgroth/openlp/pysword-import
Reviewer Review Type Date Requested Status
Raoul Snyman Approve
Review via email: mp+292713@code.launchpad.net

This proposal supersedes a proposal from 2016-04-20.

Description of the change

Added support for importing SWORD bibles using PySword.

To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) wrote : Posted in a previous version of this proposal
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

I tried to do an import from a SWORD Bible I already have, and I got this error as the import itself started.

Traceback (most recent call last):
  File "/home/raoul/Projects/OpenLP/OpenLP/pysword-import/openlp/core/ui/wizard.py", line 217, in on_current_id_changed
    self.perform_wizard()
  File "/home/raoul/Projects/OpenLP/OpenLP/pysword-import/openlp/plugins/bibles/forms/bibleimportform.py", line 805, in perform_wizard
    if importer.do_import(license_version):
TypeError: do_import() takes 1 positional argument but 2 were given

review: Needs Fixing
Revision history for this message
Tomas Groth (tomasgroth) wrote :
Revision history for this message
Raoul Snyman (raoul-snyman) wrote :

I only have 1 SWORD Bible at the moment, so I'm not sure if it's pysword or the Bible itself, but it imported in a weird order. Nothing seemed to be wrong afterward, just had the new testament first and then the old. I figure it's probably just the order of things in the SWORD module itself.

review: Approve
lp:~tomasgroth/openlp/pysword-import updated
2590. By Tomas Groth

merge trunk

2591. By Tomas Groth

fix merge issues

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/ui/lib/wizard.py'
2--- openlp/core/ui/lib/wizard.py 2016-04-22 18:32:59 +0000
3+++ openlp/core/ui/lib/wizard.py 2016-04-26 19:04:37 +0000
4@@ -45,6 +45,7 @@
5 OS = 'OpenSong'
6 OSIS = 'OSIS'
7 ZEF = 'Zefania'
8+ SWORD = 'Sword'
9 # These strings should need a good reason to be retranslated elsewhere.
10 FinishedImport = translate('OpenLP.Ui', 'Finished import.')
11 FormatLabel = translate('OpenLP.Ui', 'Format:')
12@@ -113,7 +114,7 @@
13 Set up the wizard UI.
14 :param image: path to start up image
15 """
16- self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
17+ self.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
18 self.setModal(True)
19 self.setOptions(QtWidgets.QWizard.IndependentPages |
20 QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage)
21
22=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
23--- openlp/plugins/bibles/forms/bibleimportform.py 2016-04-22 18:25:57 +0000
24+++ openlp/plugins/bibles/forms/bibleimportform.py 2016-04-26 19:04:37 +0000
25@@ -27,6 +27,11 @@
26 import urllib.error
27
28 from PyQt5 import QtWidgets
29+try:
30+ from pysword import modules
31+ PYSWORD_AVAILABLE = True
32+except:
33+ PYSWORD_AVAILABLE = False
34
35 from openlp.core.common import AppLocation, Settings, UiStrings, translate, clean_filename
36 from openlp.core.lib.db import delete_database
37@@ -34,7 +39,7 @@
38 from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
39 from openlp.core.common.languagemanager import get_locale_key
40 from openlp.plugins.bibles.lib.manager import BibleFormat
41-from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
42+from openlp.plugins.bibles.lib.db import clean_filename
43 from openlp.plugins.bibles.lib.http import CWExtract, BGExtract, BSExtract
44
45 log = logging.getLogger(__name__)
46@@ -94,6 +99,19 @@
47 self.manager.set_process_dialog(self)
48 self.restart()
49 self.select_stack.setCurrentIndex(0)
50+ if PYSWORD_AVAILABLE:
51+ self.pysword_folder_modules = modules.SwordModules()
52+ try:
53+ self.pysword_folder_modules_json = self.pysword_folder_modules.parse_modules()
54+ except FileNotFoundError:
55+ log.debug('No installed SWORD modules found in the default location')
56+ self.sword_bible_combo_box.clear()
57+ return
58+ bible_keys = self.pysword_folder_modules_json.keys()
59+ for key in bible_keys:
60+ self.sword_bible_combo_box.addItem(self.pysword_folder_modules_json[key]['description'], key)
61+ else:
62+ self.sword_tab_widget.setDisabled(True)
63
64 def custom_signals(self):
65 """
66@@ -106,6 +124,8 @@
67 self.open_song_browse_button.clicked.connect(self.on_open_song_browse_button_clicked)
68 self.zefania_browse_button.clicked.connect(self.on_zefania_browse_button_clicked)
69 self.web_update_button.clicked.connect(self.on_web_update_button_clicked)
70+ self.sword_browse_button.clicked.connect(self.on_sword_browse_button_clicked)
71+ self.sword_zipbrowse_button.clicked.connect(self.on_sword_zipbrowse_button_clicked)
72
73 def add_custom_pages(self):
74 """
75@@ -121,7 +141,7 @@
76 self.format_label = QtWidgets.QLabel(self.select_page)
77 self.format_label.setObjectName('FormatLabel')
78 self.format_combo_box = QtWidgets.QComboBox(self.select_page)
79- self.format_combo_box.addItems(['', '', '', '', ''])
80+ self.format_combo_box.addItems(['', '', '', '', '', ''])
81 self.format_combo_box.setObjectName('FormatComboBox')
82 self.format_layout.addRow(self.format_label, self.format_combo_box)
83 self.spacer = QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
84@@ -275,6 +295,64 @@
85 self.zefania_layout.addRow(self.zefania_file_label, self.zefania_file_layout)
86 self.zefania_layout.setItem(5, QtWidgets.QFormLayout.LabelRole, self.spacer)
87 self.select_stack.addWidget(self.zefania_widget)
88+ self.sword_widget = QtWidgets.QWidget(self.select_page)
89+ self.sword_widget.setObjectName('SwordWidget')
90+ self.sword_layout = QtWidgets.QVBoxLayout(self.sword_widget)
91+ self.sword_layout.setObjectName('SwordLayout')
92+ self.sword_tab_widget = QtWidgets.QTabWidget(self.sword_widget)
93+ self.sword_tab_widget.setObjectName('SwordTabWidget')
94+ self.sword_folder_tab = QtWidgets.QWidget(self.sword_tab_widget)
95+ self.sword_folder_tab.setObjectName('SwordFolderTab')
96+ self.sword_folder_tab_layout = QtWidgets.QGridLayout(self.sword_folder_tab)
97+ self.sword_folder_tab_layout.setObjectName('SwordTabFolderLayout')
98+ self.sword_folder_label = QtWidgets.QLabel(self.sword_folder_tab)
99+ self.sword_folder_label.setObjectName('SwordSourceLabel')
100+ self.sword_folder_tab_layout.addWidget(self.sword_folder_label, 0, 0)
101+ self.sword_folder_label.setObjectName('SwordFolderLabel')
102+ self.sword_folder_edit = QtWidgets.QLineEdit(self.sword_folder_tab)
103+ self.sword_folder_edit.setObjectName('SwordFolderEdit')
104+ self.sword_browse_button = QtWidgets.QToolButton(self.sword_folder_tab)
105+ self.sword_browse_button.setIcon(self.open_icon)
106+ self.sword_browse_button.setObjectName('SwordBrowseButton')
107+ self.sword_folder_tab_layout.addWidget(self.sword_folder_edit, 0, 1)
108+ self.sword_folder_tab_layout.addWidget(self.sword_browse_button, 0, 2)
109+ self.sword_bible_label = QtWidgets.QLabel(self.sword_folder_tab)
110+ self.sword_bible_label.setObjectName('SwordBibleLabel')
111+ self.sword_folder_tab_layout.addWidget(self.sword_bible_label, 1, 0)
112+ self.sword_bible_combo_box = QtWidgets.QComboBox(self.sword_folder_tab)
113+ self.sword_bible_combo_box.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
114+ self.sword_bible_combo_box.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically)
115+ self.sword_bible_combo_box.setObjectName('SwordBibleComboBox')
116+ self.sword_folder_tab_layout.addWidget(self.sword_bible_combo_box, 1, 1)
117+ self.sword_tab_widget.addTab(self.sword_folder_tab, '')
118+ self.sword_zip_tab = QtWidgets.QWidget(self.sword_tab_widget)
119+ self.sword_zip_tab.setObjectName('SwordZipTab')
120+ self.sword_zip_layout = QtWidgets.QGridLayout(self.sword_zip_tab)
121+ self.sword_zip_layout.setObjectName('SwordZipLayout')
122+ self.sword_zipfile_label = QtWidgets.QLabel(self.sword_zip_tab)
123+ self.sword_zipfile_label.setObjectName('SwordZipFileLabel')
124+ self.sword_zipfile_edit = QtWidgets.QLineEdit(self.sword_zip_tab)
125+ self.sword_zipfile_edit.setObjectName('SwordZipFileEdit')
126+ self.sword_zipbrowse_button = QtWidgets.QToolButton(self.sword_zip_tab)
127+ self.sword_zipbrowse_button.setIcon(self.open_icon)
128+ self.sword_zipbrowse_button.setObjectName('SwordZipBrowseButton')
129+ self.sword_zipbible_label = QtWidgets.QLabel(self.sword_folder_tab)
130+ self.sword_zipbible_label.setObjectName('SwordZipBibleLabel')
131+ self.sword_zipbible_combo_box = QtWidgets.QComboBox(self.sword_zip_tab)
132+ self.sword_zipbible_combo_box.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
133+ self.sword_zipbible_combo_box.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically)
134+ self.sword_zipbible_combo_box.setObjectName('SwordZipBibleComboBox')
135+ self.sword_zip_layout.addWidget(self.sword_zipfile_label, 0, 0)
136+ self.sword_zip_layout.addWidget(self.sword_zipfile_edit, 0, 1)
137+ self.sword_zip_layout.addWidget(self.sword_zipbrowse_button, 0, 2)
138+ self.sword_zip_layout.addWidget(self.sword_zipbible_label, 1, 0)
139+ self.sword_zip_layout.addWidget(self.sword_zipbible_combo_box, 1, 1)
140+ self.sword_tab_widget.addTab(self.sword_zip_tab, '')
141+ self.sword_layout.addWidget(self.sword_tab_widget)
142+ self.sword_disabled_label = QtWidgets.QLabel(self.sword_widget)
143+ self.sword_disabled_label.setObjectName('SwordDisabledLabel')
144+ self.sword_layout.addWidget(self.sword_disabled_label)
145+ self.select_stack.addWidget(self.sword_widget)
146 self.select_page_layout.addLayout(self.select_stack)
147 self.addPage(self.select_page)
148 # License Page
149@@ -323,6 +401,7 @@
150 self.format_combo_box.setItemText(BibleFormat.WebDownload, translate('BiblesPlugin.ImportWizardForm',
151 'Web Download'))
152 self.format_combo_box.setItemText(BibleFormat.Zefania, WizardStrings.ZEF)
153+ self.format_combo_box.setItemText(BibleFormat.SWORD, WizardStrings.SWORD)
154 self.osis_file_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
155 self.csv_books_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
156 self.csv_verses_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Verses file:'))
157@@ -346,6 +425,22 @@
158 self.web_tab_widget.setTabText(
159 self.web_tab_widget.indexOf(self.web_proxy_tab), translate('BiblesPlugin.ImportWizardForm',
160 'Proxy Server (Optional)'))
161+ self.sword_bible_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bibles:'))
162+ self.sword_folder_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD data folder:'))
163+ self.sword_zipfile_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD zip-file:'))
164+ self.sword_folder_edit.setPlaceholderText(translate('BiblesPlugin.ImportWizardForm',
165+ 'Defaults to the standard SWORD data folder'))
166+ self.sword_zipbible_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bibles:'))
167+ self.sword_tab_widget.setTabText(self.sword_tab_widget.indexOf(self.sword_folder_tab),
168+ translate('BiblesPlugin.ImportWizardForm', 'Import from folder'))
169+ self.sword_tab_widget.setTabText(self.sword_tab_widget.indexOf(self.sword_zip_tab),
170+ translate('BiblesPlugin.ImportWizardForm', 'Import from Zip-file'))
171+ if PYSWORD_AVAILABLE:
172+ self.sword_disabled_label.setText('')
173+ else:
174+ self.sword_disabled_label.setText(translate('BiblesPlugin.ImportWizardForm',
175+ 'To import SWORD bibles the pysword python module must be '
176+ 'installed. Please read the manual for instructions.'))
177 self.license_details_page.setTitle(
178 translate('BiblesPlugin.ImportWizardForm', 'License Details'))
179 self.license_details_page.setSubTitle(translate('BiblesPlugin.ImportWizardForm',
180@@ -374,6 +469,9 @@
181 if self.currentPage() == self.welcome_page:
182 return True
183 elif self.currentPage() == self.select_page:
184+ self.version_name_edit.clear()
185+ self.permissions_edit.clear()
186+ self.copyright_edit.clear()
187 if self.field('source_format') == BibleFormat.OSIS:
188 if not self.field('osis_location'):
189 critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % WizardStrings.OSIS)
190@@ -410,6 +508,31 @@
191 return False
192 else:
193 self.version_name_edit.setText(self.web_translation_combo_box.currentText())
194+ elif self.field('source_format') == BibleFormat.SWORD:
195+ # Test the SWORD tab that is currently active
196+ if self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_folder_tab):
197+ if not self.field('sword_folder_path') and self.sword_bible_combo_box.count() == 0:
198+ critical_error_message_box(UiStrings().NFSs,
199+ WizardStrings.YouSpecifyFolder % WizardStrings.SWORD)
200+ self.sword_folder_edit.setFocus()
201+ return False
202+ key = self.sword_bible_combo_box.itemData(self.sword_bible_combo_box.currentIndex())
203+ if 'description' in self.pysword_folder_modules_json[key]:
204+ self.version_name_edit.setText(self.pysword_folder_modules_json[key]['description'])
205+ if 'distributionlicense' in self.pysword_folder_modules_json[key]:
206+ self.permissions_edit.setText(self.pysword_folder_modules_json[key]['distributionlicense'])
207+ if 'copyright' in self.pysword_folder_modules_json[key]:
208+ self.copyright_edit.setText(self.pysword_folder_modules_json[key]['copyright'])
209+ elif self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_zip_tab):
210+ if not self.field('sword_zip_path'):
211+ critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % WizardStrings.SWORD)
212+ self.sword_zipfile_edit.setFocus()
213+ return False
214+ key = self.sword_zipbible_combo_box.itemData(self.sword_zipbible_combo_box.currentIndex())
215+ if 'description' in self.pysword_zip_modules_json[key]:
216+ self.version_name_edit.setText(self.pysword_zip_modules_json[key]['description'])
217+ if 'distributionlicense' in self.pysword_zip_modules_json[key]:
218+ self.permissions_edit.setText(self.pysword_zip_modules_json[key]['distributionlicense'])
219 return True
220 elif self.currentPage() == self.license_details_page:
221 license_version = self.field('license_version')
222@@ -531,6 +654,40 @@
223 self.web_update_button.setEnabled(True)
224 self.web_progress_bar.setVisible(False)
225
226+ def on_sword_browse_button_clicked(self):
227+ """
228+ Show the file open dialog for the SWORD folder.
229+ """
230+ self.get_folder(WizardStrings.OpenTypeFolder % WizardStrings.SWORD, self.sword_folder_edit,
231+ 'last directory import')
232+ if self.sword_folder_edit.text():
233+ try:
234+ self.pysword_folder_modules = modules.SwordModules(self.sword_folder_edit.text())
235+ self.pysword_folder_modules_json = self.pysword_folder_modules.parse_modules()
236+ bible_keys = self.pysword_folder_modules_json.keys()
237+ self.sword_bible_combo_box.clear()
238+ for key in bible_keys:
239+ self.sword_bible_combo_box.addItem(self.pysword_folder_modules_json[key]['description'], key)
240+ except:
241+ self.sword_bible_combo_box.clear()
242+
243+ def on_sword_zipbrowse_button_clicked(self):
244+ """
245+ Show the file open dialog for a SWORD zip-file.
246+ """
247+ self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.SWORD, self.sword_zipfile_edit,
248+ 'last directory import')
249+ if self.sword_zipfile_edit.text():
250+ try:
251+ self.pysword_zip_modules = modules.SwordModules(self.sword_zipfile_edit.text())
252+ self.pysword_zip_modules_json = self.pysword_zip_modules.parse_modules()
253+ bible_keys = self.pysword_zip_modules_json.keys()
254+ self.sword_zipbible_combo_box.clear()
255+ for key in bible_keys:
256+ self.sword_zipbible_combo_box.addItem(self.pysword_zip_modules_json[key]['description'], key)
257+ except:
258+ self.sword_zipbible_combo_box.clear()
259+
260 def register_fields(self):
261 """
262 Register the bible import wizard fields.
263@@ -543,6 +700,8 @@
264 self.select_page.registerField('zefania_file', self.zefania_file_edit)
265 self.select_page.registerField('web_location', self.web_source_combo_box)
266 self.select_page.registerField('web_biblename', self.web_translation_combo_box)
267+ self.select_page.registerField('sword_folder_path', self.sword_folder_edit)
268+ self.select_page.registerField('sword_zip_path', self.sword_zipfile_edit)
269 self.select_page.registerField('proxy_server', self.web_server_edit)
270 self.select_page.registerField('proxy_username', self.web_user_edit)
271 self.select_page.registerField('proxy_password', self.web_password_edit)
272@@ -565,6 +724,8 @@
273 self.setField('csv_versefile', '')
274 self.setField('opensong_file', '')
275 self.setField('zefania_file', '')
276+ self.setField('sword_folder_path', '')
277+ self.setField('sword_zip_path', '')
278 self.setField('web_location', WebDownload.Crosswalk)
279 self.setField('web_biblename', self.web_translation_combo_box.currentIndex())
280 self.setField('proxy_server', settings.value('proxy address'))
281@@ -626,9 +787,21 @@
282 language_id=language_id
283 )
284 elif bible_type == BibleFormat.Zefania:
285- # Import an Zefania bible.
286+ # Import a Zefania bible.
287 importer = self.manager.import_bible(BibleFormat.Zefania, name=license_version,
288 filename=self.field('zefania_file'))
289+ elif bible_type == BibleFormat.SWORD:
290+ # Import a SWORD bible.
291+ if self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_folder_tab):
292+ importer = self.manager.import_bible(BibleFormat.SWORD, name=license_version,
293+ sword_path=self.field('sword_folder_path'),
294+ sword_key=self.sword_bible_combo_box.itemData(
295+ self.sword_bible_combo_box.currentIndex()))
296+ else:
297+ importer = self.manager.import_bible(BibleFormat.SWORD, name=license_version,
298+ sword_path=self.field('sword_zip_path'),
299+ sword_key=self.sword_zipbible_combo_box.itemData(
300+ self.sword_zipbible_combo_box.currentIndex()))
301 if importer.do_import(license_version):
302 self.manager.save_meta_data(license_version, license_version, license_copyright, license_permissions)
303 self.manager.reload_bibles()
304
305=== modified file 'openlp/plugins/bibles/lib/manager.py'
306--- openlp/plugins/bibles/lib/manager.py 2016-04-05 17:10:51 +0000
307+++ openlp/plugins/bibles/lib/manager.py 2016-04-26 19:04:37 +0000
308@@ -31,7 +31,10 @@
309 from .opensong import OpenSongBible
310 from .osis import OSISBible
311 from .zefania import ZefaniaBible
312-
313+try:
314+ from .sword import SwordBible
315+except:
316+ pass
317
318 log = logging.getLogger(__name__)
319
320@@ -46,6 +49,7 @@
321 OpenSong = 2
322 WebDownload = 3
323 Zefania = 4
324+ SWORD = 5
325
326 @staticmethod
327 def get_class(bible_format):
328@@ -64,6 +68,8 @@
329 return HTTPBible
330 elif bible_format == BibleFormat.Zefania:
331 return ZefaniaBible
332+ elif bible_format == BibleFormat.SWORD:
333+ return SwordBible
334 else:
335 return None
336
337@@ -78,6 +84,7 @@
338 BibleFormat.OpenSong,
339 BibleFormat.WebDownload,
340 BibleFormat.Zefania,
341+ BibleFormat.SWORD
342 ]
343
344
345
346=== added file 'openlp/plugins/bibles/lib/sword.py'
347--- openlp/plugins/bibles/lib/sword.py 1970-01-01 00:00:00 +0000
348+++ openlp/plugins/bibles/lib/sword.py 2016-04-26 19:04:37 +0000
349@@ -0,0 +1,100 @@
350+# -*- coding: utf-8 -*-
351+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
352+
353+###############################################################################
354+# OpenLP - Open Source Lyrics Projection #
355+# --------------------------------------------------------------------------- #
356+# Copyright (c) 2008-2016 OpenLP Developers #
357+# --------------------------------------------------------------------------- #
358+# This program is free software; you can redistribute it and/or modify it #
359+# under the terms of the GNU General Public License as published by the Free #
360+# Software Foundation; version 2 of the License. #
361+# #
362+# This program is distributed in the hope that it will be useful, but WITHOUT #
363+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
364+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
365+# more details. #
366+# #
367+# You should have received a copy of the GNU General Public License along #
368+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
369+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
370+###############################################################################
371+
372+import logging
373+from pysword import modules
374+
375+from openlp.core.common import translate
376+from openlp.core.lib.ui import critical_error_message_box
377+from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
378+
379+
380+log = logging.getLogger(__name__)
381+
382+
383+class SwordBible(BibleDB):
384+ """
385+ SWORD Bible format importer class.
386+ """
387+ def __init__(self, parent, **kwargs):
388+ """
389+ Constructor to create and set up an instance of the SwordBible class. This class is used to import Bibles
390+ from SWORD bible modules.
391+ """
392+ log.debug(self.__class__.__name__)
393+ BibleDB.__init__(self, parent, **kwargs)
394+ self.sword_key = kwargs['sword_key']
395+ self.sword_path = kwargs['sword_path']
396+ if self.sword_path == '':
397+ self.sword_path = None
398+
399+ def do_import(self, bible_name=None):
400+ """
401+ Loads a Bible from SWORD module.
402+ """
403+ log.debug('Starting SWORD import from "%s"' % self.sword_key)
404+ success = True
405+ try:
406+ pysword_modules = modules.SwordModules(self.sword_path)
407+ pysword_module_json = pysword_modules.parse_modules()[self.sword_key]
408+ bible = pysword_modules.get_bible_from_module(self.sword_key)
409+ language = pysword_module_json['lang']
410+ language = language[language.find('.') + 1:]
411+ language_id = BiblesResourcesDB.get_language(language)['id']
412+ self.save_meta('language_id', language_id)
413+ books = bible.get_structure().get_books()
414+ # Count number of books
415+ num_books = 0
416+ if 'ot' in books:
417+ num_books += len(books['ot'])
418+ if 'nt' in books:
419+ num_books += len(books['nt'])
420+ self.wizard.progress_bar.setMaximum(num_books)
421+ # Import the bible
422+ for testament in books.keys():
423+ for book in books[testament]:
424+ book_ref_id = self.get_book_ref_id_by_name(book.name, num_books, language_id)
425+ book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
426+ db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id'])
427+ for chapter_number in range(1, book.num_chapters + 1):
428+ if self.stop_import_flag:
429+ break
430+ verses = bible.get_iter(book.name, chapter_number)
431+ verse_number = 0
432+ for verse in verses:
433+ verse_number += 1
434+ self.create_verse(db_book.id, chapter_number, verse_number, verse)
435+ self.wizard.increment_progress_bar(
436+ translate('BiblesPlugin.Sword', 'Importing %s...') % db_book.name)
437+ self.session.commit()
438+ self.application.process_events()
439+ except Exception as e:
440+ critical_error_message_box(
441+ message=translate('BiblesPlugin.SwordImport', 'An unexpected error happened while importing the SWORD '
442+ 'bible, please report this to the OpenLP developers.\n'
443+ '%s' % e))
444+ log.exception(str(e))
445+ success = False
446+ if self.stop_import_flag:
447+ return False
448+ else:
449+ return success
450
451=== modified file 'scripts/check_dependencies.py'
452--- scripts/check_dependencies.py 2015-12-31 22:46:06 +0000
453+++ scripts/check_dependencies.py 2016-04-26 19:04:37 +0000
454@@ -102,6 +102,7 @@
455 ('nose', '(testing framework)', True),
456 ('mock', '(testing module)', sys.version_info[1] < 3),
457 ('jenkins', '(access jenkins api - package name: jenkins-webapi)', True),
458+ ('pysword', '(import SWORD bibles)', True),
459 ]
460
461 w = sys.stdout.write
462
463=== added file 'tests/functional/openlp_plugins/bibles/test_swordimport.py'
464--- tests/functional/openlp_plugins/bibles/test_swordimport.py 1970-01-01 00:00:00 +0000
465+++ tests/functional/openlp_plugins/bibles/test_swordimport.py 2016-04-26 19:04:37 +0000
466@@ -0,0 +1,109 @@
467+# -*- coding: utf-8 -*-
468+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
469+
470+###############################################################################
471+# OpenLP - Open Source Lyrics Projection #
472+# --------------------------------------------------------------------------- #
473+# Copyright (c) 2008-2016 OpenLP Developers #
474+# --------------------------------------------------------------------------- #
475+# This program is free software; you can redistribute it and/or modify it #
476+# under the terms of the GNU General Public License as published by the Free #
477+# Software Foundation; version 2 of the License. #
478+# #
479+# This program is distributed in the hope that it will be useful, but WITHOUT #
480+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
481+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
482+# more details. #
483+# #
484+# You should have received a copy of the GNU General Public License along #
485+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
486+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
487+###############################################################################
488+"""
489+This module contains tests for the SWORD Bible importer.
490+"""
491+
492+import os
493+import json
494+from unittest import TestCase, SkipTest
495+
496+from tests.functional import MagicMock, patch
497+try:
498+ from openlp.plugins.bibles.lib.sword import SwordBible
499+except ImportError:
500+ raise SkipTest('PySword is not installed, skipping SWORD test.')
501+from openlp.plugins.bibles.lib.db import BibleDB
502+
503+TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
504+ '..', '..', '..', 'resources', 'bibles'))
505+
506+
507+class TestSwordImport(TestCase):
508+ """
509+ Test the functions in the :mod:`swordimport` module.
510+ """
511+
512+ def setUp(self):
513+ self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry')
514+ self.registry_patcher.start()
515+ self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager')
516+ self.manager_patcher.start()
517+
518+ def tearDown(self):
519+ self.registry_patcher.stop()
520+ self.manager_patcher.stop()
521+
522+ def create_importer_test(self):
523+ """
524+ Test creating an instance of the Sword file importer
525+ """
526+ # GIVEN: A mocked out "manager"
527+ mocked_manager = MagicMock()
528+
529+ # WHEN: An importer object is created
530+ importer = SwordBible(mocked_manager, path='.', name='.', filename='', sword_key='', sword_path='')
531+
532+ # THEN: The importer should be an instance of BibleDB
533+ self.assertIsInstance(importer, BibleDB)
534+
535+ @patch('openlp.plugins.bibles.lib.sword.SwordBible.application')
536+ @patch('openlp.plugins.bibles.lib.sword.modules')
537+ @patch('openlp.plugins.bibles.lib.db.BiblesResourcesDB')
538+ def simple_import_test(self, mocked_bible_res_db, mocked_pysword_modules, mocked_application):
539+ """
540+ Test that a simple SWORD import works
541+ """
542+ # GIVEN: Test files with a mocked out "manager", "import_wizard", and mocked functions
543+ # get_book_ref_id_by_name, create_verse, create_book, session and get_language.
544+ # Also mocked pysword structures
545+ mocked_manager = MagicMock()
546+ mocked_import_wizard = MagicMock()
547+ importer = SwordBible(mocked_manager, path='.', name='.', filename='', sword_key='', sword_path='')
548+ result_file = open(os.path.join(TEST_PATH, 'dk1933.json'), 'rb')
549+ test_data = json.loads(result_file.read().decode())
550+ importer.wizard = mocked_import_wizard
551+ importer.get_book_ref_id_by_name = MagicMock()
552+ importer.create_verse = MagicMock()
553+ importer.create_book = MagicMock()
554+ importer.session = MagicMock()
555+ mocked_bible_res_db.get_language.return_value = 'Danish'
556+ mocked_bible = MagicMock()
557+ mocked_genesis = MagicMock()
558+ mocked_genesis.name = 'Genesis'
559+ mocked_genesis.num_chapters = 1
560+ books = {'ot': [mocked_genesis]}
561+ mocked_structure = MagicMock()
562+ mocked_structure.get_books.return_value = books
563+ mocked_bible.get_structure.return_value = mocked_structure
564+ mocked_bible.get_iter.return_value = [verse[1] for verse in test_data['verses']]
565+ mocked_module = MagicMock()
566+ mocked_module.get_bible_from_module.return_value = mocked_bible
567+ mocked_pysword_modules.SwordModules.return_value = mocked_module
568+
569+ # WHEN: Importing bible file
570+ importer.do_import()
571+
572+ # THEN: The create_verse() method should have been called with each verse in the file.
573+ self.assertTrue(importer.create_verse.called)
574+ for verse_tag, verse_text in test_data['verses']:
575+ importer.create_verse.assert_any_call(importer.create_book().id, 1, int(verse_tag), verse_text)
576
577=== modified file 'tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py'
578--- tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py 2015-12-31 22:46:06 +0000
579+++ tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py 2016-04-26 19:04:37 +0000
580@@ -27,7 +27,7 @@
581 from PyQt5 import QtWidgets
582
583 from openlp.core.common import Registry
584-from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm, WebDownload
585+import openlp.plugins.bibles.forms.bibleimportform as bibleimportform
586
587 from tests.helpers.testmixin import TestMixin
588 from tests.functional import MagicMock, patch
589@@ -46,7 +46,8 @@
590 self.setup_application()
591 self.main_window = QtWidgets.QMainWindow()
592 Registry().register('main_window', self.main_window)
593- self.form = BibleImportForm(self.main_window, MagicMock(), MagicMock())
594+ bibleimportform.PYSWORD_AVAILABLE = False
595+ self.form = bibleimportform.BibleImportForm(self.main_window, MagicMock(), MagicMock())
596
597 def tearDown(self):
598 """
599@@ -76,3 +77,16 @@
600
601 # THEN: The webbible list should still be empty
602 self.assertEqual(self.form.web_bible_list, {}, 'The webbible list should be empty')
603+
604+ def custom_init_test(self):
605+ """
606+ Test that custom_init works as expected if pysword is unavailable
607+ """
608+ # GIVEN: A mocked sword_tab_widget
609+ self.form.sword_tab_widget = MagicMock()
610+
611+ # WHEN: Running custom_init
612+ self.form.custom_init()
613+
614+ # THEN: sword_tab_widget.setDisabled(True) should have been called
615+ self.form.sword_tab_widget.setDisabled.assert_called_with(True)