- Merged trunk on 2.8.16

This commit is contained in:
suutari-olli 2016-08-02 23:18:26 +03:00
commit 7eac4d5e38
12 changed files with 218 additions and 65 deletions

View File

@ -167,7 +167,7 @@ class ScreenList(object):
:param number: The screen number (int). :param number: The screen number (int).
""" """
log.info('remove_screen {number:d}'.forma(number=number)) log.info('remove_screen {number:d}'.format(number=number))
for screen in self.screen_list: for screen in self.screen_list:
if screen['number'] == number: if screen['number'] == number:
self.screen_list.remove(screen) self.screen_list.remove(screen)

View File

@ -252,7 +252,7 @@ class BGExtract(RegistryProperties):
chapter=chapter, chapter=chapter,
version=version) version=version)
soup = get_soup_for_bible_ref( soup = get_soup_for_bible_ref(
'http://legacy.biblegateway.com/passage/?{url}'.format(url=url_params), 'http://biblegateway.com/passage/?{url}'.format(url=url_params),
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='') pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='')
if not soup: if not soup:
return None return None
@ -281,7 +281,7 @@ class BGExtract(RegistryProperties):
""" """
log.debug('BGExtract.get_books_from_http("{version}")'.format(version=version)) log.debug('BGExtract.get_books_from_http("{version}")'.format(version=version))
url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '{version}'.format(version=version)}) url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '{version}'.format(version=version)})
reference_url = 'http://legacy.biblegateway.com/versions/?{url}#books'.format(url=url_params) reference_url = 'http://biblegateway.com/versions/?{url}#books'.format(url=url_params)
page = get_web_page(reference_url) page = get_web_page(reference_url)
if not page: if not page:
send_error_message('download') send_error_message('download')
@ -312,7 +312,7 @@ class BGExtract(RegistryProperties):
for book in content: for book in content:
book = book.find('td') book = book.find('td')
if book: if book:
books.append(book.contents[0]) books.append(book.contents[1])
return books return books
def get_bibles_from_http(self): def get_bibles_from_http(self):
@ -322,11 +322,11 @@ class BGExtract(RegistryProperties):
returns a list in the form [(biblename, biblekey, language_code)] returns a list in the form [(biblename, biblekey, language_code)]
""" """
log.debug('BGExtract.get_bibles_from_http') log.debug('BGExtract.get_bibles_from_http')
bible_url = 'https://legacy.biblegateway.com/versions/' bible_url = 'https://biblegateway.com/versions/'
soup = get_soup_for_bible_ref(bible_url) soup = get_soup_for_bible_ref(bible_url)
if not soup: if not soup:
return None return None
bible_select = soup.find('select', {'class': 'translation-dropdown'}) bible_select = soup.find('select', {'class': 'search-translation-select'})
if not bible_select: if not bible_select:
log.debug('No select tags found - did site change?') log.debug('No select tags found - did site change?')
return None return None
@ -532,28 +532,26 @@ class CWExtract(RegistryProperties):
returns a list in the form [(biblename, biblekey, language_code)] returns a list in the form [(biblename, biblekey, language_code)]
""" """
log.debug('CWExtract.get_bibles_from_http') log.debug('CWExtract.get_bibles_from_http')
bible_url = 'http://www.biblestudytools.com/' bible_url = 'http://www.biblestudytools.com/bible-versions/'
soup = get_soup_for_bible_ref(bible_url) soup = get_soup_for_bible_ref(bible_url)
if not soup: if not soup:
return None return None
bible_select = soup.find('select') h4_tags = soup.find_all('h4', {'class': 'small-header'})
if not bible_select: if not h4_tags:
log.debug('No select tags found - did site change?') log.debug('No h4 tags found - did site change?')
return None
option_tags = bible_select.find_all('option', {'class': 'log-translation'})
if not option_tags:
log.debug('No option tags found - did site change?')
return None return None
bibles = [] bibles = []
for ot in option_tags: for h4t in h4_tags:
tag_text = ot.get_text().strip() short_name = None
try: if h4t.span:
tag_value = ot['value'] short_name = h4t.span.get_text().strip().lower()
except KeyError: else:
log.exception('No value attribute found - did site change?') log.error('No span tag found - did site change?')
return None return None
if not tag_value: if not short_name:
continue continue
h4t.span.extract()
tag_text = h4t.get_text().strip()
# The names of non-english bibles has their language in parentheses at the end # The names of non-english bibles has their language in parentheses at the end
if tag_text.endswith(')'): if tag_text.endswith(')'):
language = tag_text[tag_text.rfind('(') + 1:-1] language = tag_text[tag_text.rfind('(') + 1:-1]
@ -561,12 +559,20 @@ class CWExtract(RegistryProperties):
language_code = CROSSWALK_LANGUAGES[language] language_code = CROSSWALK_LANGUAGES[language]
else: else:
language_code = '' language_code = ''
# ... except for the latin vulgate # ... except for those that don't...
elif 'latin' in tag_text.lower(): elif 'latin' in tag_text.lower():
language_code = 'la' language_code = 'la'
elif 'la biblia' in tag_text.lower() or 'nueva' in tag_text.lower():
language_code = 'es'
elif 'chinese' in tag_text.lower():
language_code = 'zh'
elif 'greek' in tag_text.lower():
language_code = 'el'
elif 'nova' in tag_text.lower():
language_code = 'pt'
else: else:
language_code = 'en' language_code = 'en'
bibles.append((tag_text, tag_value, language_code)) bibles.append((tag_text, short_name, language_code))
return bibles return bibles

