Merge lp:~tomasgroth/openlp/24bugfix-backport1 into lp:openlp/2.4

Proposed by Tomas Groth
Status: Merged
Approved by: Raoul Snyman
Approved revision: 2625
Merged at revision: 2624
Proposed branch: lp:~tomasgroth/openlp/24bugfix-backport1
Merge into: lp:openlp/2.4
Diff against target: 336 lines (+109/-48)
12 files modified
openlp/core/ui/exceptionform.py (+6/-4)
openlp/plugins/bibles/lib/http.py (+1/-1)
openlp/plugins/bibles/lib/mediaitem.py (+3/-0)
openlp/plugins/bibles/lib/zefania.py (+2/-1)
openlp/plugins/custom/forms/editcustomform.py (+1/-0)
openlp/plugins/songs/lib/__init__.py (+2/-1)
openlp/plugins/songs/lib/importers/easyworship.py (+40/-32)
openlp/plugins/songs/lib/importers/songimport.py (+1/-1)
tests/functional/__init__.py (+3/-3)
tests/functional/openlp_plugins/songs/test_lib.py (+25/-1)
tests/interfaces/openlp_core_lib/test_pluginmanager.py (+9/-4)
tests/interfaces/openlp_plugins/custom/forms/test_customform.py (+16/-0)
To merge this branch: bzr merge lp:~tomasgroth/openlp/24bugfix-backport1
Reviewer Review Type Date Requested Status
Raoul Snyman Approve
Tim Bentley Approve
Review via email: mp+292585@code.launchpad.net

Description of the change

Fix slide order change when splitting custom slides. Fixes bug 1554748.
Fix EasyWorship import issues with missing verses and traceback on unknown chars. Fixes bug 1553922 and 1547234.
Fix traceback in the bug-report dialog. Fixes bug 1554428.
Fix weird test bug in test_pluginmanager.py.
Fix traceback when searching for book that doesn't exists in second bible. Fixes bug 1553863.
Set progress bar steps to number of chapters in zefania import.
Fix song tag detection. Fixes bug 1549549.
Fix a method call with too many parentheses, which fixes getting bible books from crosswalk.
Fix bug that prevents song book entries to be imported.

