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,190 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa._audio_file import _AudioFile
|
|
6
|
+
from audiometa.exceptions import (
|
|
7
|
+
AudioFileMetadataParseError,
|
|
8
|
+
DurationNotFoundError,
|
|
9
|
+
FileByteMismatchError,
|
|
10
|
+
FileCorruptedError,
|
|
11
|
+
FlacMd5CheckFailedError,
|
|
12
|
+
InvalidChunkDecodeError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.unit
|
|
17
|
+
class TestAudioFileTechnicalInfoErrorHandling:
|
|
18
|
+
def test_file_byte_mismatch_error_corrupted_flac(self, tmp_path):
|
|
19
|
+
corrupted_flac = tmp_path / "corrupted.flac"
|
|
20
|
+
corrupted_flac.write_bytes(b"fake file")
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
audio_file = _AudioFile(corrupted_flac)
|
|
24
|
+
audio_file.get_duration_in_sec()
|
|
25
|
+
pytest.fail("Should have raised FileByteMismatchError or FileCorruptedError")
|
|
26
|
+
except (FileByteMismatchError, FileCorruptedError):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
def test_flac_md5_check_failed_error_corrupted_flac(self, monkeypatch, sample_flac_file: Path):
|
|
30
|
+
def mock_subprocess_run(args, *_, **_kwargs):
|
|
31
|
+
class MockResult:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
result = MockResult()
|
|
35
|
+
|
|
36
|
+
# Handle brew --prefix call from get_tool_path
|
|
37
|
+
if isinstance(args, list) and len(args) > 0 and args[0] == "brew":
|
|
38
|
+
result.stdout = ""
|
|
39
|
+
result.stderr = ""
|
|
40
|
+
result.returncode = 0
|
|
41
|
+
return result
|
|
42
|
+
|
|
43
|
+
# Handle flac -t call - return code 0 but no "ok" message to trigger FlacMd5CheckFailedError
|
|
44
|
+
result.stdout = b""
|
|
45
|
+
result.stderr = b"Some unexpected FLAC output"
|
|
46
|
+
result.returncode = 0
|
|
47
|
+
return result
|
|
48
|
+
|
|
49
|
+
monkeypatch.setattr("subprocess.run", mock_subprocess_run)
|
|
50
|
+
|
|
51
|
+
audio_file = _AudioFile(sample_flac_file)
|
|
52
|
+
try:
|
|
53
|
+
audio_file.is_flac_file_md5_valid()
|
|
54
|
+
pytest.fail("Should have raised FlacMd5CheckFailedError")
|
|
55
|
+
except FlacMd5CheckFailedError:
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def test_invalid_chunk_decode_error_corrupted_flac_chunks(self, monkeypatch):
|
|
59
|
+
def mock_get_duration_in_sec(_self):
|
|
60
|
+
try:
|
|
61
|
+
msg = "FLAC chunk decoding failed"
|
|
62
|
+
raise RuntimeError(msg)
|
|
63
|
+
except Exception as exc:
|
|
64
|
+
error_str = str(exc)
|
|
65
|
+
if "file said" in error_str and "bytes, read" in error_str:
|
|
66
|
+
raise FileByteMismatchError(error_str.capitalize()) from exc
|
|
67
|
+
if "FLAC" in error_str or "chunk" in error_str.lower():
|
|
68
|
+
msg = f"Failed to decode FLAC chunks: {error_str}"
|
|
69
|
+
raise InvalidChunkDecodeError(msg) from exc
|
|
70
|
+
raise
|
|
71
|
+
|
|
72
|
+
monkeypatch.setattr("audiometa._audio_file._AudioFile.get_duration_in_sec", mock_get_duration_in_sec)
|
|
73
|
+
|
|
74
|
+
flac_file = "audiometa/test/assets/sample.flac"
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
audio_file = _AudioFile(flac_file)
|
|
78
|
+
audio_file.get_duration_in_sec()
|
|
79
|
+
pytest.fail("Should have raised InvalidChunkDecodeError")
|
|
80
|
+
except InvalidChunkDecodeError:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
def test_duration_not_found_error_invalid_wav_duration(self, monkeypatch):
|
|
84
|
+
def mock_subprocess_run(*_args, **_kwargs):
|
|
85
|
+
class MockResult:
|
|
86
|
+
returncode = 0
|
|
87
|
+
stdout = '{"format": {"duration": "0.0"}, "streams": [{"duration": "0"}]}'
|
|
88
|
+
|
|
89
|
+
return MockResult()
|
|
90
|
+
|
|
91
|
+
monkeypatch.setattr("subprocess.run", mock_subprocess_run)
|
|
92
|
+
|
|
93
|
+
wav_file = "audiometa/test/assets/sample.wav"
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
audio_file = _AudioFile(wav_file)
|
|
97
|
+
audio_file.get_duration_in_sec()
|
|
98
|
+
pytest.fail("Should have raised DurationNotFoundError")
|
|
99
|
+
except DurationNotFoundError:
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
def test_audio_file_metadata_parse_error_invalid_json(self, monkeypatch):
|
|
103
|
+
def mock_subprocess_run(*_args, **_kwargs):
|
|
104
|
+
class MockResult:
|
|
105
|
+
returncode = 0
|
|
106
|
+
stdout = "invalid json response"
|
|
107
|
+
|
|
108
|
+
return MockResult()
|
|
109
|
+
|
|
110
|
+
monkeypatch.setattr("subprocess.run", mock_subprocess_run)
|
|
111
|
+
|
|
112
|
+
wav_file = "audiometa/test/assets/sample.wav"
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
audio_file = _AudioFile(wav_file)
|
|
116
|
+
audio_file.get_duration_in_sec()
|
|
117
|
+
pytest.fail("Should have raised AudioFileMetadataParseError")
|
|
118
|
+
except AudioFileMetadataParseError:
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
def test_file_corrupted_error_invalid_wav(self, tmp_path):
|
|
122
|
+
invalid_wav = tmp_path / "invalid.wav"
|
|
123
|
+
invalid_wav.write_bytes(b"not a valid wav file")
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
audio_file = _AudioFile(invalid_wav)
|
|
127
|
+
audio_file.get_duration_in_sec()
|
|
128
|
+
pytest.fail("Should have raised FileCorruptedError")
|
|
129
|
+
except (FileCorruptedError, RuntimeError):
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
def test_flac_duration_handles_generic_mutagen_exception(self, monkeypatch):
|
|
133
|
+
error_msg = "Some unexpected mutagen error"
|
|
134
|
+
|
|
135
|
+
class MockInfo:
|
|
136
|
+
@property
|
|
137
|
+
def length(self):
|
|
138
|
+
raise ValueError(error_msg)
|
|
139
|
+
|
|
140
|
+
class MockFLAC:
|
|
141
|
+
def __init__(self, *_args, **_kwargs):
|
|
142
|
+
self._info = MockInfo()
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def info(self):
|
|
146
|
+
return self._info
|
|
147
|
+
|
|
148
|
+
# Mock FLAC in get_duration_in_sec, not in __init__
|
|
149
|
+
original_get_duration = _AudioFile.get_duration_in_sec
|
|
150
|
+
|
|
151
|
+
def mock_get_duration(self):
|
|
152
|
+
if self.file_extension == ".flac":
|
|
153
|
+
try:
|
|
154
|
+
return float(MockFLAC(self.file_path).info.length)
|
|
155
|
+
except Exception as exc:
|
|
156
|
+
error_str = str(exc)
|
|
157
|
+
if "file said" in error_str and "bytes, read" in error_str:
|
|
158
|
+
raise FileByteMismatchError(error_str.capitalize()) from exc
|
|
159
|
+
if "FLAC" in error_str or "chunk" in error_str.lower():
|
|
160
|
+
msg = f"Failed to decode FLAC chunks: {error_str}"
|
|
161
|
+
raise InvalidChunkDecodeError(msg) from exc
|
|
162
|
+
from audiometa.utils.mutagen_exception_handler import handle_mutagen_exception
|
|
163
|
+
|
|
164
|
+
handle_mutagen_exception("read duration from FLAC file", self.file_path, exc)
|
|
165
|
+
return original_get_duration(self)
|
|
166
|
+
|
|
167
|
+
monkeypatch.setattr(_AudioFile, "get_duration_in_sec", mock_get_duration)
|
|
168
|
+
|
|
169
|
+
flac_file = "audiometa/test/assets/sample.flac"
|
|
170
|
+
audio_file = _AudioFile(flac_file)
|
|
171
|
+
|
|
172
|
+
with pytest.raises(FileCorruptedError) as exc_info:
|
|
173
|
+
audio_file.get_duration_in_sec()
|
|
174
|
+
assert "Failed to read duration from FLAC file" in str(exc_info.value)
|
|
175
|
+
assert error_msg in str(exc_info.value)
|
|
176
|
+
|
|
177
|
+
def test_flac_md5_fixing_handles_generic_exception(self, monkeypatch, sample_flac_file: Path):
|
|
178
|
+
error_msg = "Some unexpected error during MD5 fixing"
|
|
179
|
+
|
|
180
|
+
def mock_subprocess_run(*_args, **_kwargs):
|
|
181
|
+
raise ValueError(error_msg)
|
|
182
|
+
|
|
183
|
+
monkeypatch.setattr("subprocess.run", mock_subprocess_run)
|
|
184
|
+
|
|
185
|
+
audio_file = _AudioFile(sample_flac_file)
|
|
186
|
+
|
|
187
|
+
with pytest.raises(FileCorruptedError) as exc_info:
|
|
188
|
+
audio_file.get_file_with_corrected_md5()
|
|
189
|
+
assert "Failed to fix FLAC MD5 checksum" in str(exc_info.value)
|
|
190
|
+
assert error_msg in str(exc_info.value)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa import get_file_size
|
|
6
|
+
from audiometa.test.helpers.technical_info_inspector import TechnicalInfoInspector
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.unit
|
|
10
|
+
class TestFileSizeFunctions:
|
|
11
|
+
def test_file_size_mp3(self, sample_mp3_file: Path):
|
|
12
|
+
external_tool_size = TechnicalInfoInspector.get_file_size(sample_mp3_file)
|
|
13
|
+
assert external_tool_size == 17307
|
|
14
|
+
|
|
15
|
+
file_size = get_file_size(sample_mp3_file)
|
|
16
|
+
assert file_size == 17307
|
|
17
|
+
|
|
18
|
+
def test_file_size_mp3_big(self, size_big_mp3: Path):
|
|
19
|
+
external_tool_size = TechnicalInfoInspector.get_file_size(size_big_mp3)
|
|
20
|
+
assert external_tool_size == 10468959
|
|
21
|
+
|
|
22
|
+
file_size = get_file_size(size_big_mp3)
|
|
23
|
+
assert file_size == 10468959
|
|
24
|
+
|
|
25
|
+
def test_file_size_flac(self, sample_flac_file: Path):
|
|
26
|
+
external_tool_size = TechnicalInfoInspector.get_file_size(sample_flac_file)
|
|
27
|
+
assert external_tool_size == 18439
|
|
28
|
+
|
|
29
|
+
file_size = get_file_size(sample_flac_file)
|
|
30
|
+
assert file_size == 18439
|
|
31
|
+
|
|
32
|
+
def test_file_size_flac_big(self, size_big_flac: Path):
|
|
33
|
+
external_tool_size = TechnicalInfoInspector.get_file_size(size_big_flac)
|
|
34
|
+
assert external_tool_size == 27888561
|
|
35
|
+
|
|
36
|
+
file_size = get_file_size(size_big_flac)
|
|
37
|
+
assert file_size == 27888561
|
|
38
|
+
|
|
39
|
+
def test_file_size_wav(self, sample_wav_file: Path):
|
|
40
|
+
external_tool_size = TechnicalInfoInspector.get_file_size(sample_wav_file)
|
|
41
|
+
assert external_tool_size == 16822
|
|
42
|
+
|
|
43
|
+
file_size = get_file_size(sample_wav_file)
|
|
44
|
+
assert file_size == 16822
|
|
45
|
+
|
|
46
|
+
def test_file_size_wav_big(self, size_big_wav: Path):
|
|
47
|
+
external_tool_size = TechnicalInfoInspector.get_file_size(size_big_wav)
|
|
48
|
+
assert external_tool_size == 83414326
|
|
49
|
+
|
|
50
|
+
file_size = get_file_size(size_big_wav)
|
|
51
|
+
assert file_size == 83414326
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Unit tests for _AudioFile get_audio_format_name method."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from audiometa._audio_file import _AudioFile
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.unit
|
|
11
|
+
class TestAudioFileFormatName:
|
|
12
|
+
def test_get_format_name_mp3(self, sample_mp3_file: Path):
|
|
13
|
+
audio_file = _AudioFile(sample_mp3_file)
|
|
14
|
+
audio_format_name = audio_file.get_audio_format_name()
|
|
15
|
+
|
|
16
|
+
assert audio_format_name == "MP3"
|
|
17
|
+
|
|
18
|
+
def test_get_format_name_wav(self, sample_wav_file: Path):
|
|
19
|
+
audio_file = _AudioFile(sample_wav_file)
|
|
20
|
+
audio_format_name = audio_file.get_audio_format_name()
|
|
21
|
+
|
|
22
|
+
assert audio_format_name == "WAV"
|
|
23
|
+
|
|
24
|
+
def test_get_format_name_flac(self, sample_flac_file: Path):
|
|
25
|
+
audio_file = _AudioFile(sample_flac_file)
|
|
26
|
+
audio_format_name = audio_file.get_audio_format_name()
|
|
27
|
+
|
|
28
|
+
assert audio_format_name == "FLAC"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa._audio_file import _AudioFile
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.unit
|
|
9
|
+
class TestAudioFileSampleRate:
|
|
10
|
+
def test_get_sample_rate_mp3(self, sample_mp3_file: Path):
|
|
11
|
+
audio_file = _AudioFile(sample_mp3_file)
|
|
12
|
+
sample_rate = audio_file.get_sample_rate()
|
|
13
|
+
assert isinstance(sample_rate, int)
|
|
14
|
+
assert sample_rate > 0
|
|
15
|
+
|
|
16
|
+
def test_get_sample_rate_wav(self, sample_wav_file: Path):
|
|
17
|
+
audio_file = _AudioFile(sample_wav_file)
|
|
18
|
+
sample_rate = audio_file.get_sample_rate()
|
|
19
|
+
assert isinstance(sample_rate, int)
|
|
20
|
+
assert sample_rate > 0
|
|
21
|
+
|
|
22
|
+
def test_get_sample_rate_flac(self, sample_flac_file: Path):
|
|
23
|
+
audio_file = _AudioFile(sample_flac_file)
|
|
24
|
+
sample_rate = audio_file.get_sample_rate()
|
|
25
|
+
assert isinstance(sample_rate, int)
|
|
26
|
+
assert sample_rate > 0
|
|
27
|
+
|
|
28
|
+
def test_get_sample_rate_returns_int(self, sample_mp3_file: Path):
|
|
29
|
+
audio_file = _AudioFile(sample_mp3_file)
|
|
30
|
+
sample_rate = audio_file.get_sample_rate()
|
|
31
|
+
assert isinstance(sample_rate, int)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa._audio_file import _AudioFile
|
|
6
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.unit
|
|
10
|
+
class TestContextManager:
|
|
11
|
+
def test_context_manager(self, sample_mp3_file: Path):
|
|
12
|
+
with _AudioFile(sample_mp3_file) as audio_file:
|
|
13
|
+
assert isinstance(audio_file, _AudioFile)
|
|
14
|
+
assert audio_file.file_path == str(sample_mp3_file)
|
|
15
|
+
|
|
16
|
+
duration = audio_file.get_duration_in_sec()
|
|
17
|
+
assert duration > 0
|
|
18
|
+
|
|
19
|
+
def test_file_operations(self):
|
|
20
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
21
|
+
audio_file = _AudioFile(test_file)
|
|
22
|
+
|
|
23
|
+
# Test write
|
|
24
|
+
test_data = b"test audio data"
|
|
25
|
+
bytes_written = audio_file.write(test_data)
|
|
26
|
+
assert bytes_written == len(test_data)
|
|
27
|
+
|
|
28
|
+
# Test read
|
|
29
|
+
read_data = audio_file.read()
|
|
30
|
+
assert read_data == test_data
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa._audio_file import _AudioFile
|
|
6
|
+
from audiometa.exceptions import FileCorruptedError, FileTypeNotSupportedError
|
|
7
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.unit
|
|
11
|
+
class TestAudioFileFileTypeValidation:
|
|
12
|
+
def test_extension_mp3_then_ok(self, sample_mp3_file: Path):
|
|
13
|
+
audio_file = _AudioFile(sample_mp3_file)
|
|
14
|
+
assert audio_file.file_extension == ".mp3"
|
|
15
|
+
|
|
16
|
+
def test_extension_flac_then_ok(self, sample_flac_file: Path):
|
|
17
|
+
audio_file = _AudioFile(sample_flac_file)
|
|
18
|
+
assert audio_file.file_extension == ".flac"
|
|
19
|
+
|
|
20
|
+
def test_extension_wav_then_ok(self, sample_wav_file: Path):
|
|
21
|
+
audio_file = _AudioFile(sample_wav_file)
|
|
22
|
+
assert audio_file.file_extension == ".wav"
|
|
23
|
+
|
|
24
|
+
def test_extension_m4a_then_not_ok(self, sample_m4a_file: Path):
|
|
25
|
+
with pytest.raises(FileTypeNotSupportedError):
|
|
26
|
+
_AudioFile(sample_m4a_file)
|
|
27
|
+
|
|
28
|
+
def test_bad_content_then_not_ok(self):
|
|
29
|
+
# Create a file with valid extension but bad content
|
|
30
|
+
with temp_file_with_metadata({}, "mp3") as temp_audio_file_path:
|
|
31
|
+
temp_audio_file_path.write_bytes(b"not a real audio file")
|
|
32
|
+
mp3_file_path = temp_audio_file_path.with_suffix(".mp3")
|
|
33
|
+
mp3_file_path.write_bytes(b"not a real audio file")
|
|
34
|
+
|
|
35
|
+
with pytest.raises(FileCorruptedError):
|
|
36
|
+
_AudioFile(str(mp3_file_path))
|
|
37
|
+
|
|
38
|
+
def test_nonexistent_file_raises_error(self):
|
|
39
|
+
with pytest.raises(FileNotFoundError):
|
|
40
|
+
_AudioFile("nonexistent.mp3")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa import is_audio_file
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.unit
|
|
9
|
+
class TestIsAudioFile:
|
|
10
|
+
def test_valid_mp3_file_returns_true(self, sample_mp3_file: Path):
|
|
11
|
+
assert is_audio_file(sample_mp3_file) is True
|
|
12
|
+
assert is_audio_file(str(sample_mp3_file)) is True
|
|
13
|
+
|
|
14
|
+
def test_valid_flac_file_returns_true(self, sample_flac_file: Path):
|
|
15
|
+
assert is_audio_file(sample_flac_file) is True
|
|
16
|
+
assert is_audio_file(str(sample_flac_file)) is True
|
|
17
|
+
|
|
18
|
+
def test_valid_wav_file_returns_true(self, sample_wav_file: Path):
|
|
19
|
+
assert is_audio_file(sample_wav_file) is True
|
|
20
|
+
assert is_audio_file(str(sample_wav_file)) is True
|
|
21
|
+
|
|
22
|
+
def test_nonexistent_file_returns_false(self):
|
|
23
|
+
assert is_audio_file("nonexistent.mp3") is False
|
|
24
|
+
assert is_audio_file(Path("nonexistent.flac")) is False
|
|
25
|
+
|
|
26
|
+
def test_unsupported_extension_returns_false(self, sample_m4a_file: Path):
|
|
27
|
+
assert is_audio_file(sample_m4a_file) is False
|
|
28
|
+
assert is_audio_file(str(sample_m4a_file)) is False
|
|
29
|
+
|
|
30
|
+
def test_invalid_mp3_content_returns_false(self, tmp_path: Path):
|
|
31
|
+
invalid_mp3 = tmp_path / "invalid.mp3"
|
|
32
|
+
invalid_mp3.write_bytes(b"not a real audio file")
|
|
33
|
+
|
|
34
|
+
assert is_audio_file(invalid_mp3) is False
|
|
35
|
+
assert is_audio_file(str(invalid_mp3)) is False
|
|
36
|
+
|
|
37
|
+
def test_invalid_flac_content_returns_false(self, tmp_path: Path):
|
|
38
|
+
invalid_flac = tmp_path / "invalid.flac"
|
|
39
|
+
invalid_flac.write_bytes(b"not a real audio file")
|
|
40
|
+
|
|
41
|
+
assert is_audio_file(invalid_flac) is False
|
|
42
|
+
assert is_audio_file(str(invalid_flac)) is False
|
|
43
|
+
|
|
44
|
+
def test_invalid_wav_content_returns_false(self, tmp_path: Path):
|
|
45
|
+
invalid_wav = tmp_path / "invalid.wav"
|
|
46
|
+
invalid_wav.write_bytes(b"not a real audio file")
|
|
47
|
+
|
|
48
|
+
assert is_audio_file(invalid_wav) is False
|
|
49
|
+
assert is_audio_file(str(invalid_wav)) is False
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa._audio_file import _AudioFile
|
|
4
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.unit
|
|
8
|
+
class TestAudioFileOperations:
|
|
9
|
+
def test_file_operations(self):
|
|
10
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
11
|
+
audio_file = _AudioFile(test_file)
|
|
12
|
+
|
|
13
|
+
# Test write
|
|
14
|
+
test_data = b"test audio data"
|
|
15
|
+
bytes_written = audio_file.write(test_data)
|
|
16
|
+
assert bytes_written == len(test_data)
|
|
17
|
+
|
|
18
|
+
# Test read
|
|
19
|
+
read_data = audio_file.read()
|
|
20
|
+
assert read_data == test_data
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa._audio_file import _AudioFile
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.unit
|
|
9
|
+
class TestAudioFilePathHandling:
|
|
10
|
+
def test_audio_file_with_string_path(self, sample_mp3_file: Path):
|
|
11
|
+
sample_mp3_file_str = str(sample_mp3_file)
|
|
12
|
+
audio_file = _AudioFile(sample_mp3_file_str)
|
|
13
|
+
assert audio_file.file_path == sample_mp3_file_str
|
|
14
|
+
assert audio_file.file_extension == ".mp3"
|
|
15
|
+
|
|
16
|
+
def test_audio_file_with_path_object(self, sample_mp3_file: Path):
|
|
17
|
+
audio_file = _AudioFile(sample_mp3_file)
|
|
18
|
+
assert audio_file.file_path == str(sample_mp3_file)
|
|
19
|
+
assert audio_file.file_extension == ".mp3"
|
|
20
|
+
|
|
21
|
+
def test_audio_file_nonexistent_file(self):
|
|
22
|
+
with pytest.raises(FileNotFoundError):
|
|
23
|
+
_AudioFile("nonexistent_file.mp3")
|
|
File without changes
|