View File

@ -46,7 +46,7 @@ class EasySlidesImport(SongImport):
def do_import(self): def do_import(self):
log.info('Importing EasySlides XML file {source}'.format(source=self.import_source)) log.info('Importing EasySlides XML file {source}'.format(source=self.import_source))
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True, recover=True)
parsed_file = etree.parse(self.import_source, parser) parsed_file = etree.parse(self.import_source, parser)
xml = etree.tostring(parsed_file).decode() xml = etree.tostring(parsed_file).decode()
song_xml = objectify.fromstring(xml) song_xml = objectify.fromstring(xml)

View File

@ -73,6 +73,14 @@ class VideoPsalmImport(SongImport):
processed_content += c processed_content += c
c = next(file_content_it) c = next(file_content_it)
processed_content += '"' + c processed_content += '"' + c
# Remove control characters
elif (c < chr(32)):
processed_content += ' '
# Handle escaped characters
elif c == '\\':
processed_content += c
c = next(file_content_it)
processed_content += c
else: else:
processed_content += c processed_content += c
songbook = json.loads(processed_content.strip()) songbook = json.loads(processed_content.strip())

View File

@ -458,7 +458,7 @@ class OpenLyrics(object):
self._add_tag_to_formatting(tag, tags_element) self._add_tag_to_formatting(tag, tags_element)
# Replace end tags. # Replace end tags.
for tag in end_tags: for tag in end_tags:
text = text.replace('{/{tag}}}'.format(tag=tag), '</tag>') text = text.replace('{{{tag}}}'.format(tag=tag), '</tag>')
# Replace \n with <br/>. # Replace \n with <br/>.
text = text.replace('\n', '<br/>') text = text.replace('\n', '<br/>')
element = etree.XML('<lines>{text}</lines>'.format(text=text)) element = etree.XML('<lines>{text}</lines>'.format(text=text))
@ -643,7 +643,7 @@ class OpenLyrics(object):
# Append text from tail and add formatting end tag. # Append text from tail and add formatting end tag.
# TODO: Verify format() with template variables # TODO: Verify format() with template variables
if element.tag == NSMAP % 'tag' and use_endtag: if element.tag == NSMAP % 'tag' and use_endtag:
text += '{/{name}}}'.format(name=element.get('name')) text += '{{{name}}}'.format(name=element.get('name'))
# Append text from tail. # Append text from tail.
if element.tail: if element.tail:
text += element.tail text += element.tail

View File

@ -63,9 +63,10 @@ class OpenLPJobs(object):
Branch_Windows_Interface = 'Branch-04b-Windows_Interface_Tests' Branch_Windows_Interface = 'Branch-04b-Windows_Interface_Tests'
Branch_PEP = 'Branch-05a-Code_Analysis' Branch_PEP = 'Branch-05a-Code_Analysis'
Branch_Coverage = 'Branch-05b-Test_Coverage' Branch_Coverage = 'Branch-05b-Test_Coverage'
Branch_Pylint = 'Branch-05c-Code_Analysis2'
Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows_Functional, Branch_Windows_Interface, Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows_Functional, Branch_Windows_Interface,
Branch_PEP, Branch_Coverage] Branch_PEP, Branch_Coverage, Branch_Pylint]
class Colour(object): class Colour(object):

