Skip to content

Commit

Permalink
implement validate_language_marker and validate_language_marker_psalm…
Browse files Browse the repository at this point in the history
… - part of #61
  • Loading branch information
bensteUEM committed Jun 1, 2024
1 parent f55b0a8 commit 2615826
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 13 deletions.
83 changes: 76 additions & 7 deletions SngFileLanguagePart.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""This file is used to define SngFile class and somee helper methods related to it's usage."""

import abc
import itertools
import logging

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -153,15 +154,83 @@ def validate_header_language_count(self, fix: bool = False) -> bool:
def validate_language_marker(self, fix: bool = False) -> bool:
"""Validate the language markers used in content.
checks that the number of langauges in content matches the configuration from header
Args:
fix: attempt to fix language marker usage Defaults to False.
fix: attempt to fix language marker usage. Defaults to False.
* in case there are no language markers and the expected number is greater ##1 and ##2 will be added alternatly
* in case some lines do have language markers and others don't the former will apply, skipping lines that already have a language marker
* this method MUSTN'T be applied on Psalms because they can have different language orders blocks longer than one line
Returns:
if language markers match LangCount header
"""
if fix:
pass
# TODO@benste: Implement
# https://github.com/bensteUEM/SongBeamerQS/issues/61
not_implemented_link = "https://github.com/bensteUEM/SongBeamerQS/issues/61"
raise NotImplementedError(not_implemented_link)
if self.is_psalm():
return self.validate_language_marker_psalm(fix=fix)

languages_expected = int(self.header["LangCount"])

# if only single language
if len(self.get_content_unique_lang_markers()) == 1 == languages_expected:
return True

language_markers_expected = [f"##{i+1} " for i in range(languages_expected)]
valid = True
for block in self.content.values():
for slide in block[1:]:
valid &= self.validate_language_marker_slide(
slide, language_markers_expected=language_markers_expected, fix=fix
)
return valid

def validate_language_marker_slide(
self, slide: list[str], language_markers_expected: list, fix: bool = False
) -> bool:
"""More complex cases of validate_language_marker.
Args:
slide: the slide (list of lines) to check
language_markers_expected: prepared language markers that should be used
fix: attempt to fix language marker usage. Defaults to False.
Returns:
if language markers match LangCount header
"""
# reset iterator for each slide
language_markers_iterator = itertools.cycle(language_markers_expected)
for index, line in enumerate(slide):
# skip lines with existing language marker
if line.startswith("##"):
continue
# add next language marker from iterator
if fix:
slide[index] = next(language_markers_iterator) + line
self.update_editor_because_content_modified()
continue
return False
return True

def validate_language_marker_psalm(self, fix: bool = False) -> bool: # noqa: C901
"""Method used for language_marker validation of psalms.
Auto Fixing is not possible!
Psalms should have 2 or 3 langauges indicated by ##1, ##3 and ##4 but not ##2
Arguments:
fix: if fix should be attempted - impossible for psalm!
Returns:
if language markers are as expected
"""
for block in self.content.values():
for slide in block[1:]:
for line in slide:
if line.startswith(("##1", "##3", "##4")):
continue
if fix:
logger.warning(
"Can't fix '%s' line in (%s) because it's a Psalm",
line,
self.filename,
)
return False

return True
8 changes: 4 additions & 4 deletions testData/EG Psalmen & Sonstiges/709 Herr, sei nicht ferne.sng
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#Version=3
#FontSize=50
#BackgroundImage=Menschen\Verzweiflung-mann-r.jpg
#(c)=K�nig David
#(c)=K�nig David
#Bible=Psalm 22, 2 2-6 12.20
#Songbook=EG 709 - Psalm 22 I
#ChurchSongID=EG 709 - Psalm 22 I
Expand All @@ -21,9 +21,9 @@ Verse
##1 doch antwortest du nicht,
##3 und des Nachts, doch finde ich keine Ruhe.
##1 Du aber bist heilig,
##3 der du thronst �ber den Lobges�ngen Israels.
##3 der du thronst �ber den Lobges�ngen Israels.
---
#1 Unsere V�ter hofften auf dich;
1 Unsere V�ter hofften auf dich;
##3 und da sie hofften, halfst du ihnen heraus.
##1 Zu dir schrien sie und wurden errettet,
##3 sie hofften auf dich
Expand All @@ -34,4 +34,4 @@ Verse
##3 denn es ist hier kein Helfer.
---
##1 Aber du, Herr, sei nicht ferne;
##3 meine St�rke, eile, mir zu helfen!
##3 meine St�rke, eile, mir zu helfen!
23 changes: 22 additions & 1 deletion testData/Test/sample_languages.sng
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,25 @@ Verse 2
##1 2. Eine Zeile mit Sprachmarkierung
##2 2. One line with language marker
##1 deutscher text
##2 english text
##2 english text
---
Verse 3
Lang 1.1
Lang 2.1
##1 Lang 1.2
Lang 1.3
Lang 2.2
---
Verse 4
Lang 1.1
Lang 2.1
##2 Lang 2.2
Lang 1.2
---
Verse 5
##2 Lang 2.1
##2 lang 2.2
##2 lang 2.3
Lang 1.1
Lang 2.4
Lang 1.2
104 changes: 103 additions & 1 deletion tests/test_sng_language.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from pathlib import Path

