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.
Files changed (352) hide show
  1. audiometa/__init__.py +1297 -0
  2. audiometa/__main__.py +6 -0
  3. audiometa/_audio_file.py +607 -0
  4. audiometa/cli.py +476 -0
  5. audiometa/exceptions.py +167 -0
  6. audiometa/manager/_MetadataManager.py +768 -0
  7. audiometa/manager/__init__.py +1 -0
  8. audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +250 -0
  9. audiometa/manager/_rating_supporting/__init__.py +1 -0
  10. audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +1032 -0
  11. audiometa/manager/_rating_supporting/id3v2/__init__.py +25 -0
  12. audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +11 -0
  13. audiometa/manager/_rating_supporting/riff/_RiffManager.py +1002 -0
  14. audiometa/manager/_rating_supporting/riff/__init__.py +25 -0
  15. audiometa/manager/_rating_supporting/riff/_riff_constants.py +17 -0
  16. audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +542 -0
  17. audiometa/manager/_rating_supporting/vorbis/__init__.py +17 -0
  18. audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +6 -0
  19. audiometa/manager/id3v1/_Id3v1Manager.py +512 -0
  20. audiometa/manager/id3v1/__init__.py +1 -0
  21. audiometa/manager/id3v1/_constants.py +8 -0
  22. audiometa/manager/id3v1/id3v1_raw_metadata.py +242 -0
  23. audiometa/manager/id3v1/id3v1_raw_metadata_key.py +13 -0
  24. audiometa/test/__init__.py +1 -0
  25. audiometa/test/assets/create_test_files.py +72 -0
  26. audiometa/test/helpers/__init__.py +51 -0
  27. audiometa/test/helpers/common/__init__.py +6 -0
  28. audiometa/test/helpers/common/audio_file_creator.py +68 -0
  29. audiometa/test/helpers/common/external_tool_runner.py +74 -0
  30. audiometa/test/helpers/id3v1/__init__.py +8 -0
  31. audiometa/test/helpers/id3v1/id3v1_header_verifier.py +18 -0
  32. audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +37 -0
  33. audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +61 -0
  34. audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +82 -0
  35. audiometa/test/helpers/id3v2/__init__.py +28 -0
  36. audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +349 -0
  37. audiometa/test/helpers/id3v2/id3v2_header_verifier.py +38 -0
  38. audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +56 -0
  39. audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +189 -0
  40. audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +506 -0
  41. audiometa/test/helpers/riff/__init__.py +8 -0
  42. audiometa/test/helpers/riff/riff_header_verifier.py +85 -0
  43. audiometa/test/helpers/riff/riff_manual_metadata_creator.py +298 -0
  44. audiometa/test/helpers/riff/riff_metadata_deleter.py +56 -0
  45. audiometa/test/helpers/riff/riff_metadata_getter.py +219 -0
  46. audiometa/test/helpers/riff/riff_metadata_setter.py +374 -0
  47. audiometa/test/helpers/scripts/__init__.py +0 -0
  48. audiometa/test/helpers/technical_info_inspector.py +115 -0
  49. audiometa/test/helpers/temp_file_with_metadata.py +82 -0
  50. audiometa/test/helpers/vorbis/__init__.py +8 -0
  51. audiometa/test/helpers/vorbis/vorbis_header_verifier.py +31 -0
  52. audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +49 -0
  53. audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +67 -0
  54. audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +221 -0
  55. audiometa/test/tests/__init__.py +0 -0
  56. audiometa/test/tests/conftest.py +276 -0
  57. audiometa/test/tests/e2e/__init__.py +0 -0
  58. audiometa/test/tests/e2e/cli/__init__.py +0 -0
  59. audiometa/test/tests/e2e/cli/error_handling/__init__.py +1 -0
  60. audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +77 -0
  61. audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +130 -0
  62. audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +118 -0
  63. audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +172 -0
  64. audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +49 -0
  65. audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +160 -0
  66. audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +90 -0
  67. audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +51 -0
  68. audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
  69. audiometa/test/tests/e2e/cli/read/test_basic.py +58 -0
  70. audiometa/test/tests/e2e/cli/read/test_comprehensive.py +240 -0
  71. audiometa/test/tests/e2e/cli/read/test_formats.py +55 -0
  72. audiometa/test/tests/e2e/cli/read/test_metadata_content.py +164 -0
  73. audiometa/test/tests/e2e/cli/read/test_multiple_files.py +149 -0
  74. audiometa/test/tests/e2e/cli/read/test_options.py +88 -0
  75. audiometa/test/tests/e2e/cli/read/test_unified.py +84 -0
  76. audiometa/test/tests/e2e/cli/test_delete.py +20 -0
  77. audiometa/test/tests/e2e/cli/test_formatting.py +31 -0
  78. audiometa/test/tests/e2e/cli/test_help.py +41 -0
  79. audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
  80. audiometa/test/tests/e2e/cli/write/test_basic.py +51 -0
  81. audiometa/test/tests/e2e/cli/write/test_comprehensive.py +210 -0
  82. audiometa/test/tests/e2e/cli/write/test_force_format.py +336 -0
  83. audiometa/test/tests/e2e/cli/write/test_integer_fields.py +145 -0
  84. audiometa/test/tests/e2e/cli/write/test_list_fields.py +107 -0
  85. audiometa/test/tests/e2e/cli/write/test_rating.py +74 -0
  86. audiometa/test/tests/e2e/cli/write/test_string_fields.py +54 -0
  87. audiometa/test/tests/e2e/cli/write/test_validation.py +85 -0
  88. audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
  89. audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +166 -0
  90. audiometa/test/tests/e2e/workflows/__init__.py +0 -0
  91. audiometa/test/tests/e2e/workflows/test_core_workflows.py +166 -0
  92. audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +318 -0
  93. audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +165 -0
  94. audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +129 -0
  95. audiometa/test/tests/e2e/workflows/test_rating_workflows.py +124 -0
  96. audiometa/test/tests/integration/__init__.py +0 -0
  97. audiometa/test/tests/integration/audio_format/__init__.py +0 -0
  98. audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
  99. audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +108 -0
  100. audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +61 -0
  101. audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +65 -0
  102. audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +69 -0
  103. audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
  104. audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +79 -0
  105. audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +61 -0
  106. audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +67 -0
  107. audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +60 -0
  108. audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
  109. audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +87 -0
  110. audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +62 -0
  111. audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +57 -0
  112. audiometa/test/tests/integration/audio_format/wav/test_wav_with_id3v2_tags.py +83 -0
  113. audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +62 -0
  114. audiometa/test/tests/integration/conftest.py +29 -0
  115. audiometa/test/tests/integration/delete_all_metadata/__init__.py +1 -0
  116. audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +102 -0
  117. audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +77 -0
  118. audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +47 -0
  119. audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +24 -0
  120. audiometa/test/tests/integration/encoding/__init__.py +1 -0
  121. audiometa/test/tests/integration/encoding/test_encoding.py +88 -0
  122. audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +223 -0
  123. audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
  124. audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +122 -0
  125. audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +250 -0
  126. audiometa/test/tests/integration/get_full_metadata/test_consistency.py +67 -0
  127. audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +123 -0
  128. audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +40 -0
  129. audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +43 -0
  130. audiometa/test/tests/integration/get_full_metadata/test_options.py +207 -0
  131. audiometa/test/tests/integration/get_full_metadata/test_performance.py +95 -0
  132. audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +128 -0
  133. audiometa/test/tests/integration/get_full_metadata/test_structure.py +161 -0
  134. audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
  135. audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
  136. audiometa/test/tests/integration/metadata_field/album/test_deleting.py +73 -0
  137. audiometa/test/tests/integration/metadata_field/album/test_reading.py +36 -0
  138. audiometa/test/tests/integration/metadata_field/album/test_writing.py +50 -0
  139. audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
  140. audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +83 -0
  141. audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +38 -0
  142. audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +52 -0
  143. audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
  144. audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +68 -0
  145. audiometa/test/tests/integration/metadata_field/artists/test_reading.py +36 -0
  146. audiometa/test/tests/integration/metadata_field/artists/test_writing.py +46 -0
  147. audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
  148. audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +75 -0
  149. audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +32 -0
  150. audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +56 -0
  151. audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
  152. audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +68 -0
  153. audiometa/test/tests/integration/metadata_field/comment/test_reading.py +36 -0
  154. audiometa/test/tests/integration/metadata_field/comment/test_writing.py +49 -0
  155. audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
  156. audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +75 -0
  157. audiometa/test/tests/integration/metadata_field/composer/test_reading.py +34 -0
  158. audiometa/test/tests/integration/metadata_field/composer/test_writing.py +41 -0
  159. audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
  160. audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +81 -0
  161. audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +35 -0
  162. audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +41 -0
  163. audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
  164. audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +97 -0
  165. audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +92 -0
  166. audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +153 -0
  167. audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
  168. audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +56 -0
  169. audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +54 -0
  170. audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +61 -0
  171. audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
  172. audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
  173. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
  174. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +65 -0
  175. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +25 -0
  176. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +58 -0
  177. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +61 -0
  178. audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +191 -0
  179. audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +62 -0
  180. audiometa/test/tests/integration/metadata_field/genre/test_writing.py +64 -0
  181. audiometa/test/tests/integration/metadata_field/isrc/__init__.py +1 -0
  182. audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +31 -0
  183. audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +35 -0
  184. audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +165 -0
  185. audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
  186. audiometa/test/tests/integration/metadata_field/language/test_deleting.py +75 -0
  187. audiometa/test/tests/integration/metadata_field/language/test_reading.py +39 -0
  188. audiometa/test/tests/integration/metadata_field/language/test_writing.py +43 -0
  189. audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
  190. audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +129 -0
  191. audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +57 -0
  192. audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +59 -0
  193. audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
  194. audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +88 -0
  195. audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +32 -0
  196. audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +47 -0
  197. audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
  198. audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
  199. audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +81 -0
  200. audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +33 -0
  201. audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +58 -0
  202. audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +117 -0
  203. audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +137 -0
  204. audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
  205. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
  206. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +77 -0
  207. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +55 -0
  208. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +57 -0
  209. audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +192 -0
  210. audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
  211. audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +74 -0
  212. audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +82 -0
  213. audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +59 -0
  214. audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +49 -0
  215. audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +135 -0
  216. audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
  217. audiometa/test/tests/integration/metadata_field/title/test_deleting.py +73 -0
  218. audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +47 -0
  219. audiometa/test/tests/integration/metadata_field/title/test_reading.py +36 -0
  220. audiometa/test/tests/integration/metadata_field/title/test_writing.py +64 -0
  221. audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
  222. audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
  223. audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +43 -0
  224. audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +32 -0
  225. audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +59 -0
  226. audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +73 -0
  227. audiometa/test/tests/integration/multiple_values/__init__.py +1 -0
  228. audiometa/test/tests/integration/multiple_values/reading/__init__.py +1 -0
  229. audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +1 -0
  230. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +23 -0
  231. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +92 -0
  232. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +216 -0
  233. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +84 -0
  234. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +169 -0
  235. audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +209 -0
  236. audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +198 -0
  237. audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +24 -0
  238. audiometa/test/tests/integration/multiple_values/writing/__init__.py +1 -0
  239. audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +1 -0
  240. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +62 -0
  241. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +36 -0
  242. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +34 -0
  243. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +32 -0
  244. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +54 -0
  245. audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +42 -0
  246. audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +98 -0
  247. audiometa/test/tests/integration/reading/__init__.py +1 -0
  248. audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +80 -0
  249. audiometa/test/tests/integration/reading/test_reading_error_handling.py +36 -0
  250. audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
  251. audiometa/test/tests/integration/real_audio_files/test_reading.py +146 -0
  252. audiometa/test/tests/integration/real_audio_files/test_writing.py +198 -0
  253. audiometa/test/tests/integration/technical_info/__init__.py +0 -0
  254. audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
  255. audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +103 -0
  256. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/__init__.py +0 -0
  257. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_audio_data_corruption.py +21 -0
  258. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_flipped_md5.py +29 -0
  259. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_non_flac_error.py +13 -0
  260. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_partial_md5.py +29 -0
  261. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_random_md5.py +29 -0
  262. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_unset_md5.py +56 -0
  263. audiometa/test/tests/integration/technical_info/flac_md5/test_valid_md5.py +21 -0
  264. audiometa/test/tests/integration/technical_info/test_bitrate.py +79 -0
  265. audiometa/test/tests/integration/technical_info/test_channels.py +38 -0
  266. audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +38 -0
  267. audiometa/test/tests/integration/technical_info/test_sample_rate.py +40 -0
  268. audiometa/test/tests/integration/test_audio_file.py +35 -0
  269. audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +95 -0
  270. audiometa/test/tests/integration/writing/__init__.py +0 -0
  271. audiometa/test/tests/integration/writing/test_error_handling.py +44 -0
  272. audiometa/test/tests/integration/writing/test_forced_format.py +224 -0
  273. audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +223 -0
  274. audiometa/test/tests/integration/writing/test_partial_update.py +36 -0
  275. audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
  276. audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +79 -0
  277. audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +76 -0
  278. audiometa/test/tests/integration/writing/writing_strategies/test_sync_strategy.py +215 -0
  279. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
  280. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +42 -0
  281. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +93 -0
  282. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +99 -0
  283. audiometa/test/tests/unit/__init__.py +0 -0
  284. audiometa/test/tests/unit/audio_file/__init__.py +0 -0
  285. audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
  286. audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +26 -0
  287. audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +31 -0
  288. audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +38 -0
  289. audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +190 -0
  290. audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +51 -0
  291. audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +28 -0
  292. audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +31 -0
  293. audiometa/test/tests/unit/audio_file/test_context_manager.py +30 -0
  294. audiometa/test/tests/unit/audio_file/test_file_validation.py +40 -0
  295. audiometa/test/tests/unit/audio_file/test_is_audio_file.py +49 -0
  296. audiometa/test/tests/unit/audio_file/test_operations.py +20 -0
  297. audiometa/test/tests/unit/audio_file/test_path_handling.py +23 -0
  298. audiometa/test/tests/unit/cli/__init__.py +0 -0
  299. audiometa/test/tests/unit/cli/test_expand_file_patterns.py +234 -0
  300. audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
  301. audiometa/test/tests/unit/metadata_managers/conftest.py +142 -0
  302. audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
  303. audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +49 -0
  304. audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +66 -0
  305. audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +343 -0
  306. audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +53 -0
  307. audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
  308. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
  309. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
  310. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +186 -0
  311. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
  312. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +142 -0
  313. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +76 -0
  314. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
  315. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
  316. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +152 -0
  317. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +23 -0
  318. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +77 -0
  319. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
  320. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +43 -0
  321. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +151 -0
  322. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +61 -0
  323. audiometa/test/tests/unit/metadata_managers/metadata_field/test_date_format_validation.py +135 -0
  324. audiometa/test/tests/unit/metadata_managers/metadata_field/test_disc_number_validation.py +75 -0
  325. audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_format_validation.py +121 -0
  326. audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_type_validation.py +30 -0
  327. audiometa/test/tests/unit/metadata_managers/metadata_field/test_track_number_validation.py +46 -0
  328. audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +22 -0
  329. audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +83 -0
  330. audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +74 -0
  331. audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +26 -0
  332. audiometa/utils/__init__.py +1 -0
  333. audiometa/utils/id3v1_genre_code_map.py +205 -0
  334. audiometa/utils/metadata_format.py +31 -0
  335. audiometa/utils/metadata_writing_strategy.py +16 -0
  336. audiometa/utils/mutagen_exception_handler.py +24 -0
  337. audiometa/utils/os_dependencies_checker/__init__.py +24 -0
  338. audiometa/utils/os_dependencies_checker/base.py +62 -0
  339. audiometa/utils/os_dependencies_checker/config.py +77 -0
  340. audiometa/utils/os_dependencies_checker/macos.py +236 -0
  341. audiometa/utils/os_dependencies_checker/ubuntu.py +95 -0
  342. audiometa/utils/os_dependencies_checker/windows.py +227 -0
  343. audiometa/utils/rating_profiles.py +110 -0
  344. audiometa/utils/tool_path_resolver.py +135 -0
  345. audiometa/utils/types.py +82 -0
  346. audiometa/utils/unified_metadata_key.py +87 -0
  347. audiometa_python-0.6.0.dist-info/METADATA +1593 -0
  348. audiometa_python-0.6.0.dist-info/RECORD +352 -0
  349. audiometa_python-0.6.0.dist-info/WHEEL +5 -0
  350. audiometa_python-0.6.0.dist-info/entry_points.txt +2 -0
  351. audiometa_python-0.6.0.dist-info/licenses/LICENSE +202 -0
  352. audiometa_python-0.6.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,73 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field, update_metadata
