Merge lp:~phill-ridout/openlp/pathlib8 into lp:openlp

Proposed by Phill
Status: Merged
Merged at revision: 2774
Proposed branch: lp:~phill-ridout/openlp/pathlib8
Merge into: lp:openlp
Diff against target: 3277 lines (+662/-713)
66 files modified
openlp/core/lib/serviceitem.py (+2/-2)
openlp/core/ui/maindisplay.py (+1/-1)
openlp/core/ui/servicemanager.py (+3/-1)
openlp/core/ui/slidecontroller.py (+1/-1)
openlp/plugins/songs/forms/editsongform.py (+34/-38)
openlp/plugins/songs/forms/mediafilesform.py (+11/-4)
openlp/plugins/songs/forms/songexportform.py (+13/-29)
openlp/plugins/songs/forms/songimportform.py (+43/-68)
openlp/plugins/songs/lib/__init__.py (+5/-5)
openlp/plugins/songs/lib/db.py (+5/-4)
openlp/plugins/songs/lib/importers/cclifile.py (+27/-31)
openlp/plugins/songs/lib/importers/chordpro.py (+3/-4)
openlp/plugins/songs/lib/importers/dreambeam.py (+10/-8)
openlp/plugins/songs/lib/importers/easyslides.py (+1/-1)
openlp/plugins/songs/lib/importers/easyworship.py (+30/-46)
openlp/plugins/songs/lib/importers/foilpresenter.py (+2/-5)
openlp/plugins/songs/lib/importers/lyrix.py (+3/-4)
openlp/plugins/songs/lib/importers/openlp.py (+1/-1)
openlp/plugins/songs/lib/importers/openlyrics.py (+2/-5)
openlp/plugins/songs/lib/importers/openoffice.py (+5/-12)
openlp/plugins/songs/lib/importers/opensong.py (+3/-5)
openlp/plugins/songs/lib/importers/opspro.py (+9/-10)
openlp/plugins/songs/lib/importers/powerpraise.py (+4/-6)
openlp/plugins/songs/lib/importers/powersong.py (+7/-3)
openlp/plugins/songs/lib/importers/presentationmanager.py (+11/-11)
openlp/plugins/songs/lib/importers/propresenter.py (+11/-9)
openlp/plugins/songs/lib/importers/songbeamer.py (+14/-14)
openlp/plugins/songs/lib/importers/songimport.py (+26/-27)
openlp/plugins/songs/lib/importers/songpro.py (+3/-1)
openlp/plugins/songs/lib/importers/songshowplus.py (+84/-87)
openlp/plugins/songs/lib/importers/sundayplus.py (+3/-7)
openlp/plugins/songs/lib/importers/videopsalm.py (+8/-9)
openlp/plugins/songs/lib/importers/wordsofworship.py (+55/-56)
openlp/plugins/songs/lib/importers/worshipassistant.py (+11/-15)
openlp/plugins/songs/lib/importers/zionworx.py (+1/-1)
openlp/plugins/songs/lib/mediaitem.py (+16/-18)
openlp/plugins/songs/lib/openlyricsexport.py (+10/-9)
openlp/plugins/songs/lib/upgrade.py (+31/-2)
openlp/plugins/songs/reporting.py (+2/-3)
openlp/plugins/songs/songsplugin.py (+1/-3)
tests/functional/openlp_plugins/images/test_upgrade.py (+1/-0)
tests/functional/openlp_plugins/songs/test_chordproimport.py (+3/-1)
tests/functional/openlp_plugins/songs/test_easyslidesimport.py (+4/-3)
tests/functional/openlp_plugins/songs/test_ewimport.py (+35/-54)
tests/functional/openlp_plugins/songs/test_lyriximport.py (+5/-4)
tests/functional/openlp_plugins/songs/test_mediashout.py (+6/-6)
tests/functional/openlp_plugins/songs/test_openlpimporter.py (+2/-2)
tests/functional/openlp_plugins/songs/test_openlyricsexport.py (+10/-8)
tests/functional/openlp_plugins/songs/test_openlyricsimport.py (+5/-4)
tests/functional/openlp_plugins/songs/test_openoffice.py (+2/-2)
tests/functional/openlp_plugins/songs/test_opensongimport.py (+9/-8)
tests/functional/openlp_plugins/songs/test_opsproimport.py (+5/-5)
tests/functional/openlp_plugins/songs/test_powerpraiseimport.py (+4/-3)
tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py (+4/-3)
tests/functional/openlp_plugins/songs/test_propresenterimport.py (+5/-4)
tests/functional/openlp_plugins/songs/test_songbeamerimport.py (+8/-7)
tests/functional/openlp_plugins/songs/test_songproimport.py (+3/-2)
tests/functional/openlp_plugins/songs/test_songselect.py (+4/-3)
tests/functional/openlp_plugins/songs/test_songshowplusimport.py (+10/-9)
tests/functional/openlp_plugins/songs/test_sundayplusimport.py (+3/-1)
tests/functional/openlp_plugins/songs/test_videopsalm.py (+4/-3)
tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py (+5/-4)
tests/functional/openlp_plugins/songs/test_worshipassistantimport.py (+5/-4)
tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py (+3/-3)
tests/functional/openlp_plugins/songs/test_zionworximport.py (+4/-3)
tests/helpers/songfileimport.py (+1/-1)
To merge this branch: bzr merge lp:~phill-ridout/openlp/pathlib8
Reviewer Review Type Date Requested Status
Tomas Groth Approve
Tim Bentley Approve
Review via email: mp+331621@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) :
review: Approve
Revision history for this message
Tomas Groth (tomasgroth) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/lib/serviceitem.py'
2--- openlp/core/lib/serviceitem.py 2017-08-03 17:54:40 +0000
3+++ openlp/core/lib/serviceitem.py 2017-09-30 23:24:21 +0000
4@@ -426,10 +426,10 @@
5 self.background_audio = []
6 for filename in header['background_audio']:
7 # Give them real file paths.
8- filepath = filename
9+ filepath = str(filename)
10 if path:
11 # Windows can handle both forward and backward slashes, so we use ntpath to get the basename
12- filepath = os.path.join(path, ntpath.basename(filename))
13+ filepath = os.path.join(path, ntpath.basename(str(filename)))
14 self.background_audio.append(filepath)
15 self.theme_overwritten = header.get('theme_overwritten', False)
16 if self.service_item_type == ServiceItemType.Text:
17
18=== modified file 'openlp/core/ui/maindisplay.py'
19--- openlp/core/ui/maindisplay.py 2017-09-26 16:39:13 +0000
20+++ openlp/core/ui/maindisplay.py 2017-09-30 23:24:21 +0000
21@@ -684,7 +684,7 @@
22 if not isinstance(file_names, list):
23 file_names = [file_names]
24 for file_name in file_names:
25- self.playlist.addMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(file_name)))
26+ self.playlist.addMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(str(file_name))))
27
28 def next(self):
29 """
30
31=== modified file 'openlp/core/ui/servicemanager.py'
32--- openlp/core/ui/servicemanager.py 2017-09-23 13:06:42 +0000
33+++ openlp/core/ui/servicemanager.py 2017-09-30 23:24:21 +0000
34@@ -561,7 +561,7 @@
35 service_item = item['service_item'].get_service_repr(self._save_lite)
36 if service_item['header']['background_audio']:
37 for i, file_name in enumerate(service_item['header']['background_audio']):
38- new_file = os.path.join('audio', item['service_item'].unique_identifier, file_name)
39+ new_file = os.path.join('audio', item['service_item'].unique_identifier, str(file_name))
40 audio_files.append((file_name, new_file))
41 service_item['header']['background_audio'][i] = new_file
42 # Add the service item to the service.
43@@ -586,6 +586,8 @@
44 for write_from in write_list:
45 zip_file.write(write_from, write_from)
46 for audio_from, audio_to in audio_files:
47+ audio_from = str(audio_from)
48+ audio_to = str(audio_to)
49 if audio_from.startswith('audio'):
50 # When items are saved, they get new unique_identifier. Let's copy the file to the new location.
51 # Unused files can be ignored, OpenLP automatically cleans up the service manager dir on exit.
52
53=== modified file 'openlp/core/ui/slidecontroller.py'
54--- openlp/core/ui/slidecontroller.py 2017-06-06 20:58:12 +0000
55+++ openlp/core/ui/slidecontroller.py 2017-09-30 23:24:21 +0000
56@@ -868,7 +868,7 @@
57 self.track_menu.clear()
58 for counter in range(len(self.service_item.background_audio)):
59 action = self.track_menu.addAction(
60- os.path.basename(self.service_item.background_audio[counter]))
61+ os.path.basename(str(self.service_item.background_audio[counter])))
62 action.setData(counter)
63 action.triggered.connect(self.on_track_triggered)
64 self.display.audio_player.repeat = \
65
66=== modified file 'openlp/plugins/songs/forms/editsongform.py'
67--- openlp/plugins/songs/forms/editsongform.py 2017-08-25 20:03:25 +0000
68+++ openlp/plugins/songs/forms/editsongform.py 2017-09-30 23:24:21 +0000
69@@ -23,27 +23,25 @@
70 The :mod:`~openlp.plugins.songs.forms.editsongform` module contains the form
71 used to edit songs.
72 """
73-
74 import logging
75+import os
76 import re
77-import os
78-import shutil
79
80 from PyQt5 import QtCore, QtWidgets
81
82 from openlp.core.common import Registry, RegistryProperties, AppLocation, UiStrings, check_directory_exists, translate
83-from openlp.core.common.path import Path, path_to_str
84+from openlp.core.common.languagemanager import get_natural_key
85+from openlp.core.common.path import copyfile
86 from openlp.core.lib import PluginStatus, MediaType, create_separated_list
87 from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_message_box, find_and_set_in_combo_box
88 from openlp.core.ui.lib.filedialog import FileDialog
89-from openlp.core.common.languagemanager import get_natural_key
90+from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog
91+from openlp.plugins.songs.forms.editverseform import EditVerseForm
92+from openlp.plugins.songs.forms.mediafilesform import MediaFilesForm
93 from openlp.plugins.songs.lib import VerseType, clean_song
94 from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorType, Topic, MediaFile, SongBookEntry
95+from openlp.plugins.songs.lib.openlyricsxml import SongXML
96 from openlp.plugins.songs.lib.ui import SongStrings
97-from openlp.plugins.songs.lib.openlyricsxml import SongXML
98-from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog
99-from openlp.plugins.songs.forms.editverseform import EditVerseForm
100-from openlp.plugins.songs.forms.mediafilesform import MediaFilesForm
101
102 log = logging.getLogger(__name__)
103
104@@ -545,9 +543,9 @@
105 songbook_entry.entry)
106 self.audio_list_widget.clear()
107 for media in self.song.media_files:
108- media_file = QtWidgets.QListWidgetItem(os.path.split(media.file_name)[1])
109- media_file.setData(QtCore.Qt.UserRole, media.file_name)
110- self.audio_list_widget.addItem(media_file)
111+ item = QtWidgets.QListWidgetItem(media.file_path.name)
112+ item.setData(QtCore.Qt.UserRole, media.file_path)
113+ self.audio_list_widget.addItem(item)
114 self.title_edit.setFocus()
115 # Hide or show the preview button.
116 self.preview_button.setVisible(preview)
117@@ -927,12 +925,11 @@
118 Loads file(s) from the filesystem.
119 """
120 filters = '{text} (*)'.format(text=UiStrings().AllFiles)
121- file_paths, selected_filter = FileDialog.getOpenFileNames(
122- self, translate('SongsPlugin.EditSongForm', 'Open File(s)'), Path(), filters)
123+ file_paths, filter_used = FileDialog.getOpenFileNames(
124+ parent=self, caption=translate('SongsPlugin.EditSongForm', 'Open File(s)'), filter=filters)
125 for file_path in file_paths:
126- filename = path_to_str(file_path)
127- item = QtWidgets.QListWidgetItem(os.path.split(str(filename))[1])
128- item.setData(QtCore.Qt.UserRole, filename)
129+ item = QtWidgets.QListWidgetItem(file_path.name)
130+ item.setData(QtCore.Qt.UserRole, file_path)
131 self.audio_list_widget.addItem(item)
132
133 def on_audio_add_from_media_button_clicked(self):
134@@ -940,9 +937,9 @@
135 Loads file(s) from the media plugin.
136 """
137 if self.media_form.exec():
138- for filename in self.media_form.get_selected_files():
139- item = QtWidgets.QListWidgetItem(os.path.split(str(filename))[1])
140- item.setData(QtCore.Qt.UserRole, filename)
141+ for file_path in self.media_form.get_selected_files():
142+ item = QtWidgets.QListWidgetItem(file_path.name)
143+ item.setData(QtCore.Qt.UserRole, file_path)
144 self.audio_list_widget.addItem(item)
145
146 def on_audio_remove_button_clicked(self):
147@@ -1066,34 +1063,33 @@
148 # Save the song here because we need a valid id for the audio files.
149 clean_song(self.manager, self.song)
150 self.manager.save_object(self.song)
151- audio_files = [a.file_name for a in self.song.media_files]
152- log.debug(audio_files)
153- save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio',
154- str(self.song.id))
155- check_directory_exists(Path(save_path))
156+ audio_paths = [a.file_path for a in self.song.media_files]
157+ log.debug(audio_paths)
158+ save_path = AppLocation.get_section_data_path(self.media_item.plugin.name) / 'audio' / str(self.song.id)
159+ check_directory_exists(save_path)
160 self.song.media_files = []
161- files = []
162+ file_paths = []
163 for row in range(self.audio_list_widget.count()):
164 item = self.audio_list_widget.item(row)
165- filename = item.data(QtCore.Qt.UserRole)
166- if not filename.startswith(save_path):
167- old_file, filename = filename, os.path.join(save_path, os.path.split(filename)[1])
168- shutil.copyfile(old_file, filename)
169- files.append(filename)
170+ file_path = item.data(QtCore.Qt.UserRole)
171+ if save_path not in file_path.parents:
172+ old_file_path, file_path = file_path, save_path / file_path.name
173+ copyfile(old_file_path, file_path)
174+ file_paths.append(file_path)
175 media_file = MediaFile()
176- media_file.file_name = filename
177+ media_file.file_path = file_path
178 media_file.type = 'audio'
179 media_file.weight = row
180 self.song.media_files.append(media_file)
181- for audio in audio_files:
182- if audio not in files:
183+ for audio_path in audio_paths:
184+ if audio_path not in file_paths:
185 try:
186- os.remove(audio)
187+ audio_path.unlink()
188 except:
189- log.exception('Could not remove file: {audio}'.format(audio=audio))
190- if not files:
191+ log.exception('Could not remove file: {audio}'.format(audio=audio_path))
192+ if not file_paths:
193 try:
194- os.rmdir(save_path)
195+ save_path.rmdir()
196 except OSError:
197 log.exception('Could not remove directory: {path}'.format(path=save_path))
198 clean_song(self.manager, self.song)
199
200=== modified file 'openlp/plugins/songs/forms/mediafilesform.py'
201--- openlp/plugins/songs/forms/mediafilesform.py 2017-06-04 12:14:23 +0000
202+++ openlp/plugins/songs/forms/mediafilesform.py 2017-09-30 23:24:21 +0000
203@@ -41,12 +41,19 @@
204 QtCore.Qt.WindowCloseButtonHint)
205 self.setupUi(self)
206
207- def populate_files(self, files):
208+ def populate_files(self, file_paths):
209+ """
210+ :param list[openlp.core.common.path.Path] file_paths:
211+ :return:
212+ """
213 self.file_list_widget.clear()
214- for file in files:
215- item = QtWidgets.QListWidgetItem(os.path.split(file)[1])
216- item.setData(QtCore.Qt.UserRole, file)
217+ for file_path in file_paths:
218+ item = QtWidgets.QListWidgetItem(file_path.name)
219+ item.setData(QtCore.Qt.UserRole, file_path)
220 self.file_list_widget.addItem(item)
221
222 def get_selected_files(self):
223+ """
224+ :rtype: list[openlp.core.common.path.Path]
225+ """
226 return [item.data(QtCore.Qt.UserRole) for item in self.file_list_widget.selectedItems()]
227
228=== modified file 'openlp/plugins/songs/forms/songexportform.py'
229--- openlp/plugins/songs/forms/songexportform.py 2017-05-30 18:42:35 +0000
230+++ openlp/plugins/songs/forms/songexportform.py 2017-09-30 23:24:21 +0000
231@@ -27,9 +27,10 @@
232
233 from PyQt5 import QtCore, QtWidgets
234
235-from openlp.core.common import Registry, UiStrings, translate
236-from openlp.core.lib import create_separated_list, build_icon
237+from openlp.core.common import Registry, Settings, UiStrings, translate
238+from openlp.core.lib import create_separated_list
239 from openlp.core.lib.ui import critical_error_message_box
240+from openlp.core.ui.lib import PathEdit, PathType
241 from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
242 from openlp.plugins.songs.lib.db import Song
243 from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
244@@ -76,7 +77,6 @@
245 self.search_line_edit.textEdited.connect(self.on_search_line_edit_changed)
246 self.uncheck_button.clicked.connect(self.on_uncheck_button_clicked)
247 self.check_button.clicked.connect(self.on_check_button_clicked)
248- self.directory_button.clicked.connect(self.on_directory_button_clicked)
249
250 def add_custom_pages(self):
251 """
252@@ -120,21 +120,15 @@
253 self.grid_layout.setObjectName('range_layout')
254 self.selected_list_widget = QtWidgets.QListWidget(self.export_song_page)
255 self.selected_list_widget.setObjectName('selected_list_widget')
256- self.grid_layout.addWidget(self.selected_list_widget, 1, 0, 1, 1)
257- # FIXME: self.horizontal_layout is already defined above?!?!? Replace with Path Eidt!
258- self.horizontal_layout = QtWidgets.QHBoxLayout()
259- self.horizontal_layout.setObjectName('horizontal_layout')
260+ self.grid_layout.addWidget(self.selected_list_widget, 1, 0, 1, 2)
261+ self.output_directory_path_edit = PathEdit(
262+ self.export_song_page, PathType.Directories,
263+ dialog_caption=translate('SongsPlugin.ExportWizardForm', 'Select Destination Folder'), show_revert=False)
264+ self.output_directory_path_edit.path = Settings().value('songs/last directory export')
265 self.directory_label = QtWidgets.QLabel(self.export_song_page)
266 self.directory_label.setObjectName('directory_label')
267- self.horizontal_layout.addWidget(self.directory_label)
268- self.directory_line_edit = QtWidgets.QLineEdit(self.export_song_page)
269- self.directory_line_edit.setObjectName('directory_line_edit')
270- self.horizontal_layout.addWidget(self.directory_line_edit)
271- self.directory_button = QtWidgets.QToolButton(self.export_song_page)
272- self.directory_button.setIcon(build_icon(':/exports/export_load.png'))
273- self.directory_button.setObjectName('directory_button')
274- self.horizontal_layout.addWidget(self.directory_button)
275- self.grid_layout.addLayout(self.horizontal_layout, 0, 0, 1, 1)
276+ self.grid_layout.addWidget(self.directory_label, 0, 0)
277+ self.grid_layout.addWidget(self.output_directory_path_edit, 0, 1)
278 self.export_song_layout.addLayout(self.grid_layout)
279 self.addPage(self.export_song_page)
280
281@@ -188,11 +182,12 @@
282 self.selected_list_widget.addItem(song)
283 return True
284 elif self.currentPage() == self.export_song_page:
285- if not self.directory_line_edit.text():
286+ if not self.output_directory_path_edit.path:
287 critical_error_message_box(
288 translate('SongsPlugin.ExportWizardForm', 'No Save Location specified'),
289 translate('SongsPlugin.ExportWizardForm', 'You need to specify a directory.'))
290 return False
291+ Settings().setValue('songs/last directory export', self.output_directory_path_edit.path)
292 return True
293 elif self.currentPage() == self.progress_page:
294 self.available_list_widget.clear()
295@@ -211,8 +206,6 @@
296 self.finish_button.setVisible(False)
297 self.cancel_button.setVisible(True)
298 self.available_list_widget.clear()
299- self.selected_list_widget.clear()
300- self.directory_line_edit.clear()
301 self.search_line_edit.clear()
302 # Load the list of songs.
303 self.application.set_busy_cursor()
304@@ -247,7 +240,7 @@
305 song.data(QtCore.Qt.UserRole)
306 for song in find_list_widget_items(self.selected_list_widget)
307 ]
308- exporter = OpenLyricsExport(self, songs, self.directory_line_edit.text())
309+ exporter = OpenLyricsExport(self, songs, self.output_directory_path_edit.path)
310 try:
311 if exporter.do_export():
312 self.progress_label.setText(
313@@ -291,15 +284,6 @@
314 if not item.isHidden():
315 item.setCheckState(QtCore.Qt.Checked)
316
317- def on_directory_button_clicked(self):
318- """
319- Called when the *directory_button* was clicked. Opens a dialog and writes
320- the path to *directory_line_edit*.
321- """
322- self.get_folder(
323- translate('SongsPlugin.ExportWizardForm', 'Select Destination Folder'),
324- self.directory_line_edit, 'last directory export')
325-
326
327 def find_list_widget_items(list_widget, text=''):
328 """
329
330=== modified file 'openlp/plugins/songs/forms/songimportform.py'
331--- openlp/plugins/songs/forms/songimportform.py 2017-08-26 15:06:11 +0000
332+++ openlp/plugins/songs/forms/songimportform.py 2017-09-30 23:24:21 +0000
333@@ -22,15 +22,13 @@
334 """
335 The song import functions for OpenLP.
336 """
337-import codecs
338 import logging
339-import os
340
341 from PyQt5 import QtCore, QtWidgets
342
343 from openlp.core.common import RegistryProperties, Settings, UiStrings, translate
344-from openlp.core.common.path import path_to_str, str_to_path
345 from openlp.core.lib.ui import critical_error_message_box
346+from openlp.core.ui.lib import PathEdit, PathType
347 from openlp.core.ui.lib.filedialog import FileDialog
348 from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
349 from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect
350@@ -93,9 +91,7 @@
351 self.format_widgets[song_format]['addButton'].clicked.connect(self.on_add_button_clicked)
352 self.format_widgets[song_format]['removeButton'].clicked.connect(self.on_remove_button_clicked)
353 else:
354- self.format_widgets[song_format]['browseButton'].clicked.connect(self.on_browse_button_clicked)
355- self.format_widgets[song_format]['file_path_edit'].textChanged.\
356- connect(self.on_filepath_edit_text_changed)
357+ self.format_widgets[song_format]['path_edit'].pathChanged.connect(self.on_path_edit_path_changed)
358
359 def add_custom_pages(self):
360 """
361@@ -155,7 +151,6 @@
362 self.format_widgets[format_list]['removeButton'].setText(
363 translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
364 else:
365- self.format_widgets[format_list]['browseButton'].setText(UiStrings().Browse)
366 f_label = 'Filename:'
367 if select_mode == SongFormatSelect.SingleFolder:
368 f_label = 'Folder:'
369@@ -172,16 +167,11 @@
370 self.error_save_to_button.setText(translate('SongsPlugin.ImportWizardForm', 'Save to File'))
371 # Align all QFormLayouts towards each other.
372 formats = [f for f in SongFormat.get_format_list() if 'filepathLabel' in self.format_widgets[f]]
373- labels = [self.format_widgets[f]['filepathLabel'] for f in formats]
374+ labels = [self.format_widgets[f]['filepathLabel'] for f in formats] + [self.format_label]
375 # Get max width of all labels
376- max_label_width = max(self.format_label.minimumSizeHint().width(),
377- max([label.minimumSizeHint().width() for label in labels]))
378- self.format_spacer.changeSize(max_label_width, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
379- spacers = [self.format_widgets[f]['filepathSpacer'] for f in formats]
380- for index, spacer in enumerate(spacers):
381- spacer.changeSize(
382- max_label_width - labels[index].minimumSizeHint().width(), 0,
383- QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
384+ max_label_width = max(labels, key=lambda label: label.minimumSizeHint().width()).minimumSizeHint().width()
385+ for label in labels:
386+ label.setFixedWidth(max_label_width)
387 # Align descriptionLabels with rest of layout
388 for format_list in SongFormat.get_format_list():
389 if SongFormat.get(format_list, 'descriptionText') is not None:
390@@ -209,13 +199,13 @@
391 Settings().setValue('songs/last import type', this_format)
392 select_mode, class_, error_msg = SongFormat.get(this_format, 'selectMode', 'class', 'invalidSourceMsg')
393 if select_mode == SongFormatSelect.MultipleFiles:
394- import_source = self.get_list_of_files(self.format_widgets[this_format]['file_list_widget'])
395+ import_source = self.get_list_of_paths(self.format_widgets[this_format]['file_list_widget'])
396 error_title = UiStrings().IFSp
397 focus_button = self.format_widgets[this_format]['addButton']
398 else:
399- import_source = self.format_widgets[this_format]['file_path_edit'].text()
400+ import_source = self.format_widgets[this_format]['path_edit'].path
401 error_title = (UiStrings().IFSs if select_mode == SongFormatSelect.SingleFile else UiStrings().IFdSs)
402- focus_button = self.format_widgets[this_format]['browseButton']
403+ focus_button = self.format_widgets[this_format]['path_edit']
404 if not class_.is_valid_source(import_source):
405 critical_error_message_box(error_title, error_msg)
406 focus_button.setFocus()
407@@ -238,20 +228,23 @@
408 if filters:
409 filters += ';;'
410 filters += '{text} (*)'.format(text=UiStrings().AllFiles)
411- file_paths, selected_filter = FileDialog.getOpenFileNames(
412- self, title, Settings().value(self.plugin.settings_section + '/last directory import'), filters)
413+ file_paths, filter_used = FileDialog.getOpenFileNames(
414+ self, title,
415+ Settings().value(self.plugin.settings_section + '/last directory import'), filters)
416+ for file_path in file_paths:
417+ list_item = QtWidgets.QListWidgetItem(str(file_path))
418+ list_item.setData(QtCore.Qt.UserRole, file_path)
419+ listbox.addItem(list_item)
420 if file_paths:
421- file_names = [path_to_str(file_path) for file_path in file_paths]
422- listbox.addItems(file_names)
423 Settings().setValue(self.plugin.settings_section + '/last directory import', file_paths[0].parent)
424
425- def get_list_of_files(self, list_box):
426+ def get_list_of_paths(self, list_box):
427 """
428 Return a list of file from the list_box
429
430 :param list_box: The source list box
431 """
432- return [list_box.item(i).text() for i in range(list_box.count())]
433+ return [list_box.item(i).data(QtCore.Qt.UserRole) for i in range(list_box.count())]
434
435 def remove_selected_items(self, list_box):
436 """
437@@ -263,20 +256,6 @@
438 item = list_box.takeItem(list_box.row(item))
439 del item
440
441- def on_browse_button_clicked(self):
442- """
443- Browse for files or a directory.
444- """
445- this_format = self.current_format
446- select_mode, format_name, ext_filter = SongFormat.get(this_format, 'selectMode', 'name', 'filter')
447- file_path_edit = self.format_widgets[this_format]['file_path_edit']
448- if select_mode == SongFormatSelect.SingleFile:
449- self.get_file_name(WizardStrings.OpenTypeFile.format(file_type=format_name),
450- file_path_edit, 'last directory import', ext_filter)
451- elif select_mode == SongFormatSelect.SingleFolder:
452- self.get_folder(
453- WizardStrings.OpenTypeFolder.format(folder_name=format_name), file_path_edit, 'last directory import')
454-
455 def on_add_button_clicked(self):
456 """
457 Add a file or directory.
458@@ -296,7 +275,7 @@
459 self.remove_selected_items(self.format_widgets[self.current_format]['file_list_widget'])
460 self.source_page.completeChanged.emit()
461
462- def on_filepath_edit_text_changed(self):
463+ def on_path_edit_path_changed(self):
464 """
465 Called when the content of the Filename/Folder edit box changes.
466 """
467@@ -317,8 +296,6 @@
468 select_mode = SongFormat.get(format_list, 'selectMode')
469 if select_mode == SongFormatSelect.MultipleFiles:
470 self.format_widgets[format_list]['file_list_widget'].clear()
471- else:
472- self.format_widgets[format_list]['file_path_edit'].setText('')
473 self.error_report_text_edit.clear()
474 self.error_report_text_edit.setHidden(True)
475 self.error_copy_to_button.setHidden(True)
476@@ -341,14 +318,14 @@
477 select_mode = SongFormat.get(source_format, 'selectMode')
478 if select_mode == SongFormatSelect.SingleFile:
479 importer = self.plugin.import_songs(source_format,
480- filename=self.format_widgets[source_format]['file_path_edit'].text())
481+ file_path=self.format_widgets[source_format]['path_edit'].path)
482 elif select_mode == SongFormatSelect.SingleFolder:
483 importer = self.plugin.import_songs(source_format,
484- folder=self.format_widgets[source_format]['file_path_edit'].text())
485+ folder_path=self.format_widgets[source_format]['path_edit'].path)
486 else:
487 importer = self.plugin.import_songs(
488 source_format,
489- filenames=self.get_list_of_files(self.format_widgets[source_format]['file_list_widget']))
490+ file_paths=self.get_list_of_paths(self.format_widgets[source_format]['file_list_widget']))
491 importer.do_import()
492 self.progress_label.setText(WizardStrings.FinishedImport)
493
494@@ -366,18 +343,17 @@
495 """
496 file_path, filter_used = FileDialog.getSaveFileName(
497 self, Settings().value(self.plugin.settings_section + '/last directory import'))
498- if not file_path:
499+ if file_path is None:
500 return
501- with file_path.open('w', encoding='utf-8') as report_file:
502- report_file.write(self.error_report_text_edit.toPlainText())
503+ file_path.write_text(self.error_report_text_edit.toPlainText(), encoding='utf-8')
504
505 def add_file_select_item(self):
506 """
507 Add a file selection page.
508 """
509 this_format = self.current_format
510- prefix, can_disable, description_text, select_mode = \
511- SongFormat.get(this_format, 'prefix', 'canDisable', 'descriptionText', 'selectMode')
512+ format_name, prefix, can_disable, description_text, select_mode, filters = \
513+ SongFormat.get(this_format, 'name', 'prefix', 'canDisable', 'descriptionText', 'selectMode', 'filter')
514 page = QtWidgets.QWidget()
515 page.setObjectName(prefix + 'Page')
516 if can_disable:
517@@ -403,26 +379,23 @@
518 if select_mode == SongFormatSelect.SingleFile or select_mode == SongFormatSelect.SingleFolder:
519 file_path_layout = QtWidgets.QHBoxLayout()
520 file_path_layout.setObjectName(prefix + '_file_path_layout')
521- file_path_layout.setContentsMargins(0, self.format_v_spacing, 0, 0)
522 file_path_label = QtWidgets.QLabel(import_widget)
523- file_path_label.setObjectName(prefix + 'FilepathLabel')
524 file_path_layout.addWidget(file_path_label)
525- file_path_spacer = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
526- file_path_layout.addSpacerItem(file_path_spacer)
527- file_path_edit = QtWidgets.QLineEdit(import_widget)
528- file_path_edit.setObjectName(prefix + '_file_path_edit')
529- file_path_layout.addWidget(file_path_edit)
530- browse_button = QtWidgets.QToolButton(import_widget)
531- browse_button.setIcon(self.open_icon)
532- browse_button.setObjectName(prefix + 'BrowseButton')
533- file_path_layout.addWidget(browse_button)
534+ if select_mode == SongFormatSelect.SingleFile:
535+ path_type = PathType.Files
536+ dialog_caption = WizardStrings.OpenTypeFile.format(file_type=format_name)
537+ else:
538+ path_type = PathType.Directories
539+ dialog_caption = WizardStrings.OpenTypeFolder.format(folder_name=format_name)
540+ path_edit = PathEdit(
541+ parent=import_widget, path_type=path_type, dialog_caption=dialog_caption, show_revert=False)
542+ path_edit.filters = path_edit.filters + filters
543+ path_edit.path = Settings().value(self.plugin.settings_section + '/last directory import')
544+ file_path_layout.addWidget(path_edit)
545 import_layout.addLayout(file_path_layout)
546 import_layout.addSpacerItem(self.stack_spacer)
547 self.format_widgets[this_format]['filepathLabel'] = file_path_label
548- self.format_widgets[this_format]['filepathSpacer'] = file_path_spacer
549- self.format_widgets[this_format]['file_path_layout'] = file_path_layout
550- self.format_widgets[this_format]['file_path_edit'] = file_path_edit
551- self.format_widgets[this_format]['browseButton'] = browse_button
552+ self.format_widgets[this_format]['path_edit'] = path_edit
553 elif select_mode == SongFormatSelect.MultipleFiles:
554 file_list_widget = QtWidgets.QListWidget(import_widget)
555 file_list_widget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
556@@ -496,6 +469,8 @@
557 * or if SingleFolder mode, the specified folder exists
558
559 When this method returns True, the wizard's Next button is enabled.
560+
561+ :rtype: bool
562 """
563 wizard = self.wizard()
564 this_format = wizard.current_format
565@@ -505,10 +480,10 @@
566 if wizard.format_widgets[this_format]['file_list_widget'].count() > 0:
567 return True
568 else:
569- file_path = str(wizard.format_widgets[this_format]['file_path_edit'].text())
570+ file_path = wizard.format_widgets[this_format]['path_edit'].path
571 if file_path:
572- if select_mode == SongFormatSelect.SingleFile and os.path.isfile(file_path):
573+ if select_mode == SongFormatSelect.SingleFile and file_path.is_file():
574 return True
575- elif select_mode == SongFormatSelect.SingleFolder and os.path.isdir(file_path):
576+ elif select_mode == SongFormatSelect.SingleFolder and file_path.is_dir():
577 return True
578 return False
579
580=== modified file 'openlp/plugins/songs/lib/__init__.py'
581--- openlp/plugins/songs/lib/__init__.py 2017-08-03 17:54:40 +0000
582+++ openlp/plugins/songs/lib/__init__.py 2017-09-30 23:24:21 +0000
583@@ -534,13 +534,13 @@
584 media_files = song_plugin.manager.get_all_objects(MediaFile, MediaFile.song_id == song_id)
585 for media_file in media_files:
586 try:
587- os.remove(media_file.file_name)
588+ media_file.file_path.unlink()
589 except OSError:
590- log.exception('Could not remove file: {name}'.format(name=media_file.file_name))
591+ log.exception('Could not remove file: {name}'.format(name=media_file.file_path))
592 try:
593- save_path = os.path.join(str(AppLocation.get_section_data_path(song_plugin.name)), 'audio', str(song_id))
594- if os.path.exists(save_path):
595- os.rmdir(save_path)
596+ save_path = AppLocation.get_section_data_path(song_plugin.name) / 'audio' / str(song_id)
597+ if save_path.exists():
598+ save_path.rmdir()
599 except OSError:
600 log.exception('Could not remove directory: {path}'.format(path=save_path))
601 song_plugin.manager.delete_object(Song, song_id)
602
603=== modified file 'openlp/plugins/songs/lib/db.py'
604--- openlp/plugins/songs/lib/db.py 2016-12-31 11:01:36 +0000
605+++ openlp/plugins/songs/lib/db.py 2017-09-30 23:24:21 +0000
606@@ -23,14 +23,15 @@
607 The :mod:`db` module provides the database and schema that is the backend for
608 the Songs plugin
609 """
610-
611+from contextlib import suppress
612 from sqlalchemy import Column, ForeignKey, Table, types
613 from sqlalchemy.orm import mapper, relation, reconstructor
614 from sqlalchemy.sql.expression import func, text
615
616-from openlp.core.lib.db import BaseModel, init_db
617+from openlp.core.common.applocation import AppLocation
618 from openlp.core.common.languagemanager import get_natural_key
619 from openlp.core.lib import translate
620+from openlp.core.lib.db import BaseModel, PathType, init_db
621
622
623 class Author(BaseModel):
624@@ -238,7 +239,7 @@
625
626 **media_files Table**
627 * id
628- * file_name
629+ * _file_path
630 * type
631
632 **song_books Table**
633@@ -305,7 +306,7 @@
634 'media_files', metadata,
635 Column('id', types.Integer(), primary_key=True),
636 Column('song_id', types.Integer(), ForeignKey('songs.id'), default=None),
637- Column('file_name', types.Unicode(255), nullable=False),
638+ Column('file_path', PathType, nullable=False),
639 Column('type', types.Unicode(64), nullable=False, default='audio'),
640 Column('weight', types.Integer(), default=0)
641 )
642
643=== modified file 'openlp/plugins/songs/lib/importers/cclifile.py'
644--- openlp/plugins/songs/lib/importers/cclifile.py 2016-12-31 11:01:36 +0000
645+++ openlp/plugins/songs/lib/importers/cclifile.py 2017-09-30 23:24:21 +0000
646@@ -19,11 +19,9 @@
647 # with this program; if not, write to the Free Software Foundation, Inc., 59 #
648 # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
649 ###############################################################################
650-
651-import logging
652-import os
653 import chardet
654 import codecs
655+import logging
656
657 from openlp.core.lib import translate
658 from openlp.plugins.songs.lib import VerseType
659@@ -48,7 +46,7 @@
660 :param manager: The song manager for the running OpenLP installation.
661 :param kwargs: The files to be imported.
662 """
663- super(CCLIFileImport, self).__init__(manager, **kwargs)
664+ super().__init__(manager, **kwargs)
665
666 def do_import(self):
667 """
668@@ -56,37 +54,35 @@
669 """
670 log.debug('Starting CCLI File Import')
671 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
672- for filename in self.import_source:
673- filename = str(filename)
674- log.debug('Importing CCLI File: {name}'.format(name=filename))
675- if os.path.isfile(filename):
676- detect_file = open(filename, 'rb')
677- detect_content = detect_file.read(2048)
678- try:
679- str(detect_content, 'utf-8')
680- details = {'confidence': 1, 'encoding': 'utf-8'}
681- except UnicodeDecodeError:
682- details = chardet.detect(detect_content)
683- detect_file.close()
684- infile = codecs.open(filename, 'r', details['encoding'])
685- if not infile.read(1) == '\ufeff':
686+ for file_path in self.import_source:
687+ log.debug('Importing CCLI File: {name}'.format(name=file_path))
688+ if file_path.is_file():
689+ with file_path.open('rb') as detect_file:
690+ detect_content = detect_file.read(2048)
691+ try:
692+ str(detect_content, 'utf-8')
693+ details = {'confidence': 1, 'encoding': 'utf-8'}
694+ except UnicodeDecodeError:
695+ details = chardet.detect(detect_content)
696+ in_file = codecs.open(str(file_path), 'r', details['encoding'])
697+ if not in_file.read(1) == '\ufeff':
698 # not UTF or no BOM was found
699- infile.seek(0)
700- lines = infile.readlines()
701- infile.close()
702- ext = os.path.splitext(filename)[1]
703- if ext.lower() == '.usr' or ext.lower() == '.bin':
704- log.info('SongSelect USR format file found: {name}'.format(name=filename))
705+ in_file.seek(0)
706+ lines = in_file.readlines()
707+ in_file.close()
708+ ext = file_path.suffix.lower()
709+ if ext == '.usr' or ext == '.bin':
710+ log.info('SongSelect USR format file found: {name}'.format(name=file_path))
711 if not self.do_import_usr_file(lines):
712- self.log_error(filename)
713- elif ext.lower() == '.txt':
714- log.info('SongSelect TEXT format file found: {name}'.format(name=filename))
715+ self.log_error(file_path)
716+ elif ext == '.txt':
717+ log.info('SongSelect TEXT format file found: {name}'.format(name=file_path))
718 if not self.do_import_txt_file(lines):
719- self.log_error(filename)
720+ self.log_error(file_path)
721 else:
722- self.log_error(filename, translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid '
723- 'extension.'))
724- log.info('Extension {name} is not valid'.format(name=filename))
725+ self.log_error(file_path, translate('SongsPlugin.CCLIFileImport',
726+ 'The file does not have a valid extension.'))
727+ log.info('Extension {name} is not valid'.format(name=file_path))
728 if self.stop_import_flag:
729 return
730
731
732=== modified file 'openlp/plugins/songs/lib/importers/chordpro.py'
733--- openlp/plugins/songs/lib/importers/chordpro.py 2017-02-26 21:14:49 +0000
734+++ openlp/plugins/songs/lib/importers/chordpro.py 2017-09-30 23:24:21 +0000
735@@ -47,12 +47,11 @@
736 """
737 def do_import(self):
738 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
739- for filename in self.import_source:
740+ for file_path in self.import_source:
741 if self.stop_import_flag:
742 return
743- song_file = open(filename, 'rt')
744- self.do_import_file(song_file)
745- song_file.close()
746+ with file_path.open('rt') as song_file:
747+ self.do_import_file(song_file)
748
749 def do_import_file(self, song_file):
750 """
751
752=== modified file 'openlp/plugins/songs/lib/importers/dreambeam.py'
753--- openlp/plugins/songs/lib/importers/dreambeam.py 2016-12-31 11:01:36 +0000
754+++ openlp/plugins/songs/lib/importers/dreambeam.py 2017-09-30 23:24:21 +0000
755@@ -78,27 +78,29 @@
756
757 def do_import(self):
758 """
759- Receive a single file or a list of files to import.
760+ Receive a single file_path or a list of files to import.
761 """
762 if isinstance(self.import_source, list):
763 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
764- for file in self.import_source:
765+ for file_path in self.import_source:
766 if self.stop_import_flag:
767 return
768 self.set_defaults()
769 parser = etree.XMLParser(remove_blank_text=True)
770 try:
771- parsed_file = etree.parse(open(file, 'r'), parser)
772+ with file_path.open('r') as xml_file:
773+ parsed_file = etree.parse(xml_file, parser)
774 except etree.XMLSyntaxError:
775- log.exception('XML syntax error in file {name}'.format(name=file))
776- self.log_error(file, SongStrings.XMLSyntaxError)
777+ log.exception('XML syntax error in file_path {name}'.format(name=file_path))
778+ self.log_error(file_path, SongStrings.XMLSyntaxError)
779 continue
780 xml = etree.tostring(parsed_file).decode()
781 song_xml = objectify.fromstring(xml)
782 if song_xml.tag != 'DreamSong':
783 self.log_error(
784- file,
785- translate('SongsPlugin.DreamBeamImport', 'Invalid DreamBeam song file. Missing DreamSong tag.'))
786+ file_path,
787+ translate('SongsPlugin.DreamBeamImport',
788+ 'Invalid DreamBeam song file_path. Missing DreamSong tag.'))
789 continue
790 if hasattr(song_xml, 'Version'):
791 self.version = float(song_xml.Version.text)
792@@ -144,4 +146,4 @@
793 else:
794 self.parse_author(author_copyright)
795 if not self.finish():
796- self.log_error(file)
797+ self.log_error(file_path)
798
799=== modified file 'openlp/plugins/songs/lib/importers/easyslides.py'
800--- openlp/plugins/songs/lib/importers/easyslides.py 2017-01-12 21:31:01 +0000
801+++ openlp/plugins/songs/lib/importers/easyslides.py 2017-09-30 23:24:21 +0000
802@@ -47,7 +47,7 @@
803 def do_import(self):
804 log.info('Importing EasySlides XML file {source}'.format(source=self.import_source))
805 parser = etree.XMLParser(remove_blank_text=True, recover=True)
806- parsed_file = etree.parse(self.import_source, parser)
807+ parsed_file = etree.parse(str(self.import_source), parser)
808 xml = etree.tostring(parsed_file).decode()
809 song_xml = objectify.fromstring(xml)
810 self.import_wizard.progress_bar.setMaximum(len(song_xml.Item))
811
812=== modified file 'openlp/plugins/songs/lib/importers/easyworship.py'
813--- openlp/plugins/songs/lib/importers/easyworship.py 2017-04-01 04:45:12 +0000
814+++ openlp/plugins/songs/lib/importers/easyworship.py 2017-09-30 23:24:21 +0000
815@@ -22,14 +22,15 @@
816 """
817 The :mod:`easyworship` module provides the functionality for importing EasyWorship song databases into OpenLP.
818 """
819-
820+import logging
821 import os
822+import re
823 import struct
824-import re
825 import zlib
826-import logging
827+
828 import sqlite3
829
830+from openlp.core.common.path import Path
831 from openlp.core.lib import translate
832 from openlp.plugins.songs.lib import VerseType
833 from openlp.plugins.songs.lib import retrieve_windows_encoding, strip_rtf
834@@ -76,9 +77,11 @@
835 """
836 Determines the type of file to import and calls the appropiate method
837 """
838- if self.import_source.lower().endswith('ews'):
839+ self.import_source = Path(self.import_source)
840+ ext = self.import_source.suffix.lower()
841+ if ext == '.ews':
842 self.import_ews()
843- elif self.import_source.endswith('DB'):
844+ elif ext == '.db':
845 self.import_db()
846 else:
847 self.import_sqlite_db()
848@@ -91,11 +94,11 @@
849 or here: http://wiki.openlp.org/Development:EasyWorship_EWS_Format
850 """
851 # Open ews file if it exists
852- if not os.path.isfile(self.import_source):
853+ if not self.import_source.is_file():
854 log.debug('Given ews file does not exists.')
855 return
856 # Make sure there is room for at least a header and one entry
857- if os.path.getsize(self.import_source) < 892:
858+ if self.import_source.stat().st_size < 892:
859 log.debug('Given ews file is to small to contain valid data.')
860 return
861 # Take a stab at how text is encoded
862@@ -104,7 +107,7 @@
863 if not self.encoding:
864 log.debug('No encoding set.')
865 return
866- self.ews_file = open(self.import_source, 'rb')
867+ self.ews_file = self.import_source.open('rb')
868 # EWS header, version '1.6'/' 3'/' 5':
869 # Offset Field Data type Length Details
870 # --------------------------------------------------------------------------------------------------
871@@ -199,23 +202,22 @@
872 Import the songs from the database
873 """
874 # Open the DB and MB files if they exist
875- import_source_mb = self.import_source.replace('.DB', '.MB')
876- if not os.path.isfile(self.import_source):
877+ import_source_mb = self.import_source.with_suffix('.MB')
878+ if not self.import_source.is_file():
879 self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
880 'This file does not exist.'))
881 return
882- if not os.path.isfile(import_source_mb):
883+ if not import_source_mb.is_file():
884 self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
885 'Could not find the "Songs.MB" file. It must be in the same '
886 'folder as the "Songs.DB" file.'))
887 return
888- db_size = os.path.getsize(self.import_source)
889- if db_size < 0x800:
890+ if self.import_source.stat().st_size < 0x800:
891 self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
892 'This file is not a valid EasyWorship database.'))
893 return
894- db_file = open(self.import_source, 'rb')
895- self.memo_file = open(import_source_mb, 'rb')
896+ db_file = self.import_source.open('rb')
897+ self.memo_file = import_source_mb.open('rb')
898 # Don't accept files that are clearly not paradox files
899 record_size, header_size, block_size, first_block, num_fields = struct.unpack('<hhxb8xh17xh', db_file.read(35))
900 if header_size != 0x800 or block_size < 1 or block_size > 4:
901@@ -340,52 +342,34 @@
902 db_file.close()
903 self.memo_file.close()
904
905- def _find_file(self, base_path, path_list):
906- """
907- Find the specified file, with the option of the file being at any level in the specified directory structure.
908-
909- :param base_path: the location search in
910- :param path_list: the targeted file, preceded by directories that may be their parents relative to the base_path
911- :return: path for targeted file
912- """
913- target_file = ''
914- while len(path_list) > 0:
915- target_file = os.path.join(path_list[-1], target_file)
916- path_list = path_list[:len(path_list) - 1]
917- full_path = os.path.join(base_path, target_file)
918- full_path = full_path[:len(full_path) - 1]
919- if os.path.isfile(full_path):
920- return full_path
921- return ''
922-
923 def import_sqlite_db(self):
924 """
925 Import the songs from an EasyWorship 6 SQLite database
926 """
927- songs_db_path = self._find_file(self.import_source, ["Databases", "Data", "Songs.db"])
928- song_words_db_path = self._find_file(self.import_source, ["Databases", "Data", "SongWords.db"])
929- invalid_dir_msg = 'This does not appear to be a valid Easy Worship 6 database directory.'
930+ songs_db_path = next(self.import_source.rglob('Songs.db'), None)
931+ song_words_db_path = next(self.import_source.rglob('SongWords.db'), None)
932+ invalid_dir_msg = translate('SongsPlugin.EasyWorshipSongImport',
933+ 'This does not appear to be a valid Easy Worship 6 database directory.')
934+ invalid_db_msg = translate('SongsPlugin.EasyWorshipSongImport', 'This is not a valid Easy Worship 6 database.')
935 # check to see if needed files are there
936- if not os.path.isfile(songs_db_path):
937- self.log_error(songs_db_path, translate('SongsPlugin.EasyWorshipSongImport', invalid_dir_msg))
938+ if not (songs_db_path and songs_db_path.is_file()):
939+ self.log_error(self.import_source, invalid_dir_msg)
940 return
941- if not os.path.isfile(song_words_db_path):
942- self.log_error(song_words_db_path, translate('SongsPlugin.EasyWorshipSongImport', invalid_dir_msg))
943+ if not (song_words_db_path and song_words_db_path.is_file()):
944+ self.log_error(self.import_source, invalid_dir_msg)
945 return
946 # get database handles
947- songs_conn = sqlite3.connect(songs_db_path)
948- words_conn = sqlite3.connect(song_words_db_path)
949+ songs_conn = sqlite3.connect(str(songs_db_path))
950+ words_conn = sqlite3.connect(str(song_words_db_path))
951 if songs_conn is None or words_conn is None:
952- self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
953- 'This is not a valid Easy Worship 6 database.'))
954+ self.log_error(self.import_source, invalid_db_msg)
955 songs_conn.close()
956 words_conn.close()
957 return
958 songs_db = songs_conn.cursor()
959 words_db = words_conn.cursor()
960 if songs_conn is None or words_conn is None:
961- self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport',
962- 'This is not a valid Easy Worship 6 database.'))
963+ self.log_error(self.import_source, invalid_db_msg)
964 songs_conn.close()
965 words_conn.close()
966 return
967
968=== modified file 'openlp/plugins/songs/lib/importers/foilpresenter.py'
969--- openlp/plugins/songs/lib/importers/foilpresenter.py 2017-05-30 18:42:35 +0000
970+++ openlp/plugins/songs/lib/importers/foilpresenter.py 2017-09-30 23:24:21 +0000
971@@ -82,10 +82,8 @@
972 </kategorien>
973 </foilpresenterfolie>
974 """
975-
976 import logging
977 import re
978-import os
979
980 from lxml import etree, objectify
981
982@@ -121,10 +119,9 @@
983 for file_path in self.import_source:
984 if self.stop_import_flag:
985 return
986- self.import_wizard.increment_progress_bar(
987- WizardStrings.ImportingType.format(source=os.path.basename(file_path)))
988+ self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name))
989 try:
990- parsed_file = etree.parse(file_path, parser)
991+ parsed_file = etree.parse(str(file_path), parser)
992 xml = etree.tostring(parsed_file).decode()
993 self.foil_presenter.xml_to_song(xml)
994 except etree.XMLSyntaxError:
995
996=== modified file 'openlp/plugins/songs/lib/importers/lyrix.py'
997--- openlp/plugins/songs/lib/importers/lyrix.py 2016-12-31 11:01:36 +0000
998+++ openlp/plugins/songs/lib/importers/lyrix.py 2017-09-30 23:24:21 +0000
999@@ -50,12 +50,11 @@
1000 if not isinstance(self.import_source, list):
1001 return
1002 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1003- for filename in self.import_source:
1004+ for file_path in self.import_source:
1005 if self.stop_import_flag:
1006 return
1007- song_file = open(filename, 'rt', encoding='cp1251')
1008- self.do_import_file(song_file)
1009- song_file.close()
1010+ with file_path.open('rt', encoding='cp1251') as song_file:
1011+ self.do_import_file(song_file)
1012
1013 def do_import_file(self, file):
1014 """
1015
1016=== modified file 'openlp/plugins/songs/lib/importers/openlp.py'
1017--- openlp/plugins/songs/lib/importers/openlp.py 2017-05-30 18:42:35 +0000
1018+++ openlp/plugins/songs/lib/importers/openlp.py 2017-09-30 23:24:21 +0000
1019@@ -266,7 +266,7 @@
1020 if has_media_files and song.media_files:
1021 for media_file in song.media_files:
1022 existing_media_file = self.manager.get_object_filtered(
1023- MediaFile, MediaFile.file_name == media_file.file_name)
1024+ MediaFile, MediaFile.file_path == media_file.file_path)
1025 if existing_media_file:
1026 new_song.media_files.append(existing_media_file)
1027 else:
1028
1029=== modified file 'openlp/plugins/songs/lib/importers/openlyrics.py'
1030--- openlp/plugins/songs/lib/importers/openlyrics.py 2017-05-30 18:42:35 +0000
1031+++ openlp/plugins/songs/lib/importers/openlyrics.py 2017-09-30 23:24:21 +0000
1032@@ -23,9 +23,7 @@
1033 The :mod:`openlyrics` module provides the functionality for importing
1034 songs which are saved as OpenLyrics files.
1035 """
1036-
1037 import logging
1038-import os
1039
1040 from lxml import etree
1041
1042@@ -58,12 +56,11 @@
1043 for file_path in self.import_source:
1044 if self.stop_import_flag:
1045 return
1046- self.import_wizard.increment_progress_bar(
1047- WizardStrings.ImportingType.format(source=os.path.basename(file_path)))
1048+ self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name))
1049 try:
1050 # Pass a file object, because lxml does not cope with some
1051 # special characters in the path (see lp:757673 and lp:744337).
1052- parsed_file = etree.parse(open(file_path, 'rb'), parser)
1053+ parsed_file = etree.parse(file_path.open('rb'), parser)
1054 xml = etree.tostring(parsed_file).decode()
1055 self.open_lyrics.xml_to_song(xml)
1056 except etree.XMLSyntaxError:
1057
1058=== modified file 'openlp/plugins/songs/lib/importers/openoffice.py'
1059--- openlp/plugins/songs/lib/importers/openoffice.py 2016-12-31 11:01:36 +0000
1060+++ openlp/plugins/songs/lib/importers/openoffice.py 2017-09-30 23:24:21 +0000
1061@@ -20,7 +20,6 @@
1062 # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1063 ###############################################################################
1064 import logging
1065-import os
1066 import time
1067
1068 from PyQt5 import QtCore
1069@@ -70,12 +69,11 @@
1070 log.error(exc)
1071 return
1072 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1073- for filename in self.import_source:
1074+ for file_path in self.import_source:
1075 if self.stop_import_flag:
1076 break
1077- filename = str(filename)
1078- if os.path.isfile(filename):
1079- self.open_ooo_file(filename)
1080+ if file_path.is_file():
1081+ self.open_ooo_file(file_path)
1082 if self.document:
1083 self.process_ooo_document()
1084 self.close_ooo_file()
1085@@ -144,12 +142,7 @@
1086 Open the passed file in OpenOffice.org Impress
1087 """
1088 self.file_path = file_path
1089- if is_win():
1090- url = file_path.replace('\\', '/')
1091- url = url.replace(':', '|').replace(' ', '%20')
1092- url = 'file:///' + url
1093- else:
1094- url = uno.systemPathToFileUrl(file_path)
1095+ url = file_path.as_uri()
1096 properties = []
1097 properties.append(self.create_property('Hidden', True))
1098 properties = tuple(properties)
1099@@ -159,7 +152,7 @@
1100 self.document.supportsService("com.sun.star.text.TextDocument"):
1101 self.close_ooo_file()
1102 else:
1103- self.import_wizard.increment_progress_bar('Processing file ' + file_path, 0)
1104+ self.import_wizard.increment_progress_bar('Processing file {file_path}'.format(file_path=file_path), 0)
1105 except AttributeError:
1106 log.exception("open_ooo_file failed: {url}".format(url=url))
1107 return
1108
1109=== modified file 'openlp/plugins/songs/lib/importers/opensong.py'
1110--- openlp/plugins/songs/lib/importers/opensong.py 2017-02-26 21:14:49 +0000
1111+++ openlp/plugins/songs/lib/importers/opensong.py 2017-09-30 23:24:21 +0000
1112@@ -19,7 +19,6 @@
1113 # with this program; if not, write to the Free Software Foundation, Inc., 59 #
1114 # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1115 ###############################################################################
1116-
1117 import logging
1118 import re
1119
1120@@ -116,12 +115,11 @@
1121 if not isinstance(self.import_source, list):
1122 return
1123 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1124- for filename in self.import_source:
1125+ for file_path in self.import_source:
1126 if self.stop_import_flag:
1127 return
1128- song_file = open(filename, 'rb')
1129- self.do_import_file(song_file)
1130- song_file.close()
1131+ with file_path.open('rb') as song_file:
1132+ self.do_import_file(song_file)
1133
1134 def do_import_file(self, file):
1135 """
1136
1137=== modified file 'openlp/plugins/songs/lib/importers/opspro.py'
1138--- openlp/plugins/songs/lib/importers/opspro.py 2016-12-31 11:01:36 +0000
1139+++ openlp/plugins/songs/lib/importers/opspro.py 2017-09-30 23:24:21 +0000
1140@@ -231,16 +231,15 @@
1141 xor_pattern_2k = (0xa1, 0xec, 0x7a, 0x9c, 0xe1, 0x28, 0x34, 0x8a, 0x73, 0x7b, 0xd2, 0xdf, 0x50)
1142 # Access97 XOR of the source
1143 xor_pattern_97 = (0x86, 0xfb, 0xec, 0x37, 0x5d, 0x44, 0x9c, 0xfa, 0xc6, 0x5e, 0x28, 0xe6, 0x13)
1144- mdb = open(self.import_source, 'rb')
1145- mdb.seek(0x14)
1146- version = struct.unpack('B', mdb.read(1))[0]
1147- # Get encrypted logo
1148- mdb.seek(0x62)
1149- EncrypFlag = struct.unpack('B', mdb.read(1))[0]
1150- # Get encrypted password
1151- mdb.seek(0x42)
1152- encrypted_password = mdb.read(26)
1153- mdb.close()
1154+ with self.import_source.open('rb') as mdb_file:
1155+ mdb_file.seek(0x14)
1156+ version = struct.unpack('B', mdb_file.read(1))[0]
1157+ # Get encrypted logo
1158+ mdb_file.seek(0x62)
1159+ EncrypFlag = struct.unpack('B', mdb_file.read(1))[0]
1160+ # Get encrypted password
1161+ mdb_file.seek(0x42)
1162+ encrypted_password = mdb_file.read(26)
1163 # "Decrypt" the password based on the version
1164 decrypted_password = ''
1165 if version < 0x01:
1166
1167=== modified file 'openlp/plugins/songs/lib/importers/powerpraise.py'
1168--- openlp/plugins/songs/lib/importers/powerpraise.py 2017-05-30 18:42:35 +0000
1169+++ openlp/plugins/songs/lib/importers/powerpraise.py 2017-09-30 23:24:21 +0000
1170@@ -23,8 +23,6 @@
1171 The :mod:`powerpraiseimport` module provides the functionality for importing
1172 Powerpraise song files into the current database.
1173 """
1174-
1175-import os
1176 from lxml import objectify
1177
1178 from openlp.core.ui.lib.wizard import WizardStrings
1179@@ -41,10 +39,10 @@
1180 for file_path in self.import_source:
1181 if self.stop_import_flag:
1182 return
1183- self.import_wizard.increment_progress_bar(
1184- WizardStrings.ImportingType.format(source=os.path.basename(file_path)))
1185- root = objectify.parse(open(file_path, 'rb')).getroot()
1186- self.process_song(root)
1187+ self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name))
1188+ with file_path.open('rb') as xml_file:
1189+ root = objectify.parse(xml_file).getroot()
1190+ self.process_song(root)
1191
1192 def process_song(self, root):
1193 self.set_defaults()
1194
1195=== modified file 'openlp/plugins/songs/lib/importers/powersong.py'
1196--- openlp/plugins/songs/lib/importers/powersong.py 2016-12-31 11:01:36 +0000
1197+++ openlp/plugins/songs/lib/importers/powersong.py 2017-09-30 23:24:21 +0000
1198@@ -72,10 +72,14 @@
1199 Checks if source is a PowerSong 1.0 folder:
1200 * is a directory
1201 * contains at least one \*.song file
1202+
1203+ :param openlp.core.common.path.Path import_source: Should be a Path object that fulfills the above criteria
1204+ :return: If the source is valid
1205+ :rtype: bool
1206 """
1207- if os.path.isdir(import_source):
1208- for file in os.listdir(import_source):
1209- if fnmatch.fnmatch(file, '*.song'):
1210+ if import_source.is_dir():
1211+ for file_path in import_source.iterdir():
1212+ if file_path.suffix == '.song':
1213 return True
1214 return False
1215
1216
1217=== modified file 'openlp/plugins/songs/lib/importers/presentationmanager.py'
1218--- openlp/plugins/songs/lib/importers/presentationmanager.py 2017-05-30 18:42:35 +0000
1219+++ openlp/plugins/songs/lib/importers/presentationmanager.py 2017-09-30 23:24:21 +0000
1220@@ -23,13 +23,11 @@
1221 The :mod:`presentationmanager` module provides the functionality for importing
1222 Presentationmanager song files into the current database.
1223 """
1224-import os
1225 import re
1226
1227-import chardet
1228 from lxml import objectify, etree
1229
1230-from openlp.core.common import translate
1231+from openlp.core.common import get_file_encoding, translate
1232 from openlp.core.ui.lib.wizard import WizardStrings
1233 from .songimport import SongImport
1234
1235@@ -44,17 +42,14 @@
1236 for file_path in self.import_source:
1237 if self.stop_import_flag:
1238 return
1239- self.import_wizard.increment_progress_bar(
1240- WizardStrings.ImportingType.format(source=os.path.basename(file_path)))
1241+ self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name))
1242 try:
1243- tree = etree.parse(file_path, parser=etree.XMLParser(recover=True))
1244+ tree = etree.parse(str(file_path), parser=etree.XMLParser(recover=True))
1245 except etree.XMLSyntaxError:
1246 # Try to detect encoding and use it
1247- file = open(file_path, mode='rb')
1248- encoding = chardet.detect(file.read())['encoding']
1249- file.close()
1250+ encoding = get_file_encoding(file_path)['encoding']
1251 # Open file with detected encoding and remove encoding declaration
1252- text = open(file_path, mode='r', encoding=encoding).read()
1253+ text = file_path.read_text(encoding=encoding)
1254 text = re.sub('.+\?>\n', '', text)
1255 try:
1256 tree = etree.fromstring(text, parser=etree.XMLParser(recover=True))
1257@@ -80,6 +75,11 @@
1258 return ''
1259
1260 def process_song(self, root, file_path):
1261+ """
1262+ :param root:
1263+ :param openlp.core.common.path.Path file_path: Path to the file to process
1264+ :rtype: None
1265+ """
1266 self.set_defaults()
1267 attrs = None
1268 if hasattr(root, 'attributes'):
1269@@ -123,4 +123,4 @@
1270
1271 self.verse_order_list = verse_order_list
1272 if not self.finish():
1273- self.log_error(os.path.basename(file_path))
1274+ self.log_error(file_path.name)
1275
1276=== modified file 'openlp/plugins/songs/lib/importers/propresenter.py'
1277--- openlp/plugins/songs/lib/importers/propresenter.py 2017-05-30 18:42:35 +0000
1278+++ openlp/plugins/songs/lib/importers/propresenter.py 2017-09-30 23:24:21 +0000
1279@@ -23,8 +23,6 @@
1280 The :mod:`propresenter` module provides the functionality for importing
1281 ProPresenter song files into the current installation database.
1282 """
1283-
1284-import os
1285 import base64
1286 import logging
1287 from lxml import objectify
1288@@ -47,11 +45,17 @@
1289 if self.stop_import_flag:
1290 return
1291 self.import_wizard.increment_progress_bar(
1292- WizardStrings.ImportingType.format(source=os.path.basename(file_path)))
1293- root = objectify.parse(open(file_path, 'rb')).getroot()
1294- self.process_song(root, file_path)
1295+ WizardStrings.ImportingType.format(source=file_path.name))
1296+ with file_path.open('rb') as xml_file:
1297+ root = objectify.parse(xml_file).getroot()
1298+ self.process_song(root, file_path)
1299
1300- def process_song(self, root, filename):
1301+ def process_song(self, root, file_path):
1302+ """
1303+ :param root:
1304+ :param openlp.core.common.path.Path file_path: Path to the file thats being imported
1305+ :rtype: None
1306+ """
1307 self.set_defaults()
1308
1309 # Extract ProPresenter versionNumber
1310@@ -64,9 +68,7 @@
1311 # Title
1312 self.title = root.get('CCLISongTitle')
1313 if not self.title or self.title == '':
1314- self.title = os.path.basename(filename)
1315- if self.title[-5:-1] == '.pro':
1316- self.title = self.title[:-5]
1317+ self.title = file_path.stem
1318 # Notes
1319 self.comments = root.get('notes')
1320 # Author
1321
1322=== modified file 'openlp/plugins/songs/lib/importers/songbeamer.py'
1323--- openlp/plugins/songs/lib/importers/songbeamer.py 2017-08-25 20:03:25 +0000
1324+++ openlp/plugins/songs/lib/importers/songbeamer.py 2017-09-30 23:24:21 +0000
1325@@ -112,7 +112,7 @@
1326 if not isinstance(self.import_source, list):
1327 return
1328 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1329- for import_file in self.import_source:
1330+ for file_path in self.import_source:
1331 # TODO: check that it is a valid SongBeamer file
1332 if self.stop_import_flag:
1333 return
1334@@ -120,20 +120,19 @@
1335 self.current_verse = ''
1336 self.current_verse_type = VerseType.tags[VerseType.Verse]
1337 self.chord_table = None
1338- file_name = os.path.split(import_file)[1]
1339- if os.path.isfile(import_file):
1340+ if file_path.is_file():
1341 # Detect the encoding
1342- self.input_file_encoding = get_file_encoding(Path(import_file))['encoding']
1343+ self.input_file_encoding = get_file_encoding(file_path)['encoding']
1344 # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode.
1345 # So if it doesn't start with 'u' we default to cp1252. See:
1346 # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2
1347 if not self.input_file_encoding.lower().startswith('u'):
1348 self.input_file_encoding = 'cp1252'
1349- infile = open(import_file, 'rt', encoding=self.input_file_encoding)
1350- song_data = infile.readlines()
1351+ with file_path.open(encoding=self.input_file_encoding) as song_file:
1352+ song_data = song_file.readlines()
1353 else:
1354 continue
1355- self.title = file_name.split('.sng')[0]
1356+ self.title = file_path.stem
1357 read_verses = False
1358 # The first verse separator doesn't count, but the others does, so line count starts at -1
1359 line_number = -1
1360@@ -185,7 +184,7 @@
1361 # inserted by songbeamer, but are manually added headings. So restart the loop, and
1362 # count tags as lines.
1363 self.set_defaults()
1364- self.title = file_name.split('.sng')[0]
1365+ self.title = file_path.stem
1366 verse_tags_mode = VerseTagMode.ContainsNoTagsRestart
1367 read_verses = False
1368 # The first verseseparator doesn't count, but the others does, so linecount starts at -1
1369@@ -207,7 +206,7 @@
1370 self.replace_html_tags()
1371 self.add_verse(self.current_verse, self.current_verse_type)
1372 if not self.finish():
1373- self.log_error(import_file)
1374+ self.log_error(file_path)
1375
1376 def insert_chords(self, line_number, line):
1377 """
1378@@ -414,14 +413,15 @@
1379 """
1380 # The path is relative to SongBeamers Song folder
1381 if is_win():
1382- user_doc_folder = os.path.expandvars('$DOCUMENTS')
1383+ user_doc_path = Path(os.path.expandvars('$DOCUMENTS'))
1384 elif is_macosx():
1385- user_doc_folder = os.path.join(os.path.expanduser('~'), 'Documents')
1386+ user_doc_path = Path.home() / 'Documents'
1387 else:
1388 # SongBeamer only runs on mac and win...
1389 return
1390- audio_file_path = os.path.normpath(os.path.join(user_doc_folder, 'SongBeamer', 'Songs', audio_file_path))
1391- if os.path.isfile(audio_file_path):
1392+ audio_file_path = user_doc_path / 'SongBeamer' / 'Songs' / audio_file_path
1393+ if audio_file_path.is_file():
1394 self.add_media_file(audio_file_path)
1395 else:
1396- log.debug('Could not import mediafile "%s" since it does not exists!' % audio_file_path)
1397+ log.debug('Could not import mediafile "{audio_file_path}" since it does not exists!'
1398+ .format(audio_file_path=audio_file_path))
1399
1400=== modified file 'openlp/plugins/songs/lib/importers/songimport.py'
1401--- openlp/plugins/songs/lib/importers/songimport.py 2017-08-25 20:03:25 +0000
1402+++ openlp/plugins/songs/lib/importers/songimport.py 2017-09-30 23:24:21 +0000
1403@@ -22,13 +22,11 @@
1404
1405 import logging
1406 import re
1407-import shutil
1408-import os
1409
1410 from PyQt5 import QtCore
1411
1412 from openlp.core.common import Registry, AppLocation, check_directory_exists, translate
1413-from openlp.core.common.path import Path
1414+from openlp.core.common.path import copyfile
1415 from openlp.core.ui.lib.wizard import WizardStrings
1416 from openlp.plugins.songs.lib import clean_song, VerseType
1417 from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile
1418@@ -62,14 +60,14 @@
1419 """
1420 self.manager = manager
1421 QtCore.QObject.__init__(self)
1422- if 'filename' in kwargs:
1423- self.import_source = kwargs['filename']
1424- elif 'filenames' in kwargs:
1425- self.import_source = kwargs['filenames']
1426- elif 'folder' in kwargs:
1427- self.import_source = kwargs['folder']
1428+ if 'file_path' in kwargs:
1429+ self.import_source = kwargs['file_path']
1430+ elif 'file_paths' in kwargs:
1431+ self.import_source = kwargs['file_paths']
1432+ elif 'folder_path' in kwargs:
1433+ self.import_source = kwargs['folder_path']
1434 else:
1435- raise KeyError('Keyword arguments "filename[s]" or "folder" not supplied.')
1436+ raise KeyError('Keyword arguments "file_path[s]" or "folder_path" not supplied.')
1437 log.debug(self.import_source)
1438 self.import_wizard = None
1439 self.song = None
1440@@ -270,13 +268,13 @@
1441 return
1442 self.authors.append((author, type))
1443
1444- def add_media_file(self, filename, weight=0):
1445+ def add_media_file(self, file_path, weight=0):
1446 """
1447 Add a media file to the list
1448 """
1449- if filename in [x[0] for x in self.media_files]:
1450+ if file_path in [x[0] for x in self.media_files]:
1451 return
1452- self.media_files.append((filename, weight))
1453+ self.media_files.append((file_path, weight))
1454
1455 def add_verse(self, verse_text, verse_def='v', lang=None):
1456 """
1457@@ -403,29 +401,30 @@
1458 self.manager.save_object(song)
1459 # Now loop through the media files, copy them to the correct location,
1460 # and save the song again.
1461- for filename, weight in self.media_files:
1462- media_file = self.manager.get_object_filtered(MediaFile, MediaFile.file_name == filename)
1463+ for file_path, weight in self.media_files:
1464+ media_file = self.manager.get_object_filtered(MediaFile, MediaFile.file_path == file_path)
1465 if not media_file:
1466- if os.path.dirname(filename):
1467- filename = self.copy_media_file(song.id, filename)
1468- song.media_files.append(MediaFile.populate(file_name=filename, weight=weight))
1469+ if file_path.parent:
1470+ file_path = self.copy_media_file(song.id, file_path)
1471+ song.media_files.append(MediaFile.populate(file_path=file_path, weight=weight))
1472 self.manager.save_object(song)
1473 self.set_defaults()
1474 return True
1475
1476- def copy_media_file(self, song_id, filename):
1477+ def copy_media_file(self, song_id, file_path):
1478 """
1479 This method copies the media file to the correct location and returns
1480 the new file location.
1481
1482 :param song_id:
1483- :param filename: The file to copy.
1484+ :param openlp.core.common.path.Path file_path: The file to copy.
1485+ :return: The new location of the file
1486+ :rtype: openlp.core.common.path.Path
1487 """
1488 if not hasattr(self, 'save_path'):
1489- self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)),
1490- 'audio', str(song_id))
1491- check_directory_exists(Path(self.save_path))
1492- if not filename.startswith(self.save_path):
1493- old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1])
1494- shutil.copyfile(old_file, filename)
1495- return filename
1496+ self.save_path = AppLocation.get_section_data_path(self.import_wizard.plugin.name) / 'audio' / str(song_id)
1497+ check_directory_exists(self.save_path)
1498+ if self.save_path not in file_path.parents:
1499+ old_path, file_path = file_path, self.save_path / file_path.name
1500+ copyfile(old_path, file_path)
1501+ return file_path
1502
1503=== modified file 'openlp/plugins/songs/lib/importers/songpro.py'
1504--- openlp/plugins/songs/lib/importers/songpro.py 2016-12-31 11:01:36 +0000
1505+++ openlp/plugins/songs/lib/importers/songpro.py 2017-09-30 23:24:21 +0000
1506@@ -25,6 +25,7 @@
1507 """
1508 import re
1509
1510+from openlp.core.common.path import Path
1511 from openlp.plugins.songs.lib import strip_rtf
1512 from openlp.plugins.songs.lib.importers.songimport import SongImport
1513
1514@@ -72,7 +73,8 @@
1515 Receive a single file or a list of files to import.
1516 """
1517 self.encoding = None
1518- with open(self.import_source, 'rt', errors='ignore') as songs_file:
1519+ self.import_source = Path(self.import_source)
1520+ with self.import_source.open('rt', errors='ignore') as songs_file:
1521 self.import_wizard.progress_bar.setMaximum(0)
1522 tag = ''
1523 text = ''
1524
1525=== modified file 'openlp/plugins/songs/lib/importers/songshowplus.py'
1526--- openlp/plugins/songs/lib/importers/songshowplus.py 2017-06-01 06:18:47 +0000
1527+++ openlp/plugins/songs/lib/importers/songshowplus.py 2017-09-30 23:24:21 +0000
1528@@ -23,7 +23,6 @@
1529 The :mod:`songshowplus` module provides the functionality for importing SongShow Plus songs into the OpenLP
1530 database.
1531 """
1532-import os
1533 import logging
1534 import re
1535 import struct
1536@@ -93,97 +92,95 @@
1537 if not isinstance(self.import_source, list):
1538 return
1539 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1540- for file in self.import_source:
1541+ for file_path in self.import_source:
1542 if self.stop_import_flag:
1543 return
1544 self.ssp_verse_order_list = []
1545 self.other_count = 0
1546 self.other_list = {}
1547- file_name = os.path.split(file)[1]
1548- self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_name), 0)
1549- song_data = open(file, 'rb')
1550- while True:
1551- block_key, = struct.unpack("I", song_data.read(4))
1552- log.debug('block_key: %d' % block_key)
1553- # The file ends with 4 NULL's
1554- if block_key == 0:
1555- break
1556- next_block_starts, = struct.unpack("I", song_data.read(4))
1557- next_block_starts += song_data.tell()
1558- if block_key in (VERSE, CHORUS, BRIDGE):
1559- null, verse_no, = struct.unpack("BB", song_data.read(2))
1560- elif block_key == CUSTOM_VERSE:
1561- null, verse_name_length, = struct.unpack("BB", song_data.read(2))
1562- verse_name = self.decode(song_data.read(verse_name_length))
1563- length_descriptor_size, = struct.unpack("B", song_data.read(1))
1564- log.debug('length_descriptor_size: %d' % length_descriptor_size)
1565- # In the case of song_numbers the number is in the data from the
1566- # current position to the next block starts
1567- if block_key == SONG_NUMBER:
1568- sn_bytes = song_data.read(length_descriptor_size - 1)
1569- self.song_number = int.from_bytes(sn_bytes, byteorder='little')
1570- continue
1571- # Detect if/how long the length descriptor is
1572- if length_descriptor_size == 12 or length_descriptor_size == 20:
1573- length_descriptor, = struct.unpack("I", song_data.read(4))
1574- elif length_descriptor_size == 2:
1575- length_descriptor = 1
1576- elif length_descriptor_size == 9:
1577- length_descriptor = 0
1578- else:
1579- length_descriptor, = struct.unpack("B", song_data.read(1))
1580- log.debug('length_descriptor: %d' % length_descriptor)
1581- data = song_data.read(length_descriptor)
1582- log.debug(data)
1583- if block_key == TITLE:
1584- self.title = self.decode(data)
1585- elif block_key == AUTHOR:
1586- authors = self.decode(data).split(" / ")
1587- for author in authors:
1588- if author.find(",") != -1:
1589- author_parts = author.split(", ")
1590- author = author_parts[1] + " " + author_parts[0]
1591- self.parse_author(author)
1592- elif block_key == COPYRIGHT:
1593- self.add_copyright(self.decode(data))
1594- elif block_key == CCLI_NO:
1595- # Try to get the CCLI number even if the field contains additional text
1596- match = re.search(r'\d+', self.decode(data))
1597- if match:
1598- self.ccli_number = int(match.group())
1599- else:
1600- log.warning("Can't parse CCLI Number from string: {text}".format(text=self.decode(data)))
1601- elif block_key == VERSE:
1602- self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Verse],
1603- number=verse_no))
1604- elif block_key == CHORUS:
1605- self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Chorus],
1606- number=verse_no))
1607- elif block_key == BRIDGE:
1608- self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Bridge],
1609- number=verse_no))
1610- elif block_key == TOPIC:
1611- self.topics.append(self.decode(data))
1612- elif block_key == COMMENTS:
1613- self.comments = self.decode(data)
1614- elif block_key == VERSE_ORDER:
1615- verse_tag = self.to_openlp_verse_tag(self.decode(data), True)
1616- if verse_tag:
1617- if not isinstance(verse_tag, str):
1618- verse_tag = self.decode(verse_tag)
1619- self.ssp_verse_order_list.append(verse_tag)
1620- elif block_key == SONG_BOOK:
1621- self.song_book_name = self.decode(data)
1622- elif block_key == CUSTOM_VERSE:
1623- verse_tag = self.to_openlp_verse_tag(verse_name)
1624- self.add_verse(self.decode(data), verse_tag)
1625- else:
1626- log.debug("Unrecognised blockKey: {key}, data: {data}".format(key=block_key, data=data))
1627- song_data.seek(next_block_starts)
1628- self.verse_order_list = self.ssp_verse_order_list
1629- song_data.close()
1630- if not self.finish():
1631- self.log_error(file)
1632+ self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name), 0)
1633+ with file_path.open('rb') as song_file:
1634+ while True:
1635+ block_key, = struct.unpack("I", song_file.read(4))
1636+ log.debug('block_key: %d' % block_key)
1637+ # The file ends with 4 NULL's
1638+ if block_key == 0:
1639+ break
1640+ next_block_starts, = struct.unpack("I", song_file.read(4))
1641+ next_block_starts += song_file.tell()
1642+ if block_key in (VERSE, CHORUS, BRIDGE):
1643+ null, verse_no, = struct.unpack("BB", song_file.read(2))
1644+ elif block_key == CUSTOM_VERSE:
1645+ null, verse_name_length, = struct.unpack("BB", song_file.read(2))
1646+ verse_name = self.decode(song_file.read(verse_name_length))
1647+ length_descriptor_size, = struct.unpack("B", song_file.read(1))
1648+ log.debug('length_descriptor_size: %d' % length_descriptor_size)
1649+ # In the case of song_numbers the number is in the data from the
1650+ # current position to the next block starts
1651+ if block_key == SONG_NUMBER:
1652+ sn_bytes = song_file.read(length_descriptor_size - 1)
1653+ self.song_number = int.from_bytes(sn_bytes, byteorder='little')
1654+ continue
1655+ # Detect if/how long the length descriptor is
1656+ if length_descriptor_size == 12 or length_descriptor_size == 20:
1657+ length_descriptor, = struct.unpack("I", song_file.read(4))
1658+ elif length_descriptor_size == 2:
1659+ length_descriptor = 1
1660+ elif length_descriptor_size == 9:
1661+ length_descriptor = 0
1662+ else:
1663+ length_descriptor, = struct.unpack("B", song_file.read(1))
1664+ log.debug('length_descriptor: %d' % length_descriptor)
1665+ data = song_file.read(length_descriptor)
1666+ log.debug(data)
1667+ if block_key == TITLE:
1668+ self.title = self.decode(data)
1669+ elif block_key == AUTHOR:
1670+ authors = self.decode(data).split(" / ")
1671+ for author in authors:
1672+ if author.find(",") != -1:
1673+ author_parts = author.split(", ")
1674+ author = author_parts[1] + " " + author_parts[0]
1675+ self.parse_author(author)
1676+ elif block_key == COPYRIGHT:
1677+ self.add_copyright(self.decode(data))
1678+ elif block_key == CCLI_NO:
1679+ # Try to get the CCLI number even if the field contains additional text
1680+ match = re.search(r'\d+', self.decode(data))
1681+ if match:
1682+ self.ccli_number = int(match.group())
1683+ else:
1684+ log.warning("Can't parse CCLI Number from string: {text}".format(text=self.decode(data)))
1685+ elif block_key == VERSE:
1686+ self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Verse],
1687+ number=verse_no))
1688+ elif block_key == CHORUS:
1689+ self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Chorus],
1690+ number=verse_no))
1691+ elif block_key == BRIDGE:
1692+ self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Bridge],
1693+ number=verse_no))
1694+ elif block_key == TOPIC:
1695+ self.topics.append(self.decode(data))
1696+ elif block_key == COMMENTS:
1697+ self.comments = self.decode(data)
1698+ elif block_key == VERSE_ORDER:
1699+ verse_tag = self.to_openlp_verse_tag(self.decode(data), True)
1700+ if verse_tag:
1701+ if not isinstance(verse_tag, str):
1702+ verse_tag = self.decode(verse_tag)
1703+ self.ssp_verse_order_list.append(verse_tag)
1704+ elif block_key == SONG_BOOK:
1705+ self.song_book_name = self.decode(data)
1706+ elif block_key == CUSTOM_VERSE:
1707+ verse_tag = self.to_openlp_verse_tag(verse_name)
1708+ self.add_verse(self.decode(data), verse_tag)
1709+ else:
1710+ log.debug("Unrecognised blockKey: {key}, data: {data}".format(key=block_key, data=data))
1711+ song_file.seek(next_block_starts)
1712+ self.verse_order_list = self.ssp_verse_order_list
1713+ if not self.finish():
1714+ self.log_error(file_path)
1715
1716 def to_openlp_verse_tag(self, verse_name, ignore_unique=False):
1717 """
1718
1719=== modified file 'openlp/plugins/songs/lib/importers/sundayplus.py'
1720--- openlp/plugins/songs/lib/importers/sundayplus.py 2016-12-31 11:01:36 +0000
1721+++ openlp/plugins/songs/lib/importers/sundayplus.py 2017-09-30 23:24:21 +0000
1722@@ -19,11 +19,8 @@
1723 # with this program; if not, write to the Free Software Foundation, Inc., 59 #
1724 # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1725 ###############################################################################
1726-
1727 import os
1728 import re
1729-import logging
1730-
1731
1732 from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding
1733 from openlp.plugins.songs.lib import strip_rtf
1734@@ -60,12 +57,11 @@
1735
1736 def do_import(self):
1737 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1738- for filename in self.import_source:
1739+ for file_path in self.import_source:
1740 if self.stop_import_flag:
1741 return
1742- song_file = open(filename, 'rb')
1743- self.do_import_file(song_file)
1744- song_file.close()
1745+ with file_path.open('rb') as song_file:
1746+ self.do_import_file(song_file)
1747
1748 def do_import_file(self, file):
1749 """
1750
1751=== modified file 'openlp/plugins/songs/lib/importers/videopsalm.py'
1752--- openlp/plugins/songs/lib/importers/videopsalm.py 2017-02-26 21:14:49 +0000
1753+++ openlp/plugins/songs/lib/importers/videopsalm.py 2017-09-30 23:24:21 +0000
1754@@ -22,13 +22,12 @@
1755 """
1756 The :mod:`lyrix` module provides the functionality for importing songs which are
1757 exproted from Lyrix."""
1758-
1759+import json
1760 import logging
1761-import json
1762-import os
1763 import re
1764
1765 from openlp.core.common import translate, Settings
1766+from openlp.core.common.path import Path
1767 from openlp.plugins.songs.lib.importers.songimport import SongImport
1768 from openlp.plugins.songs.lib.db import AuthorType
1769
1770@@ -50,11 +49,10 @@
1771 """
1772 Process the VideoPsalm file - pass in a file-like object, not a file path.
1773 """
1774+ self.import_source = Path(self.import_source)
1775 self.set_defaults()
1776- # Open SongBook file
1777- song_file = open(self.import_source, 'rt', encoding='utf-8-sig')
1778 try:
1779- file_content = song_file.read()
1780+ file_content = self.import_source.read_text(encoding='utf-8-sig')
1781 processed_content = ''
1782 inside_quotes = False
1783 # The VideoPsalm format is not valid json, it uses illegal line breaks and unquoted keys, this must be fixed
1784@@ -89,7 +87,7 @@
1785 songs = songbook['Songs']
1786 self.import_wizard.progress_bar.setMaximum(len(songs))
1787 songbook_name = songbook['Text']
1788- media_folder = os.path.normpath(os.path.join(os.path.dirname(song_file.name), '..', 'Audio'))
1789+ media_path = Path('..', 'Audio')
1790 for song in songs:
1791 self.song_book_name = songbook_name
1792 if 'Text' in song:
1793@@ -114,7 +112,7 @@
1794 if 'Theme' in song:
1795 self.topics = song['Theme'].splitlines()
1796 if 'AudioFile' in song:
1797- self.add_media_file(os.path.join(media_folder, song['AudioFile']))
1798+ self.add_media_file(media_path / song['AudioFile'])
1799 if 'Memo1' in song:
1800 self.add_comment(song['Memo1'])
1801 if 'Memo2' in song:
1802@@ -132,4 +130,5 @@
1803 if not self.finish():
1804 self.log_error('Could not import {title}'.format(title=self.title))
1805 except Exception as e:
1806- self.log_error(song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e))
1807+ self.log_error(self.import_source.name,
1808+ translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e))
1809
1810=== modified file 'openlp/plugins/songs/lib/importers/wordsofworship.py'
1811--- openlp/plugins/songs/lib/importers/wordsofworship.py 2016-12-31 11:01:36 +0000
1812+++ openlp/plugins/songs/lib/importers/wordsofworship.py 2017-09-30 23:24:21 +0000
1813@@ -25,6 +25,7 @@
1814 """
1815 import os
1816 import logging
1817+from openlp.core.common.path import Path
1818
1819 from openlp.core.common import translate
1820 from openlp.plugins.songs.lib.importers.songimport import SongImport
1821@@ -100,62 +101,60 @@
1822 """
1823 if isinstance(self.import_source, list):
1824 self.import_wizard.progress_bar.setMaximum(len(self.import_source))
1825- for source in self.import_source:
1826+ for file_path in self.import_source:
1827 if self.stop_import_flag:
1828 return
1829 self.set_defaults()
1830- song_data = open(source, 'rb')
1831- if song_data.read(19).decode() != 'WoW File\nSong Words':
1832- self.log_error(source,
1833- translate('SongsPlugin.WordsofWorshipSongImport',
1834- 'Invalid Words of Worship song file. Missing "{text}" '
1835- 'header.').format(text='WoW File\\nSong Words'))
1836- continue
1837- # Seek to byte which stores number of blocks in the song
1838- song_data.seek(56)
1839- no_of_blocks = ord(song_data.read(1))
1840- song_data.seek(66)
1841- if song_data.read(16).decode() != 'CSongDoc::CBlock':
1842- self.log_error(source,
1843- translate('SongsPlugin.WordsofWorshipSongImport',
1844- 'Invalid Words of Worship song file. Missing "{text}" '
1845- 'string.').format(text='CSongDoc::CBlock'))
1846- continue
1847- # Seek to the beginning of the first block
1848- song_data.seek(82)
1849- for block in range(no_of_blocks):
1850- skip_char_at_end = True
1851- self.lines_to_read = ord(song_data.read(4)[:1])
1852- block_text = ''
1853- while self.lines_to_read:
1854- self.line_text = str(song_data.read(ord(song_data.read(1))), 'cp1252')
1855- if skip_char_at_end:
1856- skip_char = ord(song_data.read(1))
1857- # Check if we really should skip a char. In some wsg files we shouldn't
1858- if skip_char != 0:
1859- song_data.seek(-1, os.SEEK_CUR)
1860- skip_char_at_end = False
1861- if block_text:
1862- block_text += '\n'
1863- block_text += self.line_text
1864- self.lines_to_read -= 1
1865- block_type = BLOCK_TYPES[ord(song_data.read(4)[:1])]
1866- # Blocks are separated by 2 bytes, skip them, but not if
1867- # this is the last block!
1868- if block + 1 < no_of_blocks:
1869- song_data.seek(2, os.SEEK_CUR)
1870- self.add_verse(block_text, block_type)
1871- # Now to extract the author
1872- author_length = ord(song_data.read(1))
1873- if author_length:
1874- self.parse_author(str(song_data.read(author_length), 'cp1252'))
1875- # Finally the copyright
1876- copyright_length = ord(song_data.read(1))
1877- if copyright_length:
1878- self.add_copyright(str(song_data.read(copyright_length), 'cp1252'))
1879- file_name = os.path.split(source)[1]
1880- # Get the song title
1881- self.title = file_name.rpartition('.')[0]
1882- song_data.close()
1883- if not self.finish():
1884- self.log_error(source)
1885+ with file_path.open('rb') as song_data:
1886+ if song_data.read(19).decode() != 'WoW File\nSong Words':
1887+ self.log_error(file_path,
1888+ translate('SongsPlugin.WordsofWorshipSongImport',
1889+ 'Invalid Words of Worship song file. Missing "{text}" '
1890+ 'header.').format(text='WoW File\\nSong Words'))
1891+ continue
1892+ # Seek to byte which stores number of blocks in the song
1893+ song_data.seek(56)
1894+ no_of_blocks = ord(song_data.read(1))
1895+ song_data.seek(66)
1896+ if song_data.read(16).decode() != 'CSongDoc::CBlock':
1897+ self.log_error(file_path,
1898+ translate('SongsPlugin.WordsofWorshipSongImport',
1899+ 'Invalid Words of Worship song file. Missing "{text}" '
1900+ 'string.').format(text='CSongDoc::CBlock'))
1901+ continue
1902+ # Seek to the beginning of the first block
1903+ song_data.seek(82)
1904+ for block in range(no_of_blocks):
1905+ skip_char_at_end = True
1906+ self.lines_to_read = ord(song_data.read(4)[:1])
1907+ block_text = ''
1908+ while self.lines_to_read:
1909+ self.line_text = str(song_data.read(ord(song_data.read(1))), 'cp1252')
1910+ if skip_char_at_end:
1911+ skip_char = ord(song_data.read(1))
1912+ # Check if we really should skip a char. In some wsg files we shouldn't
1913+ if skip_char != 0:
1914+ song_data.seek(-1, os.SEEK_CUR)
1915+ skip_char_at_end = False
1916+ if block_text:
1917+ block_text += '\n'
1918+ block_text += self.line_text
1919+ self.lines_to_read -= 1
1920+ block_type = BLOCK_TYPES[ord(song_data.read(4)[:1])]
1921+ # Blocks are separated by 2 bytes, skip them, but not if
1922+ # this is the last block!
1923+ if block + 1 < no_of_blocks:
1924+ song_data.seek(2, os.SEEK_CUR)
1925+ self.add_verse(block_text, block_type)
1926+ # Now to extract the author
1927+ author_length = ord(song_data.read(1))
1928+ if author_length:
1929+ self.parse_author(str(song_data.read(author_length), 'cp1252'))
1930+ # Finally the copyright
1931+ copyright_length = ord(song_data.read(1))
1932+ if copyright_length:
1933+ self.add_copyright(str(song_data.read(copyright_length), 'cp1252'))
1934+ # Get the song title
1935+ self.title = file_path.stem
1936+ if not self.finish():
1937+ self.log_error(file_path)
1938
1939=== modified file 'openlp/plugins/songs/lib/importers/worshipassistant.py'
1940--- openlp/plugins/songs/lib/importers/worshipassistant.py 2016-12-31 11:01:36 +0000
1941+++ openlp/plugins/songs/lib/importers/worshipassistant.py 2017-09-30 23:24:21 +0000
1942@@ -28,7 +28,7 @@
1943 import logging
1944 import re
1945
1946-from openlp.core.common import translate
1947+from openlp.core.common import get_file_encoding, translate
1948 from openlp.plugins.songs.lib import VerseType
1949 from openlp.plugins.songs.lib.importers.songimport import SongImport
1950
1951@@ -81,19 +81,16 @@
1952 Receive a CSV file to import.
1953 """
1954 # Get encoding
1955- detect_file = open(self.import_source, 'rb')
1956- detect_content = detect_file.read()
1957- details = chardet.detect(detect_content)
1958- detect_file.close()
1959- songs_file = open(self.import_source, 'r', encoding=details['encoding'])
1960- songs_reader = csv.DictReader(songs_file, escapechar='\\')
1961- try:
1962- records = list(songs_reader)
1963- except csv.Error as e:
1964- self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'),
1965- translate('SongsPlugin.WorshipAssistantImport',
1966- 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e))
1967- return
1968+ encoding = get_file_encoding(self.import_source)['encoding']
1969+ with self.import_source.open('r', encoding=encoding) as songs_file:
1970+ songs_reader = csv.DictReader(songs_file, escapechar='\\')
1971+ try:
1972+ records = list(songs_reader)
1973+ except csv.Error as e:
1974+ self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'),
1975+ translate('SongsPlugin.WorshipAssistantImport',
1976+ 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e))
1977+ return
1978 num_records = len(records)
1979 log.info('{count} records found in CSV file'.format(count=num_records))
1980 self.import_wizard.progress_bar.setMaximum(num_records)
1981@@ -185,4 +182,3 @@
1982 self.log_error(translate('SongsPlugin.WorshipAssistantImport',
1983 'Record {count:d}').format(count=index) +
1984 (': "' + self.title + '"' if self.title else ''))
1985- songs_file.close()
1986
1987=== modified file 'openlp/plugins/songs/lib/importers/zionworx.py'
1988--- openlp/plugins/songs/lib/importers/zionworx.py 2016-12-31 11:01:36 +0000
1989+++ openlp/plugins/songs/lib/importers/zionworx.py 2017-09-30 23:24:21 +0000
1990@@ -76,7 +76,7 @@
1991 Receive a CSV file (from a ZionWorx database dump) to import.
1992 """
1993 # Encoding should always be ISO-8859-1
1994- with open(self.import_source, 'rt', encoding='ISO-8859-1') as songs_file:
1995+ with self.import_source.open('rt', encoding='ISO-8859-1') as songs_file:
1996 field_names = ['SongNum', 'Title1', 'Title2', 'Lyrics', 'Writer', 'Copyright', 'Keywords',
1997 'DefaultStyle']
1998 songs_reader = csv.DictReader(songs_file, field_names)
1999
2000=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
2001--- openlp/plugins/songs/lib/mediaitem.py 2017-08-25 20:03:25 +0000
2002+++ openlp/plugins/songs/lib/mediaitem.py 2017-09-30 23:24:21 +0000
2003@@ -22,25 +22,24 @@
2004
2005 import logging
2006 import os
2007-import shutil
2008
2009 from PyQt5 import QtCore, QtWidgets
2010 from sqlalchemy.sql import and_, or_
2011
2012 from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate
2013-from openlp.core.common.path import Path
2014+from openlp.core.common.languagemanager import get_natural_key
2015+from openlp.core.common.path import copyfile
2016 from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \
2017 check_item_selected, create_separated_list
2018 from openlp.core.lib.ui import create_widget_action
2019-from openlp.core.common.languagemanager import get_natural_key
2020 from openlp.plugins.songs.forms.editsongform import EditSongForm
2021+from openlp.plugins.songs.forms.songexportform import SongExportForm
2022+from openlp.plugins.songs.forms.songimportform import SongImportForm
2023 from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
2024-from openlp.plugins.songs.forms.songimportform import SongImportForm
2025-from openlp.plugins.songs.forms.songexportform import SongExportForm
2026 from openlp.plugins.songs.lib import VerseType, clean_string, delete_song
2027 from openlp.plugins.songs.lib.db import Author, AuthorType, Song, Book, MediaFile, SongBookEntry, Topic
2028+from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, SongXML
2029 from openlp.plugins.songs.lib.ui import SongStrings
2030-from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, SongXML
2031
2032 log = logging.getLogger(__name__)
2033
2034@@ -88,11 +87,11 @@
2035 def _update_background_audio(self, song, item):
2036 song.media_files = []
2037 for i, bga in enumerate(item.background_audio):
2038- dest_file = os.path.join(
2039- str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1])
2040- check_directory_exists(Path(os.path.split(dest_file)[0]))
2041- shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file)
2042- song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
2043+ dest_path =\
2044+ AppLocation.get_section_data_path(self.plugin.name) / 'audio' / str(song.id) / os.path.split(bga)[1]
2045+ check_directory_exists(dest_path.parent)
2046+ copyfile(AppLocation.get_section_data_path('servicemanager') / bga, dest_path)
2047+ song.media_files.append(MediaFile.populate(weight=i, file_path=dest_path))
2048 self.plugin.manager.save_object(song, True)
2049
2050 def add_end_header_bar(self):
2051@@ -534,14 +533,13 @@
2052 'copy', 'For song cloning'))
2053 # Copy audio files from the old to the new song
2054 if len(old_song.media_files) > 0:
2055- save_path = os.path.join(
2056- str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id))
2057- check_directory_exists(Path(save_path))
2058+ save_path = AppLocation.get_section_data_path(self.plugin.name) / 'audio' / str(new_song.id)
2059+ check_directory_exists(save_path)
2060 for media_file in old_song.media_files:
2061- new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))
2062- shutil.copyfile(media_file.file_name, new_media_file_name)
2063+ new_media_file_path = save_path / media_file.file_path.name
2064+ copyfile(media_file.file_path, new_media_file_path)
2065 new_media_file = MediaFile()
2066- new_media_file.file_name = new_media_file_name
2067+ new_media_file.file_path = new_media_file_path
2068 new_media_file.type = media_file.type
2069 new_media_file.weight = media_file.weight
2070 new_song.media_files.append(new_media_file)
2071@@ -613,7 +611,7 @@
2072 # Add the audio file to the service item.
2073 if song.media_files:
2074 service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
2075- service_item.background_audio = [m.file_name for m in song.media_files]
2076+ service_item.background_audio = [m.file_path for m in song.media_files]
2077 return True
2078
2079 def generate_footer(self, item, song):
2080
2081=== modified file 'openlp/plugins/songs/lib/openlyricsexport.py'
2082--- openlp/plugins/songs/lib/openlyricsexport.py 2017-08-25 20:03:25 +0000
2083+++ openlp/plugins/songs/lib/openlyricsexport.py 2017-09-30 23:24:21 +0000
2084@@ -24,12 +24,10 @@
2085 format.
2086 """
2087 import logging
2088-import os
2089
2090 from lxml import etree
2091
2092 from openlp.core.common import RegistryProperties, check_directory_exists, translate, clean_filename
2093-from openlp.core.common.path import Path
2094 from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
2095
2096 log = logging.getLogger(__name__)
2097@@ -42,13 +40,16 @@
2098 def __init__(self, parent, songs, save_path):
2099 """
2100 Initialise the export.
2101+
2102+ :param openlp.core.common.path.Path save_path: The directory to save the exported songs in
2103+ :rtype: None
2104 """
2105 log.debug('initialise OpenLyricsExport')
2106 self.parent = parent
2107 self.manager = parent.plugin.manager
2108 self.songs = songs
2109 self.save_path = save_path
2110- check_directory_exists(Path(self.save_path))
2111+ check_directory_exists(self.save_path)
2112
2113 def do_export(self):
2114 """
2115@@ -69,15 +70,15 @@
2116 author=', '.join([author.display_name for author in song.authors]))
2117 filename = clean_filename(filename)
2118 # Ensure the filename isn't too long for some filesystems
2119- filename_with_ext = '{name}.xml'.format(name=filename[0:250 - len(self.save_path)])
2120+ path_length = len(str(self.save_path))
2121+ filename_with_ext = '{name}.xml'.format(name=filename[0:250 - path_length])
2122 # Make sure we're not overwriting an existing file
2123 conflicts = 0
2124- while os.path.exists(os.path.join(self.save_path, filename_with_ext)):
2125+ while (self.save_path / filename_with_ext).exists():
2126 conflicts += 1
2127- filename_with_ext = '{name}-{extra}.xml'.format(name=filename[0:247 - len(self.save_path)],
2128- extra=conflicts)
2129+ filename_with_ext = '{name}-{extra}.xml'.format(name=filename[0:247 - path_length], extra=conflicts)
2130 # Pass a file object, because lxml does not cope with some special
2131 # characters in the path (see lp:757673 and lp:744337).
2132- tree.write(open(os.path.join(self.save_path, filename_with_ext), 'wb'), encoding='utf-8',
2133- xml_declaration=True, pretty_print=True)
2134+ with (self.save_path / filename_with_ext).open('wb') as out_file:
2135+ tree.write(out_file, encoding='utf-8', xml_declaration=True, pretty_print=True)
2136 return True
2137
2138=== modified file 'openlp/plugins/songs/lib/upgrade.py'
2139--- openlp/plugins/songs/lib/upgrade.py 2017-06-10 05:57:00 +0000
2140+++ openlp/plugins/songs/lib/upgrade.py 2017-09-30 23:24:21 +0000
2141@@ -23,16 +23,20 @@
2142 The :mod:`upgrade` module provides a way for the database and schema that is the
2143 backend for the Songs plugin
2144 """
2145+import json
2146 import logging
2147
2148 from sqlalchemy import Table, Column, ForeignKey, types
2149 from sqlalchemy.sql.expression import func, false, null, text
2150
2151+from openlp.core.common import AppLocation
2152 from openlp.core.common.db import drop_columns
2153-from openlp.core.lib.db import get_upgrade_op
2154+from openlp.core.common.json import OpenLPJsonEncoder
2155+from openlp.core.common.path import Path
2156+from openlp.core.lib.db import PathType, get_upgrade_op
2157
2158 log = logging.getLogger(__name__)
2159-__version__ = 6
2160+__version__ = 7
2161
2162
2163 # TODO: When removing an upgrade path the ftw-data needs updating to the minimum supported version
2164@@ -162,3 +166,28 @@
2165 op.drop_column('songs', 'song_number')
2166 # Finally, clean up our mess in people's databases
2167 op.execute('DELETE FROM songs_songbooks WHERE songbook_id = 0')
2168+
2169+
2170+def upgrade_7(session, metadata):
2171+ """
2172+ Version 7 upgrade - Move file path from old db to JSON encoded path to new db. Upgrade added in 2.5 dev
2173+ """
2174+ log.debug('Starting upgrade_7 for file_path to JSON')
2175+ old_table = Table('media_files', metadata, autoload=True)
2176+ if 'file_path' not in [col.name for col in old_table.c.values()]:
2177+ op = get_upgrade_op(session)
2178+ op.add_column('media_files', Column('file_path', PathType()))
2179+ conn = op.get_bind()
2180+ results = conn.execute('SELECT * FROM media_files')
2181+ data_path = AppLocation.get_data_path()
2182+ for row in results.fetchall():
2183+ file_path_json = json.dumps(Path(row.file_name), cls=OpenLPJsonEncoder, base_path=data_path)
2184+ sql = 'UPDATE media_files SET file_path = \'{file_path_json}\' WHERE id = {id}'.format(
2185+ file_path_json=file_path_json, id=row.id)
2186+ conn.execute(sql)
2187+ # Drop old columns
2188+ if metadata.bind.url.get_dialect().name == 'sqlite':
2189+ drop_columns(op, 'media_files', ['file_name', ])
2190+ else:
2191+ op.drop_constraint('media_files', 'foreignkey')
2192+ op.drop_column('media_files', 'filenames')
2193
2194=== modified file 'openlp/plugins/songs/reporting.py'
2195--- openlp/plugins/songs/reporting.py 2017-09-07 21:52:39 +0000
2196+++ openlp/plugins/songs/reporting.py 2017-09-30 23:24:21 +0000
2197@@ -31,7 +31,6 @@
2198 from openlp.core.ui.lib.filedialog import FileDialog
2199 from openlp.plugins.songs.lib.db import Song
2200
2201-
2202 log = logging.getLogger(__name__)
2203
2204
2205@@ -58,9 +57,9 @@
2206 report_file_path.with_suffix('.csv')
2207 Registry().get('application').set_busy_cursor()
2208 try:
2209- with report_file_path.open('wt') as file_handle:
2210+ with report_file_path.open('wt') as export_file:
2211 fieldnames = ('Title', 'Alternative Title', 'Copyright', 'Author(s)', 'Song Book', 'Topic')
2212- writer = csv.DictWriter(file_handle, fieldnames=fieldnames, quoting=csv.QUOTE_ALL)
2213+ writer = csv.DictWriter(export_file, fieldnames=fieldnames, quoting=csv.QUOTE_ALL)
2214 headers = dict((n, n) for n in fieldnames)
2215 writer.writerow(headers)
2216 song_list = plugin.manager.get_all_objects(Song)
2217
2218=== modified file 'openlp/plugins/songs/songsplugin.py'
2219--- openlp/plugins/songs/songsplugin.py 2017-08-26 15:06:11 +0000
2220+++ openlp/plugins/songs/songsplugin.py 2017-09-30 23:24:21 +0000
2221@@ -37,7 +37,6 @@
2222 from openlp.core.lib import Plugin, StringContent, build_icon
2223 from openlp.core.lib.db import Manager
2224 from openlp.core.lib.ui import create_action
2225-
2226 from openlp.plugins.songs import reporting
2227 from openlp.plugins.songs.endpoint import api_songs_endpoint, songs_endpoint
2228 from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm
2229@@ -50,7 +49,6 @@
2230 from openlp.plugins.songs.lib.mediaitem import SongSearch
2231 from openlp.plugins.songs.lib.songstab import SongsTab
2232
2233-
2234 log = logging.getLogger(__name__)
2235 __default_settings__ = {
2236 'songs/db type': 'sqlite',
2237@@ -340,7 +338,7 @@
2238 progress.forceShow()
2239 self.application.process_events()
2240 for db in song_dbs:
2241- importer = OpenLPSongImport(self.manager, filename=db)
2242+ importer = OpenLPSongImport(self.manager, file_path=db)
2243 importer.do_import(progress)
2244 self.application.process_events()
2245 progress.setValue(song_count)
2246
2247=== modified file 'tests/functional/openlp_plugins/images/test_upgrade.py'
2248--- tests/functional/openlp_plugins/images/test_upgrade.py 2017-09-24 19:33:07 +0000
2249+++ tests/functional/openlp_plugins/images/test_upgrade.py 2017-09-30 23:24:21 +0000
2250@@ -79,5 +79,6 @@
2251 2: Path('/', 'test', 'dir', 'image2.jpg'),
2252 3: Path('/', 'test', 'dir', 'subdir', 'image3.jpg')}
2253
2254+ self.assertEqual(len(upgraded_results), 3)
2255 for result in upgraded_results:
2256 self.assertEqual(expected_result_data[result.id], result.file_path)
2257
2258=== modified file 'tests/functional/openlp_plugins/songs/test_chordproimport.py'
2259--- tests/functional/openlp_plugins/songs/test_chordproimport.py 2017-05-11 20:24:20 +0000
2260+++ tests/functional/openlp_plugins/songs/test_chordproimport.py 2017-09-30 23:24:21 +0000
2261@@ -24,6 +24,8 @@
2262 """
2263 import os
2264
2265+from openlp.core.common.path import Path
2266+
2267 from tests.helpers.songfileimport import SongImportTestHelper
2268 from unittest.mock import patch, MagicMock
2269
2270@@ -48,5 +50,5 @@
2271 mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False
2272 mocked_settings.return_value = mocked_returned_settings
2273 # Do the test import
2274- self.file_import([os.path.join(TEST_PATH, 'swing-low.chordpro')],
2275+ self.file_import([Path(TEST_PATH, 'swing-low.chordpro')],
2276 self.load_external_result_data(os.path.join(TEST_PATH, 'swing-low.json')))
2277
2278=== modified file 'tests/functional/openlp_plugins/songs/test_easyslidesimport.py'
2279--- tests/functional/openlp_plugins/songs/test_easyslidesimport.py 2017-01-12 21:31:01 +0000
2280+++ tests/functional/openlp_plugins/songs/test_easyslidesimport.py 2017-09-30 23:24:21 +0000
2281@@ -21,9 +21,10 @@
2282 """
2283 This module contains tests for the EasySlides song importer.
2284 """
2285-
2286 import os
2287
2288+from openlp.core.common.path import Path
2289+
2290 from tests.helpers.songfileimport import SongImportTestHelper
2291
2292 TEST_PATH = os.path.abspath(
2293@@ -41,7 +42,7 @@
2294 """
2295 Test that loading an EasySlides file works correctly on various files
2296 """
2297- self.file_import(os.path.join(TEST_PATH, 'amazing-grace.xml'),
2298+ self.file_import(Path(TEST_PATH, 'amazing-grace.xml'),
2299 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2300- self.file_import(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.xml'),
2301+ self.file_import(Path(TEST_PATH, 'Export_2017-01-12_BB.xml'),
2302 self.load_external_result_data(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.json')))
2303
2304=== modified file 'tests/functional/openlp_plugins/songs/test_ewimport.py'
2305--- tests/functional/openlp_plugins/songs/test_ewimport.py 2017-05-22 19:07:07 +0000
2306+++ tests/functional/openlp_plugins/songs/test_ewimport.py 2017-09-30 23:24:21 +0000
2307@@ -97,7 +97,7 @@
2308 _title_assignment_list = []
2309
2310 def __init__(self, manager):
2311- EasyWorshipSongImport.__init__(self, manager, filenames=[])
2312+ EasyWorshipSongImport.__init__(self, manager, file_paths=[])
2313
2314 @property
2315 def title(self):
2316@@ -180,7 +180,7 @@
2317 mocked_manager = MagicMock()
2318
2319 # WHEN: An importer object is created
2320- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2321+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2322
2323 # THEN: The importer object should not be None
2324 self.assertIsNotNone(importer, 'Import should not be none')
2325@@ -192,7 +192,7 @@
2326 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions.
2327 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
2328 mocked_manager = MagicMock()
2329- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2330+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2331 importer.field_descriptions = TEST_FIELD_DESCS
2332
2333 # WHEN: Called with a field name that exists
2334@@ -210,7 +210,7 @@
2335 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions
2336 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
2337 mocked_manager = MagicMock()
2338- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2339+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2340 importer.field_descriptions = TEST_FIELD_DESCS
2341
2342 # WHEN: Called with a field name that does not exist
2343@@ -229,7 +229,7 @@
2344 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
2345 patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct:
2346 mocked_manager = MagicMock()
2347- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2348+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2349
2350 # WHEN: db_set_record_struct is called with a list of field descriptions
2351 return_value = importer.db_set_record_struct(TEST_FIELD_DESCS)
2352@@ -246,7 +246,7 @@
2353 # GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results
2354 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
2355 mocked_manager = MagicMock()
2356- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2357+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2358 importer.encoding = TEST_DATA_ENCODING
2359 importer.fields = TEST_FIELDS
2360 importer.field_descriptions = TEST_FIELD_DESCS
2361@@ -270,7 +270,7 @@
2362 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'):
2363 mocked_manager = MagicMock()
2364 mocked_memo_file = MagicMock()
2365- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2366+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2367 importer.memo_file = mocked_memo_file
2368 importer.encoding = TEST_DATA_ENCODING
2369
2370@@ -294,44 +294,25 @@
2371 else:
2372 mocked_memo_file.seek.assert_any_call(call[0], call[1])
2373
2374- def test_do_import_source(self):
2375- """
2376- Test the :mod:`do_import` module opens the correct files
2377- """
2378- # GIVEN: A mocked out SongImport class, a mocked out "manager"
2379- with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
2380- patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path:
2381- mocked_manager = MagicMock()
2382- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2383- mocked_os_path.isfile.side_effect = [True, False]
2384-
2385- # WHEN: Supplied with an import source
2386- importer.import_source = 'Songs.DB'
2387-
2388- # THEN: do_import should return None having called os.path.isfile
2389- self.assertIsNone(importer.do_import(), 'do_import should return None')
2390- mocked_os_path.isfile.assert_any_call('Songs.DB')
2391- mocked_os_path.isfile.assert_any_call('Songs.MB')
2392-
2393 def test_do_import_source_invalid(self):
2394 """
2395 Test the :mod:`do_import` module produces an error when Songs.MB not found.
2396 """
2397 # GIVEN: A mocked out SongImport class, a mocked out "manager"
2398 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
2399- patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path:
2400+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', side_effect=[True, False]):
2401 mocked_manager = MagicMock()
2402- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2403- importer.log_error = MagicMock()
2404- mocked_os_path.isfile.side_effect = [True, False]
2405-
2406- # WHEN: do_import is supplied with an import source (Songs.MB missing)
2407- importer.import_source = 'Songs.DB'
2408- importer.do_import()
2409-
2410- # THEN: do_import should have logged an error that the Songs.MB file could not be found.
2411- importer.log_error.assert_any_call(importer.import_source, 'Could not find the "Songs.MB" file. It must be '
2412- 'in the same folder as the "Songs.DB" file.')
2413+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2414+ with patch.object(importer, 'log_error') as mocked_log_error:
2415+
2416+ # WHEN: do_import is supplied with an import source (Songs.MB missing)
2417+ importer.import_source = 'Songs.DB'
2418+ importer.do_import()
2419+
2420+ # THEN: do_import should have logged an error that the Songs.MB file could not be found.
2421+ mocked_log_error.assert_any_call(importer.import_source,
2422+ 'Could not find the "Songs.MB" file. It must be in the same folder as '
2423+ 'the "Songs.DB" file.')
2424
2425 def test_do_import_database_validity(self):
2426 """
2427@@ -339,18 +320,19 @@
2428 """
2429 # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager"
2430 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
2431- patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path:
2432+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', return_value=True), \
2433+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.stat') as mocked_stat:
2434+
2435 mocked_manager = MagicMock()
2436- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2437- mocked_os_path.isfile.return_value = True
2438+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2439 importer.import_source = 'Songs.DB'
2440
2441 # WHEN: DB file size is less than 0x800
2442- mocked_os_path.getsize.return_value = 0x7FF
2443+ mocked_stat.return_value.st_size = 0x7FF
2444
2445- # THEN: do_import should return None having called os.path.isfile
2446+ # THEN: do_import should return None having called Path.stat()
2447 self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800')
2448- mocked_os_path.getsize.assert_any_call('Songs.DB')
2449+ mocked_stat.assert_called_once_with()
2450
2451 def test_do_import_memo_validty(self):
2452 """
2453@@ -358,13 +340,12 @@
2454 """
2455 # GIVEN: A mocked out SongImport class, a mocked out "manager"
2456 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
2457- patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \
2458- patch('builtins.open') as mocked_open, \
2459+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', return_value=True), \
2460+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.stat', **{'return_value.st_size': 0x800}), \
2461+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.open') as mocked_open, \
2462 patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct:
2463 mocked_manager = MagicMock()
2464- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2465- mocked_os_path.isfile.return_value = True
2466- mocked_os_path.getsize.return_value = 0x800
2467+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2468 importer.import_source = 'Songs.DB'
2469
2470 # WHEN: Unpacking first 35 bytes of Memo file
2471@@ -385,14 +366,14 @@
2472 """
2473 # GIVEN: A mocked out SongImport class, a mocked out "manager"
2474 with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \
2475- patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \
2476+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', return_value=True), \
2477+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.stat', **{'return_value.st_size': 0x800}), \
2478+ patch('openlp.plugins.songs.lib.importers.easyworship.Path.open'), \
2479 patch('builtins.open'), patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct, \
2480- patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \
2481+ patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \
2482 mocked_retrieve_windows_encoding:
2483 mocked_manager = MagicMock()
2484- importer = EasyWorshipSongImport(mocked_manager, filenames=[])
2485- mocked_os_path.isfile.return_value = True
2486- mocked_os_path.getsize.return_value = 0x800
2487+ importer = EasyWorshipSongImport(mocked_manager, file_paths=[])
2488 importer.import_source = 'Songs.DB'
2489
2490 # WHEN: Unpacking the code page
2491
2492=== modified file 'tests/functional/openlp_plugins/songs/test_lyriximport.py'
2493--- tests/functional/openlp_plugins/songs/test_lyriximport.py 2017-04-24 05:17:55 +0000
2494+++ tests/functional/openlp_plugins/songs/test_lyriximport.py 2017-09-30 23:24:21 +0000
2495@@ -22,7 +22,8 @@
2496 This module contains tests for the LyriX song importer.
2497 """
2498 import os
2499-from unittest.mock import patch
2500+
2501+from openlp.core.common.path import Path
2502
2503 from tests.helpers.songfileimport import SongImportTestHelper
2504
2505@@ -41,9 +42,9 @@
2506 """
2507 Test that loading an LyriX file works correctly on various files
2508 """
2509- self.file_import([os.path.join(TEST_PATH, 'A06.TXT')],
2510+ self.file_import([Path(TEST_PATH, 'A06.TXT')],
2511 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2512- self.file_import([os.path.join(TEST_PATH, 'A002.TXT')],
2513+ self.file_import([Path(TEST_PATH, 'A002.TXT')],
2514 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace2.json')))
2515- self.file_import([os.path.join(TEST_PATH, 'AO05.TXT')],
2516+ self.file_import([Path(TEST_PATH, 'AO05.TXT')],
2517 self.load_external_result_data(os.path.join(TEST_PATH, 'in die regterhand.json')))
2518
2519=== modified file 'tests/functional/openlp_plugins/songs/test_mediashout.py'
2520--- tests/functional/openlp_plugins/songs/test_mediashout.py 2017-04-24 05:17:55 +0000
2521+++ tests/functional/openlp_plugins/songs/test_mediashout.py 2017-09-30 23:24:21 +0000
2522@@ -51,7 +51,7 @@
2523 """
2524 # GIVEN: A MediaShoutImport class
2525 # WHEN: It is created
2526- importer = MediaShoutImport(MagicMock(), filename='mediashout.db')
2527+ importer = MediaShoutImport(MagicMock(), file_path='mediashout.db')
2528
2529 # THEN: It should not be None
2530 self.assertIsNotNone(importer)
2531@@ -62,7 +62,7 @@
2532 Test that do_import exits early when unable to connect to the database
2533 """
2534 # GIVEN: A MediaShoutImport instance
2535- importer = MediaShoutImport(MagicMock(), filename='mediashout.db')
2536+ importer = MediaShoutImport(MagicMock(), file_path='mediashout.db')
2537 mocked_pyodbc.connect.side_effect = Exception('Unable to connect')
2538
2539 # WHEN: do_import is called
2540@@ -89,7 +89,7 @@
2541 group = GroupRecord('Hymns')
2542
2543 # GIVEN: A MediaShoutImport instance and a bunch of stuff mocked out
2544- importer = MediaShoutImport(MagicMock(), filename='mediashout.db')
2545+ importer = MediaShoutImport(MagicMock(), file_path='mediashout.db')
2546 mocked_cursor = MagicMock()
2547 mocked_cursor.fetchall.side_effect = [[song], [verse], [play_order], [theme], [group]]
2548 mocked_cursor.tables.fetchone.return_value = True
2549@@ -124,7 +124,7 @@
2550 song = SongRecord(1, 'Amazing Grace', 'William Wilberforce', 'Public Domain', 1, '654321', '')
2551
2552 # GIVEN: A MediaShoutImport instance and a bunch of stuff mocked out
2553- importer = MediaShoutImport(MagicMock(), filename='mediashout.db')
2554+ importer = MediaShoutImport(MagicMock(), file_path='mediashout.db')
2555 mocked_cursor = MagicMock()
2556 mocked_cursor.fetchall.return_value = [song]
2557 mocked_connection = MagicMock()
2558@@ -158,7 +158,7 @@
2559 play_order = PlayOrderRecord(0, 1, 1)
2560 theme = ThemeRecord('Grace')
2561 group = GroupRecord('Hymns')
2562- importer = MediaShoutImport(MagicMock(), filename='mediashout.db')
2563+ importer = MediaShoutImport(MagicMock(), file_path='mediashout.db')
2564
2565 # WHEN: A song is processed
2566 with patch.object(importer, 'set_defaults') as mocked_set_defaults, \
2567@@ -200,7 +200,7 @@
2568 play_order = PlayOrderRecord(0, 1, 1)
2569 theme = ThemeRecord('Grace')
2570 group = GroupRecord('Hymns')
2571- importer = MediaShoutImport(MagicMock(), filename='mediashout.db')
2572+ importer = MediaShoutImport(MagicMock(), file_path='mediashout.db')
2573
2574 # WHEN: A song is processed
2575 with patch.object(importer, 'set_defaults') as mocked_set_defaults, \
2576
2577=== modified file 'tests/functional/openlp_plugins/songs/test_openlpimporter.py'
2578--- tests/functional/openlp_plugins/songs/test_openlpimporter.py 2017-04-24 05:17:55 +0000
2579+++ tests/functional/openlp_plugins/songs/test_openlpimporter.py 2017-09-30 23:24:21 +0000
2580@@ -48,7 +48,7 @@
2581 mocked_manager = MagicMock()
2582
2583 # WHEN: An importer object is created
2584- importer = OpenLPSongImport(mocked_manager, filenames=[])
2585+ importer = OpenLPSongImport(mocked_manager, file_paths=[])
2586
2587 # THEN: The importer object should not be None
2588 self.assertIsNotNone(importer, 'Import should not be none')
2589@@ -61,7 +61,7 @@
2590 with patch('openlp.plugins.songs.lib.importers.openlp.SongImport'):
2591 mocked_manager = MagicMock()
2592 mocked_import_wizard = MagicMock()
2593- importer = OpenLPSongImport(mocked_manager, filenames=[])
2594+ importer = OpenLPSongImport(mocked_manager, file_paths=[])
2595 importer.import_wizard = mocked_import_wizard
2596 importer.stop_import_flag = True
2597
2598
2599=== modified file 'tests/functional/openlp_plugins/songs/test_openlyricsexport.py'
2600--- tests/functional/openlp_plugins/songs/test_openlyricsexport.py 2017-04-24 05:17:55 +0000
2601+++ tests/functional/openlp_plugins/songs/test_openlyricsexport.py 2017-09-30 23:24:21 +0000
2602@@ -22,14 +22,14 @@
2603 """
2604 This module contains tests for the OpenLyrics song importer.
2605 """
2606-import os
2607 import shutil
2608 from tempfile import mkdtemp
2609 from unittest import TestCase
2610 from unittest.mock import MagicMock, patch
2611
2612+from openlp.core.common import Registry
2613+from openlp.core.common.path import Path, rmtree
2614 from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
2615-from openlp.core.common import Registry
2616
2617 from tests.helpers.testmixin import TestMixin
2618
2619@@ -43,13 +43,13 @@
2620 Create the registry
2621 """
2622 Registry.create()
2623- self.temp_folder = mkdtemp()
2624+ self.temp_folder = Path(mkdtemp())
2625
2626 def tearDown(self):
2627 """
2628 Cleanup
2629 """
2630- shutil.rmtree(self.temp_folder)
2631+ rmtree(self.temp_folder)
2632
2633 def test_export_same_filename(self):
2634 """
2635@@ -73,7 +73,9 @@
2636 ol_export.do_export()
2637
2638 # THEN: The exporter should have created 2 files
2639- self.assertTrue(os.path.exists(os.path.join(self.temp_folder,
2640- '%s (%s).xml' % (song.title, author.display_name))))
2641- self.assertTrue(os.path.exists(os.path.join(self.temp_folder,
2642- '%s (%s)-1.xml' % (song.title, author.display_name))))
2643+ self.assertTrue((self.temp_folder /
2644+ '{title} ({display_name}).xml'.format(
2645+ title=song.title, display_name=author.display_name)).exists())
2646+ self.assertTrue((self.temp_folder /
2647+ '{title} ({display_name})-1.xml'.format(
2648+ title=song.title, display_name=author.display_name)).exists())
2649
2650=== modified file 'tests/functional/openlp_plugins/songs/test_openlyricsimport.py'
2651--- tests/functional/openlp_plugins/songs/test_openlyricsimport.py 2017-06-06 20:58:12 +0000
2652+++ tests/functional/openlp_plugins/songs/test_openlyricsimport.py 2017-09-30 23:24:21 +0000
2653@@ -29,10 +29,11 @@
2654
2655 from lxml import etree, objectify
2656
2657+from openlp.core.common import Registry, Settings
2658+from openlp.core.common.path import Path
2659 from openlp.plugins.songs.lib.importers.openlyrics import OpenLyricsImport
2660 from openlp.plugins.songs.lib.importers.songimport import SongImport
2661 from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
2662-from openlp.core.common import Registry, Settings
2663
2664 from tests.helpers.testmixin import TestMixin
2665
2666@@ -109,7 +110,7 @@
2667 mocked_manager = MagicMock()
2668
2669 # WHEN: An importer object is created
2670- importer = OpenLyricsImport(mocked_manager, filenames=[])
2671+ importer = OpenLyricsImport(mocked_manager, file_paths=[])
2672
2673 # THEN: The importer should be an instance of SongImport
2674 self.assertIsInstance(importer, SongImport)
2675@@ -122,13 +123,13 @@
2676 for song_file in SONG_TEST_DATA:
2677 mocked_manager = MagicMock()
2678 mocked_import_wizard = MagicMock()
2679- importer = OpenLyricsImport(mocked_manager, filenames=[])
2680+ importer = OpenLyricsImport(mocked_manager, file_paths=[])
2681 importer.import_wizard = mocked_import_wizard
2682 importer.open_lyrics = MagicMock()
2683 importer.open_lyrics.xml_to_song = MagicMock()
2684
2685 # WHEN: Importing each file
2686- importer.import_source = [os.path.join(TEST_PATH, song_file)]
2687+ importer.import_source = [Path(TEST_PATH, song_file)]
2688 importer.do_import()
2689
2690 # THEN: The xml_to_song() method should have been called
2691
2692=== modified file 'tests/functional/openlp_plugins/songs/test_openoffice.py'
2693--- tests/functional/openlp_plugins/songs/test_openoffice.py 2017-04-24 05:17:55 +0000
2694+++ tests/functional/openlp_plugins/songs/test_openoffice.py 2017-09-30 23:24:21 +0000
2695@@ -54,7 +54,7 @@
2696 mocked_manager = MagicMock()
2697
2698 # WHEN: An importer object is created
2699- importer = OpenOfficeImport(mocked_manager, filenames=[])
2700+ importer = OpenOfficeImport(mocked_manager, file_paths=[])
2701
2702 # THEN: The importer object should not be None
2703 self.assertIsNotNone(importer, 'Import should not be none')
2704@@ -66,7 +66,7 @@
2705 """
2706 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a document that raises an exception
2707 mocked_manager = MagicMock()
2708- importer = OpenOfficeImport(mocked_manager, filenames=[])
2709+ importer = OpenOfficeImport(mocked_manager, file_paths=[])
2710 importer.document = MagicMock()
2711 importer.document.close = MagicMock(side_effect=Exception())
2712
2713
2714=== modified file 'tests/functional/openlp_plugins/songs/test_opensongimport.py'
2715--- tests/functional/openlp_plugins/songs/test_opensongimport.py 2017-05-11 20:24:20 +0000
2716+++ tests/functional/openlp_plugins/songs/test_opensongimport.py 2017-09-30 23:24:21 +0000
2717@@ -27,6 +27,7 @@
2718 from unittest.mock import patch, MagicMock
2719
2720 from openlp.core.common import Registry
2721+from openlp.core.common.path import Path
2722 from openlp.plugins.songs.lib.importers.opensong import OpenSongImport
2723
2724 from tests.helpers.songfileimport import SongImportTestHelper
2725@@ -52,15 +53,15 @@
2726 mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False
2727 mocked_settings.return_value = mocked_returned_settings
2728 # Do the test import
2729- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace')],
2730+ self.file_import([Path(TEST_PATH, 'Amazing Grace')],
2731 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2732- self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer')],
2733+ self.file_import([Path(TEST_PATH, 'Beautiful Garden Of Prayer')],
2734 self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
2735- self.file_import([os.path.join(TEST_PATH, 'One, Two, Three, Four, Five')],
2736+ self.file_import([Path(TEST_PATH, 'One, Two, Three, Four, Five')],
2737 self.load_external_result_data(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five.json')))
2738- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace2')],
2739+ self.file_import([Path(TEST_PATH, 'Amazing Grace2')],
2740 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2741- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace with bad CCLI')],
2742+ self.file_import([Path(TEST_PATH, 'Amazing Grace with bad CCLI')],
2743 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace without CCLI.json')))
2744
2745
2746@@ -83,7 +84,7 @@
2747 mocked_manager = MagicMock()
2748
2749 # WHEN: An importer object is created
2750- importer = OpenSongImport(mocked_manager, filenames=[])
2751+ importer = OpenSongImport(mocked_manager, file_paths=[])
2752
2753 # THEN: The importer object should not be None
2754 self.assertIsNotNone(importer, 'Import should not be none')
2755@@ -96,7 +97,7 @@
2756 with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'):
2757 mocked_manager = MagicMock()
2758 mocked_import_wizard = MagicMock()
2759- importer = OpenSongImport(mocked_manager, filenames=[])
2760+ importer = OpenSongImport(mocked_manager, file_paths=[])
2761 importer.import_wizard = mocked_import_wizard
2762 importer.stop_import_flag = True
2763
2764@@ -117,7 +118,7 @@
2765 with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'):
2766 mocked_manager = MagicMock()
2767 mocked_import_wizard = MagicMock()
2768- importer = OpenSongImport(mocked_manager, filenames=[])
2769+ importer = OpenSongImport(mocked_manager, file_paths=[])
2770 importer.import_wizard = mocked_import_wizard
2771 importer.stop_import_flag = True
2772
2773
2774=== modified file 'tests/functional/openlp_plugins/songs/test_opsproimport.py'
2775--- tests/functional/openlp_plugins/songs/test_opsproimport.py 2017-04-24 05:17:55 +0000
2776+++ tests/functional/openlp_plugins/songs/test_opsproimport.py 2017-09-30 23:24:21 +0000
2777@@ -86,7 +86,7 @@
2778 mocked_manager = MagicMock()
2779
2780 # WHEN: An importer object is created
2781- importer = OPSProImport(mocked_manager, filenames=[])
2782+ importer = OPSProImport(mocked_manager, file_paths=[])
2783
2784 # THEN: The importer object should not be None
2785 self.assertIsNotNone(importer, 'Import should not be none')
2786@@ -98,7 +98,7 @@
2787 """
2788 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry
2789 mocked_manager = MagicMock()
2790- importer = OPSProImport(mocked_manager, filenames=[])
2791+ importer = OPSProImport(mocked_manager, file_paths=[])
2792 importer.finish = MagicMock()
2793 song, lyrics = _build_data('you are so faithfull.txt', False)
2794
2795@@ -118,7 +118,7 @@
2796 """
2797 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry
2798 mocked_manager = MagicMock()
2799- importer = OPSProImport(mocked_manager, filenames=[])
2800+ importer = OPSProImport(mocked_manager, file_paths=[])
2801 importer.finish = MagicMock()
2802 song, lyrics = _build_data('amazing grace.txt', False)
2803
2804@@ -138,7 +138,7 @@
2805 """
2806 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry
2807 mocked_manager = MagicMock()
2808- importer = OPSProImport(mocked_manager, filenames=[])
2809+ importer = OPSProImport(mocked_manager, file_paths=[])
2810 importer.finish = MagicMock()
2811 song, lyrics = _build_data('amazing grace2.txt', True)
2812
2813@@ -158,7 +158,7 @@
2814 """
2815 # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry
2816 mocked_manager = MagicMock()
2817- importer = OPSProImport(mocked_manager, filenames=[])
2818+ importer = OPSProImport(mocked_manager, file_paths=[])
2819 importer.finish = MagicMock()
2820 song, lyrics = _build_data('amazing grace3.txt', True)
2821
2822
2823=== modified file 'tests/functional/openlp_plugins/songs/test_powerpraiseimport.py'
2824--- tests/functional/openlp_plugins/songs/test_powerpraiseimport.py 2016-12-31 11:01:36 +0000
2825+++ tests/functional/openlp_plugins/songs/test_powerpraiseimport.py 2017-09-30 23:24:21 +0000
2826@@ -26,8 +26,9 @@
2827
2828 import os
2829
2830+from openlp.core.common.path import Path
2831+
2832 from tests.helpers.songfileimport import SongImportTestHelper
2833-from openlp.core.common import Registry
2834
2835 TEST_PATH = os.path.abspath(
2836 os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'powerpraisesongs'))
2837@@ -44,7 +45,7 @@
2838 """
2839 Test that loading a PowerPraise file works correctly
2840 """
2841- self.file_import([os.path.join(TEST_PATH, 'Naher, mein Gott zu Dir.ppl')],
2842+ self.file_import([Path(TEST_PATH, 'Naher, mein Gott zu Dir.ppl')],
2843 self.load_external_result_data(os.path.join(TEST_PATH, 'Naher, mein Gott zu Dir.json')))
2844- self.file_import([os.path.join(TEST_PATH, 'You are so faithful.ppl')],
2845+ self.file_import([Path(TEST_PATH, 'You are so faithful.ppl')],
2846 self.load_external_result_data(os.path.join(TEST_PATH, 'You are so faithful.json')))
2847
2848=== modified file 'tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py'
2849--- tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py 2016-12-31 11:01:36 +0000
2850+++ tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py 2017-09-30 23:24:21 +0000
2851@@ -22,9 +22,10 @@
2852 """
2853 This module contains tests for the PresentationManager song importer.
2854 """
2855-
2856 import os
2857
2858+from openlp.core.common.path import Path
2859+
2860 from tests.helpers.songfileimport import SongImportTestHelper
2861
2862 TEST_PATH = os.path.abspath(
2863@@ -42,7 +43,7 @@
2864 """
2865 Test that loading a PresentationManager file works correctly
2866 """
2867- self.file_import([os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.sng')],
2868+ self.file_import([Path(TEST_PATH, 'Great Is Thy Faithfulness.sng')],
2869 self.load_external_result_data(os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.json')))
2870- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sng')],
2871+ self.file_import([Path(TEST_PATH, 'Amazing Grace.sng')],
2872 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2873
2874=== modified file 'tests/functional/openlp_plugins/songs/test_propresenterimport.py'
2875--- tests/functional/openlp_plugins/songs/test_propresenterimport.py 2016-12-31 11:01:36 +0000
2876+++ tests/functional/openlp_plugins/songs/test_propresenterimport.py 2017-09-30 23:24:21 +0000
2877@@ -23,9 +23,10 @@
2878 The :mod:`propresenterimport` module provides the functionality for importing
2879 ProPresenter song files into the current installation database.
2880 """
2881-
2882 import os
2883
2884+from openlp.core.common.path import Path
2885+
2886 from tests.helpers.songfileimport import SongImportTestHelper
2887
2888 TEST_PATH = os.path.abspath(
2889@@ -43,19 +44,19 @@
2890 """
2891 Test that loading a ProPresenter 4 file works correctly
2892 """
2893- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')],
2894+ self.file_import([Path(TEST_PATH, 'Amazing Grace.pro4')],
2895 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2896
2897 def test_pro5_song_import(self):
2898 """
2899 Test that loading a ProPresenter 5 file works correctly
2900 """
2901- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro5')],
2902+ self.file_import([Path(TEST_PATH, 'Amazing Grace.pro5')],
2903 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2904
2905 def test_pro6_song_import(self):
2906 """
2907 Test that loading a ProPresenter 6 file works correctly
2908 """
2909- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro6')],
2910+ self.file_import([Path(TEST_PATH, 'Amazing Grace.pro6')],
2911 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2912
2913=== modified file 'tests/functional/openlp_plugins/songs/test_songbeamerimport.py'
2914--- tests/functional/openlp_plugins/songs/test_songbeamerimport.py 2017-05-11 20:24:20 +0000
2915+++ tests/functional/openlp_plugins/songs/test_songbeamerimport.py 2017-09-30 23:24:21 +0000
2916@@ -26,8 +26,9 @@
2917 from unittest import TestCase
2918 from unittest.mock import MagicMock, patch
2919
2920+from openlp.core.common import Registry
2921+from openlp.core.common.path import Path
2922 from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport, SongBeamerTypes
2923-from openlp.core.common import Registry
2924
2925 from tests.helpers.songfileimport import SongImportTestHelper
2926
2927@@ -51,18 +52,18 @@
2928 mocked_returned_settings = MagicMock()
2929 mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False
2930 mocked_settings.return_value = mocked_returned_settings
2931- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sng')],
2932+ self.file_import([Path(TEST_PATH, 'Amazing Grace.sng')],
2933 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2934- self.file_import([os.path.join(TEST_PATH, 'Lobsinget dem Herrn.sng')],
2935+ self.file_import([Path(TEST_PATH, 'Lobsinget dem Herrn.sng')],
2936 self.load_external_result_data(os.path.join(TEST_PATH, 'Lobsinget dem Herrn.json')))
2937- self.file_import([os.path.join(TEST_PATH, 'When I Call On You.sng')],
2938+ self.file_import([Path(TEST_PATH, 'When I Call On You.sng')],
2939 self.load_external_result_data(os.path.join(TEST_PATH, 'When I Call On You.json')))
2940
2941 def test_cp1252_encoded_file(self):
2942 """
2943 Test that a CP1252 encoded file get's decoded properly.
2944 """
2945- self.file_import([os.path.join(TEST_PATH, 'cp1252song.sng')],
2946+ self.file_import([Path(TEST_PATH, 'cp1252song.sng')],
2947 self.load_external_result_data(os.path.join(TEST_PATH, 'cp1252song.json')))
2948
2949
2950@@ -78,7 +79,7 @@
2951 self.song_import_patcher = patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport')
2952 self.song_import_patcher.start()
2953 mocked_manager = MagicMock()
2954- self.importer = SongBeamerImport(mocked_manager, filenames=[])
2955+ self.importer = SongBeamerImport(mocked_manager, file_paths=[])
2956
2957 def tearDown(self):
2958 """
2959@@ -95,7 +96,7 @@
2960 mocked_manager = MagicMock()
2961
2962 # WHEN: An importer object is created
2963- importer = SongBeamerImport(mocked_manager, filenames=[])
2964+ importer = SongBeamerImport(mocked_manager, file_paths=[])
2965
2966 # THEN: The importer object should not be None
2967 self.assertIsNotNone(importer, 'Import should not be none')
2968
2969=== modified file 'tests/functional/openlp_plugins/songs/test_songproimport.py'
2970--- tests/functional/openlp_plugins/songs/test_songproimport.py 2016-12-31 11:01:36 +0000
2971+++ tests/functional/openlp_plugins/songs/test_songproimport.py 2017-09-30 23:24:21 +0000
2972@@ -23,9 +23,10 @@
2973 The :mod:`songproimport` module provides the functionality for importing
2974 SongPro song files into the current installation database.
2975 """
2976-
2977 import os
2978
2979+from openlp.core.common.path import Path
2980+
2981 from tests.helpers.songfileimport import SongImportTestHelper
2982
2983 TEST_PATH = os.path.abspath(
2984@@ -43,5 +44,5 @@
2985 """
2986 Test that loading an SongPro file works correctly
2987 """
2988- self.file_import(os.path.join(TEST_PATH, 'amazing-grace.txt'),
2989+ self.file_import(Path(TEST_PATH, 'amazing-grace.txt'),
2990 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
2991
2992=== modified file 'tests/functional/openlp_plugins/songs/test_songselect.py'
2993--- tests/functional/openlp_plugins/songs/test_songselect.py 2017-05-30 19:40:01 +0000
2994+++ tests/functional/openlp_plugins/songs/test_songselect.py 2017-09-30 23:24:21 +0000
2995@@ -31,6 +31,7 @@
2996 from PyQt5 import QtWidgets
2997
2998 from openlp.core import Registry
2999+from openlp.core.common.path import Path
3000 from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker
3001 from openlp.plugins.songs.lib import Song
3002 from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGIN_PAGE, LOGOUT_URL, BASE_URL
3003@@ -810,15 +811,15 @@
3004 def __init__(self, *args, **kwargs):
3005 self.importer_class_name = 'CCLIFileImport'
3006 self.importer_module_name = 'cclifile'
3007- super(TestSongSelectFileImport, self).__init__(*args, **kwargs)
3008+ super().__init__(*args, **kwargs)
3009
3010 def test_song_import(self):
3011 """
3012 Test that loading an OpenSong file works correctly on various files
3013 """
3014- self.file_import([os.path.join(TEST_PATH, 'TestSong.bin')],
3015+ self.file_import([Path(TEST_PATH, 'TestSong.bin')],
3016 self.load_external_result_data(os.path.join(TEST_PATH, 'TestSong-bin.json')))
3017- self.file_import([os.path.join(TEST_PATH, 'TestSong.txt')],
3018+ self.file_import([Path(TEST_PATH, 'TestSong.txt')],
3019 self.load_external_result_data(os.path.join(TEST_PATH, 'TestSong-txt.json')))
3020
3021
3022
3023=== modified file 'tests/functional/openlp_plugins/songs/test_songshowplusimport.py'
3024--- tests/functional/openlp_plugins/songs/test_songshowplusimport.py 2017-04-24 05:17:55 +0000
3025+++ tests/functional/openlp_plugins/songs/test_songshowplusimport.py 2017-09-30 23:24:21 +0000
3026@@ -26,6 +26,7 @@
3027 from unittest import TestCase
3028 from unittest.mock import patch, MagicMock
3029
3030+from openlp.core.common.path import Path
3031 from openlp.plugins.songs.lib import VerseType
3032 from openlp.plugins.songs.lib.importers.songshowplus import SongShowPlusImport
3033
3034@@ -46,13 +47,13 @@
3035 """
3036 Test that loading a SongShow Plus file works correctly on various files
3037 """
3038- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sbsong')],
3039+ self.file_import([Path(TEST_PATH, 'Amazing Grace.sbsong')],
3040 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
3041- self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong')],
3042+ self.file_import([Path(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong')],
3043 self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
3044- self.file_import([os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong')],
3045+ self.file_import([Path(TEST_PATH, 'a mighty fortress is our god.sbsong')],
3046 self.load_external_result_data(os.path.join(TEST_PATH, 'a mighty fortress is our god.json')))
3047- self.file_import([os.path.join(TEST_PATH, 'cleanse-me.sbsong')],
3048+ self.file_import([Path(TEST_PATH, 'cleanse-me.sbsong')],
3049 self.load_external_result_data(os.path.join(TEST_PATH, 'cleanse-me.json')))
3050
3051
3052@@ -69,7 +70,7 @@
3053 mocked_manager = MagicMock()
3054
3055 # WHEN: An importer object is created
3056- importer = SongShowPlusImport(mocked_manager, filenames=[])
3057+ importer = SongShowPlusImport(mocked_manager, file_paths=[])
3058
3059 # THEN: The importer object should not be None
3060 self.assertIsNotNone(importer, 'Import should not be none')
3061@@ -82,7 +83,7 @@
3062 with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
3063 mocked_manager = MagicMock()
3064 mocked_import_wizard = MagicMock()
3065- importer = SongShowPlusImport(mocked_manager, filenames=[])
3066+ importer = SongShowPlusImport(mocked_manager, file_paths=[])
3067 importer.import_wizard = mocked_import_wizard
3068 importer.stop_import_flag = True
3069
3070@@ -103,7 +104,7 @@
3071 with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
3072 mocked_manager = MagicMock()
3073 mocked_import_wizard = MagicMock()
3074- importer = SongShowPlusImport(mocked_manager, filenames=[])
3075+ importer = SongShowPlusImport(mocked_manager, file_paths=[])
3076 importer.import_wizard = mocked_import_wizard
3077 importer.stop_import_flag = True
3078
3079@@ -123,7 +124,7 @@
3080 # GIVEN: A mocked out SongImport class, and a mocked out "manager"
3081 with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
3082 mocked_manager = MagicMock()
3083- importer = SongShowPlusImport(mocked_manager, filenames=[])
3084+ importer = SongShowPlusImport(mocked_manager, file_paths=[])
3085
3086 # WHEN: Supplied with the following arguments replicating verses being added
3087 test_values = [
3088@@ -151,7 +152,7 @@
3089 # GIVEN: A mocked out SongImport class, and a mocked out "manager"
3090 with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'):
3091 mocked_manager = MagicMock()
3092- importer = SongShowPlusImport(mocked_manager, filenames=[])
3093+ importer = SongShowPlusImport(mocked_manager, file_paths=[])
3094
3095 # WHEN: Supplied with the following arguments replicating a verse order being added
3096 test_values = [
3097
3098=== modified file 'tests/functional/openlp_plugins/songs/test_sundayplusimport.py'
3099--- tests/functional/openlp_plugins/songs/test_sundayplusimport.py 2017-04-24 05:17:55 +0000
3100+++ tests/functional/openlp_plugins/songs/test_sundayplusimport.py 2017-09-30 23:24:21 +0000
3101@@ -24,6 +24,8 @@
3102 import os
3103 from unittest.mock import patch
3104
3105+from openlp.core.common.path import Path
3106+
3107 from tests.helpers.songfileimport import SongImportTestHelper
3108
3109 TEST_PATH = os.path.abspath(
3110@@ -44,5 +46,5 @@
3111 with patch('openlp.plugins.songs.lib.importers.sundayplus.retrieve_windows_encoding') as \
3112 mocked_retrieve_windows_encoding:
3113 mocked_retrieve_windows_encoding.return_value = 'cp1252'
3114- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.ptf')],
3115+ self.file_import([Path(TEST_PATH, 'Amazing Grace.ptf')],
3116 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
3117
3118=== modified file 'tests/functional/openlp_plugins/songs/test_videopsalm.py'
3119--- tests/functional/openlp_plugins/songs/test_videopsalm.py 2017-05-11 20:24:20 +0000
3120+++ tests/functional/openlp_plugins/songs/test_videopsalm.py 2017-09-30 23:24:21 +0000
3121@@ -21,9 +21,10 @@
3122 """
3123 This module contains tests for the VideoPsalm song importer.
3124 """
3125-
3126 import os
3127
3128+from openlp.core.common.path import Path
3129+
3130 from tests.helpers.songfileimport import SongImportTestHelper
3131 from unittest.mock import patch, MagicMock
3132
3133@@ -48,7 +49,7 @@
3134 mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False
3135 mocked_settings.return_value = mocked_returned_settings
3136 # Do the test import
3137- self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold.json'),
3138+ self.file_import(Path(TEST_PATH, 'videopsalm-as-safe-a-stronghold.json'),
3139 self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold.json')))
3140- self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold2.json'),
3141+ self.file_import(Path(TEST_PATH, 'videopsalm-as-safe-a-stronghold2.json'),
3142 self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold2.json')))
3143
3144=== modified file 'tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py'
3145--- tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py 2016-12-31 11:01:36 +0000
3146+++ tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py 2017-09-30 23:24:21 +0000
3147@@ -22,9 +22,10 @@
3148 """
3149 This module contains tests for the Words of Worship song importer.
3150 """
3151-
3152 import os
3153
3154+from openlp.core.common.path import Path
3155+
3156 from tests.helpers.songfileimport import SongImportTestHelper
3157 from openlp.plugins.songs.lib.importers.wordsofworship import WordsOfWorshipImport
3158
3159@@ -43,10 +44,10 @@
3160 """
3161 Test that loading a Words of Worship file works correctly
3162 """
3163- self.file_import([os.path.join(TEST_PATH, 'Amazing Grace (6 Verses).wow-song')],
3164+ self.file_import([Path(TEST_PATH, 'Amazing Grace (6 Verses).wow-song')],
3165 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace (6 Verses).json')))
3166- self.file_import([os.path.join(TEST_PATH, 'When morning gilds the skies.wsg')],
3167+ self.file_import([Path(TEST_PATH, 'When morning gilds the skies.wsg')],
3168 self.load_external_result_data(os.path.join(TEST_PATH, 'When morning gilds the skies.json')))
3169- self.file_import([os.path.join(TEST_PATH, 'Holy Holy Holy Lord God Almighty.wow-song')],
3170+ self.file_import([Path(TEST_PATH, 'Holy Holy Holy Lord God Almighty.wow-song')],
3171 self.load_external_result_data(os.path.join(TEST_PATH,
3172 'Holy Holy Holy Lord God Almighty.json')))
3173
3174=== modified file 'tests/functional/openlp_plugins/songs/test_worshipassistantimport.py'
3175--- tests/functional/openlp_plugins/songs/test_worshipassistantimport.py 2016-12-31 11:01:36 +0000
3176+++ tests/functional/openlp_plugins/songs/test_worshipassistantimport.py 2017-09-30 23:24:21 +0000
3177@@ -23,9 +23,10 @@
3178 The :mod:`worshipassistantimport` module provides the functionality for importing
3179 WorshipAssistant song files into the current installation database.
3180 """
3181-
3182 import os
3183
3184+from openlp.core.common.path import Path
3185+
3186 from tests.helpers.songfileimport import SongImportTestHelper
3187
3188 TEST_PATH = os.path.abspath(
3189@@ -43,9 +44,9 @@
3190 """
3191 Test that loading an Worship Assistant file works correctly
3192 """
3193- self.file_import(os.path.join(TEST_PATH, 'du_herr.csv'),
3194+ self.file_import(Path(TEST_PATH, 'du_herr.csv'),
3195 self.load_external_result_data(os.path.join(TEST_PATH, 'du_herr.json')))
3196- self.file_import(os.path.join(TEST_PATH, 'would_you_be_free.csv'),
3197+ self.file_import(Path(TEST_PATH, 'would_you_be_free.csv'),
3198 self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))
3199- self.file_import(os.path.join(TEST_PATH, 'would_you_be_free2.csv'),
3200+ self.file_import(Path(TEST_PATH, 'would_you_be_free2.csv'),
3201 self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))
3202
3203=== modified file 'tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py'
3204--- tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py 2017-04-24 05:17:55 +0000
3205+++ tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py 2017-09-30 23:24:21 +0000
3206@@ -55,7 +55,7 @@
3207 _title_assignment_list = []
3208
3209 def __init__(self, manager):
3210- WorshipCenterProImport.__init__(self, manager, filenames=[])
3211+ WorshipCenterProImport.__init__(self, manager, file_paths=[])
3212
3213 @property
3214 def title(self):
3215@@ -153,7 +153,7 @@
3216 mocked_manager = MagicMock()
3217
3218 # WHEN: An importer object is created
3219- importer = WorshipCenterProImport(mocked_manager, filenames=[])
3220+ importer = WorshipCenterProImport(mocked_manager, file_paths=[])
3221
3222 # THEN: The importer object should not be None
3223 self.assertIsNotNone(importer, 'Import should not be none')
3224@@ -170,7 +170,7 @@
3225 mocked_manager = MagicMock()
3226 mocked_log_error = MagicMock()
3227 mocked_translate.return_value = 'Translated Text'
3228- importer = WorshipCenterProImport(mocked_manager, filenames=[])
3229+ importer = WorshipCenterProImport(mocked_manager, file_paths=[])
3230 importer.log_error = mocked_log_error
3231 importer.import_source = 'import_source'
3232 pyodbc_errors = [pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError]
3233
3234=== modified file 'tests/functional/openlp_plugins/songs/test_zionworximport.py'
3235--- tests/functional/openlp_plugins/songs/test_zionworximport.py 2017-04-24 05:17:55 +0000
3236+++ tests/functional/openlp_plugins/songs/test_zionworximport.py 2017-09-30 23:24:21 +0000
3237@@ -26,9 +26,10 @@
3238 from unittest import TestCase
3239 from unittest.mock import MagicMock, patch
3240
3241+from openlp.core.common import Registry
3242+from openlp.core.common.path import Path
3243 from openlp.plugins.songs.lib.importers.zionworx import ZionWorxImport
3244 from openlp.plugins.songs.lib.importers.songimport import SongImport
3245-from openlp.core.common import Registry
3246
3247 from tests.helpers.songfileimport import SongImportTestHelper
3248
3249@@ -55,7 +56,7 @@
3250 mocked_manager = MagicMock()
3251
3252 # WHEN: An importer object is created
3253- importer = ZionWorxImport(mocked_manager, filenames=[])
3254+ importer = ZionWorxImport(mocked_manager, file_paths=[])
3255
3256 # THEN: The importer should be an instance of SongImport
3257 self.assertIsInstance(importer, SongImport)
3258@@ -72,5 +73,5 @@
3259 """
3260 Test that loading an ZionWorx file works correctly on various files
3261 """
3262- self.file_import(os.path.join(TEST_PATH, 'zionworx.csv'),
3263+ self.file_import(Path(TEST_PATH, 'zionworx.csv'),
3264 self.load_external_result_data(os.path.join(TEST_PATH, 'zionworx.json')))
3265
3266=== modified file 'tests/helpers/songfileimport.py'
3267--- tests/helpers/songfileimport.py 2017-04-24 05:17:55 +0000
3268+++ tests/helpers/songfileimport.py 2017-09-30 23:24:21 +0000
3269@@ -89,7 +89,7 @@
3270 """
3271 Import the given file and check that it has imported correctly
3272 """
3273- importer = self.importer_class(self.mocked_manager, filenames=[source_file_name])
3274+ importer = self.importer_class(self.mocked_manager, file_paths=[source_file_name])
3275 importer.import_wizard = self.mocked_import_wizard
3276 importer.stop_import_flag = False
3277 importer.topics = []