Status: | Superseded |
---|---|
Proposed branch: | lp:~phill-ridout/openlp/pathlib5 |
Merge into: | lp:openlp |
Diff against target: |
2562 lines (+771/-534) 34 files modified
openlp/core/__init__.py (+18/-24) openlp/core/common/applocation.py (+0/-1) openlp/core/common/httputils.py (+20/-22) openlp/core/common/languagemanager.py (+1/-1) openlp/core/common/registry.py (+1/-1) openlp/core/common/uistrings.py (+0/-3) openlp/core/lib/__init__.py (+14/-9) openlp/core/lib/mediamanageritem.py (+0/-2) openlp/core/lib/shutil.py (+112/-0) openlp/core/ui/firsttimeform.py (+3/-3) openlp/core/ui/lib/wizard.py (+1/-1) openlp/core/ui/mainwindow.py (+10/-9) openlp/core/ui/servicemanager.py (+20/-20) openlp/core/ui/thememanager.py (+1/-1) openlp/plugins/images/lib/mediaitem.py (+1/-1) openlp/plugins/presentations/lib/impresscontroller.py (+19/-25) openlp/plugins/presentations/lib/mediaitem.py (+79/-79) openlp/plugins/presentations/lib/messagelistener.py (+16/-13) openlp/plugins/presentations/lib/pdfcontroller.py (+54/-50) openlp/plugins/presentations/lib/powerpointcontroller.py (+7/-7) openlp/plugins/presentations/lib/pptviewcontroller.py (+18/-17) openlp/plugins/presentations/lib/presentationcontroller.py (+83/-70) openlp/plugins/presentations/lib/presentationtab.py (+5/-4) openlp/plugins/remotes/deploy.py (+1/-1) openlp/plugins/songs/reporting.py (+41/-47) tests/functional/openlp_core_common/test_httputils.py (+2/-1) tests/functional/openlp_core_lib/test_lib.py (+22/-37) tests/functional/openlp_core_lib/test_shutil.py (+170/-0) tests/functional/openlp_core_ui/test_exceptionform.py (+1/-1) tests/functional/openlp_plugins/presentations/test_impresscontroller.py (+3/-4) tests/functional/openlp_plugins/presentations/test_mediaitem.py (+10/-9) tests/functional/openlp_plugins/presentations/test_pdfcontroller.py (+8/-7) tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py (+7/-7) tests/functional/openlp_plugins/presentations/test_presentationcontroller.py (+23/-57) |
To merge this branch: | bzr merge lp:~phill-ridout/openlp/pathlib5 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Bentley | Needs Fixing | ||
Review via email: mp+330895@code.launchpad.net |
This proposal has been superseded by a proposal from 2017-09-18.
Commit message
Description of the change
More pathlib changes, focused mainly on the presentation plugin
lp:~phill-ridout/openlp/pathlib5 (revision 2773)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[FAILURE] https:/
Stopping after failure
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'openlp/core/__init__.py' |
2 | --- openlp/core/__init__.py 2017-09-03 10:18:14 +0000 |
3 | +++ openlp/core/__init__.py 2017-09-18 20:10:29 +0000 |
4 | @@ -29,8 +29,6 @@ |
5 | |
6 | import argparse |
7 | import logging |
8 | -import os |
9 | -import shutil |
10 | import sys |
11 | import time |
12 | from datetime import datetime |
13 | @@ -43,6 +41,7 @@ |
14 | from openlp.core.common.path import Path |
15 | from openlp.core.common.versionchecker import VersionThread, get_application_version |
16 | from openlp.core.lib import ScreenList |
17 | +from openlp.core.lib.shutil import copytree |
18 | from openlp.core.resources import qInitResources |
19 | from openlp.core.ui import SplashScreen |
20 | from openlp.core.ui.exceptionform import ExceptionForm |
21 | @@ -181,25 +180,20 @@ |
22 | """ |
23 | Check if the data folder path exists. |
24 | """ |
25 | - data_folder_path = str(AppLocation.get_data_path()) |
26 | - if not os.path.exists(data_folder_path): |
27 | - log.critical('Database was not found in: ' + data_folder_path) |
28 | - status = QtWidgets.QMessageBox.critical(None, translate('OpenLP', 'Data Directory Error'), |
29 | - translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}' |
30 | - '\n\nThe location of the data folder was ' |
31 | - 'previously changed from the OpenLP\'s ' |
32 | - 'default location. If the data was stored on ' |
33 | - 'removable device, that device needs to be ' |
34 | - 'made available.\n\nYou may reset the data ' |
35 | - 'location back to the default location, ' |
36 | - 'or you can try to make the current location ' |
37 | - 'available.\n\nDo you want to reset to the ' |
38 | - 'default data location? If not, OpenLP will be ' |
39 | - 'closed so you can try to fix the the problem.') |
40 | - .format(path=data_folder_path), |
41 | - QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | |
42 | - QtWidgets.QMessageBox.No), |
43 | - QtWidgets.QMessageBox.No) |
44 | + data_folder_path = AppLocation.get_data_path() |
45 | + if not data_folder_path.exists(): |
46 | + log.critical('Database was not found in: %s', data_folder_path) |
47 | + status = QtWidgets.QMessageBox.critical( |
48 | + None, translate('OpenLP', 'Data Directory Error'), |
49 | + translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}\n\nThe location of the data folder ' |
50 | + 'was previously changed from the OpenLP\'s default location. If the data was ' |
51 | + 'stored on removable device, that device needs to be made available.\n\nYou may ' |
52 | + 'reset the data location back to the default location, or you can try to make the ' |
53 | + 'current location available.\n\nDo you want to reset to the default data location? ' |
54 | + 'If not, OpenLP will be closed so you can try to fix the the problem.') |
55 | + .format(path=data_folder_path), |
56 | + QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), |
57 | + QtWidgets.QMessageBox.No) |
58 | if status == QtWidgets.QMessageBox.No: |
59 | # If answer was "No", return "True", it will shutdown OpenLP in def main |
60 | log.info('User requested termination') |
61 | @@ -253,11 +247,11 @@ |
62 | 'a backup of the old data folder?'), |
63 | defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes: |
64 | # Create copy of data folder |
65 | - data_folder_path = str(AppLocation.get_data_path()) |
66 | + data_folder_path = AppLocation.get_data_path() |
67 | timestamp = time.strftime("%Y%m%d-%H%M%S") |
68 | - data_folder_backup_path = data_folder_path + '-' + timestamp |
69 | + data_folder_backup_path = data_folder_path.with_name(data_folder_path.name + '-' + timestamp) |
70 | try: |
71 | - shutil.copytree(data_folder_path, data_folder_backup_path) |
72 | + copytree(data_folder_path, data_folder_backup_path) |
73 | except OSError: |
74 | QtWidgets.QMessageBox.warning(None, translate('OpenLP', 'Backup'), |
75 | translate('OpenLP', 'Backup of the data folder failed!')) |
76 | |
77 | === modified file 'openlp/core/common/applocation.py' |
78 | --- openlp/core/common/applocation.py 2017-08-26 15:06:11 +0000 |
79 | +++ openlp/core/common/applocation.py 2017-09-18 20:10:29 +0000 |
80 | @@ -29,7 +29,6 @@ |
81 | from openlp.core.common import Settings, is_win, is_macosx |
82 | from openlp.core.common.path import Path |
83 | |
84 | - |
85 | if not is_win() and not is_macosx(): |
86 | try: |
87 | from xdg import BaseDirectory |
88 | |
89 | === modified file 'openlp/core/common/httputils.py' |
90 | --- openlp/core/common/httputils.py 2017-08-13 05:50:44 +0000 |
91 | +++ openlp/core/common/httputils.py 2017-09-18 20:10:29 +0000 |
92 | @@ -211,7 +211,7 @@ |
93 | |
94 | :param callback: the class which needs to be updated |
95 | :param url: URL to download |
96 | - :param f_path: Destination file |
97 | + :param openlp.core.common.path.Path f_path: Destination file |
98 | :param sha256: The check sum value to be checked against the download value |
99 | """ |
100 | block_count = 0 |
101 | @@ -220,29 +220,23 @@ |
102 | log.debug("url_get_file: " + url) |
103 | while True: |
104 | try: |
105 | - filename = open(f_path, "wb") |
106 | - url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) |
107 | if sha256: |
108 | hasher = hashlib.sha256() |
109 | - # Download until finished or canceled. |
110 | - while not callback.was_cancelled: |
111 | - data = url_file.read(block_size) |
112 | - if not data: |
113 | - break |
114 | - filename.write(data) |
115 | - if sha256: |
116 | - hasher.update(data) |
117 | - block_count += 1 |
118 | - callback._download_progress(block_count, block_size) |
119 | - filename.close() |
120 | - if sha256 and hasher.hexdigest() != sha256: |
121 | - log.error('sha256 sums did not match for file: {file}'.format(file=f_path)) |
122 | - os.remove(f_path) |
123 | - return False |
124 | - except (urllib.error.URLError, socket.timeout) as err: |
125 | + with f_path.open('wb') as file: |
126 | + url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) |
127 | + # Download until finished or canceled. |
128 | + while not callback.was_cancelled: |
129 | + data = url_file.read(block_size) |
130 | + if not data: |
131 | + break |
132 | + file.write(data) |
133 | + if sha256: |
134 | + hasher.update(data) |
135 | + block_count += 1 |
136 | + callback._download_progress(block_count, block_size) |
137 | + except (urllib.error.URLError, socket.timeout): |
138 | trace_error_handler(log) |
139 | - filename.close() |
140 | - os.remove(f_path) |
141 | + f_path.unlink() |
142 | if retries > CONNECTION_RETRIES: |
143 | return False |
144 | else: |
145 | @@ -251,8 +245,12 @@ |
146 | continue |
147 | break |
148 | # Delete file if cancelled, it may be a partial file. |
149 | + if sha256 and hasher.hexdigest() != sha256: |
150 | + log.error('sha256 sums did not match for file: {file}'.format(file=f_path)) |
151 | + f_path.unlink() |
152 | + return False |
153 | if callback.was_cancelled: |
154 | - os.remove(f_path) |
155 | + f_path.unlink() |
156 | return True |
157 | |
158 | |
159 | |
160 | === modified file 'openlp/core/common/languagemanager.py' |
161 | --- openlp/core/common/languagemanager.py 2017-08-01 20:59:41 +0000 |
162 | +++ openlp/core/common/languagemanager.py 2017-09-18 20:10:29 +0000 |
163 | @@ -141,7 +141,7 @@ |
164 | if reg_ex.exactMatch(qmf): |
165 | name = '{regex}'.format(regex=reg_ex.cap(1)) |
166 | LanguageManager.__qm_list__[ |
167 | - '{count:>2i} {name}'.format(count=counter + 1, name=LanguageManager.language_name(qmf))] = name |
168 | + '{count:>2d} {name}'.format(count=counter + 1, name=LanguageManager.language_name(qmf))] = name |
169 | |
170 | @staticmethod |
171 | def get_qm_list(): |
172 | |
173 | === modified file 'openlp/core/common/registry.py' |
174 | --- openlp/core/common/registry.py 2017-03-03 19:27:31 +0000 |
175 | +++ openlp/core/common/registry.py 2017-09-18 20:10:29 +0000 |
176 | @@ -143,7 +143,7 @@ |
177 | log.exception('Exception for function {function}'.format(function=function)) |
178 | else: |
179 | trace_error_handler(log) |
180 | - log.error("Event {event} called but not registered".format(event=event)) |
181 | + log.exception('Event {event} called but not registered'.format(event=event)) |
182 | return results |
183 | |
184 | def get_flag(self, key): |
185 | |
186 | === modified file 'openlp/core/common/uistrings.py' |
187 | --- openlp/core/common/uistrings.py 2017-08-03 17:54:40 +0000 |
188 | +++ openlp/core/common/uistrings.py 2017-09-18 20:10:29 +0000 |
189 | @@ -88,9 +88,6 @@ |
190 | self.Error = translate('OpenLP.Ui', 'Error') |
191 | self.Export = translate('OpenLP.Ui', 'Export') |
192 | self.File = translate('OpenLP.Ui', 'File') |
193 | - self.FileNotFound = translate('OpenLP.Ui', 'File Not Found') |
194 | - self.FileNotFoundMessage = translate('OpenLP.Ui', |
195 | - 'File {name} not found.\nPlease try selecting it individually.') |
196 | self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit') |
197 | self.Help = translate('OpenLP.Ui', 'Help') |
198 | self.Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours') |
199 | |
200 | === modified file 'openlp/core/lib/__init__.py' |
201 | --- openlp/core/lib/__init__.py 2017-08-25 20:03:25 +0000 |
202 | +++ openlp/core/lib/__init__.py 2017-09-18 20:10:29 +0000 |
203 | @@ -32,6 +32,7 @@ |
204 | from PyQt5 import QtCore, QtGui, Qt, QtWidgets |
205 | |
206 | from openlp.core.common import translate |
207 | +from openlp.core.common.path import Path |
208 | |
209 | log = logging.getLogger(__name__ + '.__init__') |
210 | |
211 | @@ -125,10 +126,11 @@ |
212 | Build a QIcon instance from an existing QIcon, a resource location, or a physical file location. If the icon is a |
213 | QIcon instance, that icon is simply returned. If not, it builds a QIcon instance from the resource or file name. |
214 | |
215 | - :param icon: |
216 | - The icon to build. This can be a QIcon, a resource string in the form ``:/resource/file.png``, or a file |
217 | - location like ``/path/to/file.png``. However, the **recommended** way is to specify a resource string. |
218 | + :param QtGui.QIcon | Path | QtGui.QIcon | str icon: |
219 | + The icon to build. This can be a QIcon, a resource string in the form ``:/resource/file.png``, or a file path |
220 | + location like ``Path(/path/to/file.png)``. However, the **recommended** way is to specify a resource string. |
221 | :return: The build icon. |
222 | + :rtype: QtGui.QIcon |
223 | """ |
224 | if isinstance(icon, QtGui.QIcon): |
225 | return icon |
226 | @@ -136,6 +138,8 @@ |
227 | button_icon = QtGui.QIcon() |
228 | if isinstance(icon, str): |
229 | pix_map = QtGui.QPixmap(icon) |
230 | + elif isinstance(icon, Path): |
231 | + pix_map = QtGui.QPixmap(str(icon)) |
232 | elif isinstance(icon, QtGui.QImage): |
233 | pix_map = QtGui.QPixmap.fromImage(icon) |
234 | if pix_map: |
235 | @@ -217,14 +221,15 @@ |
236 | Validates whether an file's thumb still exists and if is up to date. **Note**, you must **not** call this function, |
237 | before checking the existence of the file. |
238 | |
239 | - :param file_path: The path to the file. The file **must** exist! |
240 | - :param thumb_path: The path to the thumb. |
241 | - :return: True, False if the image has changed since the thumb was created. |
242 | + :param openlp.core.common.path.Path file_path: The path to the file. The file **must** exist! |
243 | + :param openlp.core.common.path.Path thumb_path: The path to the thumb. |
244 | + :return: Has the image changed since the thumb was created? |
245 | + :rtype: bool |
246 | """ |
247 | - if not os.path.exists(thumb_path): |
248 | + if not thumb_path.exists(): |
249 | return False |
250 | - image_date = os.stat(file_path).st_mtime |
251 | - thumb_date = os.stat(thumb_path).st_mtime |
252 | + image_date = file_path.stat().st_mtime |
253 | + thumb_date = thumb_path.stat().st_mtime |
254 | return image_date <= thumb_date |
255 | |
256 | |
257 | |
258 | === modified file 'openlp/core/lib/mediamanageritem.py' |
259 | --- openlp/core/lib/mediamanageritem.py 2017-08-26 15:06:11 +0000 |
260 | +++ openlp/core/lib/mediamanageritem.py 2017-09-18 20:10:29 +0000 |
261 | @@ -359,10 +359,8 @@ |
262 | :param files: The files to be loaded. |
263 | :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files |
264 | """ |
265 | - names = [] |
266 | full_list = [] |
267 | for count in range(self.list_view.count()): |
268 | - names.append(self.list_view.item(count).text()) |
269 | full_list.append(self.list_view.item(count).data(QtCore.Qt.UserRole)) |
270 | duplicates_found = False |
271 | files_added = False |
272 | |
273 | === added file 'openlp/core/lib/shutil.py' |
274 | --- openlp/core/lib/shutil.py 1970-01-01 00:00:00 +0000 |
275 | +++ openlp/core/lib/shutil.py 2017-09-18 20:10:29 +0000 |
276 | @@ -0,0 +1,112 @@ |
277 | +# -*- coding: utf-8 -*- |
278 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
279 | + |
280 | +############################################################################### |
281 | +# OpenLP - Open Source Lyrics Projection # |
282 | +# --------------------------------------------------------------------------- # |
283 | +# Copyright (c) 2008-2017 OpenLP Developers # |
284 | +# --------------------------------------------------------------------------- # |
285 | +# This program is free software; you can redistribute it and/or modify it # |
286 | +# under the terms of the GNU General Public License as published by the Free # |
287 | +# Software Foundation; version 2 of the License. # |
288 | +# # |
289 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
290 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
291 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
292 | +# more details. # |
293 | +# # |
294 | +# You should have received a copy of the GNU General Public License along # |
295 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
296 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
297 | +############################################################################### |
298 | +""" Patch the shutil methods we use so they accept and return Path objects""" |
299 | +import shutil |
300 | + |
301 | +from openlp.core.common.path import path_to_str, str_to_path |
302 | +from openlp.core.lib import replace_params |
303 | + |
304 | + |
305 | +def copy(*args, **kwargs): |
306 | + """ |
307 | + Wraps :func:`shutil.copy` so that we can accept Path objects. |
308 | + |
309 | + :param src openlp.core.common.path.Path: Takes a Path object which is then converted to a str object |
310 | + :param dst openlp.core.common.path.Path: Takes a Path object which is then converted to a str object |
311 | + :return: Converts the str object received from :func:`shutil.copy` to a Path or NoneType object |
312 | + :rtype: openlp.core.common.path.Path | None |
313 | + |
314 | + See the following link for more information on the other parameters: |
315 | + https://docs.python.org/3/library/shutil.html#shutil.copy |
316 | + """ |
317 | + |
318 | + args, kwargs = replace_params(args, kwargs, ((0, 'src', path_to_str), (1, 'dst', path_to_str))) |
319 | + |
320 | + return str_to_path(shutil.copy(*args, **kwargs)) |
321 | + |
322 | + |
323 | +def copyfile(*args, **kwargs): |
324 | + """ |
325 | + Wraps :func:`shutil.copyfile` so that we can accept Path objects. |
326 | + |
327 | + :param openlp.core.common.path.Path src: Takes a Path object which is then converted to a str object |
328 | + :param openlp.core.common.path.Path dst: Takes a Path object which is then converted to a str object |
329 | + :return: Converts the str object received from :func:`shutil.copyfile` to a Path or NoneType object |
330 | + :rtype: openlp.core.common.path.Path | None |
331 | + |
332 | + See the following link for more information on the other parameters: |
333 | + https://docs.python.org/3/library/shutil.html#shutil.copyfile |
334 | + """ |
335 | + |
336 | + args, kwargs = replace_params(args, kwargs, ((0, 'src', path_to_str), (1, 'dst', path_to_str))) |
337 | + |
338 | + return str_to_path(shutil.copyfile(*args, **kwargs)) |
339 | + |
340 | + |
341 | +def copytree(*args, **kwargs): |
342 | + """ |
343 | + Wraps :func:shutil.copytree` so that we can accept Path objects. |
344 | + |
345 | + :param openlp.core.common.path.Path src : Takes a Path object which is then converted to a str object |
346 | + :param openlp.core.common.path.Path dst: Takes a Path object which is then converted to a str object |
347 | + :return: Converts the str object received from :func:`shutil.copytree` to a Path or NoneType object |
348 | + :rtype: openlp.core.common.path.Path | None |
349 | + |
350 | + See the following link for more information on the other parameters: |
351 | + https://docs.python.org/3/library/shutil.html#shutil.copytree |
352 | + """ |
353 | + |
354 | + args, kwargs = replace_params(args, kwargs, ((0, 'src', path_to_str), (1, 'dst', path_to_str))) |
355 | + |
356 | + return str_to_path(shutil.copytree(*args, **kwargs)) |
357 | + |
358 | + |
359 | +def rmtree(*args, **kwargs): |
360 | + """ |
361 | + Wraps :func:shutil.rmtree` so that we can accept Path objects. |
362 | + |
363 | + :param openlp.core.common.path.Path path: Takes a Path object which is then converted to a str object |
364 | + :return: Passes the return from :func:`shutil.rmtree` back |
365 | + :rtype: None |
366 | + |
367 | + See the following link for more information on the other parameters: |
368 | + https://docs.python.org/3/library/shutil.html#shutil.rmtree |
369 | + """ |
370 | + |
371 | + args, kwargs = replace_params(args, kwargs, ((0, 'path', path_to_str),)) |
372 | + |
373 | + return shutil.rmtree(*args, **kwargs) |
374 | + |
375 | + |
376 | +def which(*args, **kwargs): |
377 | + """ |
378 | + Wraps :func:shutil.which` so that it return a Path objects. |
379 | + |
380 | + :rtype: openlp.core.common.Path |
381 | + |
382 | + See the following link for more information on the other parameters: |
383 | + https://docs.python.org/3/library/shutil.html#shutil.which |
384 | + """ |
385 | + file_name = shutil.which(*args, **kwargs) |
386 | + if file_name: |
387 | + return str_to_path(file_name) |
388 | + return None |
389 | |
390 | === modified file 'openlp/core/ui/firsttimeform.py' |
391 | --- openlp/core/ui/firsttimeform.py 2017-08-25 20:03:25 +0000 |
392 | +++ openlp/core/ui/firsttimeform.py 2017-09-18 20:10:29 +0000 |
393 | @@ -563,7 +563,7 @@ |
394 | filename, sha256 = item.data(QtCore.Qt.UserRole) |
395 | self._increment_progress_bar(self.downloading.format(name=filename), 0) |
396 | self.previous_size = 0 |
397 | - destination = os.path.join(songs_destination, str(filename)) |
398 | + destination = Path(songs_destination, str(filename)) |
399 | if not url_get_file(self, '{path}{name}'.format(path=self.songs_url, name=filename), |
400 | destination, sha256): |
401 | missed_files.append('Song: {name}'.format(name=filename)) |
402 | @@ -576,7 +576,7 @@ |
403 | self._increment_progress_bar(self.downloading.format(name=bible), 0) |
404 | self.previous_size = 0 |
405 | if not url_get_file(self, '{path}{name}'.format(path=self.bibles_url, name=bible), |
406 | - os.path.join(bibles_destination, bible), |
407 | + Path(bibles_destination, bible), |
408 | sha256): |
409 | missed_files.append('Bible: {name}'.format(name=bible)) |
410 | bibles_iterator += 1 |
411 | @@ -588,7 +588,7 @@ |
412 | self._increment_progress_bar(self.downloading.format(name=theme), 0) |
413 | self.previous_size = 0 |
414 | if not url_get_file(self, '{path}{name}'.format(path=self.themes_url, name=theme), |
415 | - os.path.join(themes_destination, theme), |
416 | + Path(themes_destination, theme), |
417 | sha256): |
418 | missed_files.append('Theme: {name}'.format(name=theme)) |
419 | if missed_files: |
420 | |
421 | === modified file 'openlp/core/ui/lib/wizard.py' |
422 | --- openlp/core/ui/lib/wizard.py 2017-08-26 15:06:11 +0000 |
423 | +++ openlp/core/ui/lib/wizard.py 2017-09-18 20:10:29 +0000 |
424 | @@ -310,7 +310,7 @@ |
425 | """ |
426 | folder_path = FileDialog.getExistingDirectory( |
427 | self, title, Settings().value(self.plugin.settings_section + '/' + setting_name), |
428 | - QtWidgets.QFileDialog.ShowDirsOnly) |
429 | + FileDialog.ShowDirsOnly) |
430 | if folder_path: |
431 | editbox.setText(str(folder_path)) |
432 | Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder_path) |
433 | |
434 | === modified file 'openlp/core/ui/mainwindow.py' |
435 | --- openlp/core/ui/mainwindow.py 2017-09-03 10:18:14 +0000 |
436 | +++ openlp/core/ui/mainwindow.py 2017-09-18 20:10:29 +0000 |
437 | @@ -42,6 +42,7 @@ |
438 | from openlp.core.common.path import Path, path_to_str, str_to_path |
439 | from openlp.core.common.versionchecker import get_application_version |
440 | from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon |
441 | +from openlp.core.lib.shutil import copyfile |
442 | from openlp.core.lib.ui import create_action |
443 | from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \ |
444 | ShortcutListForm, FormattingTagForm, PreviewController |
445 | @@ -848,12 +849,12 @@ |
446 | QtWidgets.QMessageBox.No) |
447 | if answer == QtWidgets.QMessageBox.No: |
448 | return |
449 | - import_file_name, filter_used = QtWidgets.QFileDialog.getOpenFileName( |
450 | + import_file_path, filter_used = FileDialog.getOpenFileName( |
451 | self, |
452 | translate('OpenLP.MainWindow', 'Import settings'), |
453 | - '', |
454 | + None, |
455 | translate('OpenLP.MainWindow', 'OpenLP Settings (*.conf)')) |
456 | - if not import_file_name: |
457 | + if import_file_path is None: |
458 | return |
459 | setting_sections = [] |
460 | # Add main sections. |
461 | @@ -871,12 +872,12 @@ |
462 | # Add plugin sections. |
463 | setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins]) |
464 | # Copy the settings file to the tmp dir, because we do not want to change the original one. |
465 | - temp_directory = os.path.join(str(gettempdir()), 'openlp') |
466 | - check_directory_exists(Path(temp_directory)) |
467 | - temp_config = os.path.join(temp_directory, os.path.basename(import_file_name)) |
468 | - shutil.copyfile(import_file_name, temp_config) |
469 | + temp_dir_path = Path(gettempdir(), 'openlp') |
470 | + check_directory_exists(temp_dir_path) |
471 | + temp_config_path = temp_dir_path / import_file_path.name |
472 | + copyfile(import_file_path, temp_config_path) |
473 | settings = Settings() |
474 | - import_settings = Settings(temp_config, Settings.IniFormat) |
475 | + import_settings = Settings(str(temp_config_path), Settings.IniFormat) |
476 | |
477 | log.info('hook upgrade_plugin_settings') |
478 | self.plugin_manager.hook_upgrade_plugin_settings(import_settings) |
479 | @@ -920,7 +921,7 @@ |
480 | settings.setValue('{key}'.format(key=section_key), value) |
481 | now = datetime.now() |
482 | settings.beginGroup(self.header_section) |
483 | - settings.setValue('file_imported', import_file_name) |
484 | + settings.setValue('file_imported', import_file_path) |
485 | settings.setValue('file_date_imported', now.strftime("%Y-%m-%d %H:%M")) |
486 | settings.endGroup() |
487 | settings.sync() |
488 | |
489 | === modified file 'openlp/core/ui/servicemanager.py' |
490 | --- openlp/core/ui/servicemanager.py 2017-08-26 15:06:11 +0000 |
491 | +++ openlp/core/ui/servicemanager.py 2017-09-18 20:10:29 +0000 |
492 | @@ -366,16 +366,20 @@ |
493 | """ |
494 | return self._modified |
495 | |
496 | - def set_file_name(self, file_name): |
497 | + def set_file_name(self, file_path): |
498 | """ |
499 | Setter for service file. |
500 | |
501 | - :param file_name: The service file name |
502 | + :param openlp.core.common.path.Path file_path: The service file name |
503 | + :rtype: None |
504 | """ |
505 | - self._file_name = str(file_name) |
506 | + self._file_name = path_to_str(file_path) |
507 | self.main_window.set_service_modified(self.is_modified(), self.short_file_name()) |
508 | - Settings().setValue('servicemanager/last file', Path(file_name)) |
509 | - self._save_lite = self._file_name.endswith('.oszl') |
510 | + Settings().setValue('servicemanager/last file', file_path) |
511 | + if file_path and file_path.suffix() == '.oszl': |
512 | + self._save_lite = True |
513 | + else: |
514 | + self._save_lite = False |
515 | |
516 | def file_name(self): |
517 | """ |
518 | @@ -474,7 +478,7 @@ |
519 | """ |
520 | self.service_manager_list.clear() |
521 | self.service_items = [] |
522 | - self.set_file_name('') |
523 | + self.set_file_name(None) |
524 | self.service_id += 1 |
525 | self.set_modified(False) |
526 | Settings().setValue('servicemanager/last file', None) |
527 | @@ -695,27 +699,23 @@ |
528 | default_file_name = format_time(default_pattern, local_time) |
529 | else: |
530 | default_file_name = '' |
531 | - directory = path_to_str(Settings().value(self.main_window.service_manager_settings_section + '/last directory')) |
532 | - path = os.path.join(directory, default_file_name) |
533 | + directory_path = Settings().value(self.main_window.service_manager_settings_section + '/last directory') |
534 | + file_path = directory_path / default_file_name |
535 | # SaveAs from osz to oszl is not valid as the files will be deleted on exit which is not sensible or usable in |
536 | # the long term. |
537 | if self._file_name.endswith('oszl') or self.service_has_all_original_files: |
538 | - file_name, filter_used = QtWidgets.QFileDialog.getSaveFileName( |
539 | - self.main_window, UiStrings().SaveService, path, |
540 | + file_path, filter_used = FileDialog.getSaveFileName( |
541 | + self.main_window, UiStrings().SaveService, file_path, |
542 | translate('OpenLP.ServiceManager', |
543 | 'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)')) |
544 | else: |
545 | - file_name, filter_used = QtWidgets.QFileDialog.getSaveFileName( |
546 | - self.main_window, UiStrings().SaveService, path, |
547 | + file_path, filter_used = FileDialog.getSaveFileName( |
548 | + self.main_window, UiStrings().SaveService, file_path, |
549 | translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz);;')) |
550 | - if not file_name: |
551 | + if not file_path: |
552 | return False |
553 | - if os.path.splitext(file_name)[1] == '': |
554 | - file_name += '.osz' |
555 | - else: |
556 | - ext = os.path.splitext(file_name)[1] |
557 | - file_name.replace(ext, '.osz') |
558 | - self.set_file_name(file_name) |
559 | + file_path.with_suffix('.osz') |
560 | + self.set_file_name(file_path) |
561 | self.decide_save_method() |
562 | |
563 | def decide_save_method(self, field=None): |
564 | @@ -772,7 +772,7 @@ |
565 | return |
566 | file_to.close() |
567 | self.new_file() |
568 | - self.set_file_name(file_name) |
569 | + self.set_file_name(str_to_path(file_name)) |
570 | self.main_window.display_progress_bar(len(items)) |
571 | self.process_service_items(items) |
572 | delete_file(Path(p_file)) |
573 | |
574 | === modified file 'openlp/core/ui/thememanager.py' |
575 | --- openlp/core/ui/thememanager.py 2017-08-26 16:50:54 +0000 |
576 | +++ openlp/core/ui/thememanager.py 2017-09-18 20:10:29 +0000 |
577 | @@ -483,7 +483,7 @@ |
578 | name = text_name |
579 | thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=text_name)) |
580 | item_name = QtWidgets.QListWidgetItem(name) |
581 | - if validate_thumb(theme, thumb): |
582 | + if validate_thumb(Path(theme), Path(thumb)): |
583 | icon = build_icon(thumb) |
584 | else: |
585 | icon = create_thumb(theme, thumb) |
586 | |
587 | === modified file 'openlp/plugins/images/lib/mediaitem.py' |
588 | --- openlp/plugins/images/lib/mediaitem.py 2017-08-26 15:06:11 +0000 |
589 | +++ openlp/plugins/images/lib/mediaitem.py 2017-09-18 20:10:29 +0000 |
590 | @@ -360,7 +360,7 @@ |
591 | if not os.path.exists(image_file.filename): |
592 | icon = build_icon(':/general/general_delete.png') |
593 | else: |
594 | - if validate_thumb(image_file.filename, thumb): |
595 | + if validate_thumb(Path(image_file.filename), Path(thumb)): |
596 | icon = build_icon(thumb) |
597 | else: |
598 | icon = create_thumb(image_file.filename, thumb) |
599 | |
600 | === modified file 'openlp/plugins/presentations/lib/impresscontroller.py' |
601 | --- openlp/plugins/presentations/lib/impresscontroller.py 2017-08-25 20:03:25 +0000 |
602 | +++ openlp/plugins/presentations/lib/impresscontroller.py 2017-09-18 20:10:29 +0000 |
603 | @@ -32,11 +32,14 @@ |
604 | # http://nxsy.org/comparing-documents-with-openoffice-and-python |
605 | |
606 | import logging |
607 | -import os |
608 | import time |
609 | |
610 | -from openlp.core.common import is_win, Registry, delete_file |
611 | -from openlp.core.common.path import Path |
612 | +from PyQt5 import QtCore |
613 | + |
614 | +from openlp.core.common import Registry, delete_file, get_uno_command, get_uno_instance, is_win |
615 | +from openlp.core.lib import ScreenList |
616 | +from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \ |
617 | + TextType |
618 | |
619 | if is_win(): |
620 | from win32com.client import Dispatch |
621 | @@ -55,14 +58,6 @@ |
622 | except ImportError: |
623 | uno_available = False |
624 | |
625 | -from PyQt5 import QtCore |
626 | - |
627 | -from openlp.core.lib import ScreenList |
628 | -from openlp.core.common import get_uno_command, get_uno_instance |
629 | -from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \ |
630 | - TextType |
631 | - |
632 | - |
633 | log = logging.getLogger(__name__) |
634 | |
635 | |
636 | @@ -203,12 +198,15 @@ |
637 | Class which holds information and controls a single presentation. |
638 | """ |
639 | |
640 | - def __init__(self, controller, presentation): |
641 | + def __init__(self, controller, document_path): |
642 | """ |
643 | Constructor, store information about the file and initialise. |
644 | + |
645 | + :param openlp.core.common.path.Path document_path: File path for the document to load |
646 | + :rtype: None |
647 | """ |
648 | log.debug('Init Presentation OpenOffice') |
649 | - super(ImpressDocument, self).__init__(controller, presentation) |
650 | + super().__init__(controller, document_path) |
651 | self.document = None |
652 | self.presentation = None |
653 | self.control = None |
654 | @@ -225,10 +223,9 @@ |
655 | if desktop is None: |
656 | self.controller.start_process() |
657 | desktop = self.controller.get_com_desktop() |
658 | - url = 'file:///' + self.file_path.replace('\\', '/').replace(':', '|').replace(' ', '%20') |
659 | else: |
660 | desktop = self.controller.get_uno_desktop() |
661 | - url = uno.systemPathToFileUrl(self.file_path) |
662 | + url = self.file_path.as_uri() |
663 | if desktop is None: |
664 | return False |
665 | self.desktop = desktop |
666 | @@ -254,11 +251,8 @@ |
667 | log.debug('create thumbnails OpenOffice') |
668 | if self.check_thumbnails(): |
669 | return |
670 | - if is_win(): |
671 | - thumb_dir_url = 'file:///' + self.get_temp_folder().replace('\\', '/') \ |
672 | - .replace(':', '|').replace(' ', '%20') |
673 | - else: |
674 | - thumb_dir_url = uno.systemPathToFileUrl(self.get_temp_folder()) |
675 | + temp_folder_path = self.get_temp_folder() |
676 | + thumb_dir_url = temp_folder_path.as_uri() |
677 | properties = [] |
678 | properties.append(self.create_property('FilterName', 'impress_png_Export')) |
679 | properties = tuple(properties) |
680 | @@ -266,17 +260,17 @@ |
681 | pages = doc.getDrawPages() |
682 | if not pages: |
683 | return |
684 | - if not os.path.isdir(self.get_temp_folder()): |
685 | - os.makedirs(self.get_temp_folder()) |
686 | + if not temp_folder_path.is_dir(): |
687 | + temp_folder_path.mkdir(parents=True) |
688 | for index in range(pages.getCount()): |
689 | page = pages.getByIndex(index) |
690 | doc.getCurrentController().setCurrentPage(page) |
691 | - url_path = '{path}/{name}.png'.format(path=thumb_dir_url, name=str(index + 1)) |
692 | - path = os.path.join(self.get_temp_folder(), str(index + 1) + '.png') |
693 | + url_path = '{path}/{name:d}.png'.format(path=thumb_dir_url, name=index + 1) |
694 | + path = temp_folder_path / '{number:d}.png'.format(number=index + 1) |
695 | try: |
696 | doc.storeToURL(url_path, properties) |
697 | self.convert_thumbnail(path, index + 1) |
698 | - delete_file(Path(path)) |
699 | + delete_file(path) |
700 | except ErrorCodeIOException as exception: |
701 | log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode)) |
702 | except: |
703 | |
704 | === modified file 'openlp/plugins/presentations/lib/mediaitem.py' |
705 | --- openlp/plugins/presentations/lib/mediaitem.py 2017-08-26 15:06:11 +0000 |
706 | +++ openlp/plugins/presentations/lib/mediaitem.py 2017-09-18 20:10:29 +0000 |
707 | @@ -19,15 +19,13 @@ |
708 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # |
709 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
710 | ############################################################################### |
711 | - |
712 | import logging |
713 | -import os |
714 | |
715 | from PyQt5 import QtCore, QtGui, QtWidgets |
716 | |
717 | from openlp.core.common import Registry, Settings, UiStrings, translate |
718 | from openlp.core.common.languagemanager import get_locale_key |
719 | -from openlp.core.common.path import path_to_str |
720 | +from openlp.core.common.path import Path, path_to_str, str_to_path |
721 | from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext,\ |
722 | build_icon, check_item_selected, create_thumb, validate_thumb |
723 | from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box |
724 | @@ -128,7 +126,7 @@ |
725 | """ |
726 | self.list_view.setIconSize(QtCore.QSize(88, 50)) |
727 | file_paths = Settings().value(self.settings_section + '/presentations files') |
728 | - self.load_list([path_to_str(file) for file in file_paths], initial_load=True) |
729 | + self.load_list([path_to_str(path) for path in file_paths], initial_load=True) |
730 | self.populate_display_types() |
731 | |
732 | def populate_display_types(self): |
733 | @@ -152,54 +150,57 @@ |
734 | else: |
735 | self.presentation_widget.hide() |
736 | |
737 | - def load_list(self, files, target_group=None, initial_load=False): |
738 | + def load_list(self, file_paths, target_group=None, initial_load=False): |
739 | """ |
740 | Add presentations into the media manager. This is called both on initial load of the plugin to populate with |
741 | existing files, and when the user adds new files via the media manager. |
742 | + |
743 | + :param list[openlp.core.common.path.Path] file_paths: List of file paths to add to the media manager. |
744 | """ |
745 | - current_list = self.get_file_list() |
746 | - titles = [file_path.name for file_path in current_list] |
747 | + file_paths = [str_to_path(filename) for filename in file_paths] |
748 | + current_paths = self.get_file_list() |
749 | + titles = [file_path.name for file_path in current_paths] |
750 | self.application.set_busy_cursor() |
751 | if not initial_load: |
752 | - self.main_window.display_progress_bar(len(files)) |
753 | + self.main_window.display_progress_bar(len(file_paths)) |
754 | # Sort the presentations by its filename considering language specific characters. |
755 | - files.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1])) |
756 | - for file in files: |
757 | + file_paths.sort(key=lambda file_path: get_locale_key(file_path.name)) |
758 | + for file_path in file_paths: |
759 | if not initial_load: |
760 | self.main_window.increment_progress_bar() |
761 | - if current_list.count(file) > 0: |
762 | + if current_paths.count(file_path) > 0: |
763 | continue |
764 | - filename = os.path.split(file)[1] |
765 | - if not os.path.exists(file): |
766 | - item_name = QtWidgets.QListWidgetItem(filename) |
767 | + file_name = file_path.name |
768 | + if not file_path.exists(): |
769 | + item_name = QtWidgets.QListWidgetItem(file_name) |
770 | item_name.setIcon(build_icon(ERROR_IMAGE)) |
771 | - item_name.setData(QtCore.Qt.UserRole, file) |
772 | - item_name.setToolTip(file) |
773 | + item_name.setData(QtCore.Qt.UserRole, path_to_str(file_path)) |
774 | + item_name.setToolTip(str(file_path)) |
775 | self.list_view.addItem(item_name) |
776 | else: |
777 | - if titles.count(filename) > 0: |
778 | + if titles.count(file_name) > 0: |
779 | if not initial_load: |
780 | critical_error_message_box(translate('PresentationPlugin.MediaItem', 'File Exists'), |
781 | translate('PresentationPlugin.MediaItem', |
782 | 'A presentation with that filename already exists.')) |
783 | continue |
784 | - controller_name = self.find_controller_by_type(filename) |
785 | + controller_name = self.find_controller_by_type(file_path) |
786 | if controller_name: |
787 | controller = self.controllers[controller_name] |
788 | - doc = controller.add_document(file) |
789 | - thumb = os.path.join(doc.get_thumbnail_folder(), 'icon.png') |
790 | - preview = doc.get_thumbnail_path(1, True) |
791 | - if not preview and not initial_load: |
792 | + doc = controller.add_document(file_path) |
793 | + thumbnail_path = doc.get_thumbnail_folder() / 'icon.png' |
794 | + preview_path = doc.get_thumbnail_path(1, True) |
795 | + if not preview_path and not initial_load: |
796 | doc.load_presentation() |
797 | - preview = doc.get_thumbnail_path(1, True) |
798 | + preview_path = doc.get_thumbnail_path(1, True) |
799 | doc.close_presentation() |
800 | - if not (preview and os.path.exists(preview)): |
801 | + if not (preview_path and preview_path.exists()): |
802 | icon = build_icon(':/general/general_delete.png') |
803 | else: |
804 | - if validate_thumb(preview, thumb): |
805 | - icon = build_icon(thumb) |
806 | + if validate_thumb(Path(preview_path), Path(thumbnail_path)): |
807 | + icon = build_icon(thumbnail_path) |
808 | else: |
809 | - icon = create_thumb(preview, thumb) |
810 | + icon = create_thumb(str(preview_path), str(thumbnail_path)) |
811 | else: |
812 | if initial_load: |
813 | icon = build_icon(':/general/general_delete.png') |
814 | @@ -208,10 +209,10 @@ |
815 | translate('PresentationPlugin.MediaItem', |
816 | 'This type of presentation is not supported.')) |
817 | continue |
818 | - item_name = QtWidgets.QListWidgetItem(filename) |
819 | - item_name.setData(QtCore.Qt.UserRole, file) |
820 | + item_name = QtWidgets.QListWidgetItem(file_name) |
821 | + item_name.setData(QtCore.Qt.UserRole, path_to_str(file_path)) |
822 | item_name.setIcon(icon) |
823 | - item_name.setToolTip(file) |
824 | + item_name.setToolTip(str(file_path)) |
825 | self.list_view.addItem(item_name) |
826 | if not initial_load: |
827 | self.main_window.finished_progress_bar() |
828 | @@ -228,8 +229,8 @@ |
829 | self.application.set_busy_cursor() |
830 | self.main_window.display_progress_bar(len(row_list)) |
831 | for item in items: |
832 | - filepath = str(item.data(QtCore.Qt.UserRole)) |
833 | - self.clean_up_thumbnails(filepath) |
834 | + file_path = str_to_path(item.data(QtCore.Qt.UserRole)) |
835 | + self.clean_up_thumbnails(file_path) |
836 | self.main_window.increment_progress_bar() |
837 | self.main_window.finished_progress_bar() |
838 | for row in row_list: |
839 | @@ -237,30 +238,29 @@ |
840 | Settings().setValue(self.settings_section + '/presentations files', self.get_file_list()) |
841 | self.application.set_normal_cursor() |
842 | |
843 | - def clean_up_thumbnails(self, filepath, clean_for_update=False): |
844 | + def clean_up_thumbnails(self, file_path, clean_for_update=False): |
845 | """ |
846 | Clean up the files created such as thumbnails |
847 | |
848 | - :param filepath: File path of the presention to clean up after |
849 | - :param clean_for_update: Only clean thumbnails if update is needed |
850 | - :return: None |
851 | + :param openlp.core.common.path.Path file_path: File path of the presention to clean up after |
852 | + :param bool clean_for_update: Only clean thumbnails if update is needed |
853 | + :rtype: None |
854 | """ |
855 | for cidx in self.controllers: |
856 | - root, file_ext = os.path.splitext(filepath) |
857 | - file_ext = file_ext[1:] |
858 | + file_ext = file_path.suffix[1:] |
859 | if file_ext in self.controllers[cidx].supports or file_ext in self.controllers[cidx].also_supports: |
860 | - doc = self.controllers[cidx].add_document(filepath) |
861 | + doc = self.controllers[cidx].add_document(file_path) |
862 | if clean_for_update: |
863 | thumb_path = doc.get_thumbnail_path(1, True) |
864 | - if not thumb_path or not os.path.exists(filepath) or os.path.getmtime( |
865 | - thumb_path) < os.path.getmtime(filepath): |
866 | + if not thumb_path or not file_path.exists() or \ |
867 | + thumb_path.stat().st_mtime < file_path.stat().st_mtime: |
868 | doc.presentation_deleted() |
869 | else: |
870 | doc.presentation_deleted() |
871 | doc.close_presentation() |
872 | |
873 | def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, |
874 | - context=ServiceItemContext.Service, presentation_file=None): |
875 | + context=ServiceItemContext.Service, file_path=None): |
876 | """ |
877 | Generate the slide data. Needs to be implemented by the plugin. |
878 | |
879 | @@ -276,10 +276,9 @@ |
880 | items = self.list_view.selectedItems() |
881 | if len(items) > 1: |
882 | return False |
883 | - filename = presentation_file |
884 | - if filename is None: |
885 | - filename = items[0].data(QtCore.Qt.UserRole) |
886 | - file_type = os.path.splitext(filename.lower())[1][1:] |
887 | + if file_path is None: |
888 | + file_path = str_to_path(items[0].data(QtCore.Qt.UserRole)) |
889 | + file_type = file_path.suffix.lower()[1:] |
890 | if not self.display_type_combo_box.currentText(): |
891 | return False |
892 | service_item.add_capability(ItemCapabilities.CanEditTitle) |
893 | @@ -292,29 +291,28 @@ |
894 | # force a nonexistent theme |
895 | service_item.theme = -1 |
896 | for bitem in items: |
897 | - filename = presentation_file |
898 | - if filename is None: |
899 | - filename = bitem.data(QtCore.Qt.UserRole) |
900 | - (path, name) = os.path.split(filename) |
901 | - service_item.title = name |
902 | - if os.path.exists(filename): |
903 | - processor = self.find_controller_by_type(filename) |
904 | + if file_path is None: |
905 | + file_path = str_to_path(bitem.data(QtCore.Qt.UserRole)) |
906 | + path, file_name = file_path.parent, file_path.name |
907 | + service_item.title = file_name |
908 | + if file_path.exists(): |
909 | + processor = self.find_controller_by_type(file_path) |
910 | if not processor: |
911 | return False |
912 | controller = self.controllers[processor] |
913 | service_item.processor = None |
914 | - doc = controller.add_document(filename) |
915 | - if doc.get_thumbnail_path(1, True) is None or not os.path.isfile( |
916 | - os.path.join(doc.get_temp_folder(), 'mainslide001.png')): |
917 | + doc = controller.add_document(file_path) |
918 | + if doc.get_thumbnail_path(1, True) is None or \ |
919 | + not (doc.get_temp_folder() / 'mainslide001.png').is_file(): |
920 | doc.load_presentation() |
921 | i = 1 |
922 | - image = os.path.join(doc.get_temp_folder(), 'mainslide{number:0>3d}.png'.format(number=i)) |
923 | - thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide%d.png' % i) |
924 | - while os.path.isfile(image): |
925 | - service_item.add_from_image(image, name, thumbnail=thumbnail) |
926 | + image_path = doc.get_temp_folder() / 'mainslide{number:0>3d}.png'.format(number=i) |
927 | + thumbnail_path = doc.get_thumbnail_folder() / 'slide{number:d}.png'.format(number=i) |
928 | + while image_path.is_file(): |
929 | + service_item.add_from_image(str(image_path), file_name, thumbnail=str(thumbnail_path)) |
930 | i += 1 |
931 | - image = os.path.join(doc.get_temp_folder(), 'mainslide{number:0>3d}.png'.format(number=i)) |
932 | - thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide{number:d}.png'.format(number=i)) |
933 | + image_path = doc.get_temp_folder() / 'mainslide{number:0>3d}.png'.format(number=i) |
934 | + thumbnail_path = doc.get_thumbnail_folder() / 'slide{number:d}.png'.format(number=i) |
935 | service_item.add_capability(ItemCapabilities.HasThumbnails) |
936 | doc.close_presentation() |
937 | return True |
938 | @@ -324,34 +322,34 @@ |
939 | critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), |
940 | translate('PresentationPlugin.MediaItem', |
941 | 'The presentation {name} no longer exists.' |
942 | - ).format(name=filename)) |
943 | + ).format(name=file_path)) |
944 | return False |
945 | else: |
946 | service_item.processor = self.display_type_combo_box.currentText() |
947 | service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay) |
948 | for bitem in items: |
949 | - filename = bitem.data(QtCore.Qt.UserRole) |
950 | - (path, name) = os.path.split(filename) |
951 | - service_item.title = name |
952 | - if os.path.exists(filename): |
953 | + file_path = str_to_path(bitem.data(QtCore.Qt.UserRole)) |
954 | + path, file_name = file_path.parent, file_path.name |
955 | + service_item.title = file_name |
956 | + if file_path.exists: |
957 | if self.display_type_combo_box.itemData(self.display_type_combo_box.currentIndex()) == 'automatic': |
958 | - service_item.processor = self.find_controller_by_type(filename) |
959 | + service_item.processor = self.find_controller_by_type(file_path) |
960 | if not service_item.processor: |
961 | return False |
962 | controller = self.controllers[service_item.processor] |
963 | - doc = controller.add_document(filename) |
964 | + doc = controller.add_document(file_path) |
965 | if doc.get_thumbnail_path(1, True) is None: |
966 | doc.load_presentation() |
967 | i = 1 |
968 | - img = doc.get_thumbnail_path(i, True) |
969 | - if img: |
970 | + thumbnail_path = doc.get_thumbnail_path(i, True) |
971 | + if thumbnail_path: |
972 | # Get titles and notes |
973 | titles, notes = doc.get_titles_and_notes() |
974 | service_item.add_capability(ItemCapabilities.HasDisplayTitle) |
975 | if notes.count('') != len(notes): |
976 | service_item.add_capability(ItemCapabilities.HasNotes) |
977 | service_item.add_capability(ItemCapabilities.HasThumbnails) |
978 | - while img: |
979 | + while thumbnail_path: |
980 | # Use title and note if available |
981 | title = '' |
982 | if titles and len(titles) >= i: |
983 | @@ -359,9 +357,9 @@ |
984 | note = '' |
985 | if notes and len(notes) >= i: |
986 | note = notes[i - 1] |
987 | - service_item.add_from_command(path, name, img, title, note) |
988 | + service_item.add_from_command(str(path), file_name, str(thumbnail_path), title, note) |
989 | i += 1 |
990 | - img = doc.get_thumbnail_path(i, True) |
991 | + thumbnail_path = doc.get_thumbnail_path(i, True) |
992 | doc.close_presentation() |
993 | return True |
994 | else: |
995 | @@ -371,7 +369,7 @@ |
996 | 'Missing Presentation'), |
997 | translate('PresentationPlugin.MediaItem', |
998 | 'The presentation {name} is incomplete, ' |
999 | - 'please reload.').format(name=filename)) |
1000 | + 'please reload.').format(name=file_path)) |
1001 | return False |
1002 | else: |
1003 | # File is no longer present |
1004 | @@ -379,18 +377,20 @@ |
1005 | critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), |
1006 | translate('PresentationPlugin.MediaItem', |
1007 | 'The presentation {name} no longer exists.' |
1008 | - ).format(name=filename)) |
1009 | + ).format(name=file_path)) |
1010 | return False |
1011 | |
1012 | - def find_controller_by_type(self, filename): |
1013 | + def find_controller_by_type(self, file_path): |
1014 | """ |
1015 | Determine the default application controller to use for the selected file type. This is used if "Automatic" is |
1016 | set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension. |
1017 | If none found, then look for a controller which "also supports" it instead. |
1018 | |
1019 | - :param filename: The file name |
1020 | + :param openlp.core.common.path.Path file_path: The file path |
1021 | + :return: The default application controller for this file type, or None if not supported |
1022 | + :rtype: PresentationController |
1023 | """ |
1024 | - file_type = os.path.splitext(filename)[1][1:] |
1025 | + file_type = file_path.suffix[1:] |
1026 | if not file_type: |
1027 | return None |
1028 | for controller in self.controllers: |
1029 | |
1030 | === modified file 'openlp/plugins/presentations/lib/messagelistener.py' |
1031 | --- openlp/plugins/presentations/lib/messagelistener.py 2016-12-31 11:01:36 +0000 |
1032 | +++ openlp/plugins/presentations/lib/messagelistener.py 2017-09-18 20:10:29 +0000 |
1033 | @@ -19,16 +19,15 @@ |
1034 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # |
1035 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
1036 | ############################################################################### |
1037 | - |
1038 | +import copy |
1039 | import logging |
1040 | -import copy |
1041 | -import os |
1042 | |
1043 | from PyQt5 import QtCore |
1044 | |
1045 | from openlp.core.common import Registry, Settings |
1046 | +from openlp.core.common.path import Path |
1047 | +from openlp.core.lib import ServiceItemContext |
1048 | from openlp.core.ui import HideMode |
1049 | -from openlp.core.lib import ServiceItemContext |
1050 | from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES |
1051 | |
1052 | log = logging.getLogger(__name__) |
1053 | @@ -325,21 +324,25 @@ |
1054 | is_live = message[1] |
1055 | item = message[0] |
1056 | hide_mode = message[2] |
1057 | - file = item.get_frame_path() |
1058 | + file_path = Path(item.get_frame_path()) |
1059 | self.handler = item.processor |
1060 | # When starting presentation from the servicemanager we convert |
1061 | # PDF/XPS/OXPS-serviceitems into image-serviceitems. When started from the mediamanager |
1062 | # the conversion has already been done at this point. |
1063 | - file_type = os.path.splitext(file.lower())[1][1:] |
1064 | + file_type = file_path.suffix.lower()[1:] |
1065 | if file_type in PDF_CONTROLLER_FILETYPES: |
1066 | - log.debug('Converting from pdf/xps/oxps to images for serviceitem with file {name}'.format(name=file)) |
1067 | + log.debug('Converting from pdf/xps/oxps to images for serviceitem with file {name}'.format(name=file_path)) |
1068 | # Create a copy of the original item, and then clear the original item so it can be filled with images |
1069 | item_cpy = copy.copy(item) |
1070 | item.__init__(None) |
1071 | if is_live: |
1072 | - self.media_item.generate_slide_data(item, item_cpy, False, False, ServiceItemContext.Live, file) |
1073 | + # TODO: To Path object |
1074 | + self.media_item.generate_slide_data(item, item_cpy, False, False, ServiceItemContext.Live, |
1075 | + str(file_path)) |
1076 | else: |
1077 | - self.media_item.generate_slide_data(item, item_cpy, False, False, ServiceItemContext.Preview, file) |
1078 | + # TODO: To Path object |
1079 | + self.media_item.generate_slide_data(item, item_cpy, False, False, ServiceItemContext.Preview, |
1080 | + str(file_path)) |
1081 | # Some of the original serviceitem attributes is needed in the new serviceitem |
1082 | item.footer = item_cpy.footer |
1083 | item.from_service = item_cpy.from_service |
1084 | @@ -352,13 +355,13 @@ |
1085 | self.handler = None |
1086 | else: |
1087 | if self.handler == self.media_item.automatic: |
1088 | - self.handler = self.media_item.find_controller_by_type(file) |
1089 | + self.handler = self.media_item.find_controller_by_type(file_path) |
1090 | if not self.handler: |
1091 | return |
1092 | else: |
1093 | - # the saved handler is not present so need to use one based on file suffix. |
1094 | + # the saved handler is not present so need to use one based on file_path suffix. |
1095 | if not self.controllers[self.handler].available: |
1096 | - self.handler = self.media_item.find_controller_by_type(file) |
1097 | + self.handler = self.media_item.find_controller_by_type(file_path) |
1098 | if not self.handler: |
1099 | return |
1100 | if is_live: |
1101 | @@ -370,7 +373,7 @@ |
1102 | if self.handler is None: |
1103 | self.controller = controller |
1104 | else: |
1105 | - controller.add_handler(self.controllers[self.handler], file, hide_mode, message[3]) |
1106 | + controller.add_handler(self.controllers[self.handler], file_path, hide_mode, message[3]) |
1107 | self.timer.start() |
1108 | |
1109 | def slide(self, message): |
1110 | |
1111 | === modified file 'openlp/plugins/presentations/lib/pdfcontroller.py' |
1112 | --- openlp/plugins/presentations/lib/pdfcontroller.py 2017-08-26 15:06:11 +0000 |
1113 | +++ openlp/plugins/presentations/lib/pdfcontroller.py 2017-09-18 20:10:29 +0000 |
1114 | @@ -23,13 +23,13 @@ |
1115 | import os |
1116 | import logging |
1117 | import re |
1118 | -from shutil import which |
1119 | from subprocess import check_output, CalledProcessError |
1120 | |
1121 | from openlp.core.common import AppLocation, check_binary_exists |
1122 | from openlp.core.common import Settings, is_win |
1123 | from openlp.core.common.path import Path, path_to_str |
1124 | from openlp.core.lib import ScreenList |
1125 | +from openlp.core.lib.shutil import which |
1126 | from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument |
1127 | |
1128 | if is_win(): |
1129 | @@ -66,11 +66,12 @@ |
1130 | Function that checks whether a binary is either ghostscript or mudraw or neither. |
1131 | Is also used from presentationtab.py |
1132 | |
1133 | - :param program_path:The full path to the binary to check. |
1134 | + :param openlp.core.common.path.Path program_path: The full path to the binary to check. |
1135 | :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid. |
1136 | + :rtype: str | None |
1137 | """ |
1138 | program_type = None |
1139 | - runlog = check_binary_exists(Path(program_path)) |
1140 | + runlog = check_binary_exists(program_path) |
1141 | # Analyse the output to see it the program is mudraw, ghostscript or neither |
1142 | for line in runlog.splitlines(): |
1143 | decoded_line = line.decode() |
1144 | @@ -107,30 +108,29 @@ |
1145 | :return: True if program to open PDF-files was found, otherwise False. |
1146 | """ |
1147 | log.debug('check_installed Pdf') |
1148 | - self.mudrawbin = '' |
1149 | - self.mutoolbin = '' |
1150 | - self.gsbin = '' |
1151 | + self.mudrawbin = None |
1152 | + self.mutoolbin = None |
1153 | + self.gsbin = None |
1154 | self.also_supports = [] |
1155 | # Use the user defined program if given |
1156 | if Settings().value('presentations/enable_pdf_program'): |
1157 | - pdf_program = path_to_str(Settings().value('presentations/pdf_program')) |
1158 | - program_type = self.process_check_binary(pdf_program) |
1159 | + program_path = Settings().value('presentations/pdf_program') |
1160 | + program_type = self.process_check_binary(program_path) |
1161 | if program_type == 'gs': |
1162 | - self.gsbin = pdf_program |
1163 | + self.gsbin = program_path |
1164 | elif program_type == 'mudraw': |
1165 | - self.mudrawbin = pdf_program |
1166 | + self.mudrawbin = program_path |
1167 | elif program_type == 'mutool': |
1168 | - self.mutoolbin = pdf_program |
1169 | + self.mutoolbin = program_path |
1170 | else: |
1171 | # Fallback to autodetection |
1172 | - application_path = str(AppLocation.get_directory(AppLocation.AppDir)) |
1173 | + application_path = AppLocation.get_directory(AppLocation.AppDir) |
1174 | if is_win(): |
1175 | # for windows we only accept mudraw.exe or mutool.exe in the base folder |
1176 | - application_path = str(AppLocation.get_directory(AppLocation.AppDir)) |
1177 | - if os.path.isfile(os.path.join(application_path, 'mudraw.exe')): |
1178 | - self.mudrawbin = os.path.join(application_path, 'mudraw.exe') |
1179 | - elif os.path.isfile(os.path.join(application_path, 'mutool.exe')): |
1180 | - self.mutoolbin = os.path.join(application_path, 'mutool.exe') |
1181 | + if (application_path / 'mudraw.exe').is_file(): |
1182 | + self.mudrawbin = application_path / 'mudraw.exe' |
1183 | + elif (application_path / 'mutool.exe').is_file(): |
1184 | + self.mutoolbin = application_path / 'mutool.exe' |
1185 | else: |
1186 | DEVNULL = open(os.devnull, 'wb') |
1187 | # First try to find mudraw |
1188 | @@ -143,11 +143,11 @@ |
1189 | self.gsbin = which('gs') |
1190 | # Last option: check if mudraw or mutool is placed in OpenLP base folder |
1191 | if not self.mudrawbin and not self.mutoolbin and not self.gsbin: |
1192 | - application_path = str(AppLocation.get_directory(AppLocation.AppDir)) |
1193 | - if os.path.isfile(os.path.join(application_path, 'mudraw')): |
1194 | - self.mudrawbin = os.path.join(application_path, 'mudraw') |
1195 | - elif os.path.isfile(os.path.join(application_path, 'mutool')): |
1196 | - self.mutoolbin = os.path.join(application_path, 'mutool') |
1197 | + application_path = AppLocation.get_directory(AppLocation.AppDir) |
1198 | + if (application_path / 'mudraw').is_file(): |
1199 | + self.mudrawbin = application_path / 'mudraw' |
1200 | + elif (application_path / 'mutool').is_file(): |
1201 | + self.mutoolbin = application_path / 'mutool' |
1202 | if self.mudrawbin or self.mutoolbin: |
1203 | self.also_supports = ['xps', 'oxps'] |
1204 | return True |
1205 | @@ -172,12 +172,15 @@ |
1206 | image-serviceitem on the fly and present as such. Therefore some of the 'playback' |
1207 | functions is not implemented. |
1208 | """ |
1209 | - def __init__(self, controller, presentation): |
1210 | + def __init__(self, controller, document_path): |
1211 | """ |
1212 | Constructor, store information about the file and initialise. |
1213 | + |
1214 | + :param openlp.core.common.path.Path document_path: Path to the document to load |
1215 | + :rtype: None |
1216 | """ |
1217 | log.debug('Init Presentation Pdf') |
1218 | - PresentationDocument.__init__(self, controller, presentation) |
1219 | + super().__init__(controller, document_path) |
1220 | self.presentation = None |
1221 | self.blanked = False |
1222 | self.hidden = False |
1223 | @@ -200,13 +203,13 @@ |
1224 | :return: The resolution dpi to be used. |
1225 | """ |
1226 | # Use a postscript script to get size of the pdf. It is assumed that all pages have same size |
1227 | - gs_resolution_script = str(AppLocation.get_directory( |
1228 | - AppLocation.PluginsDir)) + '/presentations/lib/ghostscript_get_resolution.ps' |
1229 | + gs_resolution_script = AppLocation.get_directory( |
1230 | + AppLocation.PluginsDir) / 'presentations' / 'lib' / 'ghostscript_get_resolution.ps' |
1231 | # Run the script on the pdf to get the size |
1232 | runlog = [] |
1233 | try: |
1234 | - runlog = check_output([self.controller.gsbin, '-dNOPAUSE', '-dNODISPLAY', '-dBATCH', |
1235 | - '-sFile=' + self.file_path, gs_resolution_script], |
1236 | + runlog = check_output([str(self.controller.gsbin), '-dNOPAUSE', '-dNODISPLAY', '-dBATCH', |
1237 | + '-sFile={file_path}'.format(file_path=self.file_path), str(gs_resolution_script)], |
1238 | startupinfo=self.startupinfo) |
1239 | except CalledProcessError as e: |
1240 | log.debug(' '.join(e.cmd)) |
1241 | @@ -240,46 +243,47 @@ |
1242 | :return: True is loading succeeded, otherwise False. |
1243 | """ |
1244 | log.debug('load_presentation pdf') |
1245 | + temp_dir_path = self.get_temp_folder() |
1246 | # Check if the images has already been created, and if yes load them |
1247 | - if os.path.isfile(os.path.join(self.get_temp_folder(), 'mainslide001.png')): |
1248 | - created_files = sorted(os.listdir(self.get_temp_folder())) |
1249 | - for fn in created_files: |
1250 | - if os.path.isfile(os.path.join(self.get_temp_folder(), fn)): |
1251 | - self.image_files.append(os.path.join(self.get_temp_folder(), fn)) |
1252 | + if (temp_dir_path / 'mainslide001.png').is_file(): |
1253 | + created_files = sorted(temp_dir_path.glob('*')) |
1254 | + for image_path in created_files: |
1255 | + if image_path.is_file(): |
1256 | + self.image_files.append(image_path) |
1257 | self.num_pages = len(self.image_files) |
1258 | return True |
1259 | size = ScreenList().current['size'] |
1260 | # Generate images from PDF that will fit the frame. |
1261 | runlog = '' |
1262 | try: |
1263 | - if not os.path.isdir(self.get_temp_folder()): |
1264 | - os.makedirs(self.get_temp_folder()) |
1265 | + if not temp_dir_path.is_dir(): |
1266 | + temp_dir_path.mkdir(parents=True) |
1267 | # The %03d in the file name is handled by each binary |
1268 | if self.controller.mudrawbin: |
1269 | log.debug('loading presentation using mudraw') |
1270 | - runlog = check_output([self.controller.mudrawbin, '-w', str(size.width()), '-h', str(size.height()), |
1271 | - '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path], |
1272 | + runlog = check_output([str(self.controller.mudrawbin), '-w', str(size.width()), |
1273 | + '-h', str(size.height()), |
1274 | + '-o', str(temp_dir_path / 'mainslide%03d.png'), str(self.file_path)], |
1275 | startupinfo=self.startupinfo) |
1276 | elif self.controller.mutoolbin: |
1277 | log.debug('loading presentation using mutool') |
1278 | - runlog = check_output([self.controller.mutoolbin, 'draw', '-w', str(size.width()), '-h', |
1279 | - str(size.height()), |
1280 | - '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path], |
1281 | + runlog = check_output([str(self.controller.mutoolbin), 'draw', '-w', str(size.width()), |
1282 | + '-h', str(size.height()), '-o', str(temp_dir_path / 'mainslide%03d.png'), |
1283 | + str(self.file_path)], |
1284 | startupinfo=self.startupinfo) |
1285 | elif self.controller.gsbin: |
1286 | log.debug('loading presentation using gs') |
1287 | resolution = self.gs_get_resolution(size) |
1288 | - runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m', |
1289 | - '-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', |
1290 | - '-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), |
1291 | - self.file_path], startupinfo=self.startupinfo) |
1292 | - created_files = sorted(os.listdir(self.get_temp_folder())) |
1293 | - for fn in created_files: |
1294 | - if os.path.isfile(os.path.join(self.get_temp_folder(), fn)): |
1295 | - self.image_files.append(os.path.join(self.get_temp_folder(), fn)) |
1296 | + runlog = check_output([str(self.controller.gsbin), '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m', |
1297 | + '-r{res}'.format(res=resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', |
1298 | + '-sOutputFile={output}'.format(output=temp_dir_path / 'mainslide%03d.png'), |
1299 | + str(self.file_path)], startupinfo=self.startupinfo) |
1300 | + created_files = sorted(temp_dir_path.glob('*')) |
1301 | + for image_path in created_files: |
1302 | + if image_path.is_file(): |
1303 | + self.image_files.append(image_path) |
1304 | except Exception as e: |
1305 | - log.debug(e) |
1306 | - log.debug(runlog) |
1307 | + log.exception(runlog) |
1308 | return False |
1309 | self.num_pages = len(self.image_files) |
1310 | # Create thumbnails |
1311 | |
1312 | === modified file 'openlp/plugins/presentations/lib/powerpointcontroller.py' |
1313 | --- openlp/plugins/presentations/lib/powerpointcontroller.py 2017-07-04 23:13:51 +0000 |
1314 | +++ openlp/plugins/presentations/lib/powerpointcontroller.py 2017-09-18 20:10:29 +0000 |
1315 | @@ -120,15 +120,16 @@ |
1316 | Class which holds information and controls a single presentation. |
1317 | """ |
1318 | |
1319 | - def __init__(self, controller, presentation): |
1320 | + def __init__(self, controller, document_path): |
1321 | """ |
1322 | Constructor, store information about the file and initialise. |
1323 | |
1324 | :param controller: |
1325 | - :param presentation: |
1326 | + :param openlp.core.common.path.Path document_path: Path to the document to load |
1327 | + :rtype: None |
1328 | """ |
1329 | log.debug('Init Presentation Powerpoint') |
1330 | - super(PowerpointDocument, self).__init__(controller, presentation) |
1331 | + super().__init__(controller, document_path) |
1332 | self.presentation = None |
1333 | self.index_map = {} |
1334 | self.slide_count = 0 |
1335 | @@ -145,7 +146,7 @@ |
1336 | try: |
1337 | if not self.controller.process: |
1338 | self.controller.start_process() |
1339 | - self.controller.process.Presentations.Open(os.path.normpath(self.file_path), False, False, False) |
1340 | + self.controller.process.Presentations.Open(str(self.file_path), False, False, False) |
1341 | self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count) |
1342 | self.create_thumbnails() |
1343 | self.create_titles_and_notes() |
1344 | @@ -177,7 +178,7 @@ |
1345 | if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden: |
1346 | self.index_map[key] = num + 1 |
1347 | self.presentation.Slides(num + 1).Export( |
1348 | - os.path.join(self.get_thumbnail_folder(), 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) |
1349 | + str(self.get_thumbnail_folder() / 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) |
1350 | key += 1 |
1351 | self.slide_count = key - 1 |
1352 | |
1353 | @@ -363,9 +364,8 @@ |
1354 | width=size.width(), |
1355 | horizontal=(right - left))) |
1356 | log.debug('window title: {title}'.format(title=window_title)) |
1357 | - filename_root, filename_ext = os.path.splitext(os.path.basename(self.file_path)) |
1358 | if size.y() == top and size.height() == (bottom - top) and size.x() == left and \ |
1359 | - size.width() == (right - left) and filename_root in window_title: |
1360 | + size.width() == (right - left) and self.file_path.stem in window_title: |
1361 | log.debug('Found a match and will save the handle') |
1362 | self.presentation_hwnd = hwnd |
1363 | # Stop powerpoint from flashing in the taskbar |
1364 | |
1365 | === modified file 'openlp/plugins/presentations/lib/pptviewcontroller.py' |
1366 | --- openlp/plugins/presentations/lib/pptviewcontroller.py 2017-08-01 20:59:41 +0000 |
1367 | +++ openlp/plugins/presentations/lib/pptviewcontroller.py 2017-09-18 20:10:29 +0000 |
1368 | @@ -85,9 +85,9 @@ |
1369 | if self.process: |
1370 | return |
1371 | log.debug('start PPTView') |
1372 | - dll_path = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), |
1373 | - 'plugins', 'presentations', 'lib', 'pptviewlib', 'pptviewlib.dll') |
1374 | - self.process = cdll.LoadLibrary(dll_path) |
1375 | + dll_path = AppLocation.get_directory(AppLocation.AppDir) \ |
1376 | + / 'plugins' / 'presentations' / 'lib' / 'pptviewlib' / 'pptviewlib.dll' |
1377 | + self.process = cdll.LoadLibrary(str(dll_path)) |
1378 | if log.isEnabledFor(logging.DEBUG): |
1379 | self.process.SetDebug(1) |
1380 | |
1381 | @@ -104,12 +104,15 @@ |
1382 | """ |
1383 | Class which holds information and controls a single presentation. |
1384 | """ |
1385 | - def __init__(self, controller, presentation): |
1386 | + def __init__(self, controller, document_path): |
1387 | """ |
1388 | Constructor, store information about the file and initialise. |
1389 | + |
1390 | + :param openlp.core.common.path.Path document_path: File path to the document to load |
1391 | + :rtype: None |
1392 | """ |
1393 | log.debug('Init Presentation PowerPoint') |
1394 | - super(PptviewDocument, self).__init__(controller, presentation) |
1395 | + super().__init__(controller, document_path) |
1396 | self.presentation = None |
1397 | self.ppt_id = None |
1398 | self.blanked = False |
1399 | @@ -121,17 +124,16 @@ |
1400 | the background PptView task started earlier. |
1401 | """ |
1402 | log.debug('LoadPresentation') |
1403 | - temp_folder = self.get_temp_folder() |
1404 | + temp_path = self.get_temp_folder() |
1405 | size = ScreenList().current['size'] |
1406 | rect = RECT(size.x(), size.y(), size.right(), size.bottom()) |
1407 | - self.file_path = os.path.normpath(self.file_path) |
1408 | - preview_path = os.path.join(temp_folder, 'slide') |
1409 | + preview_path = temp_path / 'slide' |
1410 | # Ensure that the paths are null terminated |
1411 | - byte_file_path = self.file_path.encode('utf-16-le') + b'\0' |
1412 | - preview_path = preview_path.encode('utf-16-le') + b'\0' |
1413 | - if not os.path.isdir(temp_folder): |
1414 | - os.makedirs(temp_folder) |
1415 | - self.ppt_id = self.controller.process.OpenPPT(byte_file_path, None, rect, preview_path) |
1416 | + file_path_utf16 = str(self.file_path).encode('utf-16-le') + b'\0' |
1417 | + preview_path_utf16 = str(preview_path).encode('utf-16-le') + b'\0' |
1418 | + if not temp_path.is_dir(): |
1419 | + temp_path.mkdir(parents=True) |
1420 | + self.ppt_id = self.controller.process.OpenPPT(file_path_utf16, None, rect, preview_path_utf16) |
1421 | if self.ppt_id >= 0: |
1422 | self.create_thumbnails() |
1423 | self.stop_presentation() |
1424 | @@ -148,7 +150,7 @@ |
1425 | return |
1426 | log.debug('create_thumbnails proceeding') |
1427 | for idx in range(self.get_slide_count()): |
1428 | - path = '{folder}\\slide{index}.bmp'.format(folder=self.get_temp_folder(), index=str(idx + 1)) |
1429 | + path = self.get_temp_folder() / 'slide{index:d}.bmp'.format(index=idx + 1) |
1430 | self.convert_thumbnail(path, idx + 1) |
1431 | |
1432 | def create_titles_and_notes(self): |
1433 | @@ -161,13 +163,12 @@ |
1434 | """ |
1435 | titles = None |
1436 | notes = None |
1437 | - filename = os.path.normpath(self.file_path) |
1438 | # let's make sure we have a valid zipped presentation |
1439 | - if os.path.exists(filename) and zipfile.is_zipfile(filename): |
1440 | + if self.file_path.exists() and zipfile.is_zipfile(str(self.file_path)): |
1441 | namespaces = {"p": "http://schemas.openxmlformats.org/presentationml/2006/main", |
1442 | "a": "http://schemas.openxmlformats.org/drawingml/2006/main"} |
1443 | # open the file |
1444 | - with zipfile.ZipFile(filename) as zip_file: |
1445 | + with zipfile.ZipFile(str(self.file_path)) as zip_file: |
1446 | # find the presentation.xml to get the slide count |
1447 | with zip_file.open('ppt/presentation.xml') as pres: |
1448 | tree = ElementTree.parse(pres) |
1449 | |
1450 | === modified file 'openlp/plugins/presentations/lib/presentationcontroller.py' |
1451 | --- openlp/plugins/presentations/lib/presentationcontroller.py 2017-08-25 20:03:25 +0000 |
1452 | +++ openlp/plugins/presentations/lib/presentationcontroller.py 2017-09-18 20:10:29 +0000 |
1453 | @@ -19,16 +19,14 @@ |
1454 | # with this program; if not, write to the Free Software Foundation, Inc., 59 # |
1455 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
1456 | ############################################################################### |
1457 | - |
1458 | import logging |
1459 | -import os |
1460 | -import shutil |
1461 | |
1462 | from PyQt5 import QtCore |
1463 | |
1464 | from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, md5_hash |
1465 | from openlp.core.common.path import Path |
1466 | from openlp.core.lib import create_thumb, validate_thumb |
1467 | +from openlp.core.lib.shutil import rmtree |
1468 | |
1469 | log = logging.getLogger(__name__) |
1470 | |
1471 | @@ -86,20 +84,27 @@ |
1472 | Returns a path to an image containing a preview for the requested slide |
1473 | |
1474 | """ |
1475 | - def __init__(self, controller, name): |
1476 | + def __init__(self, controller, document_path): |
1477 | """ |
1478 | Constructor for the PresentationController class |
1479 | + |
1480 | + :param controller: |
1481 | + :param openlp.core.common.path.Path document_path: Path to the document to load. |
1482 | + :rtype: None |
1483 | """ |
1484 | self.controller = controller |
1485 | - self._setup(name) |
1486 | + self._setup(document_path) |
1487 | |
1488 | - def _setup(self, name): |
1489 | + def _setup(self, document_path): |
1490 | """ |
1491 | Run some initial setup. This method is separate from __init__ in order to mock it out in tests. |
1492 | + |
1493 | + :param openlp.core.common.path.Path document_path: Path to the document to load. |
1494 | + :rtype: None |
1495 | """ |
1496 | self.slide_number = 0 |
1497 | - self.file_path = name |
1498 | - check_directory_exists(Path(self.get_thumbnail_folder())) |
1499 | + self.file_path = document_path |
1500 | + check_directory_exists(self.get_thumbnail_folder()) |
1501 | |
1502 | def load_presentation(self): |
1503 | """ |
1504 | @@ -116,49 +121,54 @@ |
1505 | a file, e.g. thumbnails |
1506 | """ |
1507 | try: |
1508 | - if os.path.exists(self.get_thumbnail_folder()): |
1509 | - shutil.rmtree(self.get_thumbnail_folder()) |
1510 | - if os.path.exists(self.get_temp_folder()): |
1511 | - shutil.rmtree(self.get_temp_folder()) |
1512 | + thumbnail_folder_path = self.get_thumbnail_folder() |
1513 | + temp_folder_path = self.get_temp_folder() |
1514 | + if thumbnail_folder_path.exists(): |
1515 | + rmtree(thumbnail_folder_path) |
1516 | + if temp_folder_path.exists(): |
1517 | + rmtree(temp_folder_path) |
1518 | except OSError: |
1519 | log.exception('Failed to delete presentation controller files') |
1520 | |
1521 | - def get_file_name(self): |
1522 | - """ |
1523 | - Return just the filename of the presentation, without the directory |
1524 | - """ |
1525 | - return os.path.split(self.file_path)[1] |
1526 | - |
1527 | def get_thumbnail_folder(self): |
1528 | """ |
1529 | The location where thumbnail images will be stored |
1530 | + |
1531 | + :return: The path to the thumbnail |
1532 | + :rtype: openlp.core.common.path.Path |
1533 | """ |
1534 | # TODO: If statement can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed |
1535 | if Settings().value('presentations/thumbnail_scheme') == 'md5': |
1536 | - folder = md5_hash(self.file_path.encode('utf-8')) |
1537 | + folder = md5_hash(bytes(self.file_path)) |
1538 | else: |
1539 | - folder = self.get_file_name() |
1540 | - return os.path.join(self.controller.thumbnail_folder, folder) |
1541 | + folder = self.file_path.name |
1542 | + return Path(self.controller.thumbnail_folder, folder) |
1543 | |
1544 | def get_temp_folder(self): |
1545 | """ |
1546 | The location where thumbnail images will be stored |
1547 | + |
1548 | + :return: The path to the temporary file folder |
1549 | + :rtype: openlp.core.common.path.Path |
1550 | """ |
1551 | # TODO: If statement can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed |
1552 | if Settings().value('presentations/thumbnail_scheme') == 'md5': |
1553 | - folder = md5_hash(self.file_path.encode('utf-8')) |
1554 | + folder = md5_hash(bytes(self.file_path)) |
1555 | else: |
1556 | - folder = folder = self.get_file_name() |
1557 | - return os.path.join(self.controller.temp_folder, folder) |
1558 | + folder = self.file_path.name |
1559 | + return Path(self.controller.temp_folder, folder) |
1560 | |
1561 | def check_thumbnails(self): |
1562 | """ |
1563 | - Returns ``True`` if the thumbnail images exist and are more recent than the powerpoint file. |
1564 | + Check that the last thumbnail image exists and is valid and are more recent than the powerpoint file. |
1565 | + |
1566 | + :return: If the thumbnail is valid |
1567 | + :rtype: bool |
1568 | """ |
1569 | - last_image = self.get_thumbnail_path(self.get_slide_count(), True) |
1570 | - if not (last_image and os.path.isfile(last_image)): |
1571 | + last_image_path = self.get_thumbnail_path(self.get_slide_count(), True) |
1572 | + if not (last_image_path and last_image_path.is_file()): |
1573 | return False |
1574 | - return validate_thumb(self.file_path, last_image) |
1575 | + return validate_thumb(Path(self.file_path), Path(last_image_path)) |
1576 | |
1577 | def close_presentation(self): |
1578 | """ |
1579 | @@ -241,25 +251,31 @@ |
1580 | """ |
1581 | pass |
1582 | |
1583 | - def convert_thumbnail(self, file, idx): |
1584 | + def convert_thumbnail(self, image_path, index): |
1585 | """ |
1586 | Convert the slide image the application made to a scaled 360px height .png image. |
1587 | + |
1588 | + :param openlp.core.common.path.Path image_path: Path to the image to create a thumb nail of |
1589 | + :param int index: The index of the slide to create the thumbnail for. |
1590 | + :rtype: None |
1591 | """ |
1592 | if self.check_thumbnails(): |
1593 | return |
1594 | - if os.path.isfile(file): |
1595 | - thumb_path = self.get_thumbnail_path(idx, False) |
1596 | - create_thumb(file, thumb_path, False, QtCore.QSize(-1, 360)) |
1597 | + if image_path.is_file(): |
1598 | + thumb_path = self.get_thumbnail_path(index, False) |
1599 | + create_thumb(str(image_path), str(thumb_path), False, QtCore.QSize(-1, 360)) |
1600 | |
1601 | - def get_thumbnail_path(self, slide_no, check_exists): |
1602 | + def get_thumbnail_path(self, slide_no, check_exists=False): |
1603 | """ |
1604 | Returns an image path containing a preview for the requested slide |
1605 | |
1606 | - :param slide_no: The slide an image is required for, starting at 1 |
1607 | - :param check_exists: |
1608 | + :param int slide_no: The slide an image is required for, starting at 1 |
1609 | + :param bool check_exists: Check if the generated path exists |
1610 | + :return: The path, or None if the :param:`check_exists` is True and the file does not exist |
1611 | + :rtype: openlp.core.common.path.Path | None |
1612 | """ |
1613 | - path = os.path.join(self.get_thumbnail_folder(), self.controller.thumbnail_prefix + str(slide_no) + '.png') |
1614 | - if os.path.isfile(path) or not check_exists: |
1615 | + path = self.get_thumbnail_folder() / (self.controller.thumbnail_prefix + str(slide_no) + '.png') |
1616 | + if path.is_file() or not check_exists: |
1617 | return path |
1618 | else: |
1619 | return None |
1620 | @@ -302,44 +318,38 @@ |
1621 | Reads the titles from the titles file and |
1622 | the notes files and returns the content in two lists |
1623 | """ |
1624 | - titles = [] |
1625 | notes = [] |
1626 | - titles_file = os.path.join(self.get_thumbnail_folder(), 'titles.txt') |
1627 | - if os.path.exists(titles_file): |
1628 | + titles_path = self.get_thumbnail_folder() / 'titles.txt' |
1629 | + try: |
1630 | + titles = titles_path.read_text().splitlines() |
1631 | + except: |
1632 | + log.exception('Failed to open/read existing titles file') |
1633 | + titles = [] |
1634 | + for slide_no, title in enumerate(titles, 1): |
1635 | + notes_path = self.get_thumbnail_folder() / 'slideNotes{number:d}.txt'.format(number=slide_no) |
1636 | try: |
1637 | - with open(titles_file, encoding='utf-8') as fi: |
1638 | - titles = fi.read().splitlines() |
1639 | + note = notes_path.read_text() |
1640 | except: |
1641 | - log.exception('Failed to open/read existing titles file') |
1642 | - titles = [] |
1643 | - for slide_no, title in enumerate(titles, 1): |
1644 | - notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes{number:d}.txt'.format(number=slide_no)) |
1645 | - note = '' |
1646 | - if os.path.exists(notes_file): |
1647 | - try: |
1648 | - with open(notes_file, encoding='utf-8') as fn: |
1649 | - note = fn.read() |
1650 | - except: |
1651 | - log.exception('Failed to open/read notes file') |
1652 | - note = '' |
1653 | + log.exception('Failed to open/read notes file') |
1654 | + note = '' |
1655 | notes.append(note) |
1656 | return titles, notes |
1657 | |
1658 | def save_titles_and_notes(self, titles, notes): |
1659 | """ |
1660 | - Performs the actual persisting of titles to the titles.txt |
1661 | - and notes to the slideNote%.txt |
1662 | + Performs the actual persisting of titles to the titles.txt and notes to the slideNote%.txt |
1663 | + |
1664 | + :param list[str] titles: The titles to save |
1665 | + :param list[str] notes: The notes to save |
1666 | + :rtype: None |
1667 | """ |
1668 | if titles: |
1669 | - titles_file = os.path.join(self.get_thumbnail_folder(), 'titles.txt') |
1670 | - with open(titles_file, mode='wt', encoding='utf-8') as fo: |
1671 | - fo.writelines(titles) |
1672 | + titles_path = self.get_thumbnail_folder() / 'titles.txt' |
1673 | + titles_path.write_text('\n'.join(titles)) |
1674 | if notes: |
1675 | for slide_no, note in enumerate(notes, 1): |
1676 | - notes_file = os.path.join(self.get_thumbnail_folder(), |
1677 | - 'slideNotes{number:d}.txt'.format(number=slide_no)) |
1678 | - with open(notes_file, mode='wt', encoding='utf-8') as fn: |
1679 | - fn.write(note) |
1680 | + notes_path = self.get_thumbnail_folder() / 'slideNotes{number:d}.txt'.format(number=slide_no) |
1681 | + notes_path.write_text(note) |
1682 | |
1683 | |
1684 | class PresentationController(object): |
1685 | @@ -416,12 +426,11 @@ |
1686 | self.document_class = document_class |
1687 | self.settings_section = self.plugin.settings_section |
1688 | self.available = None |
1689 | - self.temp_folder = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), name) |
1690 | - self.thumbnail_folder = os.path.join( |
1691 | - str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails') |
1692 | + self.temp_folder = AppLocation.get_section_data_path(self.settings_section) / name |
1693 | + self.thumbnail_folder = AppLocation.get_section_data_path(self.settings_section) / 'thumbnails' |
1694 | self.thumbnail_prefix = 'slide' |
1695 | - check_directory_exists(Path(self.thumbnail_folder)) |
1696 | - check_directory_exists(Path(self.temp_folder)) |
1697 | + check_directory_exists(self.thumbnail_folder) |
1698 | + check_directory_exists(self.temp_folder) |
1699 | |
1700 | def enabled(self): |
1701 | """ |
1702 | @@ -456,11 +465,15 @@ |
1703 | log.debug('Kill') |
1704 | self.close_presentation() |
1705 | |
1706 | - def add_document(self, name): |
1707 | + def add_document(self, document_path): |
1708 | """ |
1709 | Called when a new presentation document is opened. |
1710 | + |
1711 | + :param openlp.core.common.path.Path document_path: Path to the document to load |
1712 | + :return: The document |
1713 | + :rtype: PresentationDocument |
1714 | """ |
1715 | - document = self.document_class(self, name) |
1716 | + document = self.document_class(self, document_path) |
1717 | self.docs.append(document) |
1718 | return document |
1719 | |
1720 | |
1721 | === modified file 'openlp/plugins/presentations/lib/presentationtab.py' |
1722 | --- openlp/plugins/presentations/lib/presentationtab.py 2017-08-26 15:06:11 +0000 |
1723 | +++ openlp/plugins/presentations/lib/presentationtab.py 2017-09-18 20:10:29 +0000 |
1724 | @@ -38,7 +38,6 @@ |
1725 | """ |
1726 | Constructor |
1727 | """ |
1728 | - self.parent = parent |
1729 | self.controllers = controllers |
1730 | super(PresentationTab, self).__init__(parent, title, visible_title, icon_path) |
1731 | self.activated = False |
1732 | @@ -194,7 +193,7 @@ |
1733 | pdf_program_path = self.program_path_edit.path |
1734 | enable_pdf_program = self.pdf_program_check_box.checkState() |
1735 | # If the given program is blank disable using the program |
1736 | - if not pdf_program_path: |
1737 | + if pdf_program_path is None: |
1738 | enable_pdf_program = 0 |
1739 | if pdf_program_path != Settings().value(self.settings_section + '/pdf_program'): |
1740 | Settings().setValue(self.settings_section + '/pdf_program', pdf_program_path) |
1741 | @@ -220,9 +219,11 @@ |
1742 | |
1743 | def on_program_path_edit_path_changed(self, new_path): |
1744 | """ |
1745 | - Select the mudraw or ghostscript binary that should be used. |
1746 | + Handle the `pathEditChanged` signal from program_path_edit |
1747 | + |
1748 | + :param openlp.core.common.path.Path new_path: File path to the new program |
1749 | + :rtype: None |
1750 | """ |
1751 | - new_path = path_to_str(new_path) |
1752 | if new_path: |
1753 | if not PdfController.process_check_binary(new_path): |
1754 | critical_error_message_box(UiStrings().Error, |
1755 | |
1756 | === modified file 'openlp/plugins/remotes/deploy.py' |
1757 | --- openlp/plugins/remotes/deploy.py 2017-08-12 20:58:16 +0000 |
1758 | +++ openlp/plugins/remotes/deploy.py 2017-09-18 20:10:29 +0000 |
1759 | @@ -64,6 +64,6 @@ |
1760 | file_size = get_url_file_size('https://get.openlp.org/webclient/site.zip') |
1761 | callback.setRange(0, file_size) |
1762 | if url_get_file(callback, '{host}{name}'.format(host='https://get.openlp.org/webclient/', name='site.zip'), |
1763 | - os.path.join(str(AppLocation.get_section_data_path('remotes')), 'site.zip'), |
1764 | + AppLocation.get_section_data_path('remotes') / 'site.zip', |
1765 | sha256=sha256): |
1766 | deploy_zipfile(str(AppLocation.get_section_data_path('remotes')), 'site.zip') |
1767 | |
1768 | === modified file 'openlp/plugins/songs/reporting.py' |
1769 | --- openlp/plugins/songs/reporting.py 2016-12-31 11:01:36 +0000 |
1770 | +++ openlp/plugins/songs/reporting.py 2017-09-18 20:10:29 +0000 |
1771 | @@ -25,10 +25,10 @@ |
1772 | import csv |
1773 | import logging |
1774 | |
1775 | -from PyQt5 import QtWidgets |
1776 | - |
1777 | from openlp.core.common import Registry, translate |
1778 | +from openlp.core.common.path import Path |
1779 | from openlp.core.lib.ui import critical_error_message_box |
1780 | +from openlp.core.ui.lib.filedialog import FileDialog |
1781 | from openlp.plugins.songs.lib.db import Song |
1782 | |
1783 | |
1784 | @@ -42,58 +42,55 @@ |
1785 | """ |
1786 | main_window = Registry().get('main_window') |
1787 | plugin = Registry().get('songs').plugin |
1788 | - report_file_name, filter_used = QtWidgets.QFileDialog.getSaveFileName( |
1789 | + report_file_path, filter_used = FileDialog.getSaveFileName( |
1790 | main_window, |
1791 | translate('SongPlugin.ReportSongList', 'Save File'), |
1792 | - translate('SongPlugin.ReportSongList', 'song_extract.csv'), |
1793 | + Path(translate('SongPlugin.ReportSongList', 'song_extract.csv')), |
1794 | translate('SongPlugin.ReportSongList', 'CSV format (*.csv)')) |
1795 | |
1796 | - if not report_file_name: |
1797 | + if report_file_path is None: |
1798 | main_window.error_message( |
1799 | translate('SongPlugin.ReportSongList', 'Output Path Not Selected'), |
1800 | - translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your ' |
1801 | - 'report. \nPlease select an existing path ' |
1802 | - 'on your computer.') |
1803 | + translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your report. \n' |
1804 | + 'Please select an existing path on your computer.') |
1805 | ) |
1806 | return |
1807 | - if not report_file_name.endswith('csv'): |
1808 | - report_file_name += '.csv' |
1809 | - file_handle = None |
1810 | + report_file_path.with_suffix('.csv') |
1811 | Registry().get('application').set_busy_cursor() |
1812 | try: |
1813 | - file_handle = open(report_file_name, 'wt') |
1814 | - fieldnames = ('Title', 'Alternative Title', 'Copyright', 'Author(s)', 'Song Book', 'Topic') |
1815 | - writer = csv.DictWriter(file_handle, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) |
1816 | - headers = dict((n, n) for n in fieldnames) |
1817 | - writer.writerow(headers) |
1818 | - song_list = plugin.manager.get_all_objects(Song) |
1819 | - for song in song_list: |
1820 | - author_list = [] |
1821 | - for author_song in song.authors_songs: |
1822 | - author_list.append(author_song.author.display_name) |
1823 | - author_string = ' | '.join(author_list) |
1824 | - book_list = [] |
1825 | - for book_song in song.songbook_entries: |
1826 | - if hasattr(book_song, 'entry') and book_song.entry: |
1827 | - book_list.append('{name} #{entry}'.format(name=book_song.songbook.name, entry=book_song.entry)) |
1828 | - book_string = ' | '.join(book_list) |
1829 | - topic_list = [] |
1830 | - for topic_song in song.topics: |
1831 | - if hasattr(topic_song, 'name'): |
1832 | - topic_list.append(topic_song.name) |
1833 | - topic_string = ' | '.join(topic_list) |
1834 | - writer.writerow({'Title': song.title, |
1835 | - 'Alternative Title': song.alternate_title, |
1836 | - 'Copyright': song.copyright, |
1837 | - 'Author(s)': author_string, |
1838 | - 'Song Book': book_string, |
1839 | - 'Topic': topic_string}) |
1840 | - Registry().get('application').set_normal_cursor() |
1841 | - main_window.information_message( |
1842 | - translate('SongPlugin.ReportSongList', 'Report Creation'), |
1843 | - translate('SongPlugin.ReportSongList', |
1844 | - 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name) |
1845 | - ) |
1846 | + with report_file_path.open('wt') as file_handle: |
1847 | + fieldnames = ('Title', 'Alternative Title', 'Copyright', 'Author(s)', 'Song Book', 'Topic') |
1848 | + writer = csv.DictWriter(file_handle, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) |
1849 | + headers = dict((n, n) for n in fieldnames) |
1850 | + writer.writerow(headers) |
1851 | + song_list = plugin.manager.get_all_objects(Song) |
1852 | + for song in song_list: |
1853 | + author_list = [] |
1854 | + for author_song in song.authors_songs: |
1855 | + author_list.append(author_song.author.display_name) |
1856 | + author_string = ' | '.join(author_list) |
1857 | + book_list = [] |
1858 | + for book_song in song.songbook_entries: |
1859 | + if hasattr(book_song, 'entry') and book_song.entry: |
1860 | + book_list.append('{name} #{entry}'.format(name=book_song.songbook.name, entry=book_song.entry)) |
1861 | + book_string = ' | '.join(book_list) |
1862 | + topic_list = [] |
1863 | + for topic_song in song.topics: |
1864 | + if hasattr(topic_song, 'name'): |
1865 | + topic_list.append(topic_song.name) |
1866 | + topic_string = ' | '.join(topic_list) |
1867 | + writer.writerow({'Title': song.title, |
1868 | + 'Alternative Title': song.alternate_title, |
1869 | + 'Copyright': song.copyright, |
1870 | + 'Author(s)': author_string, |
1871 | + 'Song Book': book_string, |
1872 | + 'Topic': topic_string}) |
1873 | + Registry().get('application').set_normal_cursor() |
1874 | + main_window.information_message( |
1875 | + translate('SongPlugin.ReportSongList', 'Report Creation'), |
1876 | + translate('SongPlugin.ReportSongList', |
1877 | + 'Report \n{name} \nhas been successfully created. ').format(name=report_file_path) |
1878 | + ) |
1879 | except OSError as ose: |
1880 | Registry().get('application').set_normal_cursor() |
1881 | log.exception('Failed to write out song usage records') |
1882 | @@ -101,6 +98,3 @@ |
1883 | translate('SongPlugin.ReportSongList', |
1884 | 'An error occurred while extracting: {error}' |
1885 | ).format(error=ose.strerror)) |
1886 | - finally: |
1887 | - if file_handle: |
1888 | - file_handle.close() |
1889 | |
1890 | === modified file 'tests/functional/openlp_core_common/test_httputils.py' |
1891 | --- tests/functional/openlp_core_common/test_httputils.py 2017-06-09 20:53:13 +0000 |
1892 | +++ tests/functional/openlp_core_common/test_httputils.py 2017-09-18 20:10:29 +0000 |
1893 | @@ -29,6 +29,7 @@ |
1894 | from unittest.mock import MagicMock, patch |
1895 | |
1896 | from openlp.core.common.httputils import get_user_agent, get_web_page, get_url_file_size, url_get_file, ping |
1897 | +from openlp.core.common.path import Path |
1898 | |
1899 | from tests.helpers.testmixin import TestMixin |
1900 | |
1901 | @@ -267,7 +268,7 @@ |
1902 | mocked_urlopen.side_effect = socket.timeout() |
1903 | |
1904 | # WHEN: Attempt to retrieve a file |
1905 | - url_get_file(MagicMock(), url='http://localhost/test', f_path=self.tempfile) |
1906 | + url_get_file(MagicMock(), url='http://localhost/test', f_path=Path(self.tempfile)) |
1907 | |
1908 | # THEN: socket.timeout should have been caught |
1909 | # NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files |
1910 | |
1911 | === modified file 'tests/functional/openlp_core_lib/test_lib.py' |
1912 | --- tests/functional/openlp_core_lib/test_lib.py 2017-08-25 20:03:25 +0000 |
1913 | +++ tests/functional/openlp_core_lib/test_lib.py 2017-09-18 20:10:29 +0000 |
1914 | @@ -595,61 +595,46 @@ |
1915 | Test the validate_thumb() function when the thumbnail does not exist |
1916 | """ |
1917 | # GIVEN: A mocked out os module, with path.exists returning False, and fake paths to a file and a thumb |
1918 | - with patch('openlp.core.lib.os') as mocked_os: |
1919 | - file_path = 'path/to/file' |
1920 | - thumb_path = 'path/to/thumb' |
1921 | - mocked_os.path.exists.return_value = False |
1922 | + with patch.object(Path, 'exists', return_value=False) as mocked_path_exists: |
1923 | + file_path = Path('path', 'to', 'file') |
1924 | + thumb_path = Path('path', 'to', 'thumb') |
1925 | |
1926 | # WHEN: we run the validate_thumb() function |
1927 | result = validate_thumb(file_path, thumb_path) |
1928 | |
1929 | # THEN: we should have called a few functions, and the result should be False |
1930 | - mocked_os.path.exists.assert_called_with(thumb_path) |
1931 | - assert result is False, 'The result should be False' |
1932 | + thumb_path.exists.assert_called_once_with() |
1933 | + self.assertFalse(result, 'The result should be False') |
1934 | |
1935 | def test_validate_thumb_file_exists_and_newer(self): |
1936 | """ |
1937 | Test the validate_thumb() function when the thumbnail exists and has a newer timestamp than the file |
1938 | """ |
1939 | - # GIVEN: A mocked out os module, functions rigged to work for us, and fake paths to a file and a thumb |
1940 | - with patch('openlp.core.lib.os') as mocked_os: |
1941 | - file_path = 'path/to/file' |
1942 | - thumb_path = 'path/to/thumb' |
1943 | - file_mocked_stat = MagicMock() |
1944 | - file_mocked_stat.st_mtime = datetime.now() |
1945 | - thumb_mocked_stat = MagicMock() |
1946 | - thumb_mocked_stat.st_mtime = datetime.now() + timedelta(seconds=10) |
1947 | - mocked_os.path.exists.return_value = True |
1948 | - mocked_os.stat.side_effect = [file_mocked_stat, thumb_mocked_stat] |
1949 | + with patch.object(Path, 'exists'), patch.object(Path, 'stat'): |
1950 | + # GIVEN: Mocked file_path and thumb_path which return different values fo the modified times |
1951 | + file_path = MagicMock(**{'stat.return_value': MagicMock(st_mtime=10)}) |
1952 | + thumb_path = MagicMock(**{'exists.return_value': True, 'stat.return_value': MagicMock(st_mtime=11)}) |
1953 | |
1954 | # WHEN: we run the validate_thumb() function |
1955 | + result = validate_thumb(file_path, thumb_path) |
1956 | |
1957 | - # THEN: we should have called a few functions, and the result should be True |
1958 | - # mocked_os.path.exists.assert_called_with(thumb_path) |
1959 | + # THEN: `validate_thumb` should return True |
1960 | + self.assertTrue(result) |
1961 | |
1962 | def test_validate_thumb_file_exists_and_older(self): |
1963 | """ |
1964 | Test the validate_thumb() function when the thumbnail exists but is older than the file |
1965 | """ |
1966 | - # GIVEN: A mocked out os module, functions rigged to work for us, and fake paths to a file and a thumb |
1967 | - with patch('openlp.core.lib.os') as mocked_os: |
1968 | - file_path = 'path/to/file' |
1969 | - thumb_path = 'path/to/thumb' |
1970 | - file_mocked_stat = MagicMock() |
1971 | - file_mocked_stat.st_mtime = datetime.now() |
1972 | - thumb_mocked_stat = MagicMock() |
1973 | - thumb_mocked_stat.st_mtime = datetime.now() - timedelta(seconds=10) |
1974 | - mocked_os.path.exists.return_value = True |
1975 | - mocked_os.stat.side_effect = lambda fname: file_mocked_stat if fname == file_path else thumb_mocked_stat |
1976 | - |
1977 | - # WHEN: we run the validate_thumb() function |
1978 | - result = validate_thumb(file_path, thumb_path) |
1979 | - |
1980 | - # THEN: we should have called a few functions, and the result should be False |
1981 | - mocked_os.path.exists.assert_called_with(thumb_path) |
1982 | - mocked_os.stat.assert_any_call(file_path) |
1983 | - mocked_os.stat.assert_any_call(thumb_path) |
1984 | - assert result is False, 'The result should be False' |
1985 | + # GIVEN: Mocked file_path and thumb_path which return different values fo the modified times |
1986 | + file_path = MagicMock(**{'stat.return_value': MagicMock(st_mtime=10)}) |
1987 | + thumb_path = MagicMock(**{'exists.return_value': True, 'stat.return_value': MagicMock(st_mtime=9)}) |
1988 | + |
1989 | + # WHEN: we run the validate_thumb() function |
1990 | + result = validate_thumb(file_path, thumb_path) |
1991 | + |
1992 | + # THEN: `validate_thumb` should return False |
1993 | + thumb_path.stat.assert_called_once_with() |
1994 | + self.assertFalse(result, 'The result should be False') |
1995 | |
1996 | def test_replace_params_no_params(self): |
1997 | """ |
1998 | |
1999 | === added file 'tests/functional/openlp_core_lib/test_shutil.py' |
2000 | --- tests/functional/openlp_core_lib/test_shutil.py 1970-01-01 00:00:00 +0000 |
2001 | +++ tests/functional/openlp_core_lib/test_shutil.py 2017-09-18 20:10:29 +0000 |
2002 | @@ -0,0 +1,170 @@ |
2003 | +import os |
2004 | +from unittest import TestCase |
2005 | +from unittest.mock import ANY, MagicMock, patch |
2006 | + |
2007 | +from openlp.core.common.path import Path |
2008 | +from openlp.core.lib.shutil import copy, copyfile, copytree, rmtree, which |
2009 | + |
2010 | + |
2011 | +class TestShutil(TestCase): |
2012 | + """ |
2013 | + Tests for the :mod:`openlp.core.lib.shutil` module |
2014 | + """ |
2015 | + |
2016 | + def test_copy(self): |
2017 | + """ |
2018 | + Test :func:`copy` |
2019 | + """ |
2020 | + # GIVEN: A mocked `shutil.copy` which returns a test path as a string |
2021 | + with patch('openlp.core.lib.shutil.shutil.copy', return_value=os.path.join('destination', 'test', 'path')) \ |
2022 | + as mocked_shutil_copy: |
2023 | + |
2024 | + # WHEN: Calling :func:`copy` with the src and dst parameters as Path object types |
2025 | + result = copy(Path('source', 'test', 'path'), Path('destination', 'test', 'path')) |
2026 | + |
2027 | + # THEN: :func:`shutil.copy` should have been called with the str equivalents of the Path objects. |
2028 | + # :func:`copy` should return the str type result of calling :func:`shutil.copy` as a Path object. |
2029 | + mocked_shutil_copy.assert_called_once_with(os.path.join('source', 'test', 'path'), |
2030 | + os.path.join('destination', 'test', 'path')) |
2031 | + self.assertEqual(result, Path('destination', 'test', 'path')) |
2032 | + |
2033 | + def test_copy_follow_optional_params(self): |
2034 | + """ |
2035 | + Test :func:`copy` when follow_symlinks is set to false |
2036 | + """ |
2037 | + # GIVEN: A mocked `shutil.copy` |
2038 | + with patch('openlp.core.lib.shutil.shutil.copy', return_value='') as mocked_shutil_copy: |
2039 | + |
2040 | + # WHEN: Calling :func:`copy` with :param:`follow_symlinks` set to False |
2041 | + copy(Path('source', 'test', 'path'), Path('destination', 'test', 'path'), follow_symlinks=False) |
2042 | + |
2043 | + # THEN: :func:`shutil.copy` should have been called with :param:`follow_symlinks` set to false |
2044 | + mocked_shutil_copy.assert_called_once_with(ANY, ANY, follow_symlinks=False) |
2045 | + |
2046 | + def test_copyfile(self): |
2047 | + """ |
2048 | + Test :func:`copyfile` |
2049 | + """ |
2050 | + # GIVEN: A mocked :func:`shutil.copyfile` which returns a test path as a string |
2051 | + with patch('openlp.core.lib.shutil.shutil.copyfile', |
2052 | + return_value=os.path.join('destination', 'test', 'path')) as mocked_shutil_copyfile: |
2053 | + |
2054 | + # WHEN: Calling :func:`copyfile` with the src and dst parameters as Path object types |
2055 | + result = copyfile(Path('source', 'test', 'path'), Path('destination', 'test', 'path')) |
2056 | + |
2057 | + # THEN: :func:`shutil.copyfile` should have been called with the str equivalents of the Path objects. |
2058 | + # :func:`copyfile` should return the str type result of calling :func:`shutil.copyfile` as a Path |
2059 | + # object. |
2060 | + mocked_shutil_copyfile.assert_called_once_with(os.path.join('source', 'test', 'path'), |
2061 | + os.path.join('destination', 'test', 'path')) |
2062 | + self.assertEqual(result, Path('destination', 'test', 'path')) |
2063 | + |
2064 | + def test_copyfile_optional_params(self): |
2065 | + """ |
2066 | + Test :func:`copyfile` when follow_symlinks is set to false |
2067 | + """ |
2068 | + # GIVEN: A mocked :func:`shutil.copyfile` |
2069 | + with patch('openlp.core.lib.shutil.shutil.copyfile', return_value='') as mocked_shutil_copyfile: |
2070 | + |
2071 | + # WHEN: Calling :func:`copyfile` with :param:`follow_symlinks` set to False |
2072 | + copyfile(Path('source', 'test', 'path'), Path('destination', 'test', 'path'), follow_symlinks=False) |
2073 | + |
2074 | + # THEN: :func:`shutil.copyfile` should have been called with the optional parameters, with out any of the |
2075 | + # values being modified |
2076 | + mocked_shutil_copyfile.assert_called_once_with(ANY, ANY, follow_symlinks=False) |
2077 | + |
2078 | + def test_copytree(self): |
2079 | + """ |
2080 | + Test :func:`copytree` |
2081 | + """ |
2082 | + # GIVEN: A mocked :func:`shutil.copytree` which returns a test path as a string |
2083 | + with patch('openlp.core.lib.shutil.shutil.copytree', |
2084 | + return_value=os.path.join('destination', 'test', 'path')) as mocked_shutil_copytree: |
2085 | + |
2086 | + # WHEN: Calling :func:`copytree` with the src and dst parameters as Path object types |
2087 | + result = copytree(Path('source', 'test', 'path'), Path('destination', 'test', 'path')) |
2088 | + |
2089 | + # THEN: :func:`shutil.copytree` should have been called with the str equivalents of the Path objects. |
2090 | + # :func:`patches.copytree` should return the str type result of calling :func:`shutil.copytree` as a |
2091 | + # Path object. |
2092 | + mocked_shutil_copytree.assert_called_once_with(os.path.join('source', 'test', 'path'), |
2093 | + os.path.join('destination', 'test', 'path')) |
2094 | + self.assertEqual(result, Path('destination', 'test', 'path')) |
2095 | + |
2096 | + def test_copytree_optional_params(self): |
2097 | + """ |
2098 | + Test :func:`copytree` when optional parameters are passed |
2099 | + """ |
2100 | + # GIVEN: A mocked :func:`shutil.copytree` |
2101 | + with patch('openlp.core.lib.shutil.shutil.copytree', return_value='') as mocked_shutil_copytree: |
2102 | + mocked_ignore = MagicMock() |
2103 | + mocked_copy_function = MagicMock() |
2104 | + |
2105 | + # WHEN: Calling :func:`copytree` with the optional parameters set |
2106 | + copytree(Path('source', 'test', 'path'), Path('destination', 'test', 'path'), symlinks=True, |
2107 | + ignore=mocked_ignore, copy_function=mocked_copy_function, ignore_dangling_symlinks=True) |
2108 | + |
2109 | + # THEN: :func:`shutil.copytree` should have been called with the optional parameters, with out any of the |
2110 | + # values being modified |
2111 | + mocked_shutil_copytree.assert_called_once_with(ANY, ANY, symlinks=True, ignore=mocked_ignore, |
2112 | + copy_function=mocked_copy_function, |
2113 | + ignore_dangling_symlinks=True) |
2114 | + |
2115 | + def test_rmtree(self): |
2116 | + """ |
2117 | + Test :func:`rmtree` |
2118 | + """ |
2119 | + # GIVEN: A mocked :func:`shutil.rmtree` |
2120 | + with patch('openlp.core.lib.shutil.shutil.rmtree', return_value=None) as mocked_shutil_rmtree: |
2121 | + |
2122 | + # WHEN: Calling :func:`rmtree` with the path parameter as Path object type |
2123 | + result = rmtree(Path('test', 'path')) |
2124 | + |
2125 | + # THEN: :func:`shutil.rmtree` should have been called with the str equivalents of the Path object. |
2126 | + mocked_shutil_rmtree.assert_called_once_with(os.path.join('test', 'path')) |
2127 | + self.assertIsNone(result) |
2128 | + |
2129 | + def test_rmtree_optional_params(self): |
2130 | + """ |
2131 | + Test :func:`rmtree` when optional parameters are passed |
2132 | + """ |
2133 | + # GIVEN: A mocked :func:`shutil.rmtree` |
2134 | + with patch('openlp.core.lib.shutil.shutil.rmtree', return_value='') as mocked_shutil_rmtree: |
2135 | + mocked_on_error = MagicMock() |
2136 | + |
2137 | + # WHEN: Calling :func:`rmtree` with :param:`ignore_errors` set to True and `onerror` set to a mocked object |
2138 | + rmtree(Path('test', 'path'), ignore_errors=True, onerror=mocked_on_error) |
2139 | + |
2140 | + # THEN: :func:`shutil.rmtree` should have been called with the optional parameters, with out any of the |
2141 | + # values being modified |
2142 | + mocked_shutil_rmtree.assert_called_once_with(ANY, ignore_errors=True, onerror=mocked_on_error) |
2143 | + |
2144 | + def test_which_no_command(self): |
2145 | + """ |
2146 | + Test :func:`which` when the command is not found. |
2147 | + """ |
2148 | + # GIVEN: A mocked :func:``shutil.which` when the command is not found. |
2149 | + with patch('openlp.core.lib.shutil.shutil.which', return_value=None) as mocked_shutil_which: |
2150 | + |
2151 | + # WHEN: Calling :func:`which` with a command that does not exist. |
2152 | + result = which('no_command') |
2153 | + |
2154 | + # THEN: :func:`shutil.which` should have been called with the command, and :func:`which` should return None. |
2155 | + mocked_shutil_which.assert_called_once_with('no_command') |
2156 | + self.assertIsNone(result) |
2157 | + |
2158 | + def test_which_command(self): |
2159 | + """ |
2160 | + Test :func:`which` when a command has been found. |
2161 | + """ |
2162 | + # GIVEN: A mocked :func:`shutil.which` when the command is found. |
2163 | + with patch('openlp.core.lib.shutil.shutil.which', |
2164 | + return_value=os.path.join('path', 'to', 'command')) as mocked_shutil_which: |
2165 | + |
2166 | + # WHEN: Calling :func:`which` with a command that exists. |
2167 | + result = which('command') |
2168 | + |
2169 | + # THEN: :func:`shutil.which` should have been called with the command, and :func:`which` should return a |
2170 | + # Path object equivalent of the command path. |
2171 | + mocked_shutil_which.assert_called_once_with('command') |
2172 | + self.assertEqual(result, Path('path', 'to', 'command')) |
2173 | |
2174 | === modified file 'tests/functional/openlp_core_ui/test_exceptionform.py' |
2175 | --- tests/functional/openlp_core_ui/test_exceptionform.py 2017-08-26 15:06:11 +0000 |
2176 | +++ tests/functional/openlp_core_ui/test_exceptionform.py 2017-09-18 20:10:29 +0000 |
2177 | @@ -103,7 +103,7 @@ |
2178 | os.remove(self.tempfile) |
2179 | |
2180 | @patch("openlp.core.ui.exceptionform.Ui_ExceptionDialog") |
2181 | - @patch("openlp.core.ui.exceptionform.QtWidgets.QFileDialog") |
2182 | + @patch("openlp.core.ui.exceptionform.FileDialog") |
2183 | @patch("openlp.core.ui.exceptionform.QtCore.QUrl") |
2184 | @patch("openlp.core.ui.exceptionform.QtCore.QUrlQuery.addQueryItem") |
2185 | @patch("openlp.core.ui.exceptionform.Qt") |
2186 | |
2187 | === modified file 'tests/functional/openlp_plugins/presentations/test_impresscontroller.py' |
2188 | --- tests/functional/openlp_plugins/presentations/test_impresscontroller.py 2017-06-08 21:36:17 +0000 |
2189 | +++ tests/functional/openlp_plugins/presentations/test_impresscontroller.py 2017-09-18 20:10:29 +0000 |
2190 | @@ -24,13 +24,12 @@ |
2191 | """ |
2192 | from unittest import TestCase |
2193 | from unittest.mock import MagicMock |
2194 | -import os |
2195 | import shutil |
2196 | from tempfile import mkdtemp |
2197 | |
2198 | from openlp.core.common import Settings |
2199 | -from openlp.plugins.presentations.lib.impresscontroller import \ |
2200 | - ImpressController, ImpressDocument, TextType |
2201 | +from openlp.core.common.path import Path |
2202 | +from openlp.plugins.presentations.lib.impresscontroller import ImpressController, ImpressDocument, TextType |
2203 | from openlp.plugins.presentations.presentationplugin import __default_settings__ |
2204 | |
2205 | from tests.utils.constants import TEST_RESOURCES_PATH |
2206 | @@ -82,7 +81,7 @@ |
2207 | mocked_plugin = MagicMock() |
2208 | mocked_plugin.settings_section = 'presentations' |
2209 | Settings().extend_default_settings(__default_settings__) |
2210 | - self.file_name = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'test.pptx') |
2211 | + self.file_name = Path(TEST_RESOURCES_PATH, 'presentations', 'test.pptx') |
2212 | self.ppc = ImpressController(mocked_plugin) |
2213 | self.doc = ImpressDocument(self.ppc, self.file_name) |
2214 | |
2215 | |
2216 | === modified file 'tests/functional/openlp_plugins/presentations/test_mediaitem.py' |
2217 | --- tests/functional/openlp_plugins/presentations/test_mediaitem.py 2017-04-24 05:17:55 +0000 |
2218 | +++ tests/functional/openlp_plugins/presentations/test_mediaitem.py 2017-09-18 20:10:29 +0000 |
2219 | @@ -26,6 +26,7 @@ |
2220 | from unittest.mock import patch, MagicMock, call |
2221 | |
2222 | from openlp.core.common import Registry |
2223 | +from openlp.core.common.path import Path |
2224 | from openlp.plugins.presentations.lib.mediaitem import PresentationMediaItem |
2225 | |
2226 | from tests.helpers.testmixin import TestMixin |
2227 | @@ -92,17 +93,18 @@ |
2228 | """ |
2229 | # GIVEN: A mocked controller, and mocked os.path.getmtime |
2230 | mocked_controller = MagicMock() |
2231 | - mocked_doc = MagicMock() |
2232 | + mocked_doc = MagicMock(**{'get_thumbnail_path.return_value': Path()}) |
2233 | mocked_controller.add_document.return_value = mocked_doc |
2234 | mocked_controller.supports = ['tmp'] |
2235 | self.media_item.controllers = { |
2236 | 'Mocked': mocked_controller |
2237 | } |
2238 | - presentation_file = 'file.tmp' |
2239 | - with patch('openlp.plugins.presentations.lib.mediaitem.os.path.getmtime') as mocked_getmtime, \ |
2240 | - patch('openlp.plugins.presentations.lib.mediaitem.os.path.exists') as mocked_exists: |
2241 | - mocked_getmtime.side_effect = [100, 200] |
2242 | - mocked_exists.return_value = True |
2243 | + |
2244 | + thmub_path = MagicMock(st_mtime=100) |
2245 | + file_path = MagicMock(st_mtime=400) |
2246 | + with patch.object(Path, 'stat', side_effect=[thmub_path, file_path]), \ |
2247 | + patch.object(Path, 'exists', return_value=True): |
2248 | + presentation_file = Path('file.tmp') |
2249 | |
2250 | # WHEN: calling clean_up_thumbnails |
2251 | self.media_item.clean_up_thumbnails(presentation_file, True) |
2252 | @@ -123,9 +125,8 @@ |
2253 | self.media_item.controllers = { |
2254 | 'Mocked': mocked_controller |
2255 | } |
2256 | - presentation_file = 'file.tmp' |
2257 | - with patch('openlp.plugins.presentations.lib.mediaitem.os.path.exists') as mocked_exists: |
2258 | - mocked_exists.return_value = False |
2259 | + presentation_file = Path('file.tmp') |
2260 | + with patch.object(Path, 'exists', return_value=False): |
2261 | |
2262 | # WHEN: calling clean_up_thumbnails |
2263 | self.media_item.clean_up_thumbnails(presentation_file, True) |
2264 | |
2265 | === modified file 'tests/functional/openlp_plugins/presentations/test_pdfcontroller.py' |
2266 | --- tests/functional/openlp_plugins/presentations/test_pdfcontroller.py 2017-04-24 05:17:55 +0000 |
2267 | +++ tests/functional/openlp_plugins/presentations/test_pdfcontroller.py 2017-09-18 20:10:29 +0000 |
2268 | @@ -32,6 +32,7 @@ |
2269 | |
2270 | from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument |
2271 | from openlp.core.common import Settings |
2272 | +from openlp.core.common.path import Path |
2273 | from openlp.core.lib import ScreenList |
2274 | |
2275 | from tests.utils.constants import TEST_RESOURCES_PATH |
2276 | @@ -66,8 +67,8 @@ |
2277 | self.desktop.screenGeometry.return_value = SCREEN['size'] |
2278 | self.screens = ScreenList.create(self.desktop) |
2279 | Settings().extend_default_settings(__default_settings__) |
2280 | - self.temp_folder = mkdtemp() |
2281 | - self.thumbnail_folder = mkdtemp() |
2282 | + self.temp_folder = Path(mkdtemp()) |
2283 | + self.thumbnail_folder = Path(mkdtemp()) |
2284 | self.mock_plugin = MagicMock() |
2285 | self.mock_plugin.settings_section = self.temp_folder |
2286 | |
2287 | @@ -77,8 +78,8 @@ |
2288 | """ |
2289 | del self.screens |
2290 | self.destroy_settings() |
2291 | - shutil.rmtree(self.thumbnail_folder) |
2292 | - shutil.rmtree(self.temp_folder) |
2293 | + shutil.rmtree(str(self.thumbnail_folder)) |
2294 | + shutil.rmtree(str(self.temp_folder)) |
2295 | |
2296 | def test_constructor(self): |
2297 | """ |
2298 | @@ -98,7 +99,7 @@ |
2299 | Test loading of a Pdf using the PdfController |
2300 | """ |
2301 | # GIVEN: A Pdf-file |
2302 | - test_file = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'pdf_test1.pdf') |
2303 | + test_file = Path(TEST_RESOURCES_PATH, 'presentations', 'pdf_test1.pdf') |
2304 | |
2305 | # WHEN: The Pdf is loaded |
2306 | controller = PdfController(plugin=self.mock_plugin) |
2307 | @@ -118,7 +119,7 @@ |
2308 | Test loading of a Pdf and check size of generate pictures |
2309 | """ |
2310 | # GIVEN: A Pdf-file |
2311 | - test_file = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'pdf_test1.pdf') |
2312 | + test_file = Path(TEST_RESOURCES_PATH, 'presentations', 'pdf_test1.pdf') |
2313 | |
2314 | # WHEN: The Pdf is loaded |
2315 | controller = PdfController(plugin=self.mock_plugin) |
2316 | @@ -131,7 +132,7 @@ |
2317 | |
2318 | # THEN: The load should succeed and pictures should be created and have been scales to fit the screen |
2319 | self.assertTrue(loaded, 'The loading of the PDF should succeed.') |
2320 | - image = QtGui.QImage(os.path.join(self.temp_folder, 'pdf_test1.pdf', 'mainslide001.png')) |
2321 | + image = QtGui.QImage(os.path.join(str(self.temp_folder), 'pdf_test1.pdf', 'mainslide001.png')) |
2322 | # Based on the converter used the resolution will differ a bit |
2323 | if controller.gsbin: |
2324 | self.assertEqual(760, image.height(), 'The height should be 760') |
2325 | |
2326 | === modified file 'tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py' |
2327 | --- tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py 2017-05-30 18:42:35 +0000 |
2328 | +++ tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py 2017-09-18 20:10:29 +0000 |
2329 | @@ -22,7 +22,6 @@ |
2330 | """ |
2331 | This module contains tests for the pptviewcontroller module of the Presentations plugin. |
2332 | """ |
2333 | -import os |
2334 | import shutil |
2335 | from tempfile import mkdtemp |
2336 | from unittest import TestCase |
2337 | @@ -30,6 +29,7 @@ |
2338 | |
2339 | from openlp.plugins.presentations.lib.pptviewcontroller import PptviewDocument, PptviewController |
2340 | from openlp.core.common import is_win |
2341 | +from openlp.core.common.path import Path |
2342 | |
2343 | from tests.helpers.testmixin import TestMixin |
2344 | from tests.utils.constants import TEST_RESOURCES_PATH |
2345 | @@ -184,7 +184,7 @@ |
2346 | """ |
2347 | # GIVEN: mocked PresentationController.save_titles_and_notes and a pptx file |
2348 | doc = PptviewDocument(self.mock_controller, self.mock_presentation) |
2349 | - doc.file_path = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'test.pptx') |
2350 | + doc.file_path = Path(TEST_RESOURCES_PATH, 'presentations', 'test.pptx') |
2351 | doc.save_titles_and_notes = MagicMock() |
2352 | |
2353 | # WHEN reading the titles and notes |
2354 | @@ -201,13 +201,13 @@ |
2355 | """ |
2356 | # GIVEN: mocked PresentationController.save_titles_and_notes and an nonexistent file |
2357 | with patch('builtins.open') as mocked_open, \ |
2358 | - patch('openlp.plugins.presentations.lib.pptviewcontroller.os.path.exists') as mocked_exists, \ |
2359 | + patch.object(Path, 'exists') as mocked_path_exists, \ |
2360 | patch('openlp.plugins.presentations.lib.presentationcontroller.check_directory_exists') as \ |
2361 | mocked_dir_exists: |
2362 | - mocked_exists.return_value = False |
2363 | + mocked_path_exists.return_value = False |
2364 | mocked_dir_exists.return_value = False |
2365 | doc = PptviewDocument(self.mock_controller, self.mock_presentation) |
2366 | - doc.file_path = 'Idontexist.pptx' |
2367 | + doc.file_path = Path('Idontexist.pptx') |
2368 | doc.save_titles_and_notes = MagicMock() |
2369 | |
2370 | # WHEN: Reading the titles and notes |
2371 | @@ -215,7 +215,7 @@ |
2372 | |
2373 | # THEN: File existens should have been checked, and not have been opened. |
2374 | doc.save_titles_and_notes.assert_called_once_with(None, None) |
2375 | - mocked_exists.assert_any_call('Idontexist.pptx') |
2376 | + mocked_path_exists.assert_called_with() |
2377 | self.assertEqual(mocked_open.call_count, 0, 'There should be no calls to open a file.') |
2378 | |
2379 | def test_create_titles_and_notes_invalid_file(self): |
2380 | @@ -228,7 +228,7 @@ |
2381 | mocked_is_zf.return_value = False |
2382 | mocked_open.filesize = 10 |
2383 | doc = PptviewDocument(self.mock_controller, self.mock_presentation) |
2384 | - doc.file_path = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'test.ppt') |
2385 | + doc.file_path = Path(TEST_RESOURCES_PATH, 'presentations', 'test.ppt') |
2386 | doc.save_titles_and_notes = MagicMock() |
2387 | |
2388 | # WHEN: reading the titles and notes |
2389 | |
2390 | === modified file 'tests/functional/openlp_plugins/presentations/test_presentationcontroller.py' |
2391 | --- tests/functional/openlp_plugins/presentations/test_presentationcontroller.py 2017-08-25 20:03:25 +0000 |
2392 | +++ tests/functional/openlp_plugins/presentations/test_presentationcontroller.py 2017-09-18 20:10:29 +0000 |
2393 | @@ -23,9 +23,8 @@ |
2394 | Functional tests to test the PresentationController and PresentationDocument |
2395 | classes and related methods. |
2396 | """ |
2397 | -import os |
2398 | from unittest import TestCase |
2399 | -from unittest.mock import MagicMock, mock_open, patch |
2400 | +from unittest.mock import MagicMock, call, patch |
2401 | |
2402 | from openlp.core.common.path import Path |
2403 | from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument |
2404 | @@ -67,23 +66,18 @@ |
2405 | Test PresentationDocument.save_titles_and_notes method with two valid lists |
2406 | """ |
2407 | # GIVEN: two lists of length==2 and a mocked open and get_thumbnail_folder |
2408 | - mocked_open = mock_open() |
2409 | - with patch('builtins.open', mocked_open), patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder: |
2410 | + with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.write_text') as mocked_write_text, \ |
2411 | + patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder: |
2412 | titles = ['uno', 'dos'] |
2413 | notes = ['one', 'two'] |
2414 | |
2415 | # WHEN: calling save_titles_and_notes |
2416 | - mocked_get_thumbnail_folder.return_value = 'test' |
2417 | + mocked_get_thumbnail_folder.return_value = Path('test') |
2418 | self.document.save_titles_and_notes(titles, notes) |
2419 | |
2420 | # THEN: the last call to open should have been for slideNotes2.txt |
2421 | - mocked_open.assert_any_call(os.path.join('test', 'titles.txt'), mode='wt', encoding='utf-8') |
2422 | - mocked_open.assert_any_call(os.path.join('test', 'slideNotes1.txt'), mode='wt', encoding='utf-8') |
2423 | - mocked_open.assert_any_call(os.path.join('test', 'slideNotes2.txt'), mode='wt', encoding='utf-8') |
2424 | - self.assertEqual(mocked_open.call_count, 3, 'There should be exactly three files opened') |
2425 | - mocked_open().writelines.assert_called_once_with(['uno', 'dos']) |
2426 | - mocked_open().write.assert_any_call('one') |
2427 | - mocked_open().write.assert_any_call('two') |
2428 | + self.assertEqual(mocked_write_text.call_count, 3, 'There should be exactly three files written') |
2429 | + mocked_write_text.assert_has_calls([call('uno\ndos'), call('one'), call('two')]) |
2430 | |
2431 | def test_save_titles_and_notes_with_None(self): |
2432 | """ |
2433 | @@ -107,10 +101,11 @@ |
2434 | """ |
2435 | # GIVEN: A mocked open, get_thumbnail_folder and exists |
2436 | |
2437 | - with patch('builtins.open', mock_open(read_data='uno\ndos\n')) as mocked_open, \ |
2438 | + with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text', |
2439 | + return_value='uno\ndos\n') as mocked_read_text, \ |
2440 | patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder, \ |
2441 | - patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists: |
2442 | - mocked_get_thumbnail_folder.return_value = 'test' |
2443 | + patch('openlp.plugins.presentations.lib.presentationcontroller.Path.exists') as mocked_exists: |
2444 | + mocked_get_thumbnail_folder.return_value = Path('test') |
2445 | mocked_exists.return_value = True |
2446 | |
2447 | # WHEN: calling get_titles_and_notes |
2448 | @@ -121,45 +116,36 @@ |
2449 | self.assertEqual(len(result_titles), 2, 'There should be two items in the titles') |
2450 | self.assertIs(type(result_notes), list, 'result_notes should be of type list') |
2451 | self.assertEqual(len(result_notes), 2, 'There should be two items in the notes') |
2452 | - self.assertEqual(mocked_open.call_count, 3, 'Three files should be opened') |
2453 | - mocked_open.assert_any_call(os.path.join('test', 'titles.txt'), encoding='utf-8') |
2454 | - mocked_open.assert_any_call(os.path.join('test', 'slideNotes1.txt'), encoding='utf-8') |
2455 | - mocked_open.assert_any_call(os.path.join('test', 'slideNotes2.txt'), encoding='utf-8') |
2456 | - self.assertEqual(mocked_exists.call_count, 3, 'Three files should have been checked') |
2457 | + self.assertEqual(mocked_read_text.call_count, 3, 'Three files should be read') |
2458 | |
2459 | def test_get_titles_and_notes_with_file_not_found(self): |
2460 | """ |
2461 | Test PresentationDocument.get_titles_and_notes method with file not found |
2462 | """ |
2463 | # GIVEN: A mocked open, get_thumbnail_folder and exists |
2464 | - with patch('builtins.open') as mocked_open, \ |
2465 | - patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder, \ |
2466 | - patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists: |
2467 | - mocked_get_thumbnail_folder.return_value = 'test' |
2468 | - mocked_exists.return_value = False |
2469 | + with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \ |
2470 | + patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder: |
2471 | + mocked_read_text.side_effect = FileNotFoundError() |
2472 | + mocked_get_thumbnail_folder.return_value = Path('test') |
2473 | |
2474 | # WHEN: calling get_titles_and_notes |
2475 | result_titles, result_notes = self.document.get_titles_and_notes() |
2476 | |
2477 | # THEN: it should return two empty lists |
2478 | - self.assertIs(type(result_titles), list, 'result_titles should be of type list') |
2479 | + self.assertIsInstance(result_titles, list, 'result_titles should be of type list') |
2480 | self.assertEqual(len(result_titles), 0, 'there be no titles') |
2481 | - self.assertIs(type(result_notes), list, 'result_notes should be a list') |
2482 | + self.assertIsInstance(result_notes, list, 'result_notes should be a list') |
2483 | self.assertEqual(len(result_notes), 0, 'but the list should be empty') |
2484 | - self.assertEqual(mocked_open.call_count, 0, 'No calls to open files') |
2485 | - self.assertEqual(mocked_exists.call_count, 1, 'There should be one call to file exists') |
2486 | |
2487 | def test_get_titles_and_notes_with_file_error(self): |
2488 | """ |
2489 | Test PresentationDocument.get_titles_and_notes method with file errors |
2490 | """ |
2491 | # GIVEN: A mocked open, get_thumbnail_folder and exists |
2492 | - with patch('builtins.open') as mocked_open, \ |
2493 | - patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder, \ |
2494 | - patch('openlp.plugins.presentations.lib.presentationcontroller.os.path.exists') as mocked_exists: |
2495 | - mocked_get_thumbnail_folder.return_value = 'test' |
2496 | - mocked_exists.return_value = True |
2497 | - mocked_open.side_effect = IOError() |
2498 | + with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \ |
2499 | + patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder: |
2500 | + mocked_read_text.side_effect = IOError() |
2501 | + mocked_get_thumbnail_folder.return_value = Path('test') |
2502 | |
2503 | # WHEN: calling get_titles_and_notes |
2504 | result_titles, result_notes = self.document.get_titles_and_notes() |
2505 | @@ -180,18 +166,16 @@ |
2506 | patch('openlp.plugins.presentations.lib.presentationcontroller.check_directory_exists') |
2507 | self.get_thumbnail_folder_patcher = \ |
2508 | patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') |
2509 | - self.os_patcher = patch('openlp.plugins.presentations.lib.presentationcontroller.os') |
2510 | self._setup_patcher = \ |
2511 | patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument._setup') |
2512 | |
2513 | self.mock_check_directory_exists = self.check_directory_exists_patcher.start() |
2514 | self.mock_get_thumbnail_folder = self.get_thumbnail_folder_patcher.start() |
2515 | - self.mock_os = self.os_patcher.start() |
2516 | self.mock_setup = self._setup_patcher.start() |
2517 | |
2518 | self.mock_controller = MagicMock() |
2519 | |
2520 | - self.mock_get_thumbnail_folder.return_value = 'returned/path/' |
2521 | + self.mock_get_thumbnail_folder.return_value = Path('returned/path/') |
2522 | |
2523 | def tearDown(self): |
2524 | """ |
2525 | @@ -199,7 +183,6 @@ |
2526 | """ |
2527 | self.check_directory_exists_patcher.stop() |
2528 | self.get_thumbnail_folder_patcher.stop() |
2529 | - self.os_patcher.stop() |
2530 | self._setup_patcher.stop() |
2531 | |
2532 | def test_initialise_presentation_document(self): |
2533 | @@ -227,7 +210,7 @@ |
2534 | PresentationDocument(self.mock_controller, 'Name') |
2535 | |
2536 | # THEN: check_directory_exists should have been called with 'returned/path/' |
2537 | - self.mock_check_directory_exists.assert_called_once_with(Path('returned', 'path')) |
2538 | + self.mock_check_directory_exists.assert_called_once_with(Path('returned', 'path/')) |
2539 | |
2540 | self._setup_patcher.start() |
2541 | |
2542 | @@ -244,20 +227,3 @@ |
2543 | |
2544 | # THEN: load_presentation should return false |
2545 | self.assertFalse(result, "PresentationDocument.load_presentation should return false.") |
2546 | - |
2547 | - def test_get_file_name(self): |
2548 | - """ |
2549 | - Test the PresentationDocument.get_file_name method. |
2550 | - """ |
2551 | - |
2552 | - # GIVEN: A mocked os.path.split which returns a list, an instance of PresentationDocument and |
2553 | - # arbitary file_path. |
2554 | - self.mock_os.path.split.return_value = ['directory', 'file.ext'] |
2555 | - instance = PresentationDocument(self.mock_controller, 'Name') |
2556 | - instance.file_path = 'filepath' |
2557 | - |
2558 | - # WHEN: Calling get_file_name |
2559 | - result = instance.get_file_name() |
2560 | - |
2561 | - # THEN: get_file_name should return 'file.ext' |
2562 | - self.assertEqual(result, 'file.ext') |
Sorry but you removed too much code!