diff --git a/beets/test/_common.py b/beets/test/_common.py index da81a587c..7c7defb02 100644 --- a/beets/test/_common.py +++ b/beets/test/_common.py @@ -18,6 +18,7 @@ import os import sys import unittest from contextlib import contextmanager +from pathlib import Path import beets import beets.library @@ -114,23 +115,15 @@ def import_session(lib=None, loghandler=None, paths=[], query=[], cli=False): class Assertions: """A mixin with additional unit test assertions.""" - def assertExists(self, path): - assert os.path.exists(syspath(path)), f"file does not exist: {path!r}" - - def assertNotExists(self, path): - assert not os.path.exists(syspath(path)), f"file exists: {path!r}" - def assertIsFile(self, path): - self.assertExists(path) - assert os.path.isfile(syspath(path)), ( - "path exists, but is not a regular file: {!r}".format(path) - ) + path = Path(os.fsdecode(path)) + assert path.exists() + assert path.is_file() def assertIsDir(self, path): - self.assertExists(path) - assert os.path.isdir(syspath(path)), ( - "path exists, but is not a directory: {!r}".format(path) - ) + path = Path(os.fsdecode(path)) + assert path.exists() + assert path.is_dir() def assert_equal_path(self, a, b): """Check that two paths are equal.""" diff --git a/beets/test/helper.py b/beets/test/helper.py index b6bd23f5c..6027aaede 100644 --- a/beets/test/helper.py +++ b/beets/test/helper.py @@ -184,6 +184,8 @@ class TestHelper(_common.Assertions, ConfigMixin): fixtures. """ + resource_path = Path(os.fsdecode(_common.RSRC)) / "full.mp3" + db_on_disk: ClassVar[bool] = False @cached_property @@ -194,6 +196,16 @@ class TestHelper(_common.Assertions, ConfigMixin): def temp_dir(self) -> bytes: return util.bytestring_path(self.temp_dir_path) + @cached_property + def lib_path(self) -> Path: + lib_path = self.temp_dir_path / "libdir" + lib_path.mkdir(exist_ok=True) + return lib_path + + @cached_property + def libdir(self) -> bytes: + return bytestring_path(self.lib_path) + # TODO automate teardown through hook registration def setup_beets(self): @@ -226,9 +238,7 @@ class TestHelper(_common.Assertions, ConfigMixin): ) self.env_patcher.start() - self.libdir = os.path.join(self.temp_dir, b"libdir") - os.mkdir(syspath(self.libdir)) - self.config["directory"] = os.fsdecode(self.libdir) + self.config["directory"] = str(self.lib_path) if self.db_on_disk: dbpath = util.bytestring_path(self.config["library"].as_filename()) @@ -527,7 +537,6 @@ class ImportHelper(TestHelper): autotagging library and several assertions for the library. """ - resource_path = syspath(os.path.join(_common.RSRC, b"full.mp3")) default_import_config = { "autotag": True, "copy": True, @@ -612,7 +621,7 @@ class ImportHelper(TestHelper): ] def prepare_albums_for_import(self, count: int = 1) -> None: - album_dirs = Path(os.fsdecode(self.import_dir)).glob("album_*") + album_dirs = self.import_path.glob("album_*") base_idx = int(str(max(album_dirs, default="0")).split("_")[-1]) + 1 for album_id in range(base_idx, count + base_idx): @@ -640,13 +649,13 @@ class ImportHelper(TestHelper): """Join the ``segments`` and assert that this path exists in the library directory. """ - self.assertExists(os.path.join(self.libdir, *segments)) + assert self.lib_path.joinpath(*segments).exists() def assert_file_not_in_lib(self, *segments): """Join the ``segments`` and assert that this path does not exist in the library directory. """ - self.assertNotExists(os.path.join(self.libdir, *segments)) + assert not self.lib_path.joinpath(*segments).exists() def assert_lib_dir_empty(self): assert not os.listdir(syspath(self.libdir)) diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 25af95646..7b22c2462 100755 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -2122,12 +2122,20 @@ default_commands.append(modify_cmd) def move_items( - lib, dest, query, copy, album, pretend, confirm=False, export=False + lib, + dest_path: util.PathLike, + query, + copy, + album, + pretend, + confirm=False, + export=False, ): """Moves or copies items to a new base directory, given by dest. If dest is None, then the library's base directory is used, making the command "consolidate" files. """ + dest = os.fsencode(dest_path) if dest_path else dest_path items, albums = _do_query(lib, query, album, False) objs = albums if album else items num_objs = len(objs) diff --git a/test/plugins/test_art.py b/test/plugins/test_art.py index 9f5817108..45effa9b9 100644 --- a/test/plugins/test_art.py +++ b/test/plugins/test_art.py @@ -245,13 +245,13 @@ class FetchImageTest(FetchImageTestCase): self.mock_response(self.URL, "image/png") self.source.fetch_image(self.candidate, self.settings) assert os.path.splitext(self.candidate.path)[1] == b".png" - self.assertExists(self.candidate.path) + assert Path(os.fsdecode(self.candidate.path)).exists() def test_does_not_rely_on_server_content_type(self): self.mock_response(self.URL, "image/jpeg", "image/png") self.source.fetch_image(self.candidate, self.settings) assert os.path.splitext(self.candidate.path)[1] == b".png" - self.assertExists(self.candidate.path) + assert Path(os.fsdecode(self.candidate.path)).exists() class FSArtTest(UseThePlugin): @@ -749,8 +749,8 @@ class ArtImporterTest(UseThePlugin): super().setUp() # Mock the album art fetcher to always return our test file. - self.art_file = os.path.join(self.temp_dir, b"tmpcover.jpg") - _common.touch(self.art_file) + self.art_file = self.temp_dir_path / "tmpcover.jpg" + self.art_file.touch() self.old_afa = self.plugin.art_for_album self.afa_response = fetchart.Candidate( logger, @@ -827,20 +827,20 @@ class ArtImporterTest(UseThePlugin): def test_leave_original_file_in_place(self): self._fetch_art(True) - self.assertExists(self.art_file) + assert self.art_file.exists() def test_delete_original_file(self): prev_move = config["import"]["move"].get() try: config["import"]["move"] = True self._fetch_art(True) - self.assertNotExists(self.art_file) + assert not self.art_file.exists() finally: config["import"]["move"] = prev_move def test_do_not_delete_original_if_already_in_place(self): artdest = os.path.join(os.path.dirname(self.i.path), b"cover.jpg") - shutil.copyfile(syspath(self.art_file), syspath(artdest)) + shutil.copyfile(self.art_file, syspath(artdest)) self.afa_response = fetchart.Candidate( logger, source_name="test", @@ -899,7 +899,7 @@ class ArtForAlbumTest(UseThePlugin): super().tearDown() def assertImageIsValidArt(self, image_file, should_exist): - self.assertExists(image_file) + assert Path(os.fsdecode(image_file)).exists() self.image_file = image_file candidate = self.plugin.art_for_album(self.album, [""], True) @@ -907,7 +907,7 @@ class ArtForAlbumTest(UseThePlugin): if should_exist: assert candidate is not None assert candidate.path == self.image_file - self.assertExists(candidate.path) + assert Path(os.fsdecode(candidate.path)).exists() else: assert candidate is None diff --git a/test/plugins/test_convert.py b/test/plugins/test_convert.py index 6dd28337a..c57f0c935 100644 --- a/test/plugins/test_convert.py +++ b/test/plugins/test_convert.py @@ -18,6 +18,7 @@ import os.path import re import sys import unittest +from pathlib import Path import pytest from mediafile import MediaFile @@ -190,8 +191,9 @@ class ConvertCliTest(ConvertTestCase, ConvertCommand): def test_reject_confirmation(self): with control_stdin("n"): self.run_convert() - converted = os.path.join(self.convert_dest, b"converted.mp3") - self.assertNotExists(converted) + assert not ( + Path(os.fsdecode(self.convert_dest)) / "converted.mp3" + ).exists() def test_convert_keep_new(self): assert os.path.splitext(self.item.path)[1] == b".ogg" @@ -231,8 +233,9 @@ class ConvertCliTest(ConvertTestCase, ConvertCommand): def test_pretend(self): self.run_convert("--pretend") - converted = os.path.join(self.convert_dest, b"converted.mp3") - self.assertNotExists(converted) + assert not ( + Path(os.fsdecode(self.convert_dest)) / "converted.mp3" + ).exists() def test_empty_query(self): with capture_log("beets.convert") as logs: diff --git a/test/plugins/test_embedart.py b/test/plugins/test_embedart.py index 1b8528cb7..62b2bb7d1 100644 --- a/test/plugins/test_embedart.py +++ b/test/plugins/test_embedart.py @@ -13,6 +13,7 @@ # included in all copies or substantial portions of the Software. +import os import os.path import shutil import tempfile @@ -207,7 +208,7 @@ class EmbedartCliTest(IOMixin, PluginMixin, FetchImageHelper, BeetsTestCase): self.run_command("extractart", "-n", "extracted") - self.assertExists(album.filepath / "extracted.png") + assert (album.filepath / "extracted.png").exists() def test_extracted_extension(self): resource_path = os.path.join(_common.RSRC, b"image-jpeg.mp3") @@ -217,7 +218,7 @@ class EmbedartCliTest(IOMixin, PluginMixin, FetchImageHelper, BeetsTestCase): self.run_command("extractart", "-n", "extracted") - self.assertExists(album.filepath / "extracted.jpg") + assert (album.filepath / "extracted.jpg").exists() def test_clear_art_with_yes_input(self): self._setup_data() diff --git a/test/test_art_resize.py b/test/test_art_resize.py index 8dd4d0e89..34bf810b9 100644 --- a/test/test_art_resize.py +++ b/test/test_art_resize.py @@ -16,6 +16,7 @@ import os import unittest +from pathlib import Path from unittest.mock import patch from beets.test import _common @@ -65,7 +66,7 @@ class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): max_filesize=0, ) # check valid path returned - max_filesize hasn't broken resize command - self.assertExists(im_95_qual) + assert Path(os.fsdecode(im_95_qual)).exists() # Attempt a lower filesize with same quality im_a = backend.resize( @@ -74,7 +75,7 @@ class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): quality=95, max_filesize=0.9 * os.stat(syspath(im_95_qual)).st_size, ) - self.assertExists(im_a) + assert Path(os.fsdecode(im_a)).exists() # target size was achieved assert ( os.stat(syspath(im_a)).st_size @@ -88,7 +89,7 @@ class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): quality=75, max_filesize=0, ) - self.assertExists(im_75_qual) + assert Path(os.fsdecode(im_75_qual)).exists() im_b = backend.resize( 225, @@ -96,7 +97,7 @@ class ArtResizerFileSizeTest(CleanupModulesMixin, BeetsTestCase): quality=95, max_filesize=0.9 * os.stat(syspath(im_75_qual)).st_size, ) - self.assertExists(im_b) + assert Path(os.fsdecode(im_b)).exists() # Check high (initial) quality still gives a smaller filesize assert ( os.stat(syspath(im_b)).st_size diff --git a/test/test_importer.py b/test/test_importer.py index c23b56d7a..4fbcbf9dd 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -83,23 +83,25 @@ class NonAutotaggedImportTest(AsIsImporterMixin, ImportTestCase): def test_import_with_move_deletes_import_files(self): for mediafile in self.import_media: - self.assertExists(mediafile.path) + assert Path(mediafile.path).exists() self.run_asis_importer(move=True) for mediafile in self.import_media: - self.assertNotExists(mediafile.path) + assert not Path(mediafile.path).exists() def test_import_with_move_prunes_directory_empty(self): - self.assertExists(os.path.join(self.import_dir, b"album")) + album_path = self.import_path / "album" + assert album_path.exists() self.run_asis_importer(move=True) - self.assertNotExists(os.path.join(self.import_dir, b"album")) + assert not album_path.exists() def test_import_with_move_prunes_with_extra_clutter(self): self.touch(os.path.join(self.import_dir, b"album", b"alog.log")) config["clutter"] = ["*.log"] - self.assertExists(os.path.join(self.import_dir, b"album")) + album_path = self.import_path / "album" + assert album_path.exists() self.run_asis_importer(move=True) - self.assertNotExists(os.path.join(self.import_dir, b"album")) + assert not album_path.exists() def test_threaded_import_move_arrives(self): self.run_asis_importer(move=True, threaded=True) @@ -113,22 +115,23 @@ class NonAutotaggedImportTest(AsIsImporterMixin, ImportTestCase): def test_threaded_import_move_deletes_import(self): self.run_asis_importer(move=True, threaded=True) for mediafile in self.import_media: - self.assertNotExists(mediafile.path) + assert not Path(mediafile.path).exists() def test_import_without_delete_retains_files(self): self.run_asis_importer(delete=False) for mediafile in self.import_media: - self.assertExists(mediafile.path) + assert Path(mediafile.path).exists() def test_import_with_delete_removes_files(self): self.run_asis_importer(delete=True) for mediafile in self.import_media: - self.assertNotExists(mediafile.path) + assert not Path(mediafile.path).exists() def test_import_with_delete_prunes_directory_empty(self): - self.assertExists(os.path.join(self.import_dir, b"album")) + album_path = self.import_path / "album" + assert album_path.exists() self.run_asis_importer(delete=True) - self.assertNotExists(os.path.join(self.import_dir, b"album")) + assert not album_path.exists() def test_album_mb_albumartistids(self): self.run_asis_importer() @@ -139,32 +142,24 @@ class NonAutotaggedImportTest(AsIsImporterMixin, ImportTestCase): def test_import_link_arrives(self): self.run_asis_importer(link=True) for mediafile in self.import_media: - filename = os.path.join( - self.libdir, - b"Tag Artist", - b"Tag Album", - util.bytestring_path(f"{mediafile.title}.mp3"), - ) - self.assertExists(filename) - assert os.path.islink(syspath(filename)) - self.assert_equal_path( - util.bytestring_path(os.readlink(syspath(filename))), - mediafile.path, + path = ( + self.lib_path / "Tag Artist" / "Tag Album" / "Tag Track 1.mp3" ) + assert path.exists() + assert path.is_symlink() + self.assert_equal_path(path.resolve(), mediafile.path) @unittest.skipUnless(_common.HAVE_HARDLINK, "need hardlinks") def test_import_hardlink_arrives(self): self.run_asis_importer(hardlink=True) for mediafile in self.import_media: - filename = os.path.join( - self.libdir, - b"Tag Artist", - b"Tag Album", - util.bytestring_path(f"{mediafile.title}.mp3"), + path = ( + self.lib_path / "Tag Artist" / "Tag Album" / "Tag Track 1.mp3" ) - self.assertExists(filename) + assert path.exists() + s1 = os.stat(syspath(mediafile.path)) - s2 = os.stat(syspath(filename)) + s2 = path.stat() assert (s1[stat.ST_INO], s1[stat.ST_DEV]) == ( s2[stat.ST_INO], s2[stat.ST_DEV], @@ -219,10 +214,10 @@ class RmTempTest(BeetsTestCase): zip_path = create_archive(self) archive_task = importer.ArchiveImportTask(zip_path) archive_task.extract() - tmp_path = archive_task.toppath - self.assertExists(tmp_path) + tmp_path = Path(os.fsdecode(archive_task.toppath)) + assert tmp_path.exists() archive_task.finalize(self) - self.assertNotExists(tmp_path) + assert not tmp_path.exists() class ImportZipTest(AsIsImporterMixin, ImportTestCase): @@ -467,22 +462,22 @@ class ImportTest(AutotagImportTestCase): def test_apply_with_move_deletes_import(self): config["import"]["move"] = True - import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3") - self.assertExists(import_file) + track_path = Path(self.import_media[0].path) + assert track_path.exists() self.importer.add_choice(importer.Action.APPLY) self.importer.run() - self.assertNotExists(import_file) + assert not track_path.exists() def test_apply_with_delete_deletes_import(self): config["import"]["delete"] = True - import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3") - self.assertExists(import_file) + track_path = Path(self.import_media[0].path) + assert track_path.exists() self.importer.add_choice(importer.Action.APPLY) self.importer.run() - self.assertNotExists(import_file) + assert not track_path.exists() def test_skip_does_not_add_track(self): self.importer.add_choice(importer.Action.SKIP) @@ -835,7 +830,7 @@ class ImportExistingTest(AutotagImportTestCase): self.reimporter = self.setup_importer(move=True) self.reimporter.add_choice(importer.Action.APPLY) self.reimporter.run() - self.assertNotExists(self.import_media[0].path) + assert not Path(self.import_media[0].path).exists() class GroupAlbumsImportTest(AutotagImportTestCase): @@ -1051,12 +1046,12 @@ class ImportDuplicateAlbumTest(PluginMixin, ImportTestCase): def test_remove_duplicate_album(self): item = self.lib.items().get() assert item.title == "t\xeftle 0" - self.assertExists(item.path) + assert item.filepath.exists() self.importer.default_resolution = self.importer.Resolution.REMOVE self.importer.run() - self.assertNotExists(item.path) + assert not item.filepath.exists() assert len(self.lib.albums()) == 1 assert len(self.lib.items()) == 1 item = self.lib.items().get() @@ -1066,7 +1061,7 @@ class ImportDuplicateAlbumTest(PluginMixin, ImportTestCase): config["import"]["autotag"] = False item = self.lib.items().get() assert item.title == "t\xeftle 0" - self.assertExists(item.path) + assert item.filepath.exists() # Imported item has the same artist and album as the one in the # library. @@ -1082,7 +1077,7 @@ class ImportDuplicateAlbumTest(PluginMixin, ImportTestCase): self.importer.default_resolution = self.importer.Resolution.REMOVE self.importer.run() - self.assertExists(item.path) + assert item.filepath.exists() assert len(self.lib.albums()) == 2 assert len(self.lib.items()) == 2 @@ -1169,12 +1164,12 @@ class ImportDuplicateSingletonTest(ImportTestCase): def test_remove_duplicate(self): item = self.lib.items().get() assert item.mb_trackid == "old trackid" - self.assertExists(item.path) + assert item.filepath.exists() self.importer.default_resolution = self.importer.Resolution.REMOVE self.importer.run() - self.assertNotExists(item.path) + assert not item.filepath.exists() assert len(self.lib.items()) == 1 item = self.lib.items().get() assert item.mb_trackid == "new trackid" diff --git a/test/test_ui.py b/test/test_ui.py index 7a394a3d9..fd3686ec2 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -113,8 +113,7 @@ class RemoveTest(IOMixin, BeetsTestCase): super().setUp() # Copy a file into the library. - self.item_path = os.path.join(_common.RSRC, b"full.mp3") - self.i = library.Item.from_path(self.item_path) + self.i = library.Item.from_path(self.resource_path) self.lib.add(self.i) self.i.move(operation=MoveOperation.COPY) @@ -123,29 +122,29 @@ class RemoveTest(IOMixin, BeetsTestCase): commands.remove_items(self.lib, "", False, False, False) items = self.lib.items() assert len(list(items)) == 0 - self.assertExists(self.i.path) + assert self.i.filepath.exists() def test_remove_items_with_delete(self): self.io.addinput("y") commands.remove_items(self.lib, "", False, True, False) items = self.lib.items() assert len(list(items)) == 0 - self.assertNotExists(self.i.path) + assert not self.i.filepath.exists() def test_remove_items_with_force_no_delete(self): commands.remove_items(self.lib, "", False, False, True) items = self.lib.items() assert len(list(items)) == 0 - self.assertExists(self.i.path) + assert self.i.filepath.exists() def test_remove_items_with_force_delete(self): commands.remove_items(self.lib, "", False, True, True) items = self.lib.items() assert len(list(items)) == 0 - self.assertNotExists(self.i.path) + assert not self.i.filepath.exists() def test_remove_items_select_with_delete(self): - i2 = library.Item.from_path(self.item_path) + i2 = library.Item.from_path(self.resource_path) self.lib.add(i2) i2.move(operation=MoveOperation.COPY) @@ -443,19 +442,16 @@ class MoveTest(BeetsTestCase): def setUp(self): super().setUp() - self.itempath = os.path.join(self.libdir, b"srcfile") - shutil.copy( - syspath(os.path.join(_common.RSRC, b"full.mp3")), - syspath(self.itempath), - ) + self.initial_item_path = self.lib_path / "srcfile" + shutil.copy(self.resource_path, self.initial_item_path) # Add a file to the library but don't copy it in yet. - self.i = library.Item.from_path(self.itempath) + self.i = library.Item.from_path(self.initial_item_path) self.lib.add(self.i) self.album = self.lib.add_album([self.i]) # Alternate destination directory. - self.otherdir = os.path.join(self.temp_dir, b"testotherdir") + self.otherdir = self.temp_dir_path / "testotherdir" def _move( self, @@ -474,71 +470,71 @@ class MoveTest(BeetsTestCase): self._move() self.i.load() assert b"libdir" in self.i.path - self.assertExists(self.i.path) - self.assertNotExists(self.itempath) + assert self.i.filepath.exists() + assert not self.initial_item_path.exists() def test_copy_item(self): self._move(copy=True) self.i.load() assert b"libdir" in self.i.path - self.assertExists(self.i.path) - self.assertExists(self.itempath) + assert self.i.filepath.exists() + assert self.initial_item_path.exists() def test_move_album(self): self._move(album=True) self.i.load() assert b"libdir" in self.i.path - self.assertExists(self.i.path) - self.assertNotExists(self.itempath) + assert self.i.filepath.exists() + assert not self.initial_item_path.exists() def test_copy_album(self): self._move(copy=True, album=True) self.i.load() assert b"libdir" in self.i.path - self.assertExists(self.i.path) - self.assertExists(self.itempath) + assert self.i.filepath.exists() + assert self.initial_item_path.exists() def test_move_item_custom_dir(self): self._move(dest=self.otherdir) self.i.load() assert b"testotherdir" in self.i.path - self.assertExists(self.i.path) - self.assertNotExists(self.itempath) + assert self.i.filepath.exists() + assert not self.initial_item_path.exists() def test_move_album_custom_dir(self): self._move(dest=self.otherdir, album=True) self.i.load() assert b"testotherdir" in self.i.path - self.assertExists(self.i.path) - self.assertNotExists(self.itempath) + assert self.i.filepath.exists() + assert not self.initial_item_path.exists() def test_pretend_move_item(self): self._move(dest=self.otherdir, pretend=True) self.i.load() - assert b"srcfile" in self.i.path + assert self.i.filepath == self.initial_item_path def test_pretend_move_album(self): self._move(album=True, pretend=True) self.i.load() - assert b"srcfile" in self.i.path + assert self.i.filepath == self.initial_item_path def test_export_item_custom_dir(self): self._move(dest=self.otherdir, export=True) self.i.load() - assert self.i.path == self.itempath - self.assertExists(self.otherdir) + assert self.i.filepath == self.initial_item_path + assert self.otherdir.exists() def test_export_album_custom_dir(self): self._move(dest=self.otherdir, album=True, export=True) self.i.load() - assert self.i.path == self.itempath - self.assertExists(self.otherdir) + assert self.i.filepath == self.initial_item_path + assert self.otherdir.exists() def test_pretend_export_item(self): self._move(dest=self.otherdir, pretend=True, export=True) self.i.load() - assert b"srcfile" in self.i.path - self.assertNotExists(self.otherdir) + assert self.i.filepath == self.initial_item_path + assert not self.otherdir.exists() class UpdateTest(IOMixin, BeetsTestCase):