View File

@ -22,43 +22,82 @@
""" """
Package to test the openlp.core.lib.theme package. Package to test the openlp.core.lib.theme package.
""" """
from tests.functional import MagicMock, patch
from unittest import TestCase from unittest import TestCase
import os
from openlp.core.lib.theme import ThemeXML from openlp.core.lib.theme import ThemeXML
class TestTheme(TestCase): class TestThemeXML(TestCase):
""" """
Test the functions in the Theme module Test the ThemeXML class
""" """
def setUp(self):
"""
Create the UI
"""
pass
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
pass
def test_new_theme(self): def test_new_theme(self):
""" """
Test the theme creation - basic test Test the ThemeXML constructor
""" """
# GIVEN: A new theme # GIVEN: The ThemeXML class
# WHEN: A theme object is created
# WHEN: A theme is created
default_theme = ThemeXML() default_theme = ThemeXML()
# THEN: We should get some default behaviours # THEN: The default values should be correct
self.assertTrue(default_theme.background_border_color == '#000000', 'The theme should have a black border') self.assertEqual('#000000', default_theme.background_border_color,
self.assertTrue(default_theme.background_type == 'solid', 'The theme should have a solid backgrounds') 'background_border_color should be "#000000"')
self.assertTrue(default_theme.display_vertical_align == 0, self.assertEqual('solid', default_theme.background_type, 'background_type should be "solid"')
'The theme should have a display_vertical_align of 0') self.assertEqual(0, default_theme.display_vertical_align, 'display_vertical_align should be 0')
self.assertTrue(default_theme.font_footer_name == "Arial", self.assertEqual('Arial', default_theme.font_footer_name, 'font_footer_name should be "Arial"')
'The theme should have a font_footer_name of Arial') self.assertFalse(default_theme.font_main_bold, 'font_main_bold should be False')
self.assertTrue(default_theme.font_main_bold is False, 'The theme should have a font_main_bold of false') self.assertEqual(47, len(default_theme.__dict__), 'The theme should have 47 attributes')
self.assertTrue(len(default_theme.__dict__) == 47, 'The theme should have 47 variables')
def test_expand_json(self):
"""
Test the expand_json method
"""
# GIVEN: A ThemeXML object and some JSON to "expand"
theme = ThemeXML()
theme_json = {
'background': {
'border_color': '#000000',
'type': 'solid'
},
'display': {
'vertical_align': 0
},
'font': {
'footer': {
'bold': False
},
'main': {
'name': 'Arial'
}
}
}
# WHEN: ThemeXML.expand_json() is run
theme.expand_json(theme_json)
# THEN: The attributes should be set on the object
self.assertEqual('#000000', theme.background_border_color, 'background_border_color should be "#000000"')
self.assertEqual('solid', theme.background_type, 'background_type should be "solid"')
self.assertEqual(0, theme.display_vertical_align, 'display_vertical_align should be 0')
self.assertFalse(theme.font_footer_bold, 'font_footer_bold should be False')
self.assertEqual('Arial', theme.font_main_name, 'font_main_name should be "Arial"')
def test_extend_image_filename(self):
"""
Test the extend_image_filename method
"""
# GIVEN: A theme object
theme = ThemeXML()
theme.theme_name = 'MyBeautifulTheme '
theme.background_filename = ' video.mp4'
theme.background_type = 'video'
path = os.path.expanduser('~')
# WHEN: ThemeXML.extend_image_filename is run
theme.extend_image_filename(path)
# THEN: The filename of the background should be correct
expected_filename = os.path.join(path, 'MyBeautifulTheme', 'video.mp4')
self.assertEqual(expected_filename, theme.background_filename)
self.assertEqual('MyBeautifulTheme', theme.theme_name)

View File

@ -43,3 +43,5 @@ class TestVideoPsalmFileImport(SongImportTestHelper):
""" """
self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold.json'), self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold.json'),
self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold.json'))) self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold.json')))
self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold2.json'),
self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold2.json')))

View File

