audiometa-python 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- audiometa/__init__.py +1297 -0
- audiometa/__main__.py +6 -0
- audiometa/_audio_file.py +607 -0
- audiometa/cli.py +476 -0
- audiometa/exceptions.py +167 -0
- audiometa/manager/_MetadataManager.py +768 -0
- audiometa/manager/__init__.py +1 -0
- audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +250 -0
- audiometa/manager/_rating_supporting/__init__.py +1 -0
- audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +1032 -0
- audiometa/manager/_rating_supporting/id3v2/__init__.py +25 -0
- audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +11 -0
- audiometa/manager/_rating_supporting/riff/_RiffManager.py +1002 -0
- audiometa/manager/_rating_supporting/riff/__init__.py +25 -0
- audiometa/manager/_rating_supporting/riff/_riff_constants.py +17 -0
- audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +542 -0
- audiometa/manager/_rating_supporting/vorbis/__init__.py +17 -0
- audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +6 -0
- audiometa/manager/id3v1/_Id3v1Manager.py +512 -0
- audiometa/manager/id3v1/__init__.py +1 -0
- audiometa/manager/id3v1/_constants.py +8 -0
- audiometa/manager/id3v1/id3v1_raw_metadata.py +242 -0
- audiometa/manager/id3v1/id3v1_raw_metadata_key.py +13 -0
- audiometa/test/__init__.py +1 -0
- audiometa/test/assets/create_test_files.py +72 -0
- audiometa/test/helpers/__init__.py +51 -0
- audiometa/test/helpers/common/__init__.py +6 -0
- audiometa/test/helpers/common/audio_file_creator.py +68 -0
- audiometa/test/helpers/common/external_tool_runner.py +74 -0
- audiometa/test/helpers/id3v1/__init__.py +8 -0
- audiometa/test/helpers/id3v1/id3v1_header_verifier.py +18 -0
- audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +37 -0
- audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +61 -0
- audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +82 -0
- audiometa/test/helpers/id3v2/__init__.py +28 -0
- audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +349 -0
- audiometa/test/helpers/id3v2/id3v2_header_verifier.py +38 -0
- audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +56 -0
- audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +189 -0
- audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +506 -0
- audiometa/test/helpers/riff/__init__.py +8 -0
- audiometa/test/helpers/riff/riff_header_verifier.py +85 -0
- audiometa/test/helpers/riff/riff_manual_metadata_creator.py +298 -0
- audiometa/test/helpers/riff/riff_metadata_deleter.py +56 -0
- audiometa/test/helpers/riff/riff_metadata_getter.py +219 -0
- audiometa/test/helpers/riff/riff_metadata_setter.py +374 -0
- audiometa/test/helpers/scripts/__init__.py +0 -0
- audiometa/test/helpers/technical_info_inspector.py +115 -0
- audiometa/test/helpers/temp_file_with_metadata.py +82 -0
- audiometa/test/helpers/vorbis/__init__.py +8 -0
- audiometa/test/helpers/vorbis/vorbis_header_verifier.py +31 -0
- audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +49 -0
- audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +67 -0
- audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +221 -0
- audiometa/test/tests/__init__.py +0 -0
- audiometa/test/tests/conftest.py +276 -0
- audiometa/test/tests/e2e/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/error_handling/__init__.py +1 -0
- audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +77 -0
- audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +130 -0
- audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +118 -0
- audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +172 -0
- audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +49 -0
- audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +160 -0
- audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +90 -0
- audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +51 -0
- audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/read/test_basic.py +58 -0
- audiometa/test/tests/e2e/cli/read/test_comprehensive.py +240 -0
- audiometa/test/tests/e2e/cli/read/test_formats.py +55 -0
- audiometa/test/tests/e2e/cli/read/test_metadata_content.py +164 -0
- audiometa/test/tests/e2e/cli/read/test_multiple_files.py +149 -0
- audiometa/test/tests/e2e/cli/read/test_options.py +88 -0
- audiometa/test/tests/e2e/cli/read/test_unified.py +84 -0
- audiometa/test/tests/e2e/cli/test_delete.py +20 -0
- audiometa/test/tests/e2e/cli/test_formatting.py +31 -0
- audiometa/test/tests/e2e/cli/test_help.py +41 -0
- audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/write/test_basic.py +51 -0
- audiometa/test/tests/e2e/cli/write/test_comprehensive.py +210 -0
- audiometa/test/tests/e2e/cli/write/test_force_format.py +336 -0
- audiometa/test/tests/e2e/cli/write/test_integer_fields.py +145 -0
- audiometa/test/tests/e2e/cli/write/test_list_fields.py +107 -0
- audiometa/test/tests/e2e/cli/write/test_rating.py +74 -0
- audiometa/test/tests/e2e/cli/write/test_string_fields.py +54 -0
- audiometa/test/tests/e2e/cli/write/test_validation.py +85 -0
- audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
- audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +166 -0
- audiometa/test/tests/e2e/workflows/__init__.py +0 -0
- audiometa/test/tests/e2e/workflows/test_core_workflows.py +166 -0
- audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +318 -0
- audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +165 -0
- audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +129 -0
- audiometa/test/tests/e2e/workflows/test_rating_workflows.py +124 -0
- audiometa/test/tests/integration/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +108 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +61 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +65 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +69 -0
- audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +79 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +61 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +67 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +60 -0
- audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +87 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +62 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +57 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_with_id3v2_tags.py +83 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +62 -0
- audiometa/test/tests/integration/conftest.py +29 -0
- audiometa/test/tests/integration/delete_all_metadata/__init__.py +1 -0
- audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +102 -0
- audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +77 -0
- audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +47 -0
- audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +24 -0
- audiometa/test/tests/integration/encoding/__init__.py +1 -0
- audiometa/test/tests/integration/encoding/test_encoding.py +88 -0
- audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +223 -0
- audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
- audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +122 -0
- audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +250 -0
- audiometa/test/tests/integration/get_full_metadata/test_consistency.py +67 -0
- audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +123 -0
- audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +40 -0
- audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +43 -0
- audiometa/test/tests/integration/get_full_metadata/test_options.py +207 -0
- audiometa/test/tests/integration/get_full_metadata/test_performance.py +95 -0
- audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +128 -0
- audiometa/test/tests/integration/get_full_metadata/test_structure.py +161 -0
- audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/album/test_deleting.py +73 -0
- audiometa/test/tests/integration/metadata_field/album/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/album/test_writing.py +50 -0
- audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +83 -0
- audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +38 -0
- audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +52 -0
- audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +68 -0
- audiometa/test/tests/integration/metadata_field/artists/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/artists/test_writing.py +46 -0
- audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +75 -0
- audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +32 -0
- audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +56 -0
- audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +68 -0
- audiometa/test/tests/integration/metadata_field/comment/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/comment/test_writing.py +49 -0
- audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +75 -0
- audiometa/test/tests/integration/metadata_field/composer/test_reading.py +34 -0
- audiometa/test/tests/integration/metadata_field/composer/test_writing.py +41 -0
- audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +81 -0
- audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +35 -0
- audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +41 -0
- audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +97 -0
- audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +92 -0
- audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +153 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +56 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +54 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +61 -0
- audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +65 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +25 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +58 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +61 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +191 -0
- audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +62 -0
- audiometa/test/tests/integration/metadata_field/genre/test_writing.py +64 -0
- audiometa/test/tests/integration/metadata_field/isrc/__init__.py +1 -0
- audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +31 -0
- audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +35 -0
- audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +165 -0
- audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/language/test_deleting.py +75 -0
- audiometa/test/tests/integration/metadata_field/language/test_reading.py +39 -0
- audiometa/test/tests/integration/metadata_field/language/test_writing.py +43 -0
- audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +129 -0
- audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +57 -0
- audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +59 -0
- audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +88 -0
- audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +32 -0
- audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +47 -0
- audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +81 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +33 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +58 -0
- audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +117 -0
- audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +137 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +77 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +55 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +57 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +192 -0
- audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +74 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +82 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +59 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +49 -0
- audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +135 -0
- audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/title/test_deleting.py +73 -0
- audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +47 -0
- audiometa/test/tests/integration/metadata_field/title/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/title/test_writing.py +64 -0
- audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +43 -0
- audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +32 -0
- audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +59 -0
- audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +73 -0
- audiometa/test/tests/integration/multiple_values/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/reading/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +23 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +92 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +216 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +84 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +169 -0
- audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +209 -0
- audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +198 -0
- audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +24 -0
- audiometa/test/tests/integration/multiple_values/writing/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +62 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +36 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +34 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +32 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +54 -0
- audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +42 -0
- audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +98 -0
- audiometa/test/tests/integration/reading/__init__.py +1 -0
- audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +80 -0
- audiometa/test/tests/integration/reading/test_reading_error_handling.py +36 -0
- audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
- audiometa/test/tests/integration/real_audio_files/test_reading.py +146 -0
- audiometa/test/tests/integration/real_audio_files/test_writing.py +198 -0
- audiometa/test/tests/integration/technical_info/__init__.py +0 -0
- audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
- audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +103 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/__init__.py +0 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_audio_data_corruption.py +21 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_flipped_md5.py +29 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_non_flac_error.py +13 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_partial_md5.py +29 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_random_md5.py +29 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_unset_md5.py +56 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_valid_md5.py +21 -0
- audiometa/test/tests/integration/technical_info/test_bitrate.py +79 -0
- audiometa/test/tests/integration/technical_info/test_channels.py +38 -0
- audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +38 -0
- audiometa/test/tests/integration/technical_info/test_sample_rate.py +40 -0
- audiometa/test/tests/integration/test_audio_file.py +35 -0
- audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +95 -0
- audiometa/test/tests/integration/writing/__init__.py +0 -0
- audiometa/test/tests/integration/writing/test_error_handling.py +44 -0
- audiometa/test/tests/integration/writing/test_forced_format.py +224 -0
- audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +223 -0
- audiometa/test/tests/integration/writing/test_partial_update.py +36 -0
- audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
- audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +79 -0
- audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +76 -0
- audiometa/test/tests/integration/writing/writing_strategies/test_sync_strategy.py +215 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +42 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +93 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +99 -0
- audiometa/test/tests/unit/__init__.py +0 -0
- audiometa/test/tests/unit/audio_file/__init__.py +0 -0
- audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +26 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +31 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +38 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +190 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +51 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +28 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +31 -0
- audiometa/test/tests/unit/audio_file/test_context_manager.py +30 -0
- audiometa/test/tests/unit/audio_file/test_file_validation.py +40 -0
- audiometa/test/tests/unit/audio_file/test_is_audio_file.py +49 -0
- audiometa/test/tests/unit/audio_file/test_operations.py +20 -0
- audiometa/test/tests/unit/audio_file/test_path_handling.py +23 -0
- audiometa/test/tests/unit/cli/__init__.py +0 -0
- audiometa/test/tests/unit/cli/test_expand_file_patterns.py +234 -0
- audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/conftest.py +142 -0
- audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +49 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +66 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +343 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +53 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +186 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +142 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +76 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +152 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +23 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +77 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +43 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +151 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +61 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_date_format_validation.py +135 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_disc_number_validation.py +75 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_format_validation.py +121 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_type_validation.py +30 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_track_number_validation.py +46 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +22 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +83 -0
- audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +74 -0
- audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +26 -0
- audiometa/utils/__init__.py +1 -0
- audiometa/utils/id3v1_genre_code_map.py +205 -0
- audiometa/utils/metadata_format.py +31 -0
- audiometa/utils/metadata_writing_strategy.py +16 -0
- audiometa/utils/mutagen_exception_handler.py +24 -0
- audiometa/utils/os_dependencies_checker/__init__.py +24 -0
- audiometa/utils/os_dependencies_checker/base.py +62 -0
- audiometa/utils/os_dependencies_checker/config.py +77 -0
- audiometa/utils/os_dependencies_checker/macos.py +236 -0
- audiometa/utils/os_dependencies_checker/ubuntu.py +95 -0
- audiometa/utils/os_dependencies_checker/windows.py +227 -0
- audiometa/utils/rating_profiles.py +110 -0
- audiometa/utils/tool_path_resolver.py +135 -0
- audiometa/utils/types.py +82 -0
- audiometa/utils/unified_metadata_key.py +87 -0
- audiometa_python-0.6.0.dist-info/METADATA +1593 -0
- audiometa_python-0.6.0.dist-info/RECORD +352 -0
- audiometa_python-0.6.0.dist-info/WHEEL +5 -0
- audiometa_python-0.6.0.dist-info/entry_points.txt +2 -0
- audiometa_python-0.6.0.dist-info/licenses/LICENSE +202 -0
- audiometa_python-0.6.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import get_unified_metadata_field, update_metadata
|
|
4
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
5
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
6
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.integration
|
|
10
|
+
class TestComprehensiveRatingWriting:
|
|
11
|
+
def test_write_read_with_different_max_values(self):
|
|
12
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
13
|
+
|
|
14
|
+
with temp_file_with_metadata(basic_metadata, "mp3") as test_file:
|
|
15
|
+
# Write with base 100
|
|
16
|
+
test_metadata = {UnifiedMetadataKey.RATING: 50} # 2.5 stars
|
|
17
|
+
update_metadata(
|
|
18
|
+
test_file, test_metadata, normalized_rating_max_value=100, metadata_format=MetadataFormat.ID3V2
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Read back with base 100
|
|
22
|
+
rating_100 = get_unified_metadata_field(
|
|
23
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100
|
|
24
|
+
)
|
|
25
|
+
assert rating_100 == 50
|
|
26
|
+
|
|
27
|
+
# Read back with base 255 (should be normalized)
|
|
28
|
+
rating_255 = get_unified_metadata_field(
|
|
29
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=255
|
|
30
|
+
)
|
|
31
|
+
assert rating_255 is not None
|
|
32
|
+
assert isinstance(rating_255, int | float)
|
|
33
|
+
assert rating_255 > 0
|
|
34
|
+
|
|
35
|
+
def test_cross_metadata_format_rating_consistency(self):
|
|
36
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
37
|
+
test_rating = 70
|
|
38
|
+
|
|
39
|
+
# Test ID3v2 metadata format
|
|
40
|
+
with temp_file_with_metadata(basic_metadata, "mp3") as test_file:
|
|
41
|
+
test_metadata = {UnifiedMetadataKey.RATING: test_rating}
|
|
42
|
+
update_metadata(
|
|
43
|
+
test_file, test_metadata, normalized_rating_max_value=100, metadata_format=MetadataFormat.ID3V2
|
|
44
|
+
)
|
|
45
|
+
rating = get_unified_metadata_field(test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100)
|
|
46
|
+
assert rating is not None
|
|
47
|
+
assert isinstance(rating, int | float)
|
|
48
|
+
assert rating > 0
|
|
49
|
+
|
|
50
|
+
# Test RIFF metadata format
|
|
51
|
+
with temp_file_with_metadata(basic_metadata, "wav") as test_file:
|
|
52
|
+
test_metadata = {UnifiedMetadataKey.RATING: test_rating}
|
|
53
|
+
update_metadata(
|
|
54
|
+
test_file, test_metadata, normalized_rating_max_value=100, metadata_format=MetadataFormat.RIFF
|
|
55
|
+
)
|
|
56
|
+
rating = get_unified_metadata_field(test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100)
|
|
57
|
+
assert rating is not None
|
|
58
|
+
assert isinstance(rating, int | float)
|
|
59
|
+
assert rating > 0
|
|
60
|
+
|
|
61
|
+
# Test Vorbis metadata format
|
|
62
|
+
with temp_file_with_metadata(basic_metadata, "flac") as test_file:
|
|
63
|
+
test_metadata = {UnifiedMetadataKey.RATING: test_rating}
|
|
64
|
+
update_metadata(
|
|
65
|
+
test_file, test_metadata, normalized_rating_max_value=100, metadata_format=MetadataFormat.VORBIS
|
|
66
|
+
)
|
|
67
|
+
rating = get_unified_metadata_field(test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100)
|
|
68
|
+
assert rating is not None
|
|
69
|
+
assert isinstance(rating, int | float)
|
|
70
|
+
assert rating > 0
|
|
71
|
+
|
|
72
|
+
def test_metadata_format_specific_rating_profiles(self):
|
|
73
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
74
|
+
|
|
75
|
+
# Test ID3v2 with base 255 non-proportional values
|
|
76
|
+
with temp_file_with_metadata(basic_metadata, "mp3") as test_file:
|
|
77
|
+
test_values = [0, 1, 64, 128, 196, 255]
|
|
78
|
+
for value in test_values:
|
|
79
|
+
test_metadata = {UnifiedMetadataKey.RATING: value}
|
|
80
|
+
update_metadata(
|
|
81
|
+
test_file, test_metadata, normalized_rating_max_value=255, metadata_format=MetadataFormat.ID3V2
|
|
82
|
+
)
|
|
83
|
+
rating = get_unified_metadata_field(
|
|
84
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=255
|
|
85
|
+
)
|
|
86
|
+
assert rating is not None
|
|
87
|
+
assert isinstance(rating, int | float)
|
|
88
|
+
assert 0 <= rating <= 255
|
|
89
|
+
|
|
90
|
+
# Test Vorbis with base 100 proportional values
|
|
91
|
+
with temp_file_with_metadata(basic_metadata, "flac") as test_file:
|
|
92
|
+
test_values = [0, 20, 40, 60, 80, 100]
|
|
93
|
+
for value in test_values:
|
|
94
|
+
test_metadata = {UnifiedMetadataKey.RATING: value}
|
|
95
|
+
update_metadata(
|
|
96
|
+
test_file,
|
|
97
|
+
test_metadata,
|
|
98
|
+
normalized_rating_max_value=100,
|
|
99
|
+
metadata_format=MetadataFormat.VORBIS,
|
|
100
|
+
)
|
|
101
|
+
rating = get_unified_metadata_field(
|
|
102
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100
|
|
103
|
+
)
|
|
104
|
+
assert rating is not None
|
|
105
|
+
assert rating == value
|
|
106
|
+
|
|
107
|
+
def test_rating_removal_consistency_across_formats(self):
|
|
108
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
109
|
+
|
|
110
|
+
# Test rating removal behavior across all formats
|
|
111
|
+
for format_type, file_ext in [
|
|
112
|
+
(MetadataFormat.ID3V2, "mp3"),
|
|
113
|
+
(MetadataFormat.RIFF, "wav"),
|
|
114
|
+
(MetadataFormat.VORBIS, "flac"),
|
|
115
|
+
]:
|
|
116
|
+
with temp_file_with_metadata(basic_metadata, file_ext) as test_file:
|
|
117
|
+
# First write a rating
|
|
118
|
+
test_metadata = {UnifiedMetadataKey.RATING: 80}
|
|
119
|
+
update_metadata(test_file, test_metadata, normalized_rating_max_value=100, metadata_format=format_type)
|
|
120
|
+
rating = get_unified_metadata_field(
|
|
121
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100
|
|
122
|
+
)
|
|
123
|
+
assert rating == 80
|
|
124
|
+
|
|
125
|
+
# Then remove it with None
|
|
126
|
+
test_metadata = {UnifiedMetadataKey.RATING: None}
|
|
127
|
+
update_metadata(test_file, test_metadata, normalized_rating_max_value=100, metadata_format=format_type)
|
|
128
|
+
rating = get_unified_metadata_field(
|
|
129
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100
|
|
130
|
+
)
|
|
131
|
+
# Rating removal behavior may vary - check if it's None or 0
|
|
132
|
+
assert rating is None or rating == 0
|
|
133
|
+
|
|
134
|
+
def test_write_float_rating_values_normalized_mode(self):
|
|
135
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
136
|
+
|
|
137
|
+
# Test float values with max=10 (half-star ratings)
|
|
138
|
+
with temp_file_with_metadata(basic_metadata, "mp3") as test_file:
|
|
139
|
+
test_values = [1.5, 2.5, 3.5, 4.5, 7.5]
|
|
140
|
+
for value in test_values:
|
|
141
|
+
test_metadata = {UnifiedMetadataKey.RATING: value}
|
|
142
|
+
update_metadata(
|
|
143
|
+
test_file, test_metadata, normalized_rating_max_value=10, metadata_format=MetadataFormat.ID3V2
|
|
144
|
+
)
|
|
145
|
+
rating = get_unified_metadata_field(
|
|
146
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=10
|
|
147
|
+
)
|
|
148
|
+
assert rating is not None
|
|
149
|
+
assert isinstance(rating, int | float)
|
|
150
|
+
assert rating > 0
|
|
151
|
+
|
|
152
|
+
# Test float values with max=100
|
|
153
|
+
with temp_file_with_metadata(basic_metadata, "flac") as test_file:
|
|
154
|
+
test_values = [1.5, 7.5, 15.0, 25.5, 50.0]
|
|
155
|
+
for value in test_values:
|
|
156
|
+
test_metadata = {UnifiedMetadataKey.RATING: value}
|
|
157
|
+
update_metadata(
|
|
158
|
+
test_file,
|
|
159
|
+
test_metadata,
|
|
160
|
+
normalized_rating_max_value=100,
|
|
161
|
+
metadata_format=MetadataFormat.VORBIS,
|
|
162
|
+
)
|
|
163
|
+
rating = get_unified_metadata_field(
|
|
164
|
+
test_file, UnifiedMetadataKey.RATING, normalized_rating_max_value=100
|
|
165
|
+
)
|
|
166
|
+
assert rating is not None
|
|
167
|
+
assert isinstance(rating, int | float)
|
|
168
|
+
assert rating >= 0
|
|
169
|
+
|
|
170
|
+
@pytest.mark.parametrize("rating_value", [1.5, 75.7, 128.5])
|
|
171
|
+
def test_write_float_rating_values_raw_mode(self, rating_value):
|
|
172
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
173
|
+
|
|
174
|
+
# Test fractional float values in raw mode (no normalization) - should raise error
|
|
175
|
+
from audiometa.exceptions import InvalidRatingValueError
|
|
176
|
+
|
|
177
|
+
with temp_file_with_metadata(basic_metadata, "mp3") as test_file:
|
|
178
|
+
test_metadata = {UnifiedMetadataKey.RATING: rating_value}
|
|
179
|
+
with pytest.raises(InvalidRatingValueError) as exc_info:
|
|
180
|
+
update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
181
|
+
assert "In raw mode, float values must be whole numbers" in str(exc_info.value)
|
|
182
|
+
|
|
183
|
+
@pytest.mark.parametrize("rating_value", [0.0, 128.0, 196.0, 255.0])
|
|
184
|
+
def test_write_whole_number_float_rating_values_raw_mode(self, rating_value):
|
|
185
|
+
basic_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
186
|
+
|
|
187
|
+
# Test whole-number float values in raw mode (no normalization) - should be accepted and converted to int
|
|
188
|
+
with temp_file_with_metadata(basic_metadata, "mp3") as test_file:
|
|
189
|
+
test_metadata = {UnifiedMetadataKey.RATING: rating_value}
|
|
190
|
+
update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
191
|
+
rating = get_unified_metadata_field(test_file, UnifiedMetadataKey.RATING)
|
|
192
|
+
assert rating == int(rating_value)
|
|
File without changes
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import get_unified_metadata_field, update_metadata
|
|
4
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
5
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
6
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.integration
|
|
10
|
+
class TestReleaseDateDeleting:
|
|
11
|
+
def test_delete_release_date_id3v2(self):
|
|
12
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
13
|
+
update_metadata(
|
|
14
|
+
test_file, {UnifiedMetadataKey.RELEASE_DATE: "2023-01-01"}, metadata_format=MetadataFormat.ID3V2
|
|
15
|
+
)
|
|
16
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) == "2023-01-01"
|
|
17
|
+
|
|
18
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None}, metadata_format=MetadataFormat.ID3V2)
|
|
19
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
20
|
+
|
|
21
|
+
def test_delete_release_date_id3v1(self):
|
|
22
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
23
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: "2023"}, metadata_format=MetadataFormat.ID3V1)
|
|
24
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) == "2023"
|
|
25
|
+
|
|
26
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None}, metadata_format=MetadataFormat.ID3V1)
|
|
27
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
28
|
+
|
|
29
|
+
def test_delete_release_date_riff(self):
|
|
30
|
+
with temp_file_with_metadata({}, "wav") as test_file:
|
|
31
|
+
update_metadata(
|
|
32
|
+
test_file, {UnifiedMetadataKey.RELEASE_DATE: "2023-01-01"}, metadata_format=MetadataFormat.RIFF
|
|
33
|
+
)
|
|
34
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) == "2023-01-01"
|
|
35
|
+
|
|
36
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None}, metadata_format=MetadataFormat.RIFF)
|
|
37
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
38
|
+
|
|
39
|
+
def test_delete_release_date_vorbis(self):
|
|
40
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
41
|
+
update_metadata(
|
|
42
|
+
test_file, {UnifiedMetadataKey.RELEASE_DATE: "2023-01-01"}, metadata_format=MetadataFormat.VORBIS
|
|
43
|
+
)
|
|
44
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) == "2023-01-01"
|
|
45
|
+
|
|
46
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None}, metadata_format=MetadataFormat.VORBIS)
|
|
47
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
48
|
+
|
|
49
|
+
def test_delete_release_date_preserves_other_fields(self):
|
|
50
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
51
|
+
update_metadata(
|
|
52
|
+
test_file,
|
|
53
|
+
{
|
|
54
|
+
UnifiedMetadataKey.RELEASE_DATE: "2023-01-01",
|
|
55
|
+
UnifiedMetadataKey.TITLE: "Test Title",
|
|
56
|
+
UnifiedMetadataKey.ARTISTS: ["Test Artist"],
|
|
57
|
+
},
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None})
|
|
61
|
+
|
|
62
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
63
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
|
|
64
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.ARTISTS) == ["Test Artist"]
|
|
65
|
+
|
|
66
|
+
def test_delete_release_date_already_none(self):
|
|
67
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
68
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None})
|
|
69
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
70
|
+
|
|
71
|
+
def test_delete_release_date_empty_string(self):
|
|
72
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
73
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: ""}, metadata_format=MetadataFormat.ID3V2)
|
|
74
|
+
assert get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE) is None
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import update_metadata
|
|
4
|
+
from audiometa.exceptions import InvalidMetadataFieldFormatError
|
|
5
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
6
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.integration
|
|
10
|
+
class TestReleaseDateErrorHandling:
|
|
11
|
+
def test_invalid_format_wrong_separator_mp3(self):
|
|
12
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
13
|
+
invalid_dates = [
|
|
14
|
+
"2024/01/01",
|
|
15
|
+
"2024.01.01",
|
|
16
|
+
"2024 01 01",
|
|
17
|
+
]
|
|
18
|
+
for invalid_date in invalid_dates:
|
|
19
|
+
with pytest.raises(InvalidMetadataFieldFormatError) as exc_info:
|
|
20
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: invalid_date})
|
|
21
|
+
error = exc_info.value
|
|
22
|
+
assert error.field == UnifiedMetadataKey.RELEASE_DATE.value
|
|
23
|
+
assert error.value == invalid_date
|
|
24
|
+
|
|
25
|
+
def test_invalid_format_single_digit_mp3(self):
|
|
26
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
27
|
+
invalid_dates = [
|
|
28
|
+
"2024-1-1",
|
|
29
|
+
"2024-1-01",
|
|
30
|
+
"2024-01-1",
|
|
31
|
+
]
|
|
32
|
+
for invalid_date in invalid_dates:
|
|
33
|
+
with pytest.raises(InvalidMetadataFieldFormatError):
|
|
34
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: invalid_date})
|
|
35
|
+
|
|
36
|
+
def test_invalid_format_short_year_mp3(self):
|
|
37
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
38
|
+
invalid_dates = ["24", "024", "999"]
|
|
39
|
+
for invalid_date in invalid_dates:
|
|
40
|
+
with pytest.raises(InvalidMetadataFieldFormatError):
|
|
41
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: invalid_date})
|
|
42
|
+
|
|
43
|
+
def test_invalid_format_non_numeric_mp3(self):
|
|
44
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
45
|
+
invalid_dates = [
|
|
46
|
+
"not-a-date",
|
|
47
|
+
"2024-abc-01",
|
|
48
|
+
"abcd-01-01",
|
|
49
|
+
]
|
|
50
|
+
for invalid_date in invalid_dates:
|
|
51
|
+
with pytest.raises(InvalidMetadataFieldFormatError):
|
|
52
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: invalid_date})
|
|
53
|
+
|
|
54
|
+
def test_invalid_format_wrong_separator_flac(self):
|
|
55
|
+
with temp_file_with_metadata({}, "flac") as test_file, pytest.raises(InvalidMetadataFieldFormatError):
|
|
56
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: "2024/01/01"})
|
|
57
|
+
|
|
58
|
+
def test_invalid_format_wrong_separator_wav(self):
|
|
59
|
+
with temp_file_with_metadata({}, "wav") as test_file, pytest.raises(InvalidMetadataFieldFormatError):
|
|
60
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: "2024/01/01"})
|
|
61
|
+
|
|
62
|
+
def test_valid_format_yyyy_passes(self):
|
|
63
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
64
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: "2024"})
|
|
65
|
+
|
|
66
|
+
def test_valid_format_yyyy_mm_dd_passes(self):
|
|
67
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
68
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: "2024-01-01"})
|
|
69
|
+
|
|
70
|
+
def test_none_value_allowed(self):
|
|
71
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
72
|
+
update_metadata(test_file, {UnifiedMetadataKey.RELEASE_DATE: None})
|
|
73
|
+
|
|
74
|
+
def test_invalid_format_with_multiple_fields(self):
|
|
75
|
+
with temp_file_with_metadata({}, "mp3") as test_file, pytest.raises(InvalidMetadataFieldFormatError):
|
|
76
|
+
update_metadata(
|
|
77
|
+
test_file,
|
|
78
|
+
{
|
|
79
|
+
UnifiedMetadataKey.TITLE: "Valid Title",
|
|
80
|
+
UnifiedMetadataKey.RELEASE_DATE: "2024/01/01",
|
|
81
|
+
},
|
|
82
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import get_unified_metadata_field
|
|
4
|
+
from audiometa.test.helpers.id3v1.id3v1_metadata_setter import ID3v1MetadataSetter
|
|
5
|
+
from audiometa.test.helpers.id3v2.id3v2_metadata_getter import ID3v2MetadataGetter
|
|
6
|
+
from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
|
|
7
|
+
from audiometa.test.helpers.riff.riff_metadata_getter import RIFFMetadataGetter
|
|
8
|
+
from audiometa.test.helpers.riff.riff_metadata_setter import RIFFMetadataSetter
|
|
9
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
10
|
+
from audiometa.test.helpers.vorbis.vorbis_metadata_getter import VorbisMetadataGetter
|
|
11
|
+
from audiometa.test.helpers.vorbis.vorbis_metadata_setter import VorbisMetadataSetter
|
|
12
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.integration
|
|
16
|
+
class TestReleaseDateReading:
|
|
17
|
+
def test_id3v1(self):
|
|
18
|
+
with temp_file_with_metadata({"title": "Test Song"}, "id3v1") as test_file:
|
|
19
|
+
ID3v1MetadataSetter.set_max_metadata(test_file)
|
|
20
|
+
|
|
21
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
22
|
+
assert release_date == "9999"
|
|
23
|
+
|
|
24
|
+
def test_id3v2_3(self):
|
|
25
|
+
with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
|
|
26
|
+
ID3v2MetadataSetter.set_release_date(test_file, "9999-12-31", version="2.3")
|
|
27
|
+
raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
|
|
28
|
+
assert raw_metadata["TDAT"] == ["3112"]
|
|
29
|
+
assert raw_metadata["TYER"] == ["9999"]
|
|
30
|
+
|
|
31
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
32
|
+
assert release_date == "9999-12-31"
|
|
33
|
+
|
|
34
|
+
def test_id3v2_4(self):
|
|
35
|
+
with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
|
|
36
|
+
ID3v2MetadataSetter.set_release_date(test_file, "9999-12-31", version="2.4")
|
|
37
|
+
raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.4")
|
|
38
|
+
assert raw_metadata["TDRC"] == ["9999-12-31"]
|
|
39
|
+
|
|
40
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
41
|
+
assert release_date == "9999-12-31"
|
|
42
|
+
|
|
43
|
+
def test_vorbis(self):
|
|
44
|
+
with temp_file_with_metadata({"title": "Test Song"}, "flac") as test_file:
|
|
45
|
+
VorbisMetadataSetter.set_release_date(test_file, "9999-12-31")
|
|
46
|
+
raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
|
|
47
|
+
assert "DATE=9999-12-31" in raw_metadata
|
|
48
|
+
|
|
49
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
50
|
+
assert release_date == "9999-12-31"
|
|
51
|
+
|
|
52
|
+
def test_riff(self):
|
|
53
|
+
with temp_file_with_metadata({"title": "Test Song"}, "wav") as test_file:
|
|
54
|
+
RIFFMetadataSetter.set_release_date(test_file, "9999-12-31")
|
|
55
|
+
raw_metadata = RIFFMetadataGetter.get_raw_metadata(test_file)
|
|
56
|
+
assert "TAG:date=9999-12-31" in raw_metadata
|
|
57
|
+
|
|
58
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
59
|
+
assert release_date == "9999-12-31"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import get_unified_metadata_field, update_metadata
|
|
4
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
5
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
6
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.integration
|
|
10
|
+
class TestReleaseDateWriting:
|
|
11
|
+
def test_id3v2(self):
|
|
12
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
13
|
+
test_release_date = "2024-01-01"
|
|
14
|
+
test_metadata = {UnifiedMetadataKey.RELEASE_DATE: test_release_date}
|
|
15
|
+
update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
16
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
17
|
+
assert release_date == test_release_date
|
|
18
|
+
|
|
19
|
+
def test_riff(self):
|
|
20
|
+
with temp_file_with_metadata({}, "wav") as test_file:
|
|
21
|
+
test_release_date = "2024-02-01"
|
|
22
|
+
test_metadata = {UnifiedMetadataKey.RELEASE_DATE: test_release_date}
|
|
23
|
+
update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.RIFF)
|
|
24
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
25
|
+
assert release_date == test_release_date
|
|
26
|
+
|
|
27
|
+
def test_vorbis(self):
|
|
28
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
29
|
+
test_release_date = "2024-03-01"
|
|
30
|
+
test_metadata = {UnifiedMetadataKey.RELEASE_DATE: test_release_date}
|
|
31
|
+
update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.VORBIS)
|
|
32
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
33
|
+
assert release_date == test_release_date
|
|
34
|
+
|
|
35
|
+
def test_id3v1(self):
|
|
36
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
37
|
+
test_release_date = "2024"
|
|
38
|
+
test_metadata = {UnifiedMetadataKey.RELEASE_DATE: test_release_date}
|
|
39
|
+
update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V1)
|
|
40
|
+
release_date = get_unified_metadata_field(test_file, UnifiedMetadataKey.RELEASE_DATE)
|
|
41
|
+
assert release_date == test_release_date
|
|
42
|
+
|
|
43
|
+
def test_invalid_type_raises(self):
|
|
44
|
+
from audiometa.exceptions import InvalidMetadataFieldTypeError
|
|
45
|
+
|
|
46
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
47
|
+
bad_metadata = {UnifiedMetadataKey.RELEASE_DATE: 20240101}
|
|
48
|
+
with pytest.raises(InvalidMetadataFieldTypeError):
|
|
49
|
+
update_metadata(test_file, bad_metadata)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa import UnifiedMetadataKey, get_unified_metadata_field, update_metadata
|
|
6
|
+
from audiometa.exceptions import (
|
|
7
|
+
InvalidMetadataFieldTypeError,
|
|
8
|
+
MetadataFieldNotSupportedByLibError,
|
|
9
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
10
|
+
)
|
|
11
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
12
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.integration
|
|
16
|
+
class TestMetadataFieldValidation:
|
|
17
|
+
"""Test that get_unified_metadata_field raises MetadataFieldNotSupportedByMetadataFormatError when a field is not
|
|
18
|
+
supported by the specified format.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def test_replaygain_not_supported_by_riff(self, sample_wav_file: Path):
|
|
22
|
+
with pytest.raises(
|
|
23
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
24
|
+
match="UnifiedMetadataKey.REPLAYGAIN metadata not supported by RIFF format",
|
|
25
|
+
):
|
|
26
|
+
get_unified_metadata_field(
|
|
27
|
+
sample_wav_file, UnifiedMetadataKey.REPLAYGAIN, metadata_format=MetadataFormat.RIFF
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def test_replaygain_not_supported_by_id3v1(self, sample_mp3_file: Path):
|
|
31
|
+
with pytest.raises(
|
|
32
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
33
|
+
match="UnifiedMetadataKey.REPLAYGAIN metadata not supported by ID3v1 format",
|
|
34
|
+
):
|
|
35
|
+
get_unified_metadata_field(
|
|
36
|
+
sample_mp3_file, UnifiedMetadataKey.REPLAYGAIN, metadata_format=MetadataFormat.ID3V1
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def test_album_artists_not_supported_by_id3v1(self, sample_mp3_file: Path):
|
|
40
|
+
with pytest.raises(
|
|
41
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
42
|
+
match="UnifiedMetadataKey.ALBUM_ARTISTS metadata not supported by ID3v1 format",
|
|
43
|
+
):
|
|
44
|
+
get_unified_metadata_field(
|
|
45
|
+
sample_mp3_file, UnifiedMetadataKey.ALBUM_ARTISTS, metadata_format=MetadataFormat.ID3V1
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def test_supported_field_works_with_riff(self, sample_wav_file: Path):
|
|
49
|
+
title = get_unified_metadata_field(
|
|
50
|
+
sample_wav_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.RIFF
|
|
51
|
+
)
|
|
52
|
+
assert title is None or isinstance(title, str)
|
|
53
|
+
|
|
54
|
+
def test_supported_field_works_with_id3v1(self, sample_mp3_file: Path):
|
|
55
|
+
title = get_unified_metadata_field(
|
|
56
|
+
sample_mp3_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.ID3V1
|
|
57
|
+
)
|
|
58
|
+
assert title is None or isinstance(title, str)
|
|
59
|
+
|
|
60
|
+
def test_unsupported_field_without_format_specification(self, sample_wav_file: Path):
|
|
61
|
+
bpm = get_unified_metadata_field(sample_wav_file, UnifiedMetadataKey.BPM)
|
|
62
|
+
assert bpm is None or isinstance(bpm, int)
|
|
63
|
+
|
|
64
|
+
def test_rating_supported_by_riff_indirectly(self, sample_wav_file: Path):
|
|
65
|
+
rating = get_unified_metadata_field(
|
|
66
|
+
sample_wav_file, UnifiedMetadataKey.RATING, metadata_format=MetadataFormat.RIFF
|
|
67
|
+
)
|
|
68
|
+
assert rating is None or isinstance(rating, int)
|
|
69
|
+
|
|
70
|
+
def test_field_not_supported_by_lib_exception_exists(self):
|
|
71
|
+
msg = "Test field not supported by library"
|
|
72
|
+
with pytest.raises(MetadataFieldNotSupportedByLibError, match="Test field not supported by library"):
|
|
73
|
+
raise MetadataFieldNotSupportedByLibError(msg)
|
|
74
|
+
|
|
75
|
+
def test_field_not_supported_by_lib_concept(self):
|
|
76
|
+
with (
|
|
77
|
+
temp_file_with_metadata({}, "wav") as test_file,
|
|
78
|
+
pytest.raises(MetadataFieldNotSupportedByLibError, match="Test field not supported by library"),
|
|
79
|
+
):
|
|
80
|
+
get_unified_metadata_field(test_file, "Test field not supported by library")
|
|
81
|
+
|
|
82
|
+
def test_valid_string_key_works(self, sample_mp3_file: Path):
|
|
83
|
+
"""Test that passing a string matching a UnifiedMetadataKey enum value works."""
|
|
84
|
+
# Test various string values that match enum values
|
|
85
|
+
title = get_unified_metadata_field(sample_mp3_file, "title")
|
|
86
|
+
assert title is None or isinstance(title, str)
|
|
87
|
+
|
|
88
|
+
artists = get_unified_metadata_field(sample_mp3_file, "artists")
|
|
89
|
+
assert artists is None or isinstance(artists, list)
|
|
90
|
+
|
|
91
|
+
rating = get_unified_metadata_field(sample_mp3_file, "rating")
|
|
92
|
+
assert rating is None or isinstance(rating, int)
|
|
93
|
+
|
|
94
|
+
# Verify it works the same as enum
|
|
95
|
+
title_enum = get_unified_metadata_field(sample_mp3_file, UnifiedMetadataKey.TITLE)
|
|
96
|
+
assert title == title_enum
|
|
97
|
+
|
|
98
|
+
def test_invalid_string_key_raises_error(self, sample_mp3_file: Path):
|
|
99
|
+
"""Test that passing an invalid string raises MetadataFieldNotSupportedByLibError."""
|
|
100
|
+
with pytest.raises(
|
|
101
|
+
MetadataFieldNotSupportedByLibError, match="invalid_field metadata not supported by the library"
|
|
102
|
+
):
|
|
103
|
+
get_unified_metadata_field(sample_mp3_file, "invalid_field")
|
|
104
|
+
|
|
105
|
+
def test_all_valid_enum_values_work(self, sample_mp3_file: Path):
|
|
106
|
+
"""Test that all valid UnifiedMetadataKey enum values are accepted (not rejected as invalid enum values)."""
|
|
107
|
+
for key in UnifiedMetadataKey:
|
|
108
|
+
# Should not raise MetadataFieldNotSupportedByLibError for invalid enum value
|
|
109
|
+
# (it's okay if it raises for "not supported by any format" - that's different)
|
|
110
|
+
try:
|
|
111
|
+
result = get_unified_metadata_field(sample_mp3_file, key)
|
|
112
|
+
# Result can be None if field is not present, which is valid
|
|
113
|
+
assert result is None or isinstance(result, str | int | float | list)
|
|
114
|
+
except MetadataFieldNotSupportedByLibError as e:
|
|
115
|
+
# Only fail if the error message indicates invalid enum value
|
|
116
|
+
# It's okay if it raises for "not supported by any format" - that's different
|
|
117
|
+
if "not supported by any format" not in str(e):
|
|
118
|
+
raise
|
|
119
|
+
|
|
120
|
+
def test_invalid_metadata_field_type_error_wrong_type_for_list_field(self):
|
|
121
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
122
|
+
with pytest.raises(InvalidMetadataFieldTypeError) as exc_info:
|
|
123
|
+
update_metadata(test_file, {UnifiedMetadataKey.ARTISTS: "should be list"})
|
|
124
|
+
error = exc_info.value
|
|
125
|
+
assert error.field == UnifiedMetadataKey.ARTISTS.value
|
|
126
|
+
assert "list" in error.expected_type.lower()
|
|
127
|
+
assert error.value == "should be list"
|
|
128
|
+
|
|
129
|
+
def test_invalid_metadata_field_type_error_wrong_type_for_string_field(self):
|
|
130
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
131
|
+
with pytest.raises(InvalidMetadataFieldTypeError) as exc_info:
|
|
132
|
+
update_metadata(test_file, {UnifiedMetadataKey.TITLE: 12345})
|
|
133
|
+
error = exc_info.value
|
|
134
|
+
assert error.field == UnifiedMetadataKey.TITLE.value
|
|
135
|
+
assert error.value == 12345
|
|
File without changes
|