Merge lp:~tomasgroth/openlp/bugfixes4 into lp:openlp

Proposed by Tomas Groth
Status: Merged
Approved by: Tim Bentley
Approved revision: 2448
Merged at revision: 2440
Proposed branch: lp:~tomasgroth/openlp/bugfixes4
Merge into: lp:openlp
Diff against target: 440 lines (+179/-40)
12 files modified
openlp.py (+7/-1)
openlp/core/ui/projector/__init__.py (+1/-1)
openlp/plugins/media/forms/mediaclipselectorform.py (+7/-0)
openlp/plugins/songs/forms/duplicatesongremovalform.py (+8/-6)
openlp/plugins/songs/lib/importers/wordsofworship.py (+11/-5)
openlp/plugins/songs/lib/songcompare.py (+9/-7)
tests/functional/openlp_core_ui/test_settingsform.py (+1/-1)
tests/functional/openlp_plugins/images/test_imagetab.py (+1/-1)
tests/functional/openlp_plugins/songs/test_lib.py (+16/-18)
tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py (+56/-0)
tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).json (+33/-0)
tests/resources/wordsofworshipsongs/When morning gilds the skies.json (+29/-0)
To merge this branch: bzr merge lp:~tomasgroth/openlp/bugfixes4
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Raoul Snyman Approve
Review via email: mp+240831@code.launchpad.net

Description of the change