@ -50,7 +50,8 @@ class TestBibleHTTP(TestCase):
books = handler.get_books_from_http('NIV') books = handler.get_books_from_http('NIV')
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(books) == 66, 'The bible should not have had any books added or removed' self.assertEqual(len(books), 66, 'The bible should not have had any books added or removed')
self.assertEqual(books[0], 'Genesis', 'The first bible book should be Genesis')
def test_bible_gateway_extract_books_support_redirect(self): def test_bible_gateway_extract_books_support_redirect(self):
""" """
@ -63,7 +64,7 @@ class TestBibleHTTP(TestCase):
books = handler.get_books_from_http('DN1933') books = handler.get_books_from_http('DN1933')
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(books) == 66, 'This bible should have 66 books' self.assertEqual(len(books), 66, 'This bible should have 66 books')
def test_bible_gateway_extract_verse(self): def test_bible_gateway_extract_verse(self):
""" """
@ -76,7 +77,8 @@ class TestBibleHTTP(TestCase):
results = handler.get_bible_chapter('NIV', 'John', 3) results = handler.get_bible_chapter('NIV', 'John', 3)
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' self.assertEqual(len(results.verse_list), 36,
'The book of John should not have had any verses added or removed')
def test_bible_gateway_extract_verse_nkjv(self): def test_bible_gateway_extract_verse_nkjv(self):
""" """
@ -89,7 +91,8 @@ class TestBibleHTTP(TestCase):
results = handler.get_bible_chapter('NKJV', 'John', 3) results = handler.get_bible_chapter('NKJV', 'John', 3)
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' self.assertEqual(len(results.verse_list), 36,
'The book of John should not have had any verses added or removed')
def test_crosswalk_extract_books(self): def test_crosswalk_extract_books(self):
""" """
@ -102,7 +105,7 @@ class TestBibleHTTP(TestCase):
books = handler.get_books_from_http('niv') books = handler.get_books_from_http('niv')
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(books) == 66, 'The bible should not have had any books added or removed' self.assertEqual(len(books), 66, 'The bible should not have had any books added or removed')
def test_crosswalk_extract_verse(self): def test_crosswalk_extract_verse(self):
""" """
@ -115,7 +118,8 @@ class TestBibleHTTP(TestCase):
results = handler.get_bible_chapter('niv', 'john', 3) results = handler.get_bible_chapter('niv', 'john', 3)
# THEN: We should get back a valid service item # THEN: We should get back a valid service item
assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' self.assertEqual(len(results.verse_list), 36,
'The book of John should not have had any verses added or removed')
def test_bibleserver_get_bibles(self): def test_bibleserver_get_bibles(self):
""" """
@ -144,9 +148,8 @@ class TestBibleHTTP(TestCase):
# THEN: The list should not be None, and some known bibles should be there # THEN: The list should not be None, and some known bibles should be there
self.assertIsNotNone(bibles) self.assertIsNotNone(bibles)
self.assertIn(('Holman Christian Standard Bible', 'HCSB', 'en'), bibles) self.assertIn(('Holman Christian Standard Bible (HCSB)', 'HCSB', 'en'), bibles)
@skip("Waiting for Crosswalk to fix their server")
def test_crosswalk_get_bibles(self): def test_crosswalk_get_bibles(self):
""" """
Test getting list of bibles from Crosswalk.com Test getting list of bibles from Crosswalk.com

View File

@ -0,0 +1,35 @@
{
"authors": [
["Martin Luther", "words"],
["Unknown", "music"]
],
"ccli_number": "12345",
"comments": "This is\nthe first comment\nThis is\nthe second comment\nThis is\nthe third comment\n",
"copyright": "Public Domain",
"song_book_name": "SongBook1",
"song_number": 0,
"title": "A Safe Stronghold Our God is Still",
"topics": [
"tema1",
"tema2"
],
"verse_order_list": [],
"verses": [
[
"As safe a stronghold our God is still,\nA trusty shield and weapon;\nHell help us clear from all the ill\nThat hath us now oertaken.\nThe ancient prince of hell\nHath risen with purpose fell;\nStrong mail of craft and power\nHe weareth in this hour;\nOn earth is not His fellow.",
"v"
],
[
"With \"force\" of arms we nothing can,\nFull soon were we down-ridden;\nBut for us fights \\ the proper Man,\nWhom God Himself hath bidden.\nAsk ye: Who is this same?\nChrist Jesus is His name,\nThe Lord Sabaoths Son;\nHe, and no other one,\nShall conquer in the battle.",
"v"
],
[
"And were this world all devils oer,\nAnd watching to devour us,\nWe lay it not to heart so sore;\nNot they can overpower us.\nAnd let the prince of ill\nLook grim as eer he will,\nHe harms us not a whit;\nFor why? his doom is writ;\nA word shall quickly slay him.",
"v"
],
[
"Gods word, for all their craft and force,\nOne moment will not linger,\nBut, spite of hell, shall have its course;\nTis written by His finger.\nAnd though they take our life,\nGoods, honour, children, wife,\nYet is their profit small:\nThese things shall vanish all;\nThe city of God remaineth.",
"v"
]
]
}

