Merge lp:~thelinuxguy/openlp/make-methods-static into lp:openlp

Proposed by Simon Hanna
Status: Superseded
Proposed branch: lp:~thelinuxguy/openlp/make-methods-static
Merge into: lp:openlp
Diff against target: 790 lines (+230/-150)
20 files modified
.bzrignore (+1/-0)
.coveragerc (+5/-0)
openlp/core/lib/renderer.py (+50/-48)
openlp/core/ui/mainwindow.py (+2/-1)
openlp/core/ui/servicemanager.py (+21/-34)
openlp/plugins/alerts/alertsplugin.py (+6/-3)
openlp/plugins/bibles/bibleplugin.py (+2/-1)
openlp/plugins/custom/customplugin.py (+2/-1)
openlp/plugins/images/imageplugin.py (+2/-1)
openlp/plugins/media/mediaplugin.py (+2/-1)
openlp/plugins/presentations/presentationplugin.py (+2/-1)
openlp/plugins/remotes/remoteplugin.py (+2/-1)
openlp/plugins/songs/forms/songexportform.py (+28/-27)
openlp/plugins/songs/lib/importers/foilpresenter.py (+27/-25)
openlp/plugins/songs/songsplugin.py (+5/-3)
openlp/plugins/songusage/songusageplugin.py (+3/-2)
tests/functional/openlp_plugins/media/test_mediaplugin.py (+8/-0)
tests/functional/openlp_plugins/songs/test_foilpresenterimport.py (+1/-1)
tests/functional/openlp_plugins/songusage/__init__.py (+24/-0)
tests/functional/openlp_plugins/songusage/test_songusage.py (+37/-0)
To merge this branch: bzr merge lp:~thelinuxguy/openlp/make-methods-static
Reviewer Review Type Date Requested Status
Raoul Snyman Needs Fixing
Review via email: mp+281488@code.launchpad.net

This proposal has been superseded by a proposal from 2016-01-05.

Description of the change

Make some methods static where possible

Add .coveragerc so that local html reports can be generated

To post a comment you must log in.
2593. By Simon Hanna

Make methods static that don't need to rely on instance data

Revision history for this message
Raoul Snyman (raoul-snyman) wrote :

Rather make these functions than static methods. Static methods are a little pointless in Python anyway.

review: Needs Fixing
2594. By Simon Hanna

Move some static methods out of their classes where it makes sense

2595. By Simon Hanna

update functions that were previously methods to drop the '_'
rename _child to to_str because of name conflicts

2596. By Simon Hanna

Fix some pep issues in the changed files

2597. By Simon Hanna

Merge with trunk

2598. By Simon Hanna

Fix failing test due to name conflict

2599. By Simon Hanna

Fix pep8 errors

2600. By Simon Hanna

Merge with trunk

2601. By Simon Hanna

Remove code that was added by mistake

2602. By Simon Hanna

Undo changes to instance variables

2603. By Simon Hanna

Revert Changes

2604. By Simon Hanna