Change duplicate check to pass int-string tuples to workers, to workaround bug #1388850, also added multiprocessing.freeze_support to __main__ to support multiprocessing in windows builds.
Try to fix DVD 0 track length by waiting. Fixes bug 1387293.
Fix for import of Words of Worship file, bug 1388768, added tests.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp.py'
2--- openlp.py 2014-09-04 20:10:34 +0000
3+++ openlp.py 2014-11-06 09:51:19 +0000
4@@ -28,7 +28,9 @@
5 ###############################################################################
6
7 import sys
8+import multiprocessing
9
10+from openlp.core.common import is_win, is_macosx
11 from openlp.core import main
12
13
14@@ -36,9 +38,13 @@
15 """
16 Instantiate and run the application.
17 """
18+ # Add support for using multiprocessing from frozen Windows executable (built using PyInstaller),
19+ # see https://docs.python.org/3/library/multiprocessing.html#multiprocessing.freeze_support
20+ if is_win():
21+ multiprocessing.freeze_support()
22 # Mac OS X passes arguments like '-psn_XXXX' to the application. This argument is actually a process serial number.
23 # However, this causes a conflict with other OpenLP arguments. Since we do not use this argument we can delete it
24 # to avoid any potential conflicts.
25- if sys.platform.startswith('darwin'):
26+ if is_macosx():
27 sys.argv = [x for x in sys.argv if not x.startswith('-psn')]
28 main()
29
30=== modified file 'openlp/core/ui/projector/__init__.py'
31--- openlp/core/ui/projector/__init__.py 2014-10-31 19:47:36 +0000
32+++ openlp/core/ui/projector/__init__.py 2014-11-06 09:51:19 +0000
33@@ -28,4 +28,4 @@
34 ###############################################################################
35 """
36 The Projector driver module.
37-"""
38\ No newline at end of file
39+"""
40
41=== modified file 'openlp/plugins/media/forms/mediaclipselectorform.py'
42--- openlp/plugins/media/forms/mediaclipselectorform.py 2014-10-31 22:44:22 +0000
43+++ openlp/plugins/media/forms/mediaclipselectorform.py 2014-11-06 09:51:19 +0000
44@@ -446,6 +446,13 @@
45 # Set media length info
46 self.playback_length = self.vlc_media_player.get_length()
47 log.debug('playback_length: %d ms' % self.playback_length)
48+ # if length is 0, wait a bit, maybe vlc will change its mind...
49+ loop_count = 0
50+ while self.playback_length == 0 and loop_count < 20:
51+ sleep(0.1)
52+ self.playback_length = self.vlc_media_player.get_length()
53+ loop_count += 1
54+ log.debug('in loop, playback_length: %d ms' % self.playback_length)
55 self.position_slider.setMaximum(self.playback_length)
56 # setup start and end time
57 rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0)
58
59=== modified file 'openlp/plugins/songs/forms/duplicatesongremovalform.py'
60--- openlp/plugins/songs/forms/duplicatesongremovalform.py 2014-04-21 09:49:17 +0000
61+++ openlp/plugins/songs/forms/duplicatesongremovalform.py 2014-11-06 09:51:19 +0000
62@@ -48,14 +48,15 @@
63
64 def song_generator(songs):
65 """
66- This is a generator function to return tuples of two songs. When completed then all songs have once been returned
67- combined with any other songs.
68+ This is a generator function to return tuples of tuple with two songs and their position in the song array.
69+ When completed then all songs have once been returned combined with any other songs.
70
71 :param songs: All songs in the database.
72 """
73 for outer_song_counter in range(len(songs) - 1):
74 for inner_song_counter in range(outer_song_counter + 1, len(songs)):
75- yield (songs[outer_song_counter], songs[inner_song_counter])
76+ yield ((outer_song_counter, songs[outer_song_counter].search_lyrics),
77+ (inner_song_counter, songs[inner_song_counter].search_lyrics))
78
79
80 class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
81@@ -187,16 +188,17 @@
82 # Do not accept any further tasks. Also this closes the processes if all tasks are done.
83 pool.close()
84 # While the processes are still working, start to look at the results.
85- for song_tuple in result:
86+ for pos_tuple in result:
87 self.duplicate_search_progress_bar.setValue(self.duplicate_search_progress_bar.value() + 1)
88 # The call to process_events() will keep the GUI responsive.
89 self.application.process_events()
90 if self.break_search:
91 pool.terminate()
92 return
93- if song_tuple is None:
94+ if pos_tuple is None:
95 continue
96- song1, song2 = song_tuple
97+ song1 = songs[pos_tuple[0]]
98+ song2 = songs[pos_tuple[1]]
99 duplicate_added = self.add_duplicates_to_song_list(song1, song2)
100 if duplicate_added:
101 self.found_duplicates_edit.appendPlainText(song1.title + " = " + song2.title)
102
103=== modified file 'openlp/plugins/songs/lib/importers/wordsofworship.py'
104--- openlp/plugins/songs/lib/importers/wordsofworship.py 2014-07-04 09:35:10 +0000
105+++ openlp/plugins/songs/lib/importers/wordsofworship.py 2014-11-06 09:51:19 +0000
106@@ -99,7 +99,7 @@
107 """
108 Initialise the Words of Worship importer.
109 """
110- SongImport.__init__(self, manager, **kwargs)
111+ super(WordsOfWorshipImport, self).__init__(manager, **kwargs)
112
113 def do_import(self):
114 """
115@@ -112,17 +112,17 @@
116 return
117 self.set_defaults()
118 song_data = open(source, 'rb')
119- if song_data.read(19) != 'WoW File\nSong Words':
120+ if song_data.read(19).decode() != 'WoW File\nSong Words':
121 self.log_error(source,
122 str(translate('SongsPlugin.WordsofWorshipSongImport',
123- 'Invalid Words of Worship song file. Missing "Wow File\\nSong '
124+ 'Invalid Words of Worship song file. Missing "WoW File\\nSong '
125 'Words" header.')))
126 continue
127 # Seek to byte which stores number of blocks in the song
128 song_data.seek(56)
129 no_of_blocks = ord(song_data.read(1))
130 song_data.seek(66)
131- if song_data.read(16) != 'CSongDoc::CBlock':
132+ if song_data.read(16).decode() != 'CSongDoc::CBlock':
133 self.log_error(source,
134 str(translate('SongsPlugin.WordsofWorshipSongImport',
135 'Invalid Words of Worship song file. Missing "CSongDoc::CBlock" '
136@@ -131,11 +131,17 @@
137 # Seek to the beginning of the first block
138 song_data.seek(82)
139 for block in range(no_of_blocks):
140+ skip_char_at_end = True
141 self.lines_to_read = ord(song_data.read(4)[:1])
142 block_text = ''
143 while self.lines_to_read:
144 self.line_text = str(song_data.read(ord(song_data.read(1))), 'cp1252')
145- song_data.seek(1, os.SEEK_CUR)
146+ if skip_char_at_end:
147+ skip_char = ord(song_data.read(1))
148+ # Check if we really should skip a char. In some wsg files we shouldn't
149+ if skip_char != 0:
150+ song_data.seek(-1, os.SEEK_CUR)
151+ skip_char_at_end = False
152 if block_text:
153 block_text += '\n'
154 block_text += self.line_text
155
156=== modified file 'openlp/plugins/songs/lib/songcompare.py'
157--- openlp/plugins/songs/lib/songcompare.py 2014-04-12 16:05:27 +0000
158+++ openlp/plugins/songs/lib/songcompare.py 2014-11-06 09:51:19 +0000
159@@ -59,12 +59,14 @@
160 :param song_tupel: A tuple of two songs to compare.
161 """
162 song1, song2 = song_tupel
163- if len(song1.search_lyrics) < len(song2.search_lyrics):
164- small = song1.search_lyrics
165- large = song2.search_lyrics
166+ pos1, lyrics1 = song1
167+ pos2, lyrics2 = song2
168+ if len(lyrics1) < len(lyrics2):
169+ small = lyrics1
170+ large = lyrics2
171 else:
172- small = song2.search_lyrics
173- large = song1.search_lyrics
174+ small = lyrics2
175+ large = lyrics1
176 differ = difflib.SequenceMatcher(a=large, b=small)
177 diff_tuples = differ.get_opcodes()
178 diff_no_typos = _remove_typos(diff_tuples)
179@@ -77,7 +79,7 @@
180 length_of_equal_blocks += _op_length(element)
181
182 if length_of_equal_blocks >= MIN_BLOCK_SIZE:
183- return song1, song2
184+ return pos1, pos2
185 # Check 2: Similarity based on the relative length of the longest equal block.
186 # Calculate the length of the largest equal block of the diff set.
187 length_of_longest_equal_block = 0
188@@ -85,7 +87,7 @@
189 if element[0] == "equal" and _op_length(element) > length_of_longest_equal_block:
190 length_of_longest_equal_block = _op_length(element)
191 if length_of_longest_equal_block > len(small) * 2 // 3:
192- return song1, song2
193+ return pos1, pos2
194 # Both checks failed. We assume the songs are not equal.
195 return None
196
197
198=== modified file 'tests/functional/openlp_core_ui/test_settingsform.py'
199--- tests/functional/openlp_core_ui/test_settingsform.py 2014-10-30 22:53:06 +0000
200+++ tests/functional/openlp_core_ui/test_settingsform.py 2014-11-06 09:51:19 +0000
201@@ -157,4 +157,4 @@
202
203 # THEN: The general tab's cancel() method should have been called, but not the themes tab
204 mocked_general_cancel.assert_called_with()
205- self.assertEqual(0, mocked_theme_cancel.call_count, 'The Themes tab\'s cancel() should not have been called')
206\ No newline at end of file
207+ self.assertEqual(0, mocked_theme_cancel.call_count, 'The Themes tab\'s cancel() should not have been called')
208
209=== modified file 'tests/functional/openlp_plugins/images/test_imagetab.py'
210--- tests/functional/openlp_plugins/images/test_imagetab.py 2014-11-01 11:06:17 +0000
211+++ tests/functional/openlp_plugins/images/test_imagetab.py 2014-11-06 09:51:19 +0000
212@@ -95,4 +95,4 @@
213 self.form.save()
214 # THEN: the post process should be requested
215 self.assertEqual(1, self.form.settings_form.register_post_process.call_count,
216- 'Image Post processing should have been requested')
217\ No newline at end of file
218+ 'Image Post processing should have been requested')
219
220=== modified file 'tests/functional/openlp_plugins/songs/test_lib.py'
221--- tests/functional/openlp_plugins/songs/test_lib.py 2014-05-07 23:52:51 +0000
222+++ tests/functional/openlp_plugins/songs/test_lib.py 2014-11-06 09:51:19 +0000
223@@ -58,8 +58,6 @@
224 i love that old cross where the dearest and best for a world of lost sinners was slain so ill cherish the
225 old rugged cross till my trophies at last i lay down i will cling to the old rugged cross and exchange it
226 some day for a crown'''
227- self.song1 = MagicMock()
228- self.song2 = MagicMock()
229
230 def clean_string_test(self):
231 """
232@@ -92,53 +90,53 @@
233 Test the songs_probably_equal function with twice the same song.
234 """
235 # GIVEN: Two equal songs.
236- self.song1.search_lyrics = self.full_lyrics
237- self.song2.search_lyrics = self.full_lyrics
238+ song_tuple1 = (2, self.full_lyrics)
239+ song_tuple2 = (4, self.full_lyrics)
240
241 # WHEN: We compare those songs for equality.
242- result = songs_probably_equal((self.song1, self.song2))
243+ result = songs_probably_equal((song_tuple1, song_tuple2))
244
245 # THEN: The result should be a tuple..
246- assert result == (self.song1, self.song2), 'The result should be the tuble of songs'
247+ assert result == (2, 4), 'The result should be the tuble of song positions'
248
249 def songs_probably_equal_short_song_test(self):
250 """
251 Test the songs_probably_equal function with a song and a shorter version of the same song.
252 """
253 # GIVEN: A song and a short version of the same song.
254- self.song1.search_lyrics = self.full_lyrics
255- self.song2.search_lyrics = self.short_lyrics
256+ song_tuple1 = (1, self.full_lyrics)
257+ song_tuple2 = (3, self.short_lyrics)
258
259 # WHEN: We compare those songs for equality.
260- result = songs_probably_equal((self.song1, self.song2))
261+ result = songs_probably_equal((song_tuple1, song_tuple2))
262
263 # THEN: The result should be a tuple..
264- assert result == (self.song1, self.song2), 'The result should be the tuble of songs'
265+ assert result == (1, 3), 'The result should be the tuble of song positions'
266
267 def songs_probably_equal_error_song_test(self):
268 """
269 Test the songs_probably_equal function with a song and a very erroneous version of the same song.
270 """
271 # GIVEN: A song and the same song with lots of errors.
272- self.song1.search_lyrics = self.full_lyrics
273- self.song2.search_lyrics = self.error_lyrics
274+ song_tuple1 = (4, self.full_lyrics)
275+ song_tuple2 = (7, self.error_lyrics)
276
277 # WHEN: We compare those songs for equality.
278- result = songs_probably_equal((self.song1, self.song2))
279+ result = songs_probably_equal((song_tuple1, song_tuple2))
280
281- # THEN: The result should be a tuple of songs..
282- assert result == (self.song1, self.song2), 'The result should be the tuble of songs'
283+ # THEN: The result should be a tuple of song positions.
284+ assert result == (4, 7), 'The result should be the tuble of song positions'
285
286 def songs_probably_equal_different_song_test(self):
287 """
288 Test the songs_probably_equal function with two different songs.
289 """
290 # GIVEN: Two different songs.
291- self.song1.search_lyrics = self.full_lyrics
292- self.song2.search_lyrics = self.different_lyrics
293+ song_tuple1 = (5, self.full_lyrics)
294+ song_tuple2 = (8, self.different_lyrics)
295
296 # WHEN: We compare those songs for equality.
297- result = songs_probably_equal((self.song1, self.song2))
298+ result = songs_probably_equal((song_tuple1, song_tuple2))
299
300 # THEN: The result should be None.
301 assert result is None, 'The result should be None'
302
303=== added file 'tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py'
304--- tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py 1970-01-01 00:00:00 +0000
305+++ tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py 2014-11-06 09:51:19 +0000
306@@ -0,0 +1,56 @@
307+# -*- coding: utf-8 -*-
308+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
309+
310+###############################################################################
311+# OpenLP - Open Source Lyrics Projection #
312+# --------------------------------------------------------------------------- #
313+# Copyright (c) 2008-2014 Raoul Snyman #
314+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
315+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
316+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
317+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
318+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
319+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
320+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
321+# --------------------------------------------------------------------------- #
322+# This program is free software; you can redistribute it and/or modify it #
323+# under the terms of the GNU General Public License as published by the Free #
324+# Software Foundation; version 2 of the License. #
325+# #
326+# This program is distributed in the hope that it will be useful, but WITHOUT #
327+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
328+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
329+# more details. #
330+# #
331+# You should have received a copy of the GNU General Public License along #
332+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
333+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
334+###############################################################################
335+"""
336+This module contains tests for the Words of Worship song importer.
337+"""
338+
339+import os
340+
341+from tests.helpers.songfileimport import SongImportTestHelper
342+from openlp.plugins.songs.lib.importers.wordsofworship import WordsOfWorshipImport
343+
344+TEST_PATH = os.path.abspath(
345+ os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'wordsofworshipsongs'))
346+
347+
348+class TestWordsOfWorshipFileImport(SongImportTestHelper):
349+
350+ def __init__(self, *args, **kwargs):
351+ self.importer_class_name = 'WordsOfWorshipImport'
352+ self.importer_module_name = 'wordsofworship'
353+ super(TestWordsOfWorshipFileImport, self).__init__(*args, **kwargs)
354+
355+ def test_song_import(self):
356+ """
357+ Test that loading a Words of Worship file works correctly
358+ """
359+ self.file_import([os.path.join(TEST_PATH, 'Amazing Grace (6 Verses).wow-song')],
360+ self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace (6 Verses).json')))
361+ self.file_import([os.path.join(TEST_PATH, 'When morning gilds the skies.wsg')],
362+ self.load_external_result_data(os.path.join(TEST_PATH, 'When morning gilds the skies.json')))
363
364=== added directory 'tests/resources/wordsofworshipsongs'
365=== added file 'tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).json'
366--- tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).json 1970-01-01 00:00:00 +0000
367+++ tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).json 2014-11-06 09:51:19 +0000
368@@ -0,0 +1,33 @@
369+{
370+ "authors": [
371+ "John Newton (1725-1807)"
372+ ],
373+ "title": "Amazing Grace (6 Verses)",
374+ "verse_order_list": [],
375+ "verses": [
376+ [
377+ "Amazing grace! how sweet the sound\nThat saved a wretch like me;\nI once was lost, but now am found,\nWas blind, but now I see.",
378+ "V"
379+ ],
380+ [
381+ "'Twas grace that taught my heart to fear,\nAnd grace my fears relieved;\nHow precious did that grace appear,\nThe hour I first believed!",
382+ "V"
383+ ],
384+ [
385+ "Through many dangers, toils and snares\nI have already come;\n'Tis grace that brought me safe thus far,\nAnd grace will lead me home.",
386+ "V"
387+ ],
388+ [
389+ "The Lord has promised good to me,\nHis word my hope secures;\nHe will my shield and portion be\nAs long as life endures.",
390+ "V"
391+ ],
392+ [
393+ "Yes, when this heart and flesh shall fail,\nAnd mortal life shall cease,\nI shall possess within the veil\nA life of joy and peace.",
394+ "V"
395+ ],
396+ [
397+ "When we've been there ten thousand years,\nBright shining as the sun,\nWe've no less days to sing God's praise\nThan when we first begun.",
398+ "V"
399+ ]
400+ ]
401+}
402
403=== added file 'tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).wow-song'
404Binary files tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).wow-song 1970-01-01 00:00:00 +0000 and tests/resources/wordsofworshipsongs/Amazing Grace (6 Verses).wow-song 2014-11-06 09:51:19 +0000 differ
405=== added file 'tests/resources/wordsofworshipsongs/When morning gilds the skies.json'
406--- tests/resources/wordsofworshipsongs/When morning gilds the skies.json 1970-01-01 00:00:00 +0000
407+++ tests/resources/wordsofworshipsongs/When morning gilds the skies.json 2014-11-06 09:51:19 +0000
408@@ -0,0 +1,29 @@
409+{
410+ "authors": [
411+ "Author Unknown. Tr. Edward Caswall"
412+ ],
413+ "title": "When morning gilds the skies",
414+ "verse_order_list": [],
415+ "verses": [
416+ [
417+ "When morning gilds the skies\nMy heart awaking cries:\n'May Jesus Christ be prais'd!'\nAlike at work and prayer to Jesus I repair:\n'May Jesus Christ be prais'd!'",
418+ "V"
419+ ],
420+ [
421+ "Does sadness fill my mind?\nA solace here I find:\n'May Jesus Christ be praised!'\nWhen evil thoughts molest,\nWith this I shield my breast:\n'May Jesus Christ be prais'd!'",
422+ "V"
423+ ],
424+ [
425+ "To God, the Word, on high\nThe hosts of angels cry:\n'May Jesus Christ be prais'd!'\nLet mortals, too, upraise\nTheir voice in hymns of praise:\n'May Jesus Christ be prais'd!'",
426+ "V"
427+ ],
428+ [
429+ "Let earth's wide circle round\nIn joyful notes resound:\n'May Jesus Christ be prais'd!'\nLet air, and sea, and sky,\nFrom depth to height, reply:\n'May Jesus Christ be prais'd!'",
430+ "V"
431+ ],
432+ [
433+ "Be this while life is mine\nMy canticle divine\n'May Jesus Christ be prais'd!'\nBe this the eternal song,\nThrough all the ages long:\n'May Jesus Christ be prais'd!'",
434+ "V"
435+ ]
436+ ]
437+}
438
439=== added file 'tests/resources/wordsofworshipsongs/When morning gilds the skies.wsg'
440Binary files tests/resources/wordsofworshipsongs/When morning gilds the skies.wsg 1970-01-01 00:00:00 +0000 and tests/resources/wordsofworshipsongs/When morning gilds the skies.wsg 2014-11-06 09:51:19 +0000 differ