To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) wrote :
Revision history for this message
Tim Bentley (trb143) :
review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/ui/exceptionform.py'
2--- openlp/core/ui/exceptionform.py 2016-01-09 16:26:14 +0000
3+++ openlp/core/ui/exceptionform.py 2016-04-21 20:23:31 +0000
4@@ -180,11 +180,13 @@
5 if ':' in line:
6 exception = line.split('\n')[-1].split(':')[0]
7 subject = 'Bug report: %s in %s' % (exception, source)
8- mail_to_url = QtCore.QUrlQuery('mailto:bugs@openlp.org')
9- mail_to_url.addQueryItem('subject', subject)
10- mail_to_url.addQueryItem('body', self.report_text % content)
11+ mail_urlquery = QtCore.QUrlQuery()
12+ mail_urlquery.addQueryItem('subject', subject)
13+ mail_urlquery.addQueryItem('body', self.report_text % content)
14 if self.file_attachment:
15- mail_to_url.addQueryItem('attach', self.file_attachment)
16+ mail_urlquery.addQueryItem('attach', self.file_attachment)
17+ mail_to_url = QtCore.QUrl('mailto:bugs@openlp.org')
18+ mail_to_url.setQuery(mail_urlquery)
19 QtGui.QDesktopServices.openUrl(mail_to_url)
20
21 def on_description_updated(self):
22
23=== modified file 'openlp/plugins/bibles/lib/http.py'
24--- openlp/plugins/bibles/lib/http.py 2016-02-04 20:17:40 +0000
25+++ openlp/plugins/bibles/lib/http.py 2016-04-21 20:23:31 +0000
26@@ -504,7 +504,7 @@
27 soup = get_soup_for_bible_ref(chapter_url)
28 if not soup:
29 return None
30- content = soup.find_all(('h4', {'class': 'small-header'}))
31+ content = soup.find_all('h4', {'class': 'small-header'})
32 if not content:
33 log.error('No books found in the Crosswalk response.')
34 send_error_message('parse')
35
36=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
37--- openlp/plugins/bibles/lib/mediaitem.py 2016-01-08 17:44:47 +0000
38+++ openlp/plugins/bibles/lib/mediaitem.py 2016-04-21 20:23:31 +0000
39@@ -764,6 +764,9 @@
40 except IndexError:
41 log.exception('The second_search_results does not have as many verses as the search_results.')
42 break
43+ except TypeError:
44+ log.exception('The second_search_results does not have this book.')
45+ break
46 bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version,
47 second_version)
48 else:
49
50=== modified file 'openlp/plugins/bibles/lib/zefania.py'
51--- openlp/plugins/bibles/lib/zefania.py 2015-12-31 22:46:06 +0000
52+++ openlp/plugins/bibles/lib/zefania.py 2016-04-21 20:23:31 +0000
53@@ -70,7 +70,8 @@
54 log.error('Importing books from "%s" failed' % self.filename)
55 return False
56 self.save_meta('language_id', language_id)
57- num_books = int(zefania_bible_tree.xpath("count(//BIBLEBOOK)"))
58+ num_books = int(zefania_bible_tree.xpath('count(//BIBLEBOOK)'))
59+ self.wizard.progress_bar.setMaximum(int(zefania_bible_tree.xpath('count(//CHAPTER)')))
60 # Strip tags we don't use - keep content
61 etree.strip_tags(zefania_bible_tree, ('STYLE', 'GRAM', 'NOTE', 'SUP', 'XREF'))
62 # Strip tags we don't use - remove content
63
64=== modified file 'openlp/plugins/custom/forms/editcustomform.py'
65--- openlp/plugins/custom/forms/editcustomform.py 2016-01-09 16:26:14 +0000
66+++ openlp/plugins/custom/forms/editcustomform.py 2016-04-21 20:23:31 +0000
67@@ -198,6 +198,7 @@
68 # Insert all slides to make the old_slides list complete.
69 for slide in slides:
70 old_slides.insert(old_row, slide)
71+ old_row += 1
72 self.slide_list_view.addItems(old_slides)
73 self.slide_list_view.repaint()
74
75
76=== modified file 'openlp/plugins/songs/lib/__init__.py'
77--- openlp/plugins/songs/lib/__init__.py 2015-12-31 22:46:06 +0000
78+++ openlp/plugins/songs/lib/__init__.py 2016-04-21 20:23:31 +0000
79@@ -256,6 +256,7 @@
80 for num, translation in enumerate(VerseType.translated_names):
81 if verse_name == translation.lower():
82 return num
83+ return None
84
85 @staticmethod
86 def from_loose_input(verse_name, default=Other):
87@@ -271,7 +272,7 @@
88 if verse_index is None:
89 verse_index = VerseType.from_string(verse_name, default)
90 elif len(verse_name) == 1:
91- verse_index = VerseType.from_translated_tag(verse_name, default)
92+ verse_index = VerseType.from_translated_tag(verse_name, None)
93 if verse_index is None:
94 verse_index = VerseType.from_tag(verse_name, default)
95 else:
96
97=== modified file 'openlp/plugins/songs/lib/importers/easyworship.py'
98--- openlp/plugins/songs/lib/importers/easyworship.py 2016-01-31 19:36:54 +0000
99+++ openlp/plugins/songs/lib/importers/easyworship.py 2016-04-21 20:23:31 +0000
100@@ -289,40 +289,45 @@
101 for i in range(rec_count):
102 if self.stop_import_flag:
103 break
104- raw_record = db_file.read(record_size)
105- self.fields = self.record_structure.unpack(raw_record)
106- self.set_defaults()
107- self.title = self.get_field(fi_title).decode(self.encoding)
108- # Get remaining fields.
109- copy = self.get_field(fi_copy)
110- admin = self.get_field(fi_admin)
111- ccli = self.get_field(fi_ccli)
112- authors = self.get_field(fi_author)
113- words = self.get_field(fi_words)
114- if copy:
115- self.copyright = copy.decode(self.encoding)
116- if admin:
117+ try:
118+ raw_record = db_file.read(record_size)
119+ self.fields = self.record_structure.unpack(raw_record)
120+ self.set_defaults()
121+ self.title = self.get_field(fi_title).decode(self.encoding)
122+ # Get remaining fields.
123+ copy = self.get_field(fi_copy)
124+ admin = self.get_field(fi_admin)
125+ ccli = self.get_field(fi_ccli)
126+ authors = self.get_field(fi_author)
127+ words = self.get_field(fi_words)
128 if copy:
129- self.copyright += ', '
130- self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
131- 'Administered by %s') % admin.decode(self.encoding)
132- if ccli:
133- self.ccli_number = ccli.decode(self.encoding)
134- if authors:
135- authors = authors.decode(self.encoding)
136- else:
137- authors = ''
138- # Set the SongImport object members.
139- self.set_song_import_object(authors, words)
140- if self.stop_import_flag:
141- break
142- if self.entry_error_log:
143+ self.copyright = copy.decode(self.encoding)
144+ if admin:
145+ if copy:
146+ self.copyright += ', '
147+ self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
148+ 'Administered by %s') % admin.decode(self.encoding)
149+ if ccli:
150+ self.ccli_number = ccli.decode(self.encoding)
151+ if authors:
152+ authors = authors.decode(self.encoding)
153+ else:
154+ authors = ''
155+ # Set the SongImport object members.
156+ self.set_song_import_object(authors, words)
157+ if self.stop_import_flag:
158+ break
159+ if self.entry_error_log:
160+ self.log_error(self.import_source,
161+ translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
162+ % (self.title, self.entry_error_log))
163+ self.entry_error_log = ''
164+ elif not self.finish():
165+ self.log_error(self.import_source)
166+ except Exception as e:
167 self.log_error(self.import_source,
168 translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
169- % (self.title, self.entry_error_log))
170- self.entry_error_log = ''
171- elif not self.finish():
172- self.log_error(self.import_source)
173+ % (self.title, e))
174 db_file.close()
175 self.memo_file.close()
176
177@@ -368,7 +373,7 @@
178 first_line_is_tag = False
179 # EW tags: verse, chorus, pre-chorus, bridge, tag,
180 # intro, ending, slide
181- for tag in VerseType.tags + ['tag', 'slide']:
182+ for tag in VerseType.names + ['tag', 'slide', 'end']:
183 tag = tag.lower()
184 ew_tag = verse_split[0].strip().lower()
185 if ew_tag.startswith(tag):
186@@ -390,6 +395,9 @@
187 if not number_found:
188 verse_type += '1'
189 break
190+ # If the verse only consist of the tag-line, add an empty line to create an empty slide
191+ if first_line_is_tag and len(verse_split) == 1:
192+ verse_split.append("")
193 self.add_verse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type)
194 if len(self.comments) > 5:
195 self.comments += str(translate('SongsPlugin.EasyWorshipSongImport',
196
197=== modified file 'openlp/plugins/songs/lib/importers/songimport.py'
198--- openlp/plugins/songs/lib/importers/songimport.py 2015-12-31 22:46:06 +0000
199+++ openlp/plugins/songs/lib/importers/songimport.py 2016-04-21 20:23:31 +0000
200@@ -371,7 +371,7 @@
201 song_book = self.manager.get_object_filtered(Book, Book.name == self.song_book_name)
202 if song_book is None:
203 song_book = Book.populate(name=self.song_book_name, publisher=self.song_book_pub)
204- song.book = song_book
205+ song.add_songbook_entry(song_book, song.song_number)
206 for topic_text in self.topics:
207 if not topic_text:
208 continue
209
210=== modified file 'tests/functional/__init__.py'
211--- tests/functional/__init__.py 2015-12-31 22:46:06 +0000
212+++ tests/functional/__init__.py 2016-04-21 20:23:31 +0000
213@@ -26,12 +26,12 @@
214 from PyQt5 import QtWidgets
215
216 if sys.version_info[1] >= 3:
217- from unittest.mock import ANY, MagicMock, patch, mock_open, call
218+ from unittest.mock import ANY, MagicMock, patch, mock_open, call, PropertyMock
219 else:
220- from mock import ANY, MagicMock, patch, mock_open, call
221+ from mock import ANY, MagicMock, patch, mock_open, call, PropertyMock
222
223 # Only one QApplication can be created. Use QtWidgets.QApplication.instance() when you need to "create" a QApplication.
224 application = QtWidgets.QApplication([])
225 application.setApplicationName('OpenLP')
226
227-__all__ = ['ANY', 'MagicMock', 'patch', 'mock_open', 'call', 'application']
228+__all__ = ['ANY', 'MagicMock', 'patch', 'mock_open', 'call', 'application', 'PropertyMock']
229
230=== modified file 'tests/functional/openlp_plugins/songs/test_lib.py'
231--- tests/functional/openlp_plugins/songs/test_lib.py 2015-12-31 22:46:06 +0000
232+++ tests/functional/openlp_plugins/songs/test_lib.py 2016-04-21 20:23:31 +0000
233@@ -26,7 +26,7 @@
234
235 from openlp.plugins.songs.lib import VerseType, clean_string, clean_title, strip_rtf
236 from openlp.plugins.songs.lib.songcompare import songs_probably_equal, _remove_typos, _op_length
237-from tests.functional import patch, MagicMock
238+from tests.functional import patch, MagicMock, PropertyMock
239
240
241 class TestLib(TestCase):
242@@ -477,3 +477,27 @@
243
244 # THEN: The result should be None
245 self.assertIsNone(result, 'The result should be None, but was "%s"' % result)
246+
247+ @patch('openlp.plugins.songs.lib.VerseType.translated_tags', new_callable=PropertyMock, return_value=['x'])
248+ def from_loose_input_with_invalid_input_test(self, mocked_translated_tags):
249+ """
250+ Test that the from_loose_input() method returns a sane default when passed an invalid tag and None as default.
251+ """
252+ # GIVEN: A mocked VerseType.translated_tags
253+ # WHEN: We run the from_loose_input() method with an invalid verse type, we get the specified default back
254+ result = VerseType.from_loose_input('m', None)
255+
256+ # THEN: The result should be None
257+ self.assertIsNone(result, 'The result should be None, but was "%s"' % result)
258+
259+ @patch('openlp.plugins.songs.lib.VerseType.translated_tags', new_callable=PropertyMock, return_value=['x'])
260+ def from_loose_input_with_valid_input_test(self, mocked_translated_tags):
261+ """
262+ Test that the from_loose_input() method returns valid output on valid input.
263+ """
264+ # GIVEN: A mocked VerseType.translated_tags
265+ # WHEN: We run the from_loose_input() method with a valid verse type, we get the expected VerseType back
266+ result = VerseType.from_loose_input('v')
267+
268+ # THEN: The result should be a Verse
269+ self.assertEqual(result, VerseType.Verse, 'The result should be a verse, but was "%s"' % result)
270
271=== modified file 'tests/interfaces/openlp_core_lib/test_pluginmanager.py'
272--- tests/interfaces/openlp_core_lib/test_pluginmanager.py 2015-12-31 22:46:06 +0000
273+++ tests/interfaces/openlp_core_lib/test_pluginmanager.py 2016-04-21 20:23:31 +0000
274@@ -32,7 +32,7 @@
275
276 from openlp.core.common import Registry, Settings
277 from openlp.core.lib.pluginmanager import PluginManager
278-from tests.interfaces import MagicMock
279+from tests.interfaces import MagicMock, patch
280 from tests.helpers.testmixin import TestMixin
281
282
283@@ -45,13 +45,12 @@
284 """
285 Some pre-test setup required.
286 """
287- Settings.setDefaultFormat(Settings.IniFormat)
288+ self.setup_application()
289 self.build_settings()
290 self.temp_dir = mkdtemp('openlp')
291 Settings().setValue('advanced/data path', self.temp_dir)
292 Registry.create()
293 Registry().register('service_list', MagicMock())
294- self.setup_application()
295 self.main_window = QtWidgets.QMainWindow()
296 Registry().register('main_window', self.main_window)
297
298@@ -64,7 +63,13 @@
299 gc.collect()
300 shutil.rmtree(self.temp_dir)
301
302- def find_plugins_test(self):
303+ @patch('openlp.plugins.songusage.lib.db.init_schema')
304+ @patch('openlp.plugins.songs.lib.db.init_schema')
305+ @patch('openlp.plugins.images.lib.db.init_schema')
306+ @patch('openlp.plugins.custom.lib.db.init_schema')
307+ @patch('openlp.plugins.alerts.lib.db.init_schema')
308+ @patch('openlp.plugins.bibles.lib.db.init_schema')
309+ def find_plugins_test(self, mocked_is1, mocked_is2, mocked_is3, mocked_is4, mocked_is5, mocked_is6):
310 """
311 Test the find_plugins() method to ensure it imports the correct plugins
312 """
313
314=== modified file 'tests/interfaces/openlp_plugins/custom/forms/test_customform.py'
315--- tests/interfaces/openlp_plugins/custom/forms/test_customform.py 2015-12-31 22:46:06 +0000
316+++ tests/interfaces/openlp_plugins/custom/forms/test_customform.py 2016-04-21 20:23:31 +0000
317@@ -128,3 +128,19 @@
318 # THEN: The validate method should have returned False.
319 assert not result, 'The _validate() method should have retured False'
320 mocked_critical_error_message_box.assert_called_with(message='You need to add at least one slide.')
321+
322+ def update_slide_list_test(self):
323+ """
324+ Test the update_slide_list() method
325+ """
326+ # GIVEN: Mocked slide_list_view with a slide with 3 lines
327+ self.form.slide_list_view = MagicMock()
328+ self.form.slide_list_view.count.return_value = 1
329+ self.form.slide_list_view.currentRow.return_value = 0
330+ self.form.slide_list_view.item.return_value = MagicMock(return_value='1st Slide\n2nd Slide\n3rd Slide')
331+
332+ # WHEN: updating the slide by splitting the lines into slides
333+ self.form.update_slide_list(['1st Slide', '2nd Slide', '3rd Slide'])
334+
335+ # THEN: The slides should be created in correct order
336+ self.form.slide_list_view.addItems.assert_called_with(['1st Slide', '2nd Slide', '3rd Slide'])

Subscribers

People subscribed via source and target branches

to all changes: