diff --git a/create_deck.py b/create_deck.py index 3c9e5d4..42e9522 100644 --- a/create_deck.py +++ b/create_deck.py @@ -38,7 +38,7 @@ decks = [] if len(data) == 0: - sys.exit(1) + raise ValueError("No cards were generated. The page may be empty or contain no supported toggle lists.") # Model / Template stuff mt = data[0].get("settings", {}) diff --git a/helpers/cards.py b/helpers/cards.py index 248ee3e..58300c0 100644 --- a/helpers/cards.py +++ b/helpers/cards.py @@ -1,6 +1,7 @@ """ Helper functions for working with the flashcards """ +import sys import ftfy @@ -14,12 +15,12 @@ def get_safe_value(value): try: value = value.decode('utf-8') # Decode bytes to string, handling potential errors except UnicodeDecodeError: - print("Warning: Could not decode bytes using utf-8. Returning empty string.") + print("Warning: Could not decode bytes using utf-8. Returning empty string.", file=sys.stderr) return "" elif value is None: return "" elif not isinstance(value, str): - print(f"Warning: get_safe_value received unexpected input type: {type(value)}. Returning empty string.") + print(f"Warning: get_safe_value received unexpected input type: {type(value)}. Returning empty string.", file=sys.stderr) return "" return ftfy.fixes.fix_surrogates(value) diff --git a/helpers/write_apkg.py b/helpers/write_apkg.py index 8c9fb3a..e85dc1d 100644 --- a/helpers/write_apkg.py +++ b/helpers/write_apkg.py @@ -69,7 +69,7 @@ def write_package_to_temp_file(package): try: package.write_to_file(temp_path) except Exception as e: - print(f"Error writing to temporary file: {e}") + print(f"Error writing to temporary file: {e}", file=sys.stderr) raise return temp_path @@ -146,7 +146,11 @@ def _write_new_apkg(deck_payloads, media_files): """ decks, first_deck_id = create_decks(deck_payloads) package = Package(decks) - package.media_files = media_files + existing_media = [f for f in media_files if os.path.exists(f)] + if len(existing_media) < len(media_files): + missing = set(media_files) - set(existing_media) + print(f"Skipping {len(missing)} missing media file(s): {missing}", file=sys.stderr) + package.media_files = existing_media sanitized_name = sanitize_filename(deck_payloads[0]["name"]) if deck_payloads else "default" temp_path = write_package_to_temp_file(package) diff --git a/tests/test_write_apkg.py b/tests/test_write_apkg.py index c7915f7..c8d3074 100644 --- a/tests/test_write_apkg.py +++ b/tests/test_write_apkg.py @@ -96,12 +96,17 @@ def test_write_new_apkg_with_media(self, mock_replace, mock_package): "desc": "Test Description", "notes": [note] } - media_files = ['test.jpg', 'audio.mp3'] - + with tempfile.TemporaryDirectory() as tmpdir: + img_path = os.path.join(tmpdir, 'test.jpg') + audio_path = os.path.join(tmpdir, 'audio.mp3') + open(img_path, 'w').close() + open(audio_path, 'w').close() + media_files = [img_path, audio_path] + with mock.patch('os.getcwd', return_value=tmpdir): _write_new_apkg([deck_payload], media_files) - + mock_package.assert_called_once() package_instance = mock_package.return_value self.assertEqual(package_instance.media_files, media_files) @@ -110,6 +115,28 @@ def test_write_new_apkg_with_media(self, mock_replace, mock_package): mock_package.return_value.write_to_file.assert_called_once() mock_replace.assert_called_once() + @mock.patch('helpers.write_apkg.Package') + @mock.patch('helpers.write_apkg.os.replace') + def test_write_new_apkg_skips_missing_media(self, mock_replace, mock_package): + note = Note(model=self.test_model, fields=['Q1', 'A1']) + deck_payload = { + "id": 1234567890, + "name": "Test Deck", + "desc": "Test Description", + "notes": [note] + } + + with tempfile.TemporaryDirectory() as tmpdir: + existing_path = os.path.join(tmpdir, 'exists.jpg') + open(existing_path, 'w').close() + media_files = [existing_path, 'image.png'] + + with mock.patch('os.getcwd', return_value=tmpdir): + _write_new_apkg([deck_payload], media_files) + + package_instance = mock_package.return_value + self.assertEqual(package_instance.media_files, [existing_path]) + @mock.patch('helpers.write_apkg.Package') @mock.patch('helpers.write_apkg.os.replace') def test_write_new_apkg_empty_deck_list(self, mock_replace, mock_package):