4
+ from audiometa.test.helpers.id3v1 import ID3v1MetadataSetter
5
+ from audiometa.test.helpers.id3v2 import ID3v2MetadataSetter
6
+ from audiometa.test.helpers.riff import RIFFMetadataSetter
7
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.test.helpers.vorbis import VorbisMetadataSetter
9
+ from audiometa.utils.metadata_format import MetadataFormat
10
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
11
+
12
+
13
+ @pytest.mark.integration
14
+ class TestTitleDeleting:
15
+ def test_delete_title_id3v2(self):
16
+ with temp_file_with_metadata({}, "mp3") as test_file:
17
+ ID3v2MetadataSetter.set_title(test_file, "Test Title")
18
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
19
+
20
+ # Delete metadata using library API
21
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: None}, metadata_format=MetadataFormat.ID3V2)
22
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
23
+
24
+ def test_delete_title_id3v1(self):
25
+ with temp_file_with_metadata({}, "id3v1") as test_file:
26
+ ID3v1MetadataSetter.set_title(test_file, "Test Title")
27
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
28
+
29
+ # Delete metadata using library API
30
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: None}, metadata_format=MetadataFormat.ID3V1)
31
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
32
+
33
+ def test_delete_title_riff(self):
34
+ with temp_file_with_metadata({}, "wav") as test_file:
35
+ RIFFMetadataSetter.set_title(test_file, "Test Title")
36
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
37
+
38
+ # Delete metadata using library API
39
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: None}, metadata_format=MetadataFormat.RIFF)
40
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
41
+
42
+ def test_delete_title_vorbis(self):
43
+ with temp_file_with_metadata({}, "flac") as test_file:
44
+ VorbisMetadataSetter.add_title(test_file, "Test Title")
45
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
46
+
47
+ # Delete metadata using library API
48
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: None}, metadata_format=MetadataFormat.VORBIS)
49
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
50
+
51
+ def test_delete_title_preserves_other_fields(self):
52
+ with temp_file_with_metadata({}, "mp3") as test_file:
53
+ ID3v2MetadataSetter.set_title(test_file, "Test Title")
54
+ ID3v2MetadataSetter.set_artists(test_file, "Test Artist")
55
+ ID3v2MetadataSetter.set_album(test_file, "Test Album")
56
+
57
+ # Delete only title using library API
58
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: None}, metadata_format=MetadataFormat.ID3V2)
59
+
60
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
61
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.ARTISTS) == ["Test Artist"]
62
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.ALBUM) == "Test Album"
63
+
64
+ def test_delete_title_already_none(self):
65
+ with temp_file_with_metadata({}, "mp3") as test_file:
66
+ # Try to delete title that doesn't exist
67
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: None}, metadata_format=MetadataFormat.ID3V2)
68
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
69
+
70
+ def test_delete_title_empty_string(self):
71
+ with temp_file_with_metadata({}, "mp3") as test_file:
72
+ update_metadata(test_file, {UnifiedMetadataKey.TITLE: ""}, metadata_format=MetadataFormat.ID3V2)
73
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) is None
@@ -0,0 +1,47 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+ from audiometa import get_unified_metadata_field, update_metadata
6
+ from audiometa.exceptions import FileTypeNotSupportedError
7
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
9
+
10
+
11
+ @pytest.mark.integration
12
+ class TestTitleErrorHandling:
13
+ def test_title_unsupported_file_type(self):
14
+ with temp_file_with_metadata({}, "mp3") as temp_file_path:
15
+ temp_file_path.write_bytes(b"fake audio content")
16
+ temp_txt = temp_file_path.with_suffix(".txt")
17
+ temp_txt.write_bytes(b"fake audio content")
18
+
19
+ with pytest.raises(FileTypeNotSupportedError):
20
+ get_unified_metadata_field(str(temp_txt), UnifiedMetadataKey.TITLE)
21
+
22
+ with pytest.raises(FileTypeNotSupportedError):
23
+ update_metadata(str(temp_txt), {UnifiedMetadataKey.TITLE: "Test Title"})
24
+
25
+ def test_title_nonexistent_file(self):
26
+ nonexistent_file = "nonexistent_file.mp3"
27
+
28
+ with pytest.raises(FileNotFoundError):
29
+ get_unified_metadata_field(nonexistent_file, UnifiedMetadataKey.TITLE)
30
+
31
+ with pytest.raises(FileNotFoundError):
32
+ update_metadata(nonexistent_file, {UnifiedMetadataKey.TITLE: "Test Title"})
33
+
34
+ def test_title_empty_values(self, sample_mp3_file: Path):
35
+ # Test with empty title values using temp file with sample content
36
+ with temp_file_with_metadata({}, "mp3") as temp_file_path:
37
+ temp_file_path.write_bytes(sample_mp3_file.read_bytes())
38
+
39
+ # Empty string should be handled gracefully
40
+ update_metadata(temp_file_path, {UnifiedMetadataKey.TITLE: ""})
41
+ title = get_unified_metadata_field(temp_file_path, UnifiedMetadataKey.TITLE)
42
+ assert title == "" or title is None
43
+
44
+ # None should be handled gracefully
45
+ update_metadata(temp_file_path, {UnifiedMetadataKey.TITLE: None})
46
+ title = get_unified_metadata_field(temp_file_path, UnifiedMetadataKey.TITLE)
47
+ assert title is None or title == ""
@@ -0,0 +1,36 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.id3v1 import ID3v1MetadataSetter
5
+ from audiometa.test.helpers.id3v2 import ID3v2MetadataSetter
6
+ from audiometa.test.helpers.riff import RIFFMetadataSetter
7
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.test.helpers.vorbis import VorbisMetadataSetter
9
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
10
+
11
+
12
+ @pytest.mark.integration
13
+ class TestTitleReading:
14
+ def test_id3v1(self):
15
+ with temp_file_with_metadata({"title": "Test Song"}, "id3v1") as test_file:
16
+ ID3v1MetadataSetter.set_max_metadata(test_file)
17
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
18
+ assert title == "a" * 30
19
+
20
+ def test_id3v2(self):
21
+ with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
22
+ ID3v2MetadataSetter.set_max_metadata(test_file)
23
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
24
+ assert title == "a" * 1000
25
+
26
+ def test_vorbis(self):
27
+ with temp_file_with_metadata({"title": "Test Song"}, "flac") as test_file:
28
+ VorbisMetadataSetter.set_max_metadata(test_file)
29
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
30
+ assert title == "a" * 1000
31
+
32
+ def test_riff(self):
33
+ with temp_file_with_metadata({"title": "Test Song"}, "wav") as test_file:
34
+ RIFFMetadataSetter.set_max_metadata(test_file)
35
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
36
+ assert title == "a" * 1000
@@ -0,0 +1,64 @@
1
+ """Tests for writing title metadata using external scripts.
2
+
3
+ This refactored version uses external scripts instead of the app's update functions to prevent circular dependencies in
4
+ tests.
5
+ """
6
+
7
+ import pytest
8
+
9
+ from audiometa import get_unified_metadata_field
10
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
11
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
12
+
13
+
14
+ @pytest.mark.integration
15
+ class TestTitleWriting:
16
+ def test_id3v2(self):
17
+ test_title = "Test Title ID3v2"
18
+ test_metadata = {"title": test_title}
19
+
20
+ # Use external script to set metadata instead of app's update function
21
+ with temp_file_with_metadata(test_metadata, "mp3") as test_file:
22
+ # Now test that our reading logic works correctly
23
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
24
+ assert title == test_title
25
+
26
+ def test_riff(self):
27
+ test_title = "Test Title RIFF"
28
+ test_metadata = {"title": test_title}
29
+
30
+ # Use external script to set metadata instead of app's update function
31
+ with temp_file_with_metadata(test_metadata, "wav") as test_file:
32
+ # Now test that our reading logic works correctly
33
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
34
+ assert title == test_title
35
+
36
+ def test_vorbis(self):
37
+ test_title = "Test Title Vorbis"
38
+ test_metadata = {"title": test_title}
39
+
40
+ # Use external script to set metadata instead of app's update function
41
+ with temp_file_with_metadata(test_metadata, "flac") as test_file:
42
+ # Now test that our reading logic works correctly
43
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
44
+ assert title == test_title
45
+
46
+ def test_id3v1(self):
47
+ from audiometa import update_metadata
48
+ from audiometa.utils.metadata_format import MetadataFormat
49
+
50
+ with temp_file_with_metadata({}, "mp3") as test_file:
51
+ test_title = "Test Title ID3v1"
52
+ test_metadata = {UnifiedMetadataKey.TITLE: test_title}
53
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V1)
54
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
55
+ assert title == test_title
56
+
57
+ def test_invalid_type_raises(self):
58
+ from audiometa import update_metadata
59
+ from audiometa.exceptions import InvalidMetadataFieldTypeError
60
+
61
+ with temp_file_with_metadata({}, "mp3") as test_file:
62
+ bad_metadata = {UnifiedMetadataKey.TITLE: 123}
63
+ with pytest.raises(InvalidMetadataFieldTypeError):
64
+ update_metadata(test_file, bad_metadata)
@@ -0,0 +1,43 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
5
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
6
+
7
+
8
+ @pytest.mark.integration
9
+ class TestTrackNumberReadingEdgeCases:
10
+ def test_trailing_slash(self):
11
+ with temp_file_with_metadata({"track_number": "5/"}, "mp3") as test_file:
12
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
13
+ assert track_number == "5/"
14
+
15
+ def test_leading_slash_no_track(self):
16
+ with temp_file_with_metadata({"track_number": "/12"}, "mp3") as test_file:
17
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
18
+ assert track_number is None
19
+
20
+ def test_non_numeric_values(self):
21
+ with temp_file_with_metadata({"track_number": "abc/def"}, "mp3") as test_file:
22
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
23
+ assert track_number is None
24
+
25
+ def test_empty_string(self):
26
+ with temp_file_with_metadata({"track_number": ""}, "mp3") as test_file:
27
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
28
+ assert track_number is None
29
+
30
+ def test_multiple_slashes(self):
31
+ with temp_file_with_metadata({"track_number": "5/12/15"}, "mp3") as test_file:
32
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
33
+ assert track_number is None
34
+
35
+ def test_different_separator(self):
36
+ with temp_file_with_metadata({"track_number": "5-12"}, "mp3") as test_file:
37
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
38
+ assert track_number == "5-12"
39
+
40
+ def test_leading_zeros_preserved(self):
41
+ with temp_file_with_metadata({"track_number": "01"}, "mp3") as test_file:
42
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
43
+ assert track_number == "01"
@@ -0,0 +1,32 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.id3v1.id3v1_metadata_getter import ID3v1MetadataGetter
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 TestTrackNumberReading:
11
+ def test_id3v1_1(self):
12
+ with temp_file_with_metadata({"title": "Test Song", "track": "99"}, "id3v1") as test_file:
13
+ raw_metadata = ID3v1MetadataGetter.get_raw_metadata(test_file)
14
+ assert raw_metadata.get("track") == 99
15
+
16
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
17
+ assert track_number == "99"
18
+
19
+ def test_id3v2(self):
20
+ with temp_file_with_metadata({"title": "Test Song", "track_number": "99/99"}, "mp3") as test_file:
21
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
22
+ assert track_number == "99/99"
23
+
24
+ def test_vorbis(self):
25
+ with temp_file_with_metadata({"title": "Test Song", "track_number": "99"}, "flac") as test_file:
26
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
27
+ assert track_number == "99"
28
+
29
+ def test_riff(self):
30
+ with temp_file_with_metadata({"title": "Test Song", "track_number": None}, "wav") as test_file:
31
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
32
+ assert track_number is None
@@ -0,0 +1,59 @@
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 TestTrackNumberDeleting:
11
+ def test_delete_track_number_id3v2(self):
12
+ with temp_file_with_metadata({}, "mp3") as test_file:
13
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: 5}, metadata_format=MetadataFormat.ID3V2)
14
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) == "5"
15
+
16
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: None}, metadata_format=MetadataFormat.ID3V2)
17
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) is None
18
+
19
+ def test_delete_track_number_id3v1(self):
20
+ with temp_file_with_metadata({}, "mp3") as test_file:
21
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: 3}, metadata_format=MetadataFormat.ID3V1)
22
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) == "3"
23
+
24
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: None}, metadata_format=MetadataFormat.ID3V1)
25
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) is None
26
+
27
+ def test_delete_track_number_preserves_other_fields(self):
28
+ with temp_file_with_metadata({}, "mp3") as test_file:
29
+ update_metadata(
30
+ test_file,
31
+ {
32
+ UnifiedMetadataKey.TRACK_NUMBER: 7,
33
+ UnifiedMetadataKey.TITLE: "Test Title",
34
+ UnifiedMetadataKey.ARTISTS: ["Test Artist"],
35
+ },
36
+ )
37
+
38
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: None})
39
+
40
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) is None
41
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
42
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.ARTISTS) == ["Test Artist"]
43
+
44
+ def test_delete_track_number_already_none(self):
45
+ with temp_file_with_metadata({}, "mp3") as test_file:
46
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: None})
47
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) is None
48
+
49
+ def test_delete_track_number_zero(self):
50
+ with temp_file_with_metadata({}, "mp3") as test_file:
51
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: 0})
52
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) == "0"
53
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: None})
54
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) is None
55
+
56
+ def test_delete_track_number_empty_string(self):
57
+ with temp_file_with_metadata({}, "mp3") as test_file:
58
+ update_metadata(test_file, {UnifiedMetadataKey.TRACK_NUMBER: ""}, metadata_format=MetadataFormat.ID3V2)
59
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER) is None
@@ -0,0 +1,73 @@
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 TestTrackNumberWriting:
11
+ @pytest.mark.parametrize(
12
+ ("input_value", "expected"),
13
+ [
14
+ (5, "5"),
15
+ ("5", "5"),
16
+ ("5/12", "5"),
17
+ ("99/99", "99"),
18
+ ],
19
+ )
20
+ def test_id3v1_track_number_writing(self, input_value, expected):
21
+ with temp_file_with_metadata({}, "mp3") as test_file:
22
+ test_metadata = {UnifiedMetadataKey.TRACK_NUMBER: input_value}
23
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V1)
24
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
25
+ assert track_number == expected
26
+
27
+ @pytest.mark.parametrize(
28
+ ("input_value", "expected"),
29
+ [
30
+ (5, "5"),
31
+ ("5", "5"),
32
+ ("5/12", "5/12"),
33
+ ("99/99", "99/99"),
34
+ ],
35
+ )
36
+ def test_id3v2_track_number_writing(self, input_value, expected):
37
+ with temp_file_with_metadata({}, "mp3") as test_file:
38
+ test_metadata = {UnifiedMetadataKey.TRACK_NUMBER: input_value}
39
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2)
40
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
41
+ assert track_number == expected
42
+
43
+ @pytest.mark.parametrize(
44
+ ("input_value", "expected"),
45
+ [
46
+ (5, "5"),
47
+ ("5", "5"),
48
+ ("5/12", "5/12"),
49
+ ("99/99", "99/99"),
50
+ ],
51
+ )
52
+ def test_riff_track_number_writing(self, input_value, expected):
53
+ with temp_file_with_metadata({}, "wav") as test_file:
54
+ test_metadata = {UnifiedMetadataKey.TRACK_NUMBER: input_value}
55
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.RIFF)
56
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
57
+ assert track_number == expected
58
+
59
+ @pytest.mark.parametrize(
60
+ ("input_value", "expected"),
61
+ [
62
+ (5, "5"),
63
+ ("5", "5"),
64
+ ("5/12", "5/12"),
65
+ ("99/99", "99/99"),
66
+ ],
67
+ )
68
+ def test_vorbis_track_number_writing(self, input_value, expected):
69
+ with temp_file_with_metadata({}, "flac") as test_file:
70
+ test_metadata = {UnifiedMetadataKey.TRACK_NUMBER: input_value}
71
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.VORBIS)
72
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
73
+ assert track_number == expected
@@ -0,0 +1 @@
1
+ """Tests for multiple entries for the same tag."""
@@ -0,0 +1 @@
1
+ """Tests for reading multiple entries for the same tag."""
@@ -0,0 +1 @@
1
+ """Tests for reading multiple entries for the same tag in different metadata formats."""
@@ -0,0 +1,23 @@
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.temp_file_with_metadata import temp_file_with_metadata
6
+ from audiometa.utils.metadata_format import MetadataFormat
7
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
8
+
9
+
10
+ @pytest.mark.integration
11
+ class TestId3v1:
12
+ def test_semicolon_separated_artists(self):
13
+ with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
14
+ ID3v1MetadataSetter.set_artist(test_file, "Artist One;Artist Two")
15
+
16
+ artists = get_unified_metadata_field(
17
+ test_file, UnifiedMetadataKey.ARTISTS, metadata_format=MetadataFormat.ID3V1
18
+ )
19
+
20
+ assert isinstance(artists, list)
21
+ assert len(artists) == 2
22
+ assert "Artist One" in artists
23
+ assert "Artist Two" in artists
@@ -0,0 +1,92 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.id3v2 import ID3v2HeaderVerifier
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.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.utils.metadata_format import MetadataFormat
9
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
10
+
11
+
12
+ @pytest.mark.integration
13
+ class TestId3v23:
14
+ def test_semicolon_separated_artists(self):
15
+ with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
16
+ ID3v2MetadataSetter.set_artists(
17
+ test_file, ["Artist One;Artist Two;Artist Three"], in_separate_frames=False, version="2.3"
18
+ )
19
+
20
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 3, 0)
21
+
22
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
23
+ assert raw_metadata["TPE1"] == ["Artist One;Artist Two;Artist Three"]
24
+
25
+ artists = get_unified_metadata_field(
26
+ test_file,
27
+ unified_metadata_key=UnifiedMetadataKey.ARTISTS,
28
+ metadata_format=MetadataFormat.ID3V2,
29
+ id3v2_version=(2, 3, 0),
30
+ )
31
+
32
+ assert isinstance(artists, list)
33
+ assert len(artists) == 3
34
+ assert "Artist One" in artists
35
+ assert "Artist Two" in artists
36
+ assert "Artist Three" in artists
37
+
38
+ def test_multiple_entries(self):
39
+ with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
40
+ ID3v2MetadataSetter.set_artists(test_file, ["One", "Two", "Three"], version="2.3", in_separate_frames=True)
41
+
42
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 3, 0)
43
+
44
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
45
+ assert raw_metadata["TPE1"] == ["One", "Two", "Three"]
46
+
47
+ artists = get_unified_metadata_field(
48
+ test_file, UnifiedMetadataKey.ARTISTS, metadata_format=MetadataFormat.ID3V2
49
+ )
50
+
51
+ assert isinstance(artists, list)
52
+ assert len(artists) == 3
53
+ assert "One" in artists
54
+ assert "Two" in artists
55
+ assert "Three" in artists
56
+
57
+ def test_mixed_separators_and_multiple_entries(self):
58
+ with temp_file_with_metadata({"title": "Test Song"}, "id3v2.3") as test_file:
59
+ ID3v2MetadataSetter.set_artists(
60
+ test_file, ["Artist 1;Artist 2", "Artist 3"], version="2.3", in_separate_frames=True
61
+ )
62
+
63
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 3, 0)
64
+
65
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
66
+ assert raw_metadata["TPE1"] == ["Artist 1;Artist 2", "Artist 3"]
67
+
68
+ artists = get_unified_metadata_field(
69
+ test_file, UnifiedMetadataKey.ARTISTS, metadata_format=MetadataFormat.ID3V2
70
+ )
71
+ assert isinstance(artists, list)
72
+ assert len(artists) == 2
73
+ assert "Artist 1;Artist 2" in artists
74
+ assert "Artist 3" in artists
75
+
76
+ def test_multiple_title_entries_then_first_one(self):
77
+ with temp_file_with_metadata({"title": "Initial Title"}, "mp3") as test_file:
78
+ ID3v2MetadataSetter.set_titles(
79
+ test_file, ["Title One", "Title Two", "Title Three"], version="2.3", in_separate_frames=True
80
+ )
81
+
82
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 3, 0)
83
+
84
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
85
+ assert raw_metadata["TIT2"] == ["Title One", "Title Two", "Title Three"]
86
+
87
+ title = get_unified_metadata_field(
88
+ test_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.ID3V2
89
+ )
90
+
91
+ assert isinstance(title, str)
92
+ assert title == "Title One"