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

Proposed by Phill
Status: Merged
Merged at revision: 2771
Proposed branch: lp:~phill-ridout/openlp/pathlib7
Merge into: lp:openlp
Diff against target: 1282 lines (+304/-310)
13 files modified
openlp/core/lib/json/theme.json (+1/-1)
openlp/core/lib/renderer.py (+4/-3)
openlp/core/lib/theme.py (+19/-15)
openlp/core/ui/maindisplay.py (+4/-4)
openlp/core/ui/themeform.py (+31/-27)
openlp/core/ui/thememanager.py (+184/-209)
openlp/core/ui/themestab.py (+2/-2)
openlp/plugins/images/lib/upgrade.py (+0/-1)
tests/functional/openlp_core_lib/test_theme.py (+6/-5)
tests/functional/openlp_core_ui/test_maindisplay.py (+9/-9)
tests/functional/openlp_core_ui/test_themeform.py (+1/-1)
tests/functional/openlp_core_ui/test_thememanager.py (+22/-29)
tests/interfaces/openlp_core_ui/test_thememanager.py (+21/-4)
To merge this branch: bzr merge lp:~phill-ridout/openlp/pathlib7
Reviewer Review Type Date Requested Status
Tomas Groth Approve
Tim Bentley Approve
Review via email: mp+331364@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Phill (phill-ridout) wrote :

Also automatically upgrades themes from XML to json.

Revision history for this message
Tim Bentley (trb143) wrote :

Looks good and finishes my changes from XML to json. Thanks

review: Approve
Revision history for this message
Tomas Groth (tomasgroth) wrote :

Seems legit ;-)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/lib/json/theme.json'
2--- openlp/core/lib/json/theme.json 2013-10-18 18:10:47 +0000
3+++ openlp/core/lib/json/theme.json 2017-09-26 17:09:04 +0000
4@@ -4,7 +4,7 @@
5 "color": "#000000",
6 "direction": "vertical",
7 "end_color": "#000000",
8- "filename": "",
9+ "filename": null,
10 "start_color": "#000000",
11 "type": "solid"
12 },
13
14=== modified file 'openlp/core/lib/renderer.py'
15--- openlp/core/lib/renderer.py 2017-01-25 21:17:27 +0000
16+++ openlp/core/lib/renderer.py 2017-09-26 17:09:04 +0000
17@@ -26,6 +26,7 @@
18 from PyQt5 import QtGui, QtCore, QtWebKitWidgets
19
20 from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, RegistryMixin, Settings
21+from openlp.core.common.path import path_to_str
22 from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, ScreenList, ServiceItem, expand_tags, \
23 build_lyrics_format_css, build_lyrics_outline_css, build_chords_css
24 from openlp.core.common import ThemeLevel
25@@ -118,7 +119,7 @@
26 theme_data, main_rect, footer_rect = self._theme_dimensions[theme_name]
27 # if No file do not update cache
28 if theme_data.background_filename:
29- self.image_manager.add_image(theme_data.background_filename,
30+ self.image_manager.add_image(path_to_str(theme_data.background_filename),
31 ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
32
33 def pre_render(self, override_theme_data=None):
34@@ -207,8 +208,8 @@
35 service_item.raw_footer = FOOTER
36 # if No file do not update cache
37 if theme_data.background_filename:
38- self.image_manager.add_image(
39- theme_data.background_filename, ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
40+ self.image_manager.add_image(path_to_str(theme_data.background_filename),
41+ ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
42 theme_data, main, footer = self.pre_render(theme_data)
43 service_item.theme_data = theme_data
44 service_item.main = main
45
46=== modified file 'openlp/core/lib/theme.py'
47--- openlp/core/lib/theme.py 2017-08-12 17:45:56 +0000
48+++ openlp/core/lib/theme.py 2017-09-26 17:09:04 +0000
49@@ -22,13 +22,13 @@
50 """
51 Provide the theme XML and handling functions for OpenLP v2 themes.
52 """
53-import os
54+import json
55 import logging
56-import json
57
58 from lxml import etree, objectify
59 from openlp.core.common import AppLocation, de_hump
60-
61+from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
62+from openlp.core.common.path import Path, str_to_path
63 from openlp.core.lib import str_to_bool, ScreenList, get_text_file_string
64
65 log = logging.getLogger(__name__)
66@@ -160,9 +160,8 @@
67 # basic theme object with defaults
68 json_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'lib' / 'json' / 'theme.json'
69 jsn = get_text_file_string(json_path)
70- jsn = json.loads(jsn)
71- self.expand_json(jsn)
72- self.background_filename = ''
73+ self.load_theme(jsn)
74+ self.background_filename = None
75
76 def expand_json(self, var, prev=None):
77 """
78@@ -174,8 +173,6 @@
79 for key, value in var.items():
80 if prev:
81 key = prev + "_" + key
82- else:
83- key = key
84 if isinstance(value, dict):
85 self.expand_json(value, key)
86 else:
87@@ -185,13 +182,13 @@
88 """
89 Add the path name to the image name so the background can be rendered.
90
91- :param path: The path name to be added.
92+ :param openlp.core.common.path.Path path: The path name to be added.
93+ :rtype: None
94 """
95 if self.background_type == 'image' or self.background_type == 'video':
96 if self.background_filename and path:
97 self.theme_name = self.theme_name.strip()
98- self.background_filename = self.background_filename.strip()
99- self.background_filename = os.path.join(path, self.theme_name, self.background_filename)
100+ self.background_filename = path / self.theme_name / self.background_filename
101
102 def set_default_header_footer(self):
103 """
104@@ -206,16 +203,21 @@
105 self.font_footer_y = current_screen['size'].height() * 9 / 10
106 self.font_footer_height = current_screen['size'].height() / 10
107
108- def load_theme(self, theme):
109+ def load_theme(self, theme, theme_path=None):
110 """
111 Convert the JSON file and expand it.
112
113 :param theme: the theme string
114+ :param openlp.core.common.path.Path theme_path: The path to the theme
115+ :rtype: None
116 """
117- jsn = json.loads(theme)
118+ if theme_path:
119+ jsn = json.loads(theme, cls=OpenLPJsonDecoder, base_path=theme_path)
120+ else:
121+ jsn = json.loads(theme, cls=OpenLPJsonDecoder)
122 self.expand_json(jsn)
123
124- def export_theme(self):
125+ def export_theme(self, theme_path=None):
126 """
127 Loop through the fields and build a dictionary of them
128
129@@ -223,7 +225,9 @@
130 theme_data = {}
131 for attr, value in self.__dict__.items():
132 theme_data["{attr}".format(attr=attr)] = value
133- return json.dumps(theme_data)
134+ if theme_path:
135+ return json.dumps(theme_data, cls=OpenLPJsonEncoder, base_path=theme_path)
136+ return json.dumps(theme_data, cls=OpenLPJsonEncoder)
137
138 def parse(self, xml):
139 """
140
141=== modified file 'openlp/core/ui/maindisplay.py'
142--- openlp/core/ui/maindisplay.py 2017-09-05 04:28:50 +0000
143+++ openlp/core/ui/maindisplay.py 2017-09-26 17:09:04 +0000
144@@ -346,7 +346,7 @@
145 if not hasattr(self, 'service_item'):
146 return False
147 self.override['image'] = path
148- self.override['theme'] = self.service_item.theme_data.background_filename
149+ self.override['theme'] = path_to_str(self.service_item.theme_data.background_filename)
150 self.image(path)
151 # Update the preview frame.
152 if self.is_live:
153@@ -454,7 +454,7 @@
154 Registry().execute('video_background_replaced')
155 self.override = {}
156 # We have a different theme.
157- elif self.override['theme'] != service_item.theme_data.background_filename:
158+ elif self.override['theme'] != path_to_str(service_item.theme_data.background_filename):
159 Registry().execute('live_theme_changed')
160 self.override = {}
161 else:
162@@ -466,7 +466,7 @@
163 if self.service_item.theme_data.background_type == 'image':
164 if self.service_item.theme_data.background_filename:
165 self.service_item.bg_image_bytes = self.image_manager.get_image_bytes(
166- self.service_item.theme_data.background_filename, ImageSource.Theme)
167+ path_to_str(self.service_item.theme_data.background_filename), ImageSource.Theme)
168 if image_path:
169 image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
170 created_html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes,
171@@ -488,7 +488,7 @@
172 path = os.path.join(str(AppLocation.get_section_data_path('themes')),
173 self.service_item.theme_data.theme_name)
174 service_item.add_from_command(path,
175- self.service_item.theme_data.background_filename,
176+ path_to_str(self.service_item.theme_data.background_filename),
177 ':/media/slidecontroller_multimedia.png')
178 self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True)
179 self._hide_mouse()
180
181=== modified file 'openlp/core/ui/themeform.py'
182--- openlp/core/ui/themeform.py 2017-08-25 20:03:25 +0000
183+++ openlp/core/ui/themeform.py 2017-09-26 17:09:04 +0000
184@@ -28,7 +28,6 @@
185 from PyQt5 import QtCore, QtGui, QtWidgets
186
187 from openlp.core.common import Registry, RegistryProperties, UiStrings, translate, get_images_filter, is_not_image_file
188-from openlp.core.common.path import Path, path_to_str, str_to_path
189 from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
190 from openlp.core.lib.ui import critical_error_message_box
191 from openlp.core.ui import ThemeLayoutForm
192@@ -61,7 +60,7 @@
193 self.setupUi(self)
194 self.registerFields()
195 self.update_theme_allowed = True
196- self.temp_background_filename = ''
197+ self.temp_background_filename = None
198 self.theme_layout_form = ThemeLayoutForm(self)
199 self.background_combo_box.currentIndexChanged.connect(self.on_background_combo_box_current_index_changed)
200 self.gradient_combo_box.currentIndexChanged.connect(self.on_gradient_combo_box_current_index_changed)
201@@ -188,8 +187,7 @@
202 """
203 background_image = BackgroundType.to_string(BackgroundType.Image)
204 if self.page(self.currentId()) == self.background_page and \
205- self.theme.background_type == background_image and \
206- is_not_image_file(Path(self.theme.background_filename)):
207+ self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename):
208 QtWidgets.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),
209 translate('OpenLP.ThemeWizard', 'You have not selected a '
210 'background image. Please select one before continuing.'))
211@@ -273,7 +271,7 @@
212 Run the wizard.
213 """
214 log.debug('Editing theme {name}'.format(name=self.theme.theme_name))
215- self.temp_background_filename = ''
216+ self.temp_background_filename = None
217 self.update_theme_allowed = False
218 self.set_defaults()
219 self.update_theme_allowed = True
220@@ -318,11 +316,11 @@
221 self.setField('background_type', 1)
222 elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
223 self.image_color_button.color = self.theme.background_border_color
224- self.image_path_edit.path = str_to_path(self.theme.background_filename)
225+ self.image_path_edit.path = self.theme.background_filename
226 self.setField('background_type', 2)
227 elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
228 self.video_color_button.color = self.theme.background_border_color
229- self.video_path_edit.path = str_to_path(self.theme.background_filename)
230+ self.video_path_edit.path = self.theme.background_filename
231 self.setField('background_type', 4)
232 elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
233 self.setField('background_type', 3)
234@@ -402,14 +400,14 @@
235 self.theme.background_type = BackgroundType.to_string(index)
236 if self.theme.background_type != BackgroundType.to_string(BackgroundType.Image) and \
237 self.theme.background_type != BackgroundType.to_string(BackgroundType.Video) and \
238- self.temp_background_filename == '':
239+ self.temp_background_filename is None:
240 self.temp_background_filename = self.theme.background_filename
241- self.theme.background_filename = ''
242+ self.theme.background_filename = None
243 if (self.theme.background_type == BackgroundType.to_string(BackgroundType.Image) or
244 self.theme.background_type != BackgroundType.to_string(BackgroundType.Video)) and \
245- self.temp_background_filename != '':
246+ self.temp_background_filename is not None:
247 self.theme.background_filename = self.temp_background_filename
248- self.temp_background_filename = ''
249+ self.temp_background_filename = None
250 self.set_background_page_values()
251
252 def on_gradient_combo_box_current_index_changed(self, index):
253@@ -450,18 +448,24 @@
254 """
255 self.theme.background_end_color = color
256
257- def on_image_path_edit_path_changed(self, file_path):
258- """
259- Background Image button pushed.
260- """
261- self.theme.background_filename = path_to_str(file_path)
262+ def on_image_path_edit_path_changed(self, new_path):
263+ """
264+ Handle the `pathEditChanged` signal from image_path_edit
265+
266+ :param openlp.core.common.path.Path new_path: Path to the new image
267+ :rtype: None
268+ """
269+ self.theme.background_filename = new_path
270 self.set_background_page_values()
271
272- def on_video_path_edit_path_changed(self, file_path):
273- """
274- Background video button pushed.
275- """
276- self.theme.background_filename = path_to_str(file_path)
277+ def on_video_path_edit_path_changed(self, new_path):
278+ """
279+ Handle the `pathEditChanged` signal from video_path_edit
280+
281+ :param openlp.core.common.path.Path new_path: Path to the new video
282+ :rtype: None
283+ """
284+ self.theme.background_filename = new_path
285 self.set_background_page_values()
286
287 def on_main_color_changed(self, color):
288@@ -537,14 +541,14 @@
289 translate('OpenLP.ThemeWizard', 'Theme Name Invalid'),
290 translate('OpenLP.ThemeWizard', 'Invalid theme name. Please enter one.'))
291 return
292- save_from = None
293- save_to = None
294+ source_path = None
295+ destination_path = None
296 if self.theme.background_type == BackgroundType.to_string(BackgroundType.Image) or \
297 self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
298- filename = os.path.split(str(self.theme.background_filename))[1]
299- save_to = os.path.join(self.path, self.theme.theme_name, filename)
300- save_from = self.theme.background_filename
301+ file_name = self.theme.background_filename.name
302+ destination_path = self.path / self.theme.theme_name / file_name
303+ source_path = self.theme.background_filename
304 if not self.edit_mode and not self.theme_manager.check_if_theme_exists(self.theme.theme_name):
305 return
306- self.theme_manager.save_theme(self.theme, save_from, save_to)
307+ self.theme_manager.save_theme(self.theme, source_path, destination_path)
308 return QtWidgets.QDialog.accept(self)
309
310=== modified file 'openlp/core/ui/thememanager.py'
311--- openlp/core/ui/thememanager.py 2017-09-17 19:43:15 +0000
312+++ openlp/core/ui/thememanager.py 2017-09-26 17:09:04 +0000
313@@ -24,14 +24,14 @@
314 """
315 import os
316 import zipfile
317-import shutil
318-
319 from xml.etree.ElementTree import ElementTree, XML
320+
321 from PyQt5 import QtCore, QtGui, QtWidgets
322
323 from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
324- UiStrings, check_directory_exists, translate, is_win, get_filesystem_encoding, delete_file
325-from openlp.core.common.path import Path, path_to_str, str_to_path
326+ UiStrings, check_directory_exists, translate, delete_file
327+from openlp.core.common.languagemanager import get_locale_key
328+from openlp.core.common.path import Path, copyfile, path_to_str, rmtree
329 from openlp.core.lib import ImageSource, ValidationError, get_text_file_string, build_icon, \
330 check_item_selected, create_thumb, validate_thumb
331 from openlp.core.lib.theme import Theme, BackgroundType
332@@ -39,7 +39,6 @@
333 from openlp.core.ui import FileRenameForm, ThemeForm
334 from openlp.core.ui.lib import OpenLPToolbar
335 from openlp.core.ui.lib.filedialog import FileDialog
336-from openlp.core.common.languagemanager import get_locale_key
337
338
339 class Ui_ThemeManager(object):
340@@ -135,7 +134,7 @@
341 self.settings_section = 'themes'
342 # Variables
343 self.theme_list = []
344- self.old_background_image = None
345+ self.old_background_image_path = None
346
347 def bootstrap_initialise(self):
348 """
349@@ -145,25 +144,41 @@
350 self.global_theme = Settings().value(self.settings_section + '/global theme')
351 self.build_theme_path()
352 self.load_first_time_themes()
353+ self.upgrade_themes()
354
355 def bootstrap_post_set_up(self):
356 """
357 process the bootstrap post setup request
358 """
359 self.theme_form = ThemeForm(self)
360- self.theme_form.path = self.path
361+ self.theme_form.path = self.theme_path
362 self.file_rename_form = FileRenameForm()
363 Registry().register_function('theme_update_global', self.change_global_from_tab)
364 self.load_themes()
365
366+ def upgrade_themes(self):
367+ """
368+ Upgrade the xml files to json.
369+
370+ :rtype: None
371+ """
372+ xml_file_paths = AppLocation.get_section_data_path('themes').glob('*/*.xml')
373+ for xml_file_path in xml_file_paths:
374+ theme_data = get_text_file_string(xml_file_path)
375+ theme = self._create_theme_from_xml(theme_data, self.theme_path)
376+ self._write_theme(theme)
377+ xml_file_path.unlink()
378+
379 def build_theme_path(self):
380 """
381 Set up the theme path variables
382+
383+ :rtype: None
384 """
385- self.path = str(AppLocation.get_section_data_path(self.settings_section))
386- check_directory_exists(Path(self.path))
387- self.thumb_path = os.path.join(self.path, 'thumbnails')
388- check_directory_exists(Path(self.thumb_path))
389+ self.theme_path = AppLocation.get_section_data_path(self.settings_section)
390+ check_directory_exists(self.theme_path)
391+ self.thumb_path = self.theme_path / 'thumbnails'
392+ check_directory_exists(self.thumb_path)
393
394 def check_list_state(self, item, field=None):
395 """
396@@ -298,17 +313,18 @@
397 """
398 Takes a theme and makes a new copy of it as well as saving it.
399
400- :param theme_data: The theme to be used
401- :param new_theme_name: The new theme name to save the data to
402+ :param Theme theme_data: The theme to be used
403+ :param str new_theme_name: The new theme name of the theme
404+ :rtype: None
405 """
406- save_to = None
407- save_from = None
408+ destination_path = None
409+ source_path = None
410 if theme_data.background_type == 'image' or theme_data.background_type == 'video':
411- save_to = os.path.join(self.path, new_theme_name, os.path.split(str(theme_data.background_filename))[1])
412- save_from = theme_data.background_filename
413+ destination_path = self.theme_path / new_theme_name / theme_data.background_filename.name
414+ source_path = theme_data.background_filename
415 theme_data.theme_name = new_theme_name
416- theme_data.extend_image_filename(self.path)
417- self.save_theme(theme_data, save_from, save_to)
418+ theme_data.extend_image_filename(self.theme_path)
419+ self.save_theme(theme_data, source_path, destination_path)
420 self.load_themes()
421
422 def on_edit_theme(self, field=None):
423@@ -322,10 +338,10 @@
424 item = self.theme_list_widget.currentItem()
425 theme = self.get_theme_data(item.data(QtCore.Qt.UserRole))
426 if theme.background_type == 'image' or theme.background_type == 'video':
427- self.old_background_image = theme.background_filename
428+ self.old_background_image_path = theme.background_filename
429 self.theme_form.theme = theme
430 self.theme_form.exec(True)
431- self.old_background_image = None
432+ self.old_background_image_path = None
433 self.renderer.update_theme(theme.theme_name)
434 self.load_themes()
435
436@@ -355,77 +371,76 @@
437 """
438 self.theme_list.remove(theme)
439 thumb = '{name}.png'.format(name=theme)
440- delete_file(Path(self.path, thumb))
441- delete_file(Path(self.thumb_path, thumb))
442+ delete_file(self.theme_path / thumb)
443+ delete_file(self.thumb_path / thumb)
444 try:
445- # Windows is always unicode, so no need to encode filenames
446- if is_win():
447- shutil.rmtree(os.path.join(self.path, theme))
448- else:
449- encoding = get_filesystem_encoding()
450- shutil.rmtree(os.path.join(self.path, theme).encode(encoding))
451- except OSError as os_error:
452- shutil.Error = os_error
453+ rmtree(self.theme_path / theme)
454+ except OSError:
455 self.log_exception('Error deleting theme {name}'.format(name=theme))
456
457- def on_export_theme(self, field=None):
458+ def on_export_theme(self, checked=None):
459 """
460- Export the theme in a zip file
461- :param field:
462+ Export the theme to a zip file
463+
464+ :param bool checked: Sent by the QAction.triggered signal. It's not used in this method.
465+ :rtype: None
466 """
467 item = self.theme_list_widget.currentItem()
468 if item is None:
469 critical_error_message_box(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.'))
470 return
471- theme = item.data(QtCore.Qt.UserRole)
472+ theme_name = item.data(QtCore.Qt.UserRole)
473 export_path, filter_used = \
474 FileDialog.getSaveFileName(self.main_window,
475- translate('OpenLP.ThemeManager', 'Save Theme - ({name})').
476- format(name=theme),
477+ translate('OpenLP.ThemeManager',
478+ 'Save Theme - ({name})').format(name=theme_name),
479 Settings().value(self.settings_section + '/last directory export'),
480+ translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'),
481 translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
482 self.application.set_busy_cursor()
483 if export_path:
484 Settings().setValue(self.settings_section + '/last directory export', export_path.parent)
485- if self._export_theme(str(export_path), theme):
486+ if self._export_theme(export_path.with_suffix('.otz'), theme_name):
487 QtWidgets.QMessageBox.information(self,
488 translate('OpenLP.ThemeManager', 'Theme Exported'),
489 translate('OpenLP.ThemeManager',
490 'Your theme has been successfully exported.'))
491 self.application.set_normal_cursor()
492
493- def _export_theme(self, theme_path, theme):
494+ def _export_theme(self, theme_path, theme_name):
495 """
496 Create the zipfile with the theme contents.
497- :param theme_path: Location where the zip file will be placed
498- :param theme: The name of the theme to be exported
499+
500+ :param openlp.core.common.path.Path theme_path: Location where the zip file will be placed
501+ :param str theme_name: The name of the theme to be exported
502+ :return: The success of creating the zip file
503+ :rtype: bool
504 """
505- theme_zip = None
506 try:
507- theme_zip = zipfile.ZipFile(theme_path, 'w')
508- source = os.path.join(self.path, theme)
509- for files in os.walk(source):
510- for name in files[2]:
511- theme_zip.write(os.path.join(source, name), os.path.join(theme, name))
512- theme_zip.close()
513+ with zipfile.ZipFile(str(theme_path), 'w') as theme_zip:
514+ source_path = self.theme_path / theme_name
515+ for file_path in source_path.iterdir():
516+ theme_zip.write(str(file_path), os.path.join(theme_name, file_path.name))
517 return True
518 except OSError as ose:
519 self.log_exception('Export Theme Failed')
520 critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
521- translate('OpenLP.ThemeManager', 'The theme export failed because this error '
522- 'occurred: {err}').format(err=ose.strerror))
523- if theme_zip:
524- theme_zip.close()
525- shutil.rmtree(theme_path, True)
526+ translate('OpenLP.ThemeManager',
527+ 'The theme_name export failed because this error occurred: {err}')
528+ .format(err=ose.strerror))
529+ if theme_path.exists():
530+ rmtree(theme_path, True)
531 return False
532
533- def on_import_theme(self, field=None):
534+ def on_import_theme(self, checked=None):
535 """
536 Opens a file dialog to select the theme file(s) to import before attempting to extract OpenLP themes from
537 those files. This process will only load version 2 themes.
538- :param field:
539+
540+ :param bool checked: Sent by the QAction.triggered signal. It's not used in this method.
541+ :rtype: None
542 """
543- file_paths, selected_filter = FileDialog.getOpenFileNames(
544+ file_paths, filter_used = FileDialog.getOpenFileNames(
545 self,
546 translate('OpenLP.ThemeManager', 'Select Theme Import File'),
547 Settings().value(self.settings_section + '/last directory import'),
548@@ -435,8 +450,8 @@
549 return
550 self.application.set_busy_cursor()
551 for file_path in file_paths:
552- self.unzip_theme(path_to_str(file_path), self.path)
553- Settings().setValue(self.settings_section + '/last directory import', file_path)
554+ self.unzip_theme(file_path, self.theme_path)
555+ Settings().setValue(self.settings_section + '/last directory import', file_path.parent)
556 self.load_themes()
557 self.application.set_normal_cursor()
558
559@@ -445,17 +460,17 @@
560 Imports any themes on start up and makes sure there is at least one theme
561 """
562 self.application.set_busy_cursor()
563- files = AppLocation.get_files(self.settings_section, '.otz')
564- for theme_file in files:
565- theme_file = os.path.join(self.path, str(theme_file))
566- self.unzip_theme(theme_file, self.path)
567- delete_file(Path(theme_file))
568- files = AppLocation.get_files(self.settings_section, '.png')
569+ theme_paths = AppLocation.get_files(self.settings_section, '.otz')
570+ for theme_path in theme_paths:
571+ theme_path = self.theme_path / theme_path
572+ self.unzip_theme(theme_path, self.theme_path)
573+ delete_file(theme_path)
574+ theme_paths = AppLocation.get_files(self.settings_section, '.png')
575 # No themes have been found so create one
576- if not files:
577+ if not theme_paths:
578 theme = Theme()
579 theme.theme_name = UiStrings().Default
580- self._write_theme(theme, None, None)
581+ self._write_theme(theme)
582 Settings().setValue(self.settings_section + '/global theme', theme.theme_name)
583 self.application.set_normal_cursor()
584
585@@ -471,22 +486,21 @@
586 # Sort the themes by its name considering language specific
587 files.sort(key=lambda file_name: get_locale_key(str(file_name)))
588 # now process the file list of png files
589- for name in files:
590- name = str(name)
591+ for file in files:
592 # check to see file is in theme root directory
593- theme = os.path.join(self.path, name)
594- if os.path.exists(theme):
595- text_name = os.path.splitext(name)[0]
596+ theme_path = self.theme_path / file
597+ if theme_path.exists():
598+ text_name = theme_path.stem
599 if text_name == self.global_theme:
600 name = translate('OpenLP.ThemeManager', '{name} (default)').format(name=text_name)
601 else:
602 name = text_name
603- thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=text_name))
604+ thumb = self.thumb_path / '{name}.png'.format(name=text_name)
605 item_name = QtWidgets.QListWidgetItem(name)
606- if validate_thumb(Path(theme), Path(thumb)):
607+ if validate_thumb(theme_path, thumb):
608 icon = build_icon(thumb)
609 else:
610- icon = create_thumb(theme, thumb)
611+ icon = create_thumb(str(theme_path), str(thumb))
612 item_name.setIcon(icon)
613 item_name.setData(QtCore.Qt.UserRole, text_name)
614 self.theme_list_widget.addItem(item_name)
615@@ -507,27 +521,19 @@
616
617 def get_theme_data(self, theme_name):
618 """
619- Returns a theme object from an XML or JSON file
620+ Returns a theme object from a JSON file
621
622- :param theme_name: Name of the theme to load from file
623- :return: The theme object.
624+ :param str theme_name: Name of the theme to load from file
625+ :return: The theme object.
626+ :rtype: Theme
627 """
628- self.log_debug('get theme data for theme {name}'.format(name=theme_name))
629- theme_file_path = Path(self.path, str(theme_name), '{file_name}.json'.format(file_name=theme_name))
630+ theme_name = str(theme_name)
631+ theme_file_path = self.theme_path / theme_name / '{file_name}.json'.format(file_name=theme_name)
632 theme_data = get_text_file_string(theme_file_path)
633- jsn = True
634- if not theme_data:
635- theme_file_path = theme_file_path.with_suffix('.xml')
636- theme_data = get_text_file_string(theme_file_path)
637- jsn = False
638 if not theme_data:
639 self.log_debug('No theme data - using default theme')
640 return Theme()
641- else:
642- if jsn:
643- return self._create_theme_from_json(theme_data, self.path)
644- else:
645- return self._create_theme_from_xml(theme_data, self.path)
646+ return self._create_theme_from_json(theme_data, self.theme_path)
647
648 def over_write_message_box(self, theme_name):
649 """
650@@ -543,172 +549,148 @@
651 defaultButton=QtWidgets.QMessageBox.No)
652 return ret == QtWidgets.QMessageBox.Yes
653
654- def unzip_theme(self, file_name, directory):
655+ def unzip_theme(self, file_path, directory_path):
656 """
657 Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
658 and upgrade if necessary.
659- :param file_name:
660- :param directory:
661+ :param openlp.core.common.path.Path file_path:
662+ :param openlp.core.common.path.Path directory_path:
663 """
664- self.log_debug('Unzipping theme {name}'.format(name=file_name))
665- theme_zip = None
666- out_file = None
667+ self.log_debug('Unzipping theme {name}'.format(name=file_path))
668 file_xml = None
669 abort_import = True
670 json_theme = False
671 theme_name = ""
672 try:
673- theme_zip = zipfile.ZipFile(file_name)
674- json_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.json']
675- if len(json_file) != 1:
676- # TODO: remove XML handling at some point but would need a auto conversion to run first.
677- xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml']
678- if len(xml_file) != 1:
679- self.log_error('Theme contains "{val:d}" theme files'.format(val=len(xml_file)))
680- raise ValidationError
681- xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
682- theme_version = xml_tree.get('version', default=None)
683- if not theme_version or float(theme_version) < 2.0:
684- self.log_error('Theme version is less than 2.0')
685- raise ValidationError
686- theme_name = xml_tree.find('name').text.strip()
687- else:
688- new_theme = Theme()
689- new_theme.load_theme(theme_zip.read(json_file[0]).decode("utf-8"))
690- theme_name = new_theme.theme_name
691- json_theme = True
692- theme_folder = os.path.join(directory, theme_name)
693- theme_exists = os.path.exists(theme_folder)
694- if theme_exists and not self.over_write_message_box(theme_name):
695- abort_import = True
696- return
697- else:
698- abort_import = False
699- for name in theme_zip.namelist():
700- out_name = name.replace('/', os.path.sep)
701- split_name = out_name.split(os.path.sep)
702- if split_name[-1] == '' or len(split_name) == 1:
703- # is directory or preview file
704- continue
705- full_name = os.path.join(directory, out_name)
706- check_directory_exists(Path(os.path.dirname(full_name)))
707- if os.path.splitext(name)[1].lower() == '.xml' or os.path.splitext(name)[1].lower() == '.json':
708- file_xml = str(theme_zip.read(name), 'utf-8')
709- out_file = open(full_name, 'w', encoding='utf-8')
710- out_file.write(file_xml)
711- else:
712- out_file = open(full_name, 'wb')
713- out_file.write(theme_zip.read(name))
714- out_file.close()
715+ with zipfile.ZipFile(str(file_path)) as theme_zip:
716+ json_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.json']
717+ if len(json_file) != 1:
718+ # TODO: remove XML handling after the 2.6 release.
719+ xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml']
720+ if len(xml_file) != 1:
721+ self.log_error('Theme contains "{val:d}" theme files'.format(val=len(xml_file)))
722+ raise ValidationError
723+ xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
724+ theme_version = xml_tree.get('version', default=None)
725+ if not theme_version or float(theme_version) < 2.0:
726+ self.log_error('Theme version is less than 2.0')
727+ raise ValidationError
728+ theme_name = xml_tree.find('name').text.strip()
729+ else:
730+ new_theme = Theme()
731+ new_theme.load_theme(theme_zip.read(json_file[0]).decode("utf-8"))
732+ theme_name = new_theme.theme_name
733+ json_theme = True
734+ theme_folder = directory_path / theme_name
735+ if theme_folder.exists() and not self.over_write_message_box(theme_name):
736+ abort_import = True
737+ return
738+ else:
739+ abort_import = False
740+ for zipped_file in theme_zip.namelist():
741+ zipped_file_rel_path = Path(zipped_file)
742+ split_name = zipped_file_rel_path.parts
743+ if split_name[-1] == '' or len(split_name) == 1:
744+ # is directory or preview file
745+ continue
746+ full_name = directory_path / zipped_file_rel_path
747+ check_directory_exists(full_name.parent)
748+ if zipped_file_rel_path.suffix.lower() == '.xml' or zipped_file_rel_path.suffix.lower() == '.json':
749+ file_xml = str(theme_zip.read(zipped_file), 'utf-8')
750+ with full_name.open('w', encoding='utf-8') as out_file:
751+ out_file.write(file_xml)
752+ else:
753+ with full_name.open('wb') as out_file:
754+ out_file.write(theme_zip.read(zipped_file))
755 except (IOError, zipfile.BadZipfile):
756- self.log_exception('Importing theme from zip failed {name}'.format(name=file_name))
757+ self.log_exception('Importing theme from zip failed {name}'.format(name=file_path))
758 raise ValidationError
759 except ValidationError:
760 critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),
761 translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
762 finally:
763- # Close the files, to be able to continue creating the theme.
764- if theme_zip:
765- theme_zip.close()
766- if out_file:
767- out_file.close()
768 if not abort_import:
769 # As all files are closed, we can create the Theme.
770 if file_xml:
771 if json_theme:
772- theme = self._create_theme_from_json(file_xml, self.path)
773+ theme = self._create_theme_from_json(file_xml, self.theme_path)
774 else:
775- theme = self._create_theme_from_xml(file_xml, self.path)
776+ theme = self._create_theme_from_xml(file_xml, self.theme_path)
777 self.generate_and_save_image(theme_name, theme)
778- # Only show the error message, when IOError was not raised (in
779- # this case the error message has already been shown).
780- elif theme_zip is not None:
781- critical_error_message_box(
782- translate('OpenLP.ThemeManager', 'Validation Error'),
783- translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
784- self.log_error('Theme file does not contain XML data {name}'.format(name=file_name))
785
786 def check_if_theme_exists(self, theme_name):
787 """
788 Check if theme already exists and displays error message
789
790- :param theme_name: Name of the Theme to test
791+ :param str theme_name: Name of the Theme to test
792 :return: True or False if theme exists
793+ :rtype: bool
794 """
795- theme_dir = os.path.join(self.path, theme_name)
796- if os.path.exists(theme_dir):
797+ if (self.theme_path / theme_name).exists():
798 critical_error_message_box(
799 translate('OpenLP.ThemeManager', 'Validation Error'),
800 translate('OpenLP.ThemeManager', 'A theme with this name already exists.'))
801 return False
802 return True
803
804- def save_theme(self, theme, image_from, image_to):
805+ def save_theme(self, theme, image_source_path, image_destination_path):
806 """
807 Called by theme maintenance Dialog to save the theme and to trigger the reload of the theme list
808
809- :param theme: The theme data object.
810- :param image_from: Where the theme image is currently located.
811- :param image_to: Where the Theme Image is to be saved to
812+ :param Theme theme: The theme data object.
813+ :param openlp.core.common.path.Path image_source_path: Where the theme image is currently located.
814+ :param openlp.core.common.path.Path image_destination_path: Where the Theme Image is to be saved to
815+ :rtype: None
816 """
817- self._write_theme(theme, image_from, image_to)
818+ self._write_theme(theme, image_source_path, image_destination_path)
819 if theme.background_type == BackgroundType.to_string(BackgroundType.Image):
820- self.image_manager.update_image_border(theme.background_filename,
821+ self.image_manager.update_image_border(path_to_str(theme.background_filename),
822 ImageSource.Theme,
823 QtGui.QColor(theme.background_border_color))
824 self.image_manager.process_updates()
825
826- def _write_theme(self, theme, image_from, image_to):
827+ def _write_theme(self, theme, image_source_path=None, image_destination_path=None):
828 """
829 Writes the theme to the disk and handles the background image if necessary
830
831- :param theme: The theme data object.
832- :param image_from: Where the theme image is currently located.
833- :param image_to: Where the Theme Image is to be saved to
834+ :param Theme theme: The theme data object.
835+ :param openlp.core.common.path.Path image_source_path: Where the theme image is currently located.
836+ :param openlp.core.common.path.Path image_destination_path: Where the Theme Image is to be saved to
837+ :rtype: None
838 """
839 name = theme.theme_name
840- theme_pretty = theme.export_theme()
841- theme_dir = os.path.join(self.path, name)
842- check_directory_exists(Path(theme_dir))
843- theme_file = os.path.join(theme_dir, name + '.json')
844- if self.old_background_image and image_to != self.old_background_image:
845- delete_file(Path(self.old_background_image))
846- out_file = None
847+ theme_pretty = theme.export_theme(self.theme_path)
848+ theme_dir = self.theme_path / name
849+ check_directory_exists(theme_dir)
850+ theme_path = theme_dir / '{file_name}.json'.format(file_name=name)
851 try:
852- out_file = open(theme_file, 'w', encoding='utf-8')
853- out_file.write(theme_pretty)
854+ theme_path.write_text(theme_pretty)
855 except IOError:
856 self.log_exception('Saving theme to file failed')
857- finally:
858- if out_file:
859- out_file.close()
860- if image_from and os.path.abspath(image_from) != os.path.abspath(image_to):
861- try:
862- # Windows is always unicode, so no need to encode filenames
863- if is_win():
864- shutil.copyfile(image_from, image_to)
865- else:
866- encoding = get_filesystem_encoding()
867- shutil.copyfile(image_from.encode(encoding), image_to.encode(encoding))
868- except IOError as xxx_todo_changeme:
869- shutil.Error = xxx_todo_changeme
870- self.log_exception('Failed to save theme image')
871+ if image_source_path and image_destination_path:
872+ if self.old_background_image_path and image_destination_path != self.old_background_image_path:
873+ delete_file(self.old_background_image_path)
874+ if image_source_path != image_destination_path:
875+ try:
876+ copyfile(image_source_path, image_destination_path)
877+ except IOError:
878+ self.log_exception('Failed to save theme image')
879 self.generate_and_save_image(name, theme)
880
881- def generate_and_save_image(self, name, theme):
882+ def generate_and_save_image(self, theme_name, theme):
883 """
884 Generate and save a preview image
885
886- :param name: The name of the theme.
887+ :param str theme_name: The name of the theme.
888 :param theme: The theme data object.
889 """
890 frame = self.generate_image(theme)
891- sample_path_name = os.path.join(self.path, name + '.png')
892- if os.path.exists(sample_path_name):
893- os.unlink(sample_path_name)
894- frame.save(sample_path_name, 'png')
895- thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=name))
896- create_thumb(sample_path_name, thumb, False)
897+ sample_path_name = self.theme_path / '{file_name}.png'.format(file_name=theme_name)
898+ if sample_path_name.exists():
899+ sample_path_name.unlink()
900+ frame.save(str(sample_path_name), 'png')
901+ thumb_path = self.thumb_path / '{name}.png'.format(name=theme_name)
902+ create_thumb(str(sample_path_name), str(thumb_path), False)
903
904 def update_preview_images(self):
905 """
906@@ -730,39 +712,32 @@
907 """
908 return self.renderer.generate_preview(theme_data, force_page)
909
910- def get_preview_image(self, theme):
911- """
912- Return an image representing the look of the theme
913-
914- :param theme: The theme to return the image for.
915- """
916- return os.path.join(self.path, theme + '.png')
917-
918 @staticmethod
919 def _create_theme_from_xml(theme_xml, image_path):
920 """
921 Return a theme object using information parsed from XML
922
923 :param theme_xml: The Theme data object.
924- :param image_path: Where the theme image is stored
925+ :param openlp.core.common.path.Path image_path: Where the theme image is stored
926 :return: Theme data.
927+ :rtype: Theme
928 """
929 theme = Theme()
930 theme.parse(theme_xml)
931 theme.extend_image_filename(image_path)
932 return theme
933
934- @staticmethod
935- def _create_theme_from_json(theme_json, image_path):
936+ def _create_theme_from_json(self, theme_json, image_path):
937 """
938 Return a theme object using information parsed from JSON
939
940 :param theme_json: The Theme data object.
941- :param image_path: Where the theme image is stored
942+ :param openlp.core.common.path.Path image_path: Where the theme image is stored
943 :return: Theme data.
944+ :rtype: Theme
945 """
946 theme = Theme()
947- theme.load_theme(theme_json)
948+ theme.load_theme(theme_json, self.theme_path)
949 theme.extend_image_filename(image_path)
950 return theme
951
952
953=== modified file 'openlp/core/ui/themestab.py'
954--- openlp/core/ui/themestab.py 2016-12-31 11:01:36 +0000
955+++ openlp/core/ui/themestab.py 2017-09-26 17:09:04 +0000
956@@ -211,8 +211,8 @@
957 """
958 Utility method to update the global theme preview image.
959 """
960- image = self.theme_manager.get_preview_image(self.global_theme)
961- preview = QtGui.QPixmap(str(image))
962+ image_path = self.theme_manager.theme_path / '{file_name}.png'.format(file_name=self.global_theme)
963+ preview = QtGui.QPixmap(str(image_path))
964 if not preview.isNull():
965 preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
966 self.default_list_view.setPixmap(preview)
967
968=== modified file 'openlp/plugins/images/lib/upgrade.py'
969--- openlp/plugins/images/lib/upgrade.py 2017-09-23 13:06:42 +0000
970+++ openlp/plugins/images/lib/upgrade.py 2017-09-26 17:09:04 +0000
971@@ -48,7 +48,6 @@
972 """
973 Version 2 upgrade - Move file path from old db to JSON encoded path to new db. Added during 2.5 dev
974 """
975- # TODO: Update tests
976 log.debug('Starting upgrade_2 for file_path to JSON')
977 old_table = Table('image_filenames', metadata, autoload=True)
978 if 'file_path' not in [col.name for col in old_table.c.values()]:
979
980=== modified file 'tests/functional/openlp_core_lib/test_theme.py'
981--- tests/functional/openlp_core_lib/test_theme.py 2017-05-24 20:04:48 +0000
982+++ tests/functional/openlp_core_lib/test_theme.py 2017-09-26 17:09:04 +0000
983@@ -22,8 +22,9 @@
984 """
985 Package to test the openlp.core.lib.theme package.
986 """
987+import os
988+from pathlib import Path
989 from unittest import TestCase
990-import os
991
992 from openlp.core.lib.theme import Theme
993
994@@ -79,16 +80,16 @@
995 """
996 # GIVEN: A theme object
997 theme = Theme()
998- theme.theme_name = 'MyBeautifulTheme '
999- theme.background_filename = ' video.mp4'
1000+ theme.theme_name = 'MyBeautifulTheme'
1001+ theme.background_filename = Path('video.mp4')
1002 theme.background_type = 'video'
1003- path = os.path.expanduser('~')
1004+ path = Path.home()
1005
1006 # WHEN: Theme.extend_image_filename is run
1007 theme.extend_image_filename(path)
1008
1009 # THEN: The filename of the background should be correct
1010- expected_filename = os.path.join(path, 'MyBeautifulTheme', 'video.mp4')
1011+ expected_filename = path / 'MyBeautifulTheme' / 'video.mp4'
1012 self.assertEqual(expected_filename, theme.background_filename)
1013 self.assertEqual('MyBeautifulTheme', theme.theme_name)
1014
1015
1016=== modified file 'tests/functional/openlp_core_ui/test_maindisplay.py'
1017--- tests/functional/openlp_core_ui/test_maindisplay.py 2017-07-08 13:12:31 +0000
1018+++ tests/functional/openlp_core_ui/test_maindisplay.py 2017-09-26 17:09:04 +0000
1019@@ -27,10 +27,10 @@
1020
1021 from PyQt5 import QtCore
1022
1023-from openlp.core.common import Registry, is_macosx, Settings
1024+from openlp.core.common import Registry, is_macosx
1025+from openlp.core.common.path import Path
1026 from openlp.core.lib import ScreenList, PluginManager
1027 from openlp.core.ui import MainDisplay, AudioPlayer
1028-from openlp.core.ui.media import MediaController
1029 from openlp.core.ui.maindisplay import TRANSPARENT_STYLESHEET, OPAQUE_STYLESHEET
1030
1031 from tests.helpers.testmixin import TestMixin
1032@@ -184,7 +184,7 @@
1033 self.assertEqual(pyobjc_nsview.window().collectionBehavior(), NSWindowCollectionBehaviorManaged,
1034 'Window collection behavior should be NSWindowCollectionBehaviorManaged')
1035
1036- @patch(u'openlp.core.ui.maindisplay.Settings')
1037+ @patch('openlp.core.ui.maindisplay.Settings')
1038 def test_show_display_startup_logo(self, MockedSettings):
1039 # GIVEN: Mocked show_display, setting for logo visibility
1040 display = MagicMock()
1041@@ -204,7 +204,7 @@
1042 # THEN: setVisible should had been called with "True"
1043 main_display.setVisible.assert_called_once_with(True)
1044
1045- @patch(u'openlp.core.ui.maindisplay.Settings')
1046+ @patch('openlp.core.ui.maindisplay.Settings')
1047 def test_show_display_hide_startup_logo(self, MockedSettings):
1048 # GIVEN: Mocked show_display, setting for logo visibility
1049 display = MagicMock()
1050@@ -224,8 +224,8 @@
1051 # THEN: setVisible should had not been called
1052 main_display.setVisible.assert_not_called()
1053
1054- @patch(u'openlp.core.ui.maindisplay.Settings')
1055- @patch(u'openlp.core.ui.maindisplay.build_html')
1056+ @patch('openlp.core.ui.maindisplay.Settings')
1057+ @patch('openlp.core.ui.maindisplay.build_html')
1058 def test_build_html_no_video(self, MockedSettings, Mocked_build_html):
1059 # GIVEN: Mocked display
1060 display = MagicMock()
1061@@ -252,8 +252,8 @@
1062 self.assertEquals(main_display.media_controller.video.call_count, 0,
1063 'Media Controller video should not have been called')
1064
1065- @patch(u'openlp.core.ui.maindisplay.Settings')
1066- @patch(u'openlp.core.ui.maindisplay.build_html')
1067+ @patch('openlp.core.ui.maindisplay.Settings')
1068+ @patch('openlp.core.ui.maindisplay.build_html')
1069 def test_build_html_video(self, MockedSettings, Mocked_build_html):
1070 # GIVEN: Mocked display
1071 display = MagicMock()
1072@@ -270,7 +270,7 @@
1073 service_item.theme_data = MagicMock()
1074 service_item.theme_data.background_type = 'video'
1075 service_item.theme_data.theme_name = 'name'
1076- service_item.theme_data.background_filename = 'background_filename'
1077+ service_item.theme_data.background_filename = Path('background_filename')
1078 mocked_plugin = MagicMock()
1079 display.plugin_manager = PluginManager()
1080 display.plugin_manager.plugins = [mocked_plugin]
1081
1082=== modified file 'tests/functional/openlp_core_ui/test_themeform.py'
1083--- tests/functional/openlp_core_ui/test_themeform.py 2017-08-25 20:03:25 +0000
1084+++ tests/functional/openlp_core_ui/test_themeform.py 2017-09-26 17:09:04 +0000
1085@@ -49,5 +49,5 @@
1086 self.instance.on_image_path_edit_path_changed(Path('/', 'new', 'pat.h'))
1087
1088 # THEN: The theme background file should be set and `set_background_page_values` should have been called
1089- self.assertEqual(self.instance.theme.background_filename, '/new/pat.h')
1090+ self.assertEqual(self.instance.theme.background_filename, Path('/', 'new', 'pat.h'))
1091 mocked_set_background_page_values.assert_called_once_with()
1092
1093=== modified file 'tests/functional/openlp_core_ui/test_thememanager.py'
1094--- tests/functional/openlp_core_ui/test_thememanager.py 2017-08-12 17:45:56 +0000
1095+++ tests/functional/openlp_core_ui/test_thememanager.py 2017-09-26 17:09:04 +0000
1096@@ -30,8 +30,9 @@
1097
1098 from PyQt5 import QtWidgets
1099
1100+from openlp.core.common import Registry
1101+from openlp.core.common.path import Path
1102 from openlp.core.ui import ThemeManager
1103-from openlp.core.common import Registry
1104
1105 from tests.utils.constants import TEST_RESOURCES_PATH
1106
1107@@ -57,13 +58,13 @@
1108 """
1109 # GIVEN: A new ThemeManager instance.
1110 theme_manager = ThemeManager()
1111- theme_manager.path = os.path.join(TEST_RESOURCES_PATH, 'themes')
1112+ theme_manager.theme_path = Path(TEST_RESOURCES_PATH, 'themes')
1113 with patch('zipfile.ZipFile.__init__') as mocked_zipfile_init, \
1114 patch('zipfile.ZipFile.write') as mocked_zipfile_write:
1115 mocked_zipfile_init.return_value = None
1116
1117 # WHEN: The theme is exported
1118- theme_manager._export_theme(os.path.join('some', 'path', 'Default.otz'), 'Default')
1119+ theme_manager._export_theme(Path('some', 'path', 'Default.otz'), 'Default')
1120
1121 # THEN: The zipfile should be created at the given path
1122 mocked_zipfile_init.assert_called_with(os.path.join('some', 'path', 'Default.otz'), 'w')
1123@@ -86,57 +87,49 @@
1124 """
1125 Test that we don't try to overwrite a theme background image with itself
1126 """
1127- # GIVEN: A new theme manager instance, with mocked builtins.open, shutil.copyfile,
1128+ # GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
1129 # theme, check_directory_exists and thememanager-attributes.
1130- with patch('builtins.open') as mocked_open, \
1131- patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \
1132+ with patch('openlp.core.ui.thememanager.copyfile') as mocked_copyfile, \
1133 patch('openlp.core.ui.thememanager.check_directory_exists'):
1134- mocked_open.return_value = MagicMock()
1135 theme_manager = ThemeManager(None)
1136 theme_manager.old_background_image = None
1137 theme_manager.generate_and_save_image = MagicMock()
1138- theme_manager.path = ''
1139+ theme_manager.theme_path = MagicMock()
1140 mocked_theme = MagicMock()
1141 mocked_theme.theme_name = 'themename'
1142 mocked_theme.extract_formatted_xml = MagicMock()
1143 mocked_theme.extract_formatted_xml.return_value = 'fake_theme_xml'.encode()
1144
1145 # WHEN: Calling _write_theme with path to the same image, but the path written slightly different
1146- file_name1 = os.path.join(TEST_RESOURCES_PATH, 'church.jpg')
1147- # Do replacement from end of string to avoid problems with path start
1148- file_name2 = file_name1[::-1].replace(os.sep, os.sep + os.sep, 2)[::-1]
1149- theme_manager._write_theme(mocked_theme, file_name1, file_name2)
1150+ file_name1 = Path(TEST_RESOURCES_PATH, 'church.jpg')
1151+ theme_manager._write_theme(mocked_theme, file_name1, file_name1)
1152
1153 # THEN: The mocked_copyfile should not have been called
1154- self.assertFalse(mocked_copyfile.called, 'shutil.copyfile should not be called')
1155+ self.assertFalse(mocked_copyfile.called, 'copyfile should not be called')
1156
1157 def test_write_theme_diff_images(self):
1158 """
1159 Test that we do overwrite a theme background image when a new is submitted
1160 """
1161- # GIVEN: A new theme manager instance, with mocked builtins.open, shutil.copyfile,
1162+ # GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
1163 # theme, check_directory_exists and thememanager-attributes.
1164- with patch('builtins.open') as mocked_open, \
1165- patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \
1166+ with patch('openlp.core.ui.thememanager.copyfile') as mocked_copyfile, \
1167 patch('openlp.core.ui.thememanager.check_directory_exists'):
1168- mocked_open.return_value = MagicMock()
1169 theme_manager = ThemeManager(None)
1170 theme_manager.old_background_image = None
1171 theme_manager.generate_and_save_image = MagicMock()
1172- theme_manager.path = ''
1173+ theme_manager.theme_path = MagicMock()
1174 mocked_theme = MagicMock()
1175 mocked_theme.theme_name = 'themename'
1176 mocked_theme.filename = "filename"
1177- # mocked_theme.extract_formatted_xml = MagicMock()
1178- # mocked_theme.extract_formatted_xml.return_value = 'fake_theme_xml'.encode()
1179
1180 # WHEN: Calling _write_theme with path to different images
1181- file_name1 = os.path.join(TEST_RESOURCES_PATH, 'church.jpg')
1182- file_name2 = os.path.join(TEST_RESOURCES_PATH, 'church2.jpg')
1183+ file_name1 = Path(TEST_RESOURCES_PATH, 'church.jpg')
1184+ file_name2 = Path(TEST_RESOURCES_PATH, 'church2.jpg')
1185 theme_manager._write_theme(mocked_theme, file_name1, file_name2)
1186
1187 # THEN: The mocked_copyfile should not have been called
1188- self.assertTrue(mocked_copyfile.called, 'shutil.copyfile should be called')
1189+ self.assertTrue(mocked_copyfile.called, 'copyfile should be called')
1190
1191 def test_write_theme_special_char_name(self):
1192 """
1193@@ -146,7 +139,7 @@
1194 theme_manager = ThemeManager(None)
1195 theme_manager.old_background_image = None
1196 theme_manager.generate_and_save_image = MagicMock()
1197- theme_manager.path = self.temp_folder
1198+ theme_manager.theme_path = Path(self.temp_folder)
1199 mocked_theme = MagicMock()
1200 mocked_theme.theme_name = 'theme 愛 name'
1201 mocked_theme.export_theme.return_value = "{}"
1202@@ -208,17 +201,17 @@
1203 theme_manager = ThemeManager(None)
1204 theme_manager._create_theme_from_xml = MagicMock()
1205 theme_manager.generate_and_save_image = MagicMock()
1206- theme_manager.path = ''
1207- folder = mkdtemp()
1208- theme_file = os.path.join(TEST_RESOURCES_PATH, 'themes', 'Moss_on_tree.otz')
1209+ theme_manager.theme_path = None
1210+ folder = Path(mkdtemp())
1211+ theme_file = Path(TEST_RESOURCES_PATH, 'themes', 'Moss_on_tree.otz')
1212
1213 # WHEN: We try to unzip it
1214 theme_manager.unzip_theme(theme_file, folder)
1215
1216 # THEN: Files should be unpacked
1217- self.assertTrue(os.path.exists(os.path.join(folder, 'Moss on tree', 'Moss on tree.xml')))
1218+ self.assertTrue((folder / 'Moss on tree' / 'Moss on tree.xml').exists())
1219 self.assertEqual(mocked_critical_error_message_box.call_count, 0, 'No errors should have happened')
1220- shutil.rmtree(folder)
1221+ shutil.rmtree(str(folder))
1222
1223 def test_unzip_theme_invalid_version(self):
1224 """
1225
1226=== modified file 'tests/interfaces/openlp_core_ui/test_thememanager.py'
1227--- tests/interfaces/openlp_core_ui/test_thememanager.py 2017-04-24 05:17:55 +0000
1228+++ tests/interfaces/openlp_core_ui/test_thememanager.py 2017-09-26 17:09:04 +0000
1229@@ -26,7 +26,8 @@
1230 from unittest.mock import patch, MagicMock
1231
1232 from openlp.core.common import Registry, Settings
1233-from openlp.core.ui import ThemeManager, ThemeForm, FileRenameForm
1234+from openlp.core.common.path import Path
1235+from openlp.core.ui import ThemeManager
1236
1237 from tests.helpers.testmixin import TestMixin
1238
1239@@ -91,6 +92,23 @@
1240 assert self.theme_manager.thumb_path.startswith(self.theme_manager.path) is True, \
1241 'The thumb path and the main path should start with the same value'
1242
1243+ def test_build_theme_path(self):
1244+ """
1245+ Test the thememanager build_theme_path - basic test
1246+ """
1247+ # GIVEN: A new a call to initialise
1248+ with patch('openlp.core.common.AppLocation.get_section_data_path', return_value=Path('test/path')):
1249+ Settings().setValue('themes/global theme', 'my_theme')
1250+
1251+ self.theme_manager.theme_form = MagicMock()
1252+ self.theme_manager.load_first_time_themes = MagicMock()
1253+
1254+ # WHEN: the build_theme_path is run
1255+ self.theme_manager.build_theme_path()
1256+
1257+ # THEN: The thumbnail path should be a sub path of the test path
1258+ self.assertEqual(self.theme_manager.thumb_path, Path('test/path/thumbnails'))
1259+
1260 def test_click_on_new_theme(self):
1261 """
1262 Test the on_add_theme event handler is called by the UI
1263@@ -109,17 +127,16 @@
1264
1265 @patch('openlp.core.ui.themeform.ThemeForm._setup')
1266 @patch('openlp.core.ui.filerenameform.FileRenameForm._setup')
1267- def test_bootstrap_post(self, mocked_theme_form, mocked_rename_form):
1268+ def test_bootstrap_post(self, mocked_rename_form, mocked_theme_form):
1269 """
1270 Test the functions of bootstrap_post_setup are called.
1271 """
1272 # GIVEN:
1273 self.theme_manager.load_themes = MagicMock()
1274- self.theme_manager.path = MagicMock()
1275+ self.theme_manager.theme_path = MagicMock()
1276
1277 # WHEN:
1278 self.theme_manager.bootstrap_post_set_up()
1279
1280 # THEN:
1281- self.assertEqual(self.theme_manager.path, self.theme_manager.theme_form.path)
1282 self.assertEqual(1, self.theme_manager.load_themes.call_count, "load_themes should have been called once")