import pytest
Expand Down Expand Up @@ -66,7 +67,7 @@ def test_get_content(self, filename: Path, languages: list[str] | None) -> None:
(
Path("testData/EG Psalmen & Sonstiges")
/ "709 Herr, sei nicht ferne.sng",
{"##1", "##3"},
{"##1", "##3", None},
None,
),
],
Expand Down Expand Up @@ -164,3 +165,104 @@ def test_validate_header_language_count(
}
result = sample_song.validate_header_language_count(fix=fix)
assert expected_result == result

@pytest.mark.parametrize(
("filename", "verses", "fix", "expected_result"),
[
(Path("testData/Test") / "sample_languages.sng", ["Verse 2"], False, True),
(Path("testData/Test") / "sample_languages.sng", ["Verse 3"], False, False),
(Path("testData/Test") / "sample_languages.sng", ["Verse 4"], True, True),
(Path("testData/Test") / "sample_languages.sng", ["Verse 5"], False, False),
],
)
def test_validate_language_marker(
self, filename: str, verses: list[str] | None, fix: bool, expected_result: bool
) -> None:
"""Checking different params with validate_language_marker.
Args:
filename: the file to use
verses: the verse selection to use as content
fix: if fix attempt should be performed
expected_result: if should be valid after function run
"""
sample_song = SngFile(filename=filename)
sample_song.content = {
key: value for key, value in sample_song.content.items() if key in verses
}
result = sample_song.validate_language_marker(fix=fix)
assert expected_result == result

# check language marker equals Lang x. text in line of verse 3-5
if fix:
for block in sample_song.content.values():
if block[1][2] in [3, 4, 5]:
continue
for slide in block[1:]:
self.helper_language_marker_as_expected(slide=slide)

def helper_language_marker_as_expected(self, slide: list[str]) -> bool:
"""Helper for test_validate_language_marker.
Validates marker matches syntax for all lines
e.g. '##2 Lang 2.1' ma
Args:
slide: one slide with all it's text lines
Returns:
if everything is as expected
"""
for line in slide:
assert line.startswith("##")
text_items = line.split(" ")
marked_language = text_items[0][2:]
expected_language = text_items[2][:1]
assert marked_language == expected_language

@pytest.mark.usefixtures("caplog")
def test_validate_language_marker_psalm(
self, caplog: pytest.LogCaptureFixture
) -> None:
"""Checking psalm cases of validate_language_marker.
Psalms should not be fixable or already valid
complete sample should be invalid because of error
attempt to fix it should log an "unfixable"
looking at first 2 slides of verse only it should be valid
"""
filepath = Path("testData/EG Psalmen & Sonstiges")
filename = "709 Herr, sei nicht ferne.sng"
sample_song = SngFile(filename=filepath / filename, songbook_prefix="EG")
result = sample_song.validate_language_marker_psalm(fix=False)
assert not result

caplog.set_level(logging.INFO)
result = sample_song.validate_language_marker_psalm(fix=True)
assert not result
assert len(caplog.records) > 0

# reduced scope should be valid
sample_song.content["Verse"] = sample_song.content["Verse"][0:2]
result = sample_song.validate_language_marker_psalm(fix=False)
assert result

@pytest.mark.usefixtures("caplog")
def test_validate_langauge_marker_indirect_psalm(
self, caplog: pytest.LogCaptureFixture
) -> None:
"""Checks that running validate_langauge_marker results in psalm specific log message."""
filepath = Path("testData/EG Psalmen & Sonstiges")
filename = "709 Herr, sei nicht ferne.sng"
sample_song = SngFile(filename=filepath / filename, songbook_prefix="EG")

caplog.set_level(logging.INFO)
result = sample_song.validate_language_marker(fix=True)
assert not result

problematic_line = "1 Unsere V�ter hofften auf dich;"
expected_log = "WARNING SngFileLanguagePart:SngFileLanguagePart.py:229 "
f"Can't fix '{problematic_line}' line"
f" in ({sample_song.filename}) because it's a Psalm\n"

assert expected_log in caplog.text

0 comments on commit 2615826

Please sign in to comment.