View File

@ -0,0 +1,47 @@
{Abbreviation:"SB1",Copyright:"Public domain",Songs:[{ID:3,Composer:"Unknown",Author:"Martin Luther",Copyright:"Public
Domain",Theme:"tema1
tema2",CCLI:"12345",Alias:"A safe stronghold",Memo1:"This is
the first comment
",Memo2:"This is
the second comment
",Memo3:"This is
the third comment
",Reference:"reference",Guid:"jtCkrJdPIUOmECjaQylg/g",Verses:[{
Text:"As safe a stronghold our God is still,
A trusty shield and weapon;
Hell help us clear from all the ill
That hath us now oertaken.
The ancient prince of hell
Hath risen with purpose fell;
Strong mail of craft and power
He weareth in this hour;
On earth is not His fellow."},{ID:2,
Text:"With \"force\" of arms we nothing can,
Full soon were we down-ridden;
But for us fights \\ the proper Man,
Whom God Himself hath bidden.
Ask ye: Who is this same?
Christ Jesus is His name,
The Lord Sabaoths Son;
He, and no other one,
Shall conquer in the battle."},{ID:3,
Text:"And were this world all devils oer,
And watching to devour us,
We lay it not to heart so sore;
Not they can overpower us.
And let the prince of ill
Look grim as eer he will,
He harms us not a whit;
For why? his doom is writ;
A word shall quickly slay him."},{ID:4,
Text:"Gods word, for all their craft and force,
One moment will not linger,
But, spite of hell, shall have its course;
Tis written by His finger.
And though they take our life,
Goods, honour, children, wife,
Yet is their profit small:
These things shall vanish all;
The city of God remaineth."}],AudioFile:"282.mp3",IsAudioFileEnabled:1,
Text:"A Safe Stronghold Our God is Still"}],Guid:"khiHU2blX0Kb41dGdbDLhA",VersionDate:"20121012000000",
Text:"SongBook1"}

View File

@ -23,8 +23,8 @@
Package to test for proper bzr tags. Package to test for proper bzr tags.
""" """
import os import os
import logging
import platform import platform
import sys
from unittest import TestCase, SkipTest from unittest import TestCase, SkipTest
try: try:
@ -46,9 +46,18 @@ class TestPylint(TestCase):
""" """
Test for pylint errors Test for pylint errors
""" """
# Test if this file is specified in the arguments, if not skip the test.
in_argv = False
for arg in sys.argv:
if arg.endswith('test_pylint.py') or arg.endswith('test_pylint'):
in_argv = True
break
if not in_argv:
raise SkipTest('test_pylint.py not specified in arguments - skipping tests using pylint.')
# GIVEN: Some checks to disable and enable, and the pylint script # GIVEN: Some checks to disable and enable, and the pylint script
disabled_checks = 'import-error,no-member' disabled_checks = 'import-error,no-member'
enabled_checks = 'missing-format-argument-key,unused-format-string-argument' enabled_checks = 'missing-format-argument-key,unused-format-string-argument,bad-format-string'
if is_win() or 'arch' in platform.dist()[0].lower(): if is_win() or 'arch' in platform.dist()[0].lower():
pylint_script = 'pylint' pylint_script = 'pylint'
else: else:
@ -84,6 +93,9 @@ class TestPylint(TestCase):
# Filter out PyQt related errors # Filter out PyQt related errors
elif ('no-name-in-module' in line or 'no-member' in line) and 'PyQt5' in line: elif ('no-name-in-module' in line or 'no-member' in line) and 'PyQt5' in line:
continue continue
# Filter out distutils related errors
elif 'distutils' in line:
continue
elif self._is_line_tolerated(line): elif self._is_line_tolerated(line):
continue continue
else: else: