From 3e1f7569d32f88e058631b538c13df6870ac536c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:02:38 +0000 Subject: [PATCH 1/5] Initial plan From b26e46fabec604d1c8f2f8f97d6bf99d7c4bbc06 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:08:34 +0000 Subject: [PATCH 2/5] Implement TODO filtering for song extraction Co-authored-by: ApsiV11 <47868046+ApsiV11@users.noreply.github.com> --- extract_songs.py | 22 +++++++- test_integration.py | 76 +++++++++++++++++++++++++++ test_todo_filter.py | 122 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 test_integration.py create mode 100644 test_todo_filter.py diff --git a/extract_songs.py b/extract_songs.py index a7bf766..e259f3a 100644 --- a/extract_songs.py +++ b/extract_songs.py @@ -685,6 +685,24 @@ def parse_tex(content: Union[str, bytes]) -> List[SongInfo]: WHITELIST = ("",) +def song_contains_todo(song: SongInfo) -> bool: + """Check if a song contains 'TODO' in any of its fields.""" + fields_to_check = [ + song.name, + song.melody, + song.composer, + song.arranger, + song.lyrics, + song.notes + ] + + for field in fields_to_check: + if field and "TODO" in field: + return True + + return False + + def main(): songs = [] failed_files = [] @@ -718,7 +736,9 @@ def main(): # Process each song (main song and subsongs) for song in parsed_songs: if song.name != "Parse Error": - songs.append(asdict(song)) + # Filter out songs that contain TODO in any field + if not song_contains_todo(song): + songs.append(asdict(song)) else: failed_files.append(pa) break # If any song failed, mark the whole file as failed diff --git a/test_integration.py b/test_integration.py new file mode 100644 index 0000000..4e4f70f --- /dev/null +++ b/test_integration.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +"""Integration test for TODO filtering in the main extraction process.""" + +import tempfile +import os +import json +from pathlib import Path + +# Create a temporary directory structure to simulate Fiisut-V/songs/ +def test_main_extraction_with_todo_filtering(): + """Test that the main function properly filters out songs with TODO.""" + + # Create temporary directory structure + with tempfile.TemporaryDirectory() as temp_dir: + songs_dir = Path(temp_dir) / "Fiisut-V" / "songs" + songs_dir.mkdir(parents=True) + + # Create a mock .tex file with a song containing TODO + song_with_todo = songs_dir / "song_with_todo.tex" + song_with_todo.write_text(r""" +\begin{song}{TODO: Add proper title}{Traditional}{}{}{}{}{} +\begin{uverse} +This is a test song with TODO in title +\end{uverse} +\end{song} +""") + + # Create a mock .tex file with a normal song + normal_song = songs_dir / "normal_song.tex" + normal_song.write_text(r""" +\begin{song}{Normal Song}{Traditional}{}{}{}{}{} +\begin{uverse} +This is a normal song without any issues +\end{uverse} +\end{song} +""") + + # Change to the temp directory and run extraction + original_cwd = os.getcwd() + try: + os.chdir(temp_dir) + + # Import and run the main function + import sys + sys.path.insert(0, original_cwd) + from extract_songs import main + + # Run the extraction + main() + + # Check the results + songs_file = Path(temp_dir) / "songs.json" + if songs_file.exists(): + with open(songs_file, 'r', encoding='utf-8') as f: + songs = json.load(f) + + print(f"Total songs extracted: {len(songs)}") + + # Check that songs with TODO were filtered out + song_names = [song['name'] for song in songs] + print(f"Song names: {song_names}") + + # Verify no song has TODO in the name + todo_songs = [song for song in songs if 'TODO' in song.get('name', '')] + assert len(todo_songs) == 0, f"Found songs with TODO that should have been filtered: {todo_songs}" + + print("✓ TODO filtering test passed!") + else: + print("No songs.json file was created") + + finally: + os.chdir(original_cwd) + + +if __name__ == "__main__": + test_main_extraction_with_todo_filtering() \ No newline at end of file diff --git a/test_todo_filter.py b/test_todo_filter.py new file mode 100644 index 0000000..3ed3a8b --- /dev/null +++ b/test_todo_filter.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +"""Test TODO filtering functionality.""" + +import pytest +from extract_songs import SongInfo, song_contains_todo + + +def test_song_contains_todo_in_name(): + """Test that songs with TODO in name are detected.""" + song = SongInfo( + name="TODO: Add lyrics", + melody=None, + composer=None, + arranger=None, + lyrics="Some lyrics", + notes=None + ) + assert song_contains_todo(song) is True + + +def test_song_contains_todo_in_lyrics(): + """Test that songs with TODO in lyrics are detected.""" + song = SongInfo( + name="Test Song", + melody=None, + composer=None, + arranger=None, + lyrics="First verse\nTODO: Write second verse", + notes=None + ) + assert song_contains_todo(song) is True + + +def test_song_contains_todo_in_melody(): + """Test that songs with TODO in melody are detected.""" + song = SongInfo( + name="Test Song", + melody="TODO: Add melody", + composer=None, + arranger=None, + lyrics="Some lyrics", + notes=None + ) + assert song_contains_todo(song) is True + + +def test_song_contains_todo_in_composer(): + """Test that songs with TODO in composer are detected.""" + song = SongInfo( + name="Test Song", + melody=None, + composer="TODO: Find composer", + arranger=None, + lyrics="Some lyrics", + notes=None + ) + assert song_contains_todo(song) is True + + +def test_song_contains_todo_in_arranger(): + """Test that songs with TODO in arranger are detected.""" + song = SongInfo( + name="Test Song", + melody=None, + composer=None, + arranger="TODO: Credit arranger", + lyrics="Some lyrics", + notes=None + ) + assert song_contains_todo(song) is True + + +def test_song_contains_todo_in_notes(): + """Test that songs with TODO in notes are detected.""" + song = SongInfo( + name="Test Song", + melody=None, + composer=None, + arranger=None, + lyrics="Some lyrics", + notes="TODO: Add historical context" + ) + assert song_contains_todo(song) is True + + +def test_song_without_todo(): + """Test that songs without TODO are not filtered.""" + song = SongInfo( + name="Test Song", + melody="Traditional", + composer="John Doe", + arranger="Jane Smith", + lyrics="Verse 1\nVerse 2\nChorus", + notes="Written in 1950" + ) + assert song_contains_todo(song) is False + + +def test_song_with_none_fields(): + """Test that songs with None fields don't cause errors.""" + song = SongInfo( + name="Test Song", + melody=None, + composer=None, + arranger=None, + lyrics="Some lyrics", + notes=None + ) + assert song_contains_todo(song) is False + + +def test_case_sensitive_todo(): + """Test that TODO detection is case-sensitive.""" + song = SongInfo( + name="Test Song", + melody=None, + composer=None, + arranger=None, + lyrics="This has todo in lowercase", + notes=None + ) + assert song_contains_todo(song) is False \ No newline at end of file From d49b8100b9a800b2011deeb17dee80a76f543907 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:09:39 +0000 Subject: [PATCH 3/5] Clean up temporary test files and finalize implementation Co-authored-by: ApsiV11 <47868046+ApsiV11@users.noreply.github.com> --- test_integration.py | 76 --------------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 test_integration.py diff --git a/test_integration.py b/test_integration.py deleted file mode 100644 index 4e4f70f..0000000 --- a/test_integration.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 -"""Integration test for TODO filtering in the main extraction process.""" - -import tempfile -import os -import json -from pathlib import Path - -# Create a temporary directory structure to simulate Fiisut-V/songs/ -def test_main_extraction_with_todo_filtering(): - """Test that the main function properly filters out songs with TODO.""" - - # Create temporary directory structure - with tempfile.TemporaryDirectory() as temp_dir: - songs_dir = Path(temp_dir) / "Fiisut-V" / "songs" - songs_dir.mkdir(parents=True) - - # Create a mock .tex file with a song containing TODO - song_with_todo = songs_dir / "song_with_todo.tex" - song_with_todo.write_text(r""" -\begin{song}{TODO: Add proper title}{Traditional}{}{}{}{}{} -\begin{uverse} -This is a test song with TODO in title -\end{uverse} -\end{song} -""") - - # Create a mock .tex file with a normal song - normal_song = songs_dir / "normal_song.tex" - normal_song.write_text(r""" -\begin{song}{Normal Song}{Traditional}{}{}{}{}{} -\begin{uverse} -This is a normal song without any issues -\end{uverse} -\end{song} -""") - - # Change to the temp directory and run extraction - original_cwd = os.getcwd() - try: - os.chdir(temp_dir) - - # Import and run the main function - import sys - sys.path.insert(0, original_cwd) - from extract_songs import main - - # Run the extraction - main() - - # Check the results - songs_file = Path(temp_dir) / "songs.json" - if songs_file.exists(): - with open(songs_file, 'r', encoding='utf-8') as f: - songs = json.load(f) - - print(f"Total songs extracted: {len(songs)}") - - # Check that songs with TODO were filtered out - song_names = [song['name'] for song in songs] - print(f"Song names: {song_names}") - - # Verify no song has TODO in the name - todo_songs = [song for song in songs if 'TODO' in song.get('name', '')] - assert len(todo_songs) == 0, f"Found songs with TODO that should have been filtered: {todo_songs}" - - print("✓ TODO filtering test passed!") - else: - print("No songs.json file was created") - - finally: - os.chdir(original_cwd) - - -if __name__ == "__main__": - test_main_extraction_with_todo_filtering() \ No newline at end of file From a7df5cee738889403251cbc8d535d81745af40dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:12:51 +0000 Subject: [PATCH 4/5] Remove test_todo_filter.py as requested Co-authored-by: ApsiV11 <47868046+ApsiV11@users.noreply.github.com> --- test_todo_filter.py | 122 -------------------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 test_todo_filter.py diff --git a/test_todo_filter.py b/test_todo_filter.py deleted file mode 100644 index 3ed3a8b..0000000 --- a/test_todo_filter.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -"""Test TODO filtering functionality.""" - -import pytest -from extract_songs import SongInfo, song_contains_todo - - -def test_song_contains_todo_in_name(): - """Test that songs with TODO in name are detected.""" - song = SongInfo( - name="TODO: Add lyrics", - melody=None, - composer=None, - arranger=None, - lyrics="Some lyrics", - notes=None - ) - assert song_contains_todo(song) is True - - -def test_song_contains_todo_in_lyrics(): - """Test that songs with TODO in lyrics are detected.""" - song = SongInfo( - name="Test Song", - melody=None, - composer=None, - arranger=None, - lyrics="First verse\nTODO: Write second verse", - notes=None - ) - assert song_contains_todo(song) is True - - -def test_song_contains_todo_in_melody(): - """Test that songs with TODO in melody are detected.""" - song = SongInfo( - name="Test Song", - melody="TODO: Add melody", - composer=None, - arranger=None, - lyrics="Some lyrics", - notes=None - ) - assert song_contains_todo(song) is True - - -def test_song_contains_todo_in_composer(): - """Test that songs with TODO in composer are detected.""" - song = SongInfo( - name="Test Song", - melody=None, - composer="TODO: Find composer", - arranger=None, - lyrics="Some lyrics", - notes=None - ) - assert song_contains_todo(song) is True - - -def test_song_contains_todo_in_arranger(): - """Test that songs with TODO in arranger are detected.""" - song = SongInfo( - name="Test Song", - melody=None, - composer=None, - arranger="TODO: Credit arranger", - lyrics="Some lyrics", - notes=None - ) - assert song_contains_todo(song) is True - - -def test_song_contains_todo_in_notes(): - """Test that songs with TODO in notes are detected.""" - song = SongInfo( - name="Test Song", - melody=None, - composer=None, - arranger=None, - lyrics="Some lyrics", - notes="TODO: Add historical context" - ) - assert song_contains_todo(song) is True - - -def test_song_without_todo(): - """Test that songs without TODO are not filtered.""" - song = SongInfo( - name="Test Song", - melody="Traditional", - composer="John Doe", - arranger="Jane Smith", - lyrics="Verse 1\nVerse 2\nChorus", - notes="Written in 1950" - ) - assert song_contains_todo(song) is False - - -def test_song_with_none_fields(): - """Test that songs with None fields don't cause errors.""" - song = SongInfo( - name="Test Song", - melody=None, - composer=None, - arranger=None, - lyrics="Some lyrics", - notes=None - ) - assert song_contains_todo(song) is False - - -def test_case_sensitive_todo(): - """Test that TODO detection is case-sensitive.""" - song = SongInfo( - name="Test Song", - melody=None, - composer=None, - arranger=None, - lyrics="This has todo in lowercase", - notes=None - ) - assert song_contains_todo(song) is False \ No newline at end of file From 415c94a5f436d5d3284ce85c7b1ad839a462d771 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:22:18 +0000 Subject: [PATCH 5/5] Fix formatting issues by consolidating imports and running Black formatter Co-authored-by: ApsiV11 <47868046+ApsiV11@users.noreply.github.com> --- extract_songs.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/extract_songs.py b/extract_songs.py index e259f3a..c59dace 100644 --- a/extract_songs.py +++ b/extract_songs.py @@ -2,6 +2,11 @@ from typing import Optional, Union, List from TexSoup import TexSoup import re +import json +import os +from glob import glob +from dataclasses import dataclass, asdict +from tqdm import tqdm from TexSoup.data import TexNamedEnv, BraceGroup, TexCmd, TexMathModeEnv, TexNode @@ -543,9 +548,6 @@ def _extract_notes_from_content(nodes): return notes -from dataclasses import dataclass - - @dataclass class SongInfo: name: str @@ -675,12 +677,6 @@ def parse_tex(content: Union[str, bytes]) -> List[SongInfo]: ] -from glob import glob -from dataclasses import asdict -import json -from tqdm import tqdm -import os - # WHITELIST = ("eino", "") WHITELIST = ("",) @@ -693,13 +689,13 @@ def song_contains_todo(song: SongInfo) -> bool: song.composer, song.arranger, song.lyrics, - song.notes + song.notes, ] - + for field in fields_to_check: if field and "TODO" in field: return True - + return False