Merge with trunk

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2015-05-07 21:29:43 +0000
3+++ .bzrignore 2016-01-05 22:29:06 +0000
4@@ -43,3 +43,4 @@
5 .coverage
6 cover
7 *.kdev4
8+coverage
9
10=== added file '.coveragerc'
11--- .coveragerc 1970-01-01 00:00:00 +0000
12+++ .coveragerc 2016-01-05 22:29:06 +0000
13@@ -0,0 +1,5 @@
14+[run]
15+source = openlp
16+
17+[html]
18+directory = coverage
19
20=== modified file 'openlp/core/lib/renderer.py'
21--- openlp/core/lib/renderer.py 2015-12-31 22:46:06 +0000
22+++ openlp/core/lib/renderer.py 2016-01-05 22:29:06 +0000
23@@ -273,7 +273,7 @@
24 except ValueError:
25 text_to_render = text.split('\n[---]\n')[0]
26 text = ''
27- text_to_render, raw_tags, html_tags = self._get_start_tags(text_to_render)
28+ text_to_render, raw_tags, html_tags = Renderer._get_start_tags(text_to_render)
29 if text:
30 text = raw_tags + text
31 else:
32@@ -441,7 +441,7 @@
33 previous_raw = line + line_end
34 continue
35 # Figure out how many words of the line will fit on screen as the line will not fit as a whole.
36- raw_words = self._words_split(line)
37+ raw_words = Renderer._words_split(line)
38 html_words = list(map(expand_tags, raw_words))
39 previous_html, previous_raw = \
40 self._binary_chop(formatted, previous_html, previous_raw, html_words, raw_words, ' ', line_end)
41@@ -451,42 +451,6 @@
42 formatted.append(previous_raw)
43 return formatted
44
45- def _get_start_tags(self, raw_text):
46- """
47- Tests the given text for not closed formatting tags and returns a tuple consisting of three unicode strings::
48-
49- ('{st}{r}Text text text{/r}{/st}', '{st}{r}', '<strong><span style="-webkit-text-fill-color:red">')
50-
51- The first unicode string is the text, with correct closing tags. The second unicode string are OpenLP's opening
52- formatting tags and the third unicode string the html opening formatting tags.
53-
54- :param raw_text: The text to test. The text must **not** contain html tags, only OpenLP formatting tags
55- are allowed::
56- {st}{r}Text text text
57- """
58- raw_tags = []
59- html_tags = []
60- for tag in FormattingTags.get_html_tags():
61- if tag['start tag'] == '{br}':
62- continue
63- if raw_text.count(tag['start tag']) != raw_text.count(tag['end tag']):
64- raw_tags.append((raw_text.find(tag['start tag']), tag['start tag'], tag['end tag']))
65- html_tags.append((raw_text.find(tag['start tag']), tag['start html']))
66- # Sort the lists, so that the tags which were opened first on the first slide (the text we are checking) will be
67- # opened first on the next slide as well.
68- raw_tags.sort(key=lambda tag: tag[0])
69- html_tags.sort(key=lambda tag: tag[0])
70- # Create a list with closing tags for the raw_text.
71- end_tags = []
72- start_tags = []
73- for tag in raw_tags:
74- start_tags.append(tag[1])
75- end_tags.append(tag[2])
76- end_tags.reverse()
77- # Remove the indexes.
78- html_tags = [tag[1] for tag in html_tags]
79- return raw_text + ''.join(end_tags), ''.join(start_tags), ''.join(html_tags)
80-
81 def _binary_chop(self, formatted, previous_html, previous_raw, html_list, raw_list, separator, line_end):
82 """
83 This implements the binary chop algorithm for faster rendering. This algorithm works line based (line by line)
84@@ -521,7 +485,7 @@
85 if smallest_index == index or highest_index == index:
86 index = smallest_index
87 text = previous_raw.rstrip('<br>') + separator.join(raw_list[:index + 1])
88- text, raw_tags, html_tags = self._get_start_tags(text)
89+ text, raw_tags, html_tags = _get_start_tags(text)
90 formatted.append(text)
91 previous_html = ''
92 previous_raw = ''
93@@ -556,12 +520,50 @@
94 self.web_frame.evaluateJavaScript('show_text("%s")' % text.replace('\\', '\\\\').replace('\"', '\\\"'))
95 return self.web_frame.contentsSize().height() <= self.empty_height
96
97- def _words_split(self, line):
98- """
99- Split the slide up by word so can wrap better
100-
101- :param line: Line to be split
102- """
103- # this parse we are to be wordy
104- line = line.replace('\n', ' ')
105- return line.split(' ')
106+
107+def _words_split(line):
108+ """
109+ Split the slide up by word so can wrap better
110+
111+ :param line: Line to be split
112+ """
113+ # this parse we are to be wordy
114+ line = line.replace('\n', ' ')
115+ return line.split(' ')
116+
117+def _get_start_tags(raw_text):
118+ """
119+ Tests the given text for not closed formatting tags and returns a tuple consisting of three unicode strings::
120+
121+ ('{st}{r}Text text text{/r}{/st}', '{st}{r}', '<strong><span style="-webkit-text-fill-color:red">')
122+
123+ The first unicode string is the text, with correct closing tags. The second unicode string are OpenLP's opening
124+ formatting tags and the third unicode string the html opening formatting tags.
125+
126+ :param raw_text: The text to test. The text must **not** contain html tags, only OpenLP formatting tags
127+ are allowed::
128+ {st}{r}Text text text
129+ """
130+ raw_tags = []
131+ html_tags = []
132+ for tag in FormattingTags.get_html_tags():
133+ if tag['start tag'] == '{br}':
134+ continue
135+ if raw_text.count(tag['start tag']) != raw_text.count(tag['end tag']):
136+ raw_tags.append((raw_text.find(tag['start tag']), tag['start tag'], tag['end tag']))
137+ html_tags.append((raw_text.find(tag['start tag']), tag['start html']))
138+ # Sort the lists, so that the tags which were opened first on the first slide (the text we are checking) will be
139+ # opened first on the next slide as well.
140+ raw_tags.sort(key=lambda tag: tag[0])
141+ html_tags.sort(key=lambda tag: tag[0])
142+ # Create a list with closing tags for the raw_text.
143+ end_tags = []
144+ start_tags = []
145+ for tag in raw_tags:
146+ start_tags.append(tag[1])
147+ end_tags.append(tag[2])
148+ end_tags.reverse()
149+ # Remove the indexes.
150+ html_tags = [tag[1] for tag in html_tags]
151+ return raw_text + ''.join(end_tags), ''.join(start_tags), ''.join(html_tags)
152+
153
154=== modified file 'openlp/core/ui/mainwindow.py'
155--- openlp/core/ui/mainwindow.py 2015-12-31 22:46:06 +0000
156+++ openlp/core/ui/mainwindow.py 2016-01-05 22:29:06 +0000
157@@ -47,6 +47,7 @@
158 from openlp.core.utils.actions import ActionList, CategoryOrder
159 from openlp.core.ui.firsttimeform import FirstTimeForm
160 from openlp.core.ui.projector.manager import ProjectorManager
161+from openlp.core.ui.printserviceform import PrintServiceForm
162
163 log = logging.getLogger(__name__)
164
165@@ -197,7 +198,7 @@
166 triggers=self.service_manager_contents.save_file_as)
167 self.print_service_order_item = create_action(main_window, 'printServiceItem', can_shortcuts=True,
168 category=UiStrings().File,
169- triggers=self.service_manager_contents.print_service_order)
170+ triggers=lambda x: PrintServiceForm().exec())
171 self.file_exit_item = create_action(main_window, 'fileExitItem', icon=':/system/system_exit.png',
172 can_shortcuts=True,
173 category=UiStrings().File, triggers=main_window.close)
174
175=== modified file 'openlp/core/ui/servicemanager.py'
176--- openlp/core/ui/servicemanager.py 2015-12-31 22:46:06 +0000
177+++ openlp/core/ui/servicemanager.py 2016-01-05 22:29:06 +0000
178@@ -144,8 +144,8 @@
179 self.service_manager_list.customContextMenuRequested.connect(self.context_menu)
180 self.service_manager_list.setObjectName('service_manager_list')
181 # enable drop
182- self.service_manager_list.__class__.dragEnterEvent = self.drag_enter_event
183- self.service_manager_list.__class__.dragMoveEvent = self.drag_enter_event
184+ self.service_manager_list.__class__.dragEnterEvent = lambda x, event: event.accept()
185+ self.service_manager_list.__class__.dragMoveEvent = lambda x, event: event.accept()
186 self.service_manager_list.__class__.dropEvent = self.drop_event
187 self.layout.addWidget(self.service_manager_list)
188 # Add the bottom toolbar
189@@ -293,14 +293,6 @@
190 Registry().register_function('theme_update_global', self.theme_change)
191 Registry().register_function('mediaitem_suffix_reset', self.reset_supported_suffixes)
192
193- def drag_enter_event(self, event):
194- """
195- Accept Drag events
196-
197- :param event: Handle of the event passed
198- """
199- event.accept()
200-
201
202 class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceManager, RegistryProperties):
203 """
204@@ -1585,7 +1577,7 @@
205 if item is None:
206 end_pos = len(self.service_items)
207 else:
208- end_pos = self._get_parent_item_data(item) - 1
209+ end_pos = _get_parent_item_data(item) - 1
210 service_item = self.service_items[start_pos]
211 self.service_items.remove(service_item)
212 self.service_items.insert(end_pos, service_item)
213@@ -1598,21 +1590,21 @@
214 self.drop_position = len(self.service_items)
215 else:
216 # we are over something so lets investigate
217- pos = self._get_parent_item_data(item) - 1
218+ pos = _get_parent_item_data(item) - 1
219 service_item = self.service_items[pos]
220 if (plugin == service_item['service_item'].name and
221 service_item['service_item'].is_capable(ItemCapabilities.CanAppend)):
222 action = self.dnd_menu.exec(QtGui.QCursor.pos())
223 # New action required
224 if action == self.new_action:
225- self.drop_position = self._get_parent_item_data(item)
226+ self.drop_position = _get_parent_item_data(item)
227 # Append to existing action
228 if action == self.add_to_action:
229- self.drop_position = self._get_parent_item_data(item)
230+ self.drop_position = _get_parent_item_data(item)
231 item.setSelected(True)
232 replace = True
233 else:
234- self.drop_position = self._get_parent_item_data(item) - 1
235+ self.drop_position = _get_parent_item_data(item) - 1
236 Registry().execute('%s_add_service_item' % plugin, replace)
237
238 def update_theme_list(self, theme_list):
239@@ -1656,27 +1648,22 @@
240 self.service_items[item]['service_item'].update_theme(theme)
241 self.regenerate_service_items(True)
242
243- def _get_parent_item_data(self, item):
244- """
245- Finds and returns the parent item for any item
246-
247- :param item: The service item list item to be checked.
248- """
249- parent_item = item.parent()
250- if parent_item is None:
251- return item.data(0, QtCore.Qt.UserRole)
252- else:
253- return parent_item.data(0, QtCore.Qt.UserRole)
254-
255- def print_service_order(self, field=None):
256- """
257- Print a Service Order Sheet.
258- """
259- setting_dialog = PrintServiceForm()
260- setting_dialog.exec()
261-
262 def get_drop_position(self):
263 """
264 Getter for drop_position. Used in: MediaManagerItem
265 """
266 return self.drop_position
267+
268+
269+def _get_parent_item_data(item):
270+ """
271+ Finds and returns the parent item for any item
272+
273+ :param item: The service item list item to be checked.
274+ """
275+ parent_item = item.parent()
276+ if parent_item is None:
277+ return item.data(0, QtCore.Qt.UserRole)
278+ else:
279+ return parent_item.data(0, QtCore.Qt.UserRole)
280+
281
282=== modified file 'openlp/plugins/alerts/alertsplugin.py'
283--- openlp/plugins/alerts/alertsplugin.py 2015-12-31 22:46:06 +0000
284+++ openlp/plugins/alerts/alertsplugin.py 2016-01-05 22:29:06 +0000
285@@ -191,7 +191,8 @@
286 self.alert_form.load_list()
287 self.alert_form.exec()
288
289- def about(self):
290+ @staticmethod
291+ def about():
292 """
293 Plugin Alerts about method
294
295@@ -215,7 +216,8 @@
296 'title': translate('AlertsPlugin', 'Alerts', 'container title')
297 }
298
299- def get_display_javascript(self):
300+ @staticmethod
301+ def get_display_javascript():
302 """
303 Add Javascript to the main display.
304 """
305@@ -229,7 +231,8 @@
306 return CSS % (align, self.settings_tab.font_face, self.settings_tab.font_size, self.settings_tab.font_color,
307 self.settings_tab.background_color)
308
309- def get_display_html(self):
310+ @staticmethod
311+ def get_display_html():
312 """
313 Add HTML to the main display.
314 """
315
316=== modified file 'openlp/plugins/bibles/bibleplugin.py'
317--- openlp/plugins/bibles/bibleplugin.py 2015-12-31 22:46:06 +0000
318+++ openlp/plugins/bibles/bibleplugin.py 2016-01-05 22:29:06 +0000
319@@ -167,7 +167,8 @@
320 if self.media_item:
321 self.media_item.on_import_click()
322
323- def about(self):
324+ @staticmethod
325+ def about():
326 """
327 Return the about text for the plugin manager
328 """
329
330=== modified file 'openlp/plugins/custom/customplugin.py'
331--- openlp/plugins/custom/customplugin.py 2015-12-31 22:46:06 +0000
332+++ openlp/plugins/custom/customplugin.py 2016-01-05 22:29:06 +0000
333@@ -62,7 +62,8 @@
334 self.icon_path = ':/plugins/plugin_custom.png'
335 self.icon = build_icon(self.icon_path)
336
337- def about(self):
338+ @staticmethod
339+ def about():
340 about_text = translate('CustomPlugin', '<strong>Custom Slide Plugin </strong><br />The custom slide plugin '
341 'provides the ability to set up custom text slides that can be displayed on the screen '
342 'the same way songs are. This plugin provides greater freedom over the songs plugin.')
343
344=== modified file 'openlp/plugins/images/imageplugin.py'
345--- openlp/plugins/images/imageplugin.py 2015-12-31 22:46:06 +0000
346+++ openlp/plugins/images/imageplugin.py 2016-01-05 22:29:06 +0000
347@@ -53,7 +53,8 @@
348 self.icon_path = ':/plugins/plugin_images.png'
349 self.icon = build_icon(self.icon_path)
350
351- def about(self):
352+ @staticmethod
353+ def about():
354 about_text = translate('ImagePlugin', '<strong>Image Plugin</strong>'
355 '<br />The image plugin provides displaying of images.<br />One '
356 'of the distinguishing features of this plugin is the ability to '
357
358=== modified file 'openlp/plugins/media/mediaplugin.py'
359--- openlp/plugins/media/mediaplugin.py 2015-12-31 22:46:06 +0000
360+++ openlp/plugins/media/mediaplugin.py 2016-01-05 22:29:06 +0000
361@@ -84,7 +84,8 @@
362 visible_name = self.get_string(StringContent.VisibleName)
363 self.settings_tab = MediaTab(parent, self.name, visible_name['title'], self.icon_path)
364
365- def about(self):
366+ @staticmethod
367+ def about():
368 """
369 Return the about text for the plugin manager
370 """
371
372=== modified file 'openlp/plugins/presentations/presentationplugin.py'
373--- openlp/plugins/presentations/presentationplugin.py 2015-12-31 22:46:06 +0000
374+++ openlp/plugins/presentations/presentationplugin.py 2016-01-05 22:29:06 +0000
375@@ -137,7 +137,8 @@
376 self.register_controllers(controller)
377 return bool(self.controllers)
378
379- def about(self):
380+ @staticmethod
381+ def about():
382 """
383 Return information about this plugin.
384 """
385
386=== modified file 'openlp/plugins/remotes/remoteplugin.py'
387--- openlp/plugins/remotes/remoteplugin.py 2015-12-31 22:46:06 +0000
388+++ openlp/plugins/remotes/remoteplugin.py 2016-01-05 22:29:06 +0000
389@@ -88,7 +88,8 @@
390 self.server.stop_server()
391 self.server = None
392
393- def about(self):
394+ @staticmethod
395+ def about():
396 """
397 Information about this plugin
398 """
399
400=== modified file 'openlp/plugins/songs/forms/songexportform.py'
401--- openlp/plugins/songs/forms/songexportform.py 2015-12-31 22:46:06 +0000
402+++ openlp/plugins/songs/forms/songexportform.py 2016-01-05 22:29:06 +0000
403@@ -72,7 +72,7 @@
404 """
405 Song wizard specific signals.
406 """
407- self.available_list_widget.itemActivated.connect(self.on_item_activated)
408+ self.available_list_widget.itemActivated.connect(_on_item_activated)
409 self.search_line_edit.textEdited.connect(self.on_search_line_edit_changed)
410 self.uncheck_button.clicked.connect(self.on_uncheck_button_clicked)
411 self.check_button.clicked.connect(self.on_check_button_clicked)
412@@ -172,7 +172,7 @@
413 return True
414 elif self.currentPage() == self.available_songs_page:
415 items = [
416- item for item in self._find_list_widget_items(self.available_list_widget) if item.checkState()
417+ item for item in _find_list_widget_items(self.available_list_widget) if item.checkState()
418 ]
419 if not items:
420 critical_error_message_box(
421@@ -241,7 +241,7 @@
422 """
423 songs = [
424 song.data(QtCore.Qt.UserRole)
425- for song in self._find_list_widget_items(self.selected_list_widget)
426+ for song in _find_list_widget_items(self.selected_list_widget)
427 ]
428 exporter = OpenLyricsExport(self, songs, self.directory_line_edit.text())
429 try:
430@@ -255,28 +255,6 @@
431 self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed because this '
432 'error occurred: %s') % ose.strerror)
433
434- def _find_list_widget_items(self, list_widget, text=''):
435- """
436- Returns a list of *QListWidgetItem*s of the ``list_widget``. Note, that hidden items are included.
437-
438- :param list_widget: The widget to get all items from. (QListWidget)
439- :param text: The text to search for. (unicode string)
440- """
441- return [
442- item for item in list_widget.findItems(text, QtCore.Qt.MatchContains)
443- ]
444-
445- def on_item_activated(self, item):
446- """
447- Called, when an item in the *available_list_widget* has been triggered.
448- The item is check if it was not checked, whereas it is unchecked when it
449- was checked.
450-
451- :param item: The *QListWidgetItem* which was triggered.
452- """
453- item.setCheckState(
454- QtCore.Qt.Unchecked if item.checkState() else QtCore.Qt.Checked)
455-
456 def on_search_line_edit_changed(self, text):
457 """
458 The *search_line_edit*'s text has been changed. Update the list of
459@@ -286,9 +264,9 @@
460 :param text: The text of the *search_line_edit*.
461 """
462 search_result = [
463- song for song in self._find_list_widget_items(self.available_list_widget, text)
464+ song for song in _find_list_widget_items(self.available_list_widget, text)
465 ]
466- for item in self._find_list_widget_items(self.available_list_widget):
467+ for item in _find_list_widget_items(self.available_list_widget):
468 item.setHidden(item not in search_result)
469
470 def on_uncheck_button_clicked(self):
471@@ -317,3 +295,26 @@
472 self.get_folder(
473 translate('SongsPlugin.ExportWizardForm', 'Select Destination Folder'),
474 self.directory_line_edit, 'last directory export')
475+
476+
477+def _find_list_widget_items(list_widget, text=''):
478+ """
479+ Returns a list of *QListWidgetItem*s of the ``list_widget``. Note, that hidden items are included.
480+
481+ :param list_widget: The widget to get all items from. (QListWidget)
482+ :param text: The text to search for. (unicode string)
483+ """
484+ return [
485+ item for item in list_widget.findItems(text, QtCore.Qt.MatchContains)
486+ ]
487+
488+def _on_item_activated(item):
489+ """
490+ Called, when an item in the *available_list_widget* has been triggered.
491+ The item is check if it was not checked, whereas it is unchecked when it
492+ was checked.
493+
494+ :param item: The *QListWidgetItem* which was triggered.
495+ """
496+ item.setCheckState(QtCore.Qt.Unchecked if item.checkState() else QtCore.Qt.Checked)
497+
498
499=== modified file 'openlp/plugins/songs/lib/importers/foilpresenter.py'
500--- openlp/plugins/songs/lib/importers/foilpresenter.py 2015-12-31 22:46:06 +0000
501+++ openlp/plugins/songs/lib/importers/foilpresenter.py 2016-01-05 22:29:06 +0000
502@@ -234,16 +234,6 @@
503 clean_song(self.manager, song)
504 self.manager.save_object(song)
505
506- def _child(self, element):
507- """
508- This returns the text of an element as unicode string.
509-
510- :param element: The element
511- """
512- if element is not None:
513- return str(element)
514- return ''
515-
516 def _process_authors(self, foilpresenterfolie, song):
517 """
518 Adds the authors specified in the XML to the song.
519@@ -253,7 +243,7 @@
520 """
521 authors = []
522 try:
523- copyright = self._child(foilpresenterfolie.copyright.text_)
524+ copyright = _child(foilpresenterfolie.copyright.text_)
525 except AttributeError:
526 copyright = None
527 if copyright:
528@@ -346,7 +336,7 @@
529 :param song: The song object.
530 """
531 try:
532- song.ccli_number = self._child(foilpresenterfolie.ccliid)
533+ song.ccli_number = _child(foilpresenterfolie.ccliid)
534 except AttributeError:
535 song.ccli_number = ''
536
537@@ -358,7 +348,7 @@
538 :param song: The song object.
539 """
540 try:
541- song.comments = self._child(foilpresenterfolie.notiz)
542+ song.comments = _child(foilpresenterfolie.notiz)
543 except AttributeError:
544 song.comments = ''
545
546@@ -370,7 +360,7 @@
547 :param song: The song object.
548 """
549 try:
550- song.copyright = self._child(foilpresenterfolie.copyright.text_)
551+ song.copyright = _child(foilpresenterfolie.copyright.text_)
552 except AttributeError:
553 song.copyright = ''
554
555@@ -396,19 +386,19 @@
556 VerseType.tags[VerseType.PreChorus]: 1
557 }
558 if not hasattr(foilpresenterfolie.strophen, 'strophe'):
559- self.importer.log_error(self._child(foilpresenterfolie.titel),
560+ self.importer.log_error(_child(foilpresenterfolie.titel),
561 str(translate('SongsPlugin.FoilPresenterSongImport',
562 'Invalid Foilpresenter song file. No verses found.')))
563 self.save_song = False
564 return
565 for strophe in foilpresenterfolie.strophen.strophe:
566- text = self._child(strophe.text_) if hasattr(strophe, 'text_') else ''
567- verse_name = self._child(strophe.key)
568+ text = _child(strophe.text_) if hasattr(strophe, 'text_') else ''
569+ verse_name = _child(strophe.key)
570 children = strophe.getchildren()
571 sortnr = False
572 for child in children:
573 if child.tag == 'sortnr':
574- verse_sortnr = self._child(strophe.sortnr)
575+ verse_sortnr = _child(strophe.sortnr)
576 sortnr = True
577 # In older Version there is no sortnr, but we need one
578 if not sortnr:
579@@ -484,7 +474,7 @@
580 song.song_number = ''
581 try:
582 for bucheintrag in foilpresenterfolie.buch.bucheintrag:
583- book_name = self._child(bucheintrag.name)
584+ book_name = _child(bucheintrag.name)
585 if book_name:
586 book = self.manager.get_object_filtered(Book, Book.name == book_name)
587 if book is None:
588@@ -493,8 +483,8 @@
589 self.manager.save_object(book)
590 song.song_book_id = book.id
591 try:
592- if self._child(bucheintrag.nummer):
593- song.song_number = self._child(bucheintrag.nummer)
594+ if _child(bucheintrag.nummer):
595+ song.song_number = _child(bucheintrag.nummer)
596 except AttributeError:
597 pass
598 # We only support one song book, so take the first one.
599@@ -512,13 +502,13 @@
600 try:
601 for title_string in foilpresenterfolie.titel.titelstring:
602 if not song.title:
603- song.title = self._child(title_string)
604+ song.title = _child(title_string)
605 song.alternate_title = ''
606 else:
607- song.alternate_title = self._child(title_string)
608+ song.alternate_title = _child(title_string)
609 except AttributeError:
610 # Use first line of first verse
611- first_line = self._child(foilpresenterfolie.strophen.strophe.text_)
612+ first_line = _child(foilpresenterfolie.strophen.strophe.text_)
613 song.title = first_line.split('\n')[0]
614
615 def _process_topics(self, foilpresenterfolie, song):
616@@ -530,7 +520,7 @@
617 """
618 try:
619 for name in foilpresenterfolie.kategorien.name:
620- topic_text = self._child(name)
621+ topic_text = _child(name)
622 if topic_text:
623 topic = self.manager.get_object_filtered(Topic, Topic.name == topic_text)
624 if topic is None:
625@@ -540,3 +530,15 @@
626 song.topics.append(topic)
627 except AttributeError:
628 pass
629+
630+
631+def _child(element):
632+ """
633+ This returns the text of an element as unicode string.
634+
635+ :param element: The element
636+ """
637+ if element is not None:
638+ return str(element)
639+ return ''
640+
641
642=== modified file 'openlp/plugins/songs/songsplugin.py'
643--- openlp/plugins/songs/songsplugin.py 2015-12-31 22:46:06 +0000
644+++ openlp/plugins/songs/songsplugin.py 2016-01-05 22:29:06 +0000
645@@ -211,7 +211,8 @@
646 if self.media_item:
647 self.media_item.on_export_click()
648
649- def about(self):
650+ @staticmethod
651+ def about():
652 """
653 Provides information for the plugin manager to display.
654
655@@ -296,7 +297,7 @@
656 if sfile.startswith('songs_') and sfile.endswith('.sqlite'):
657 self.application.process_events()
658 song_dbs.append(os.path.join(db_dir, sfile))
659- song_count += self._count_songs(os.path.join(db_dir, sfile))
660+ song_count += SongsPlugin._count_songs(os.path.join(db_dir, sfile))
661 if not song_dbs:
662 return
663 self.application.process_events()
664@@ -343,7 +344,8 @@
665 for song in songs:
666 self.manager.delete_object(Song, song.id)
667
668- def _count_songs(self, db_file):
669+ @staticmethod
670+ def _count_songs(db_file):
671 """
672 Provide a count of the songs in the database
673
674
675=== modified file 'openlp/plugins/songusage/songusageplugin.py'
676--- openlp/plugins/songusage/songusageplugin.py 2015-12-31 22:46:06 +0000
677+++ openlp/plugins/songusage/songusageplugin.py 2016-01-05 22:29:06 +0000
678@@ -226,8 +226,9 @@
679 """
680 self.song_usage_detail_form.initialise()
681 self.song_usage_detail_form.exec()
682-
683- def about(self):
684+
685+ @staticmethod
686+ def about():
687 """
688 The plugin about text
689
690
691=== modified file 'tests/functional/openlp_plugins/media/test_mediaplugin.py'
692--- tests/functional/openlp_plugins/media/test_mediaplugin.py 2015-12-31 22:46:06 +0000
693+++ tests/functional/openlp_plugins/media/test_mediaplugin.py 2016-01-05 22:29:06 +0000
694@@ -57,3 +57,11 @@
695 mocked_settings.get_files_from_config.assert_called_with(media_plugin)
696 mocked_settings.setValue.assert_called_with('media/media files', True)
697 mocked_initialise.assert_called_with()
698+
699+ def test_about_text(self):
700+ # GIVEN: The MediaPlugin
701+ # WHEN: Retrieving the about text
702+ # THEN: about() should return a string object
703+ self.assertIsInstance(MediaPlugin.about(), str)
704+ # THEN: about() should return a non-empty string
705+ self.assertNotEquals(len(MediaPlugin.about()), 0)
706
707=== modified file 'tests/functional/openlp_plugins/songs/test_foilpresenterimport.py'
708--- tests/functional/openlp_plugins/songs/test_foilpresenterimport.py 2015-12-31 22:46:06 +0000
709+++ tests/functional/openlp_plugins/songs/test_foilpresenterimport.py 2016-01-05 22:29:06 +0000
710@@ -50,7 +50,7 @@
711 # _process_topics
712
713 def setUp(self):
714- self.child_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._child')
715+ self.child_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter._child')
716 self.clean_song_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.clean_song')
717 self.objectify_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.objectify')
718 self.process_authors_patcher = \
719
720=== added directory 'tests/functional/openlp_plugins/songusage'
721=== added file 'tests/functional/openlp_plugins/songusage/__init__.py'
722--- tests/functional/openlp_plugins/songusage/__init__.py 1970-01-01 00:00:00 +0000
723+++ tests/functional/openlp_plugins/songusage/__init__.py 2016-01-05 22:29:06 +0000
724@@ -0,0 +1,24 @@
725+# -*- coding: utf-8 -*-
726+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
727+
728+###############################################################################
729+# OpenLP - Open Source Lyrics Projection #
730+# --------------------------------------------------------------------------- #
731+# Copyright (c) 2008-2016 OpenLP Developers #
732+# --------------------------------------------------------------------------- #
733+# This program is free software; you can redistribute it and/or modify it #
734+# under the terms of the GNU General Public License as published by the Free #
735+# Software Foundation; version 2 of the License. #
736+# #
737+# This program is distributed in the hope that it will be useful, but WITHOUT #
738+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
739+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
740+# more details. #
741+# #
742+# You should have received a copy of the GNU General Public License along #
743+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
744+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
745+###############################################################################
746+"""
747+Tests for the Songusage plugin
748+"""
749
750=== added file 'tests/functional/openlp_plugins/songusage/test_songusage.py'
751--- tests/functional/openlp_plugins/songusage/test_songusage.py 1970-01-01 00:00:00 +0000
752+++ tests/functional/openlp_plugins/songusage/test_songusage.py 2016-01-05 22:29:06 +0000
753@@ -0,0 +1,37 @@
754+# -*- coding: utf-8 -*-
755+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
756+
757+###############################################################################
758+# OpenLP - Open Source Lyrics Projection #
759+# --------------------------------------------------------------------------- #
760+# Copyright (c) 2008-2016 OpenLP Developers #
761+# --------------------------------------------------------------------------- #
762+# This program is free software; you can redistribute it and/or modify it #
763+# under the terms of the GNU General Public License as published by the Free #
764+# Software Foundation; version 2 of the License. #
765+# #
766+# This program is distributed in the hope that it will be useful, but WITHOUT #
767+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
768+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
769+# more details. #
770+# #
771+# You should have received a copy of the GNU General Public License along #
772+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
773+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
774+###############################################################################
775+"""
776+This module contains tests for the Songusage plugin.
777+"""
778+from unittest import TestCase
779+from openlp.plugins.songusage.songusageplugin import SongUsagePlugin
780+
781+class TestSongUsage(TestCase):
782+
783+ def test_about_text(self):
784+ # GIVEN: The SongUsagePlugin
785+ # WHEN: Retrieving the about text
786+ # THEN: about() should return a string object
787+ self.assertIsInstance(SongUsagePlugin.about(), str)
788+ # THEN: about() should return a non-empty string
789+ self.assertNotEquals(len(SongUsagePlugin.about()), 0)
790+ self.assertNotEquals(len(SongUsagePlugin.about()), 0)