mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Update dependencies and do not install reflink on Windows for tests (#5407)
See my comment under #5406 for context > The build on win32 is failing to install reflink because it's [only supported until Python 3.7](https://gitlab.com/rubdos/pyreflink/-/blob/master/setup.py?ref_type=heads). > > I will address this in a separate PR and rebase this one accordingly once the fix is merged. > > Note: this issue popped up now because I added a new requests-mock dependency which invalidated cached dependencies.
This commit is contained in:
commit
54b2435c72
9 changed files with 803 additions and 742 deletions
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
run: |
|
||||
sudo apt update
|
||||
sudo apt install ffmpeg gobject-introspection libgirepository1.0-dev
|
||||
poetry install --extras replaygain
|
||||
poetry install --extras=replaygain --extras=reflink
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: poetry install --only=main,test --extras=autobpm
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
|
@ -66,13 +65,6 @@ _item_ident = 0
|
|||
HAVE_SYMLINK = sys.platform != "win32"
|
||||
HAVE_HARDLINK = sys.platform != "win32"
|
||||
|
||||
try:
|
||||
import reflink
|
||||
|
||||
HAVE_REFLINK = reflink.supported_at(tempfile.gettempdir())
|
||||
except ImportError:
|
||||
HAVE_REFLINK = False
|
||||
|
||||
|
||||
def item(lib=None):
|
||||
global _item_ident
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ from enum import Enum
|
|||
from functools import cached_property
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from tempfile import mkdtemp, mkstemp
|
||||
from tempfile import gettempdir, mkdtemp, mkstemp
|
||||
from typing import Any, ClassVar
|
||||
from unittest.mock import patch
|
||||
|
||||
|
|
@ -147,6 +147,20 @@ def has_program(cmd, args=["--version"]):
|
|||
return True
|
||||
|
||||
|
||||
def check_reflink_support(path: str) -> bool:
|
||||
try:
|
||||
import reflink
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
return reflink.supported_at(path)
|
||||
|
||||
|
||||
NEEDS_REFLINK = unittest.skipUnless(
|
||||
check_reflink_support(gettempdir()), "no reflink support for libdir"
|
||||
)
|
||||
|
||||
|
||||
class TestHelper(_common.Assertions):
|
||||
"""Helper mixin for high-level cli and plugin tests.
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
"""Miscellaneous utility functions."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import errno
|
||||
|
|
@ -29,6 +30,7 @@ import traceback
|
|||
from collections import Counter
|
||||
from contextlib import suppress
|
||||
from enum import Enum
|
||||
from importlib import import_module
|
||||
from logging import Logger
|
||||
from multiprocessing.pool import ThreadPool
|
||||
from pathlib import Path
|
||||
|
|
@ -615,31 +617,33 @@ def reflink(
|
|||
Raise an `OSError` if `dest` already exists, unless `replace` is
|
||||
True. If `path` == `dest`, then do nothing.
|
||||
|
||||
If reflinking fails and `fallback` is enabled, try copying the file
|
||||
instead. Otherwise, raise an error without trying a plain copy.
|
||||
|
||||
May raise an `ImportError` if the `reflink` module is not available.
|
||||
If `fallback` is enabled, ignore errors and copy the file instead.
|
||||
Otherwise, errors are re-raised as FilesystemError with an explanation.
|
||||
"""
|
||||
import reflink as pyreflink
|
||||
|
||||
if samefile(path, dest):
|
||||
return
|
||||
|
||||
if os.path.exists(syspath(dest)) and not replace:
|
||||
raise FilesystemError("file exists", "rename", (path, dest))
|
||||
raise FilesystemError("target exists", "rename", (path, dest))
|
||||
|
||||
if fallback:
|
||||
with suppress(Exception):
|
||||
return import_module("reflink").reflink(path, dest)
|
||||
return copy(path, dest, replace)
|
||||
|
||||
try:
|
||||
pyreflink.reflink(path, dest)
|
||||
except (NotImplementedError, pyreflink.ReflinkImpossibleError):
|
||||
if fallback:
|
||||
copy(path, dest, replace)
|
||||
else:
|
||||
import_module("reflink").reflink(path, dest)
|
||||
except (ImportError, OSError):
|
||||
raise
|
||||
except Exception as exc:
|
||||
msg = {
|
||||
"EXDEV": "Cannot reflink across devices",
|
||||
"EOPNOTSUPP": "Device does not support reflinks",
|
||||
}.get(str(exc), "OS does not support reflinks")
|
||||
|
||||
raise FilesystemError(
|
||||
"OS/filesystem does not support reflinks.",
|
||||
"link",
|
||||
(path, dest),
|
||||
traceback.format_exc(),
|
||||
)
|
||||
msg, "reflink", (path, dest), traceback.format_exc()
|
||||
) from exc
|
||||
|
||||
|
||||
def unique_path(path: bytes) -> bytes:
|
||||
|
|
|
|||
|
|
@ -606,7 +606,7 @@ documentation. Note that you need to install ``pyreflink``, either through
|
|||
The option is ignored if ``move`` is enabled (i.e., beets can move or
|
||||
copy files but it doesn't make sense to do both).
|
||||
|
||||
.. _file clones: https://blogs.oracle.com/otn/save-disk-space-on-linux-by-cloning-files-on-btrfs-and-ocfs2
|
||||
.. _file clones: https://en.wikipedia.org/wiki/Copy-on-write
|
||||
.. _pyreflink: https://reflink.readthedocs.io/en/latest/
|
||||
|
||||
resume
|
||||
|
|
|
|||
1442
poetry.lock
generated
1442
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -43,6 +43,7 @@ musicbrainzngs = ">=0.4"
|
|||
pyyaml = "*"
|
||||
typing_extensions = { version = "*", python = "<=3.10" }
|
||||
unidecode = ">=1.3.6"
|
||||
|
||||
beautifulsoup4 = { version = "*", optional = true }
|
||||
dbus-python = { version = "*", optional = true }
|
||||
flask = { version = "*", optional = true }
|
||||
|
|
@ -61,7 +62,7 @@ pyxdg = { version = "*", optional = true }
|
|||
rarfile = { version = "*", optional = true }
|
||||
reflink = { version = "*", optional = true }
|
||||
requests = { version = "*", optional = true }
|
||||
resampy = {version = ">=0.4.3", optional = true}
|
||||
resampy = { version = ">=0.4.3", optional = true }
|
||||
requests-oauthlib = { version = ">=0.6.1", optional = true }
|
||||
soco = { version = "*", optional = true }
|
||||
|
||||
|
|
@ -79,7 +80,6 @@ python3-discogs-client = ">=2.3.15"
|
|||
py7zr = "*"
|
||||
pyxdg = "*"
|
||||
rarfile = "*"
|
||||
reflink = "*"
|
||||
requests_oauthlib = "*"
|
||||
responses = ">=0.3.0"
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@
|
|||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
"""Test file manipulation functionality of Item.
|
||||
"""
|
||||
"""Test file manipulation functionality of Item."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
|
@ -27,7 +26,7 @@ import beets.library
|
|||
from beets import util
|
||||
from beets.test import _common
|
||||
from beets.test._common import item, touch
|
||||
from beets.test.helper import BeetsTestCase
|
||||
from beets.test.helper import NEEDS_REFLINK, BeetsTestCase
|
||||
from beets.util import MoveOperation, bytestring_path, syspath
|
||||
|
||||
|
||||
|
|
@ -87,22 +86,20 @@ class MoveTest(BeetsTestCase):
|
|||
self.i.move(operation=MoveOperation.COPY)
|
||||
self.assertExists(self.path)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
def test_reflink_arrives(self):
|
||||
self.i.move(operation=MoveOperation.REFLINK_AUTO)
|
||||
self.assertExists(self.dest)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
def test_reflink_does_not_depart(self):
|
||||
self.i.move(operation=MoveOperation.REFLINK_AUTO)
|
||||
self.assertExists(self.path)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
@NEEDS_REFLINK
|
||||
def test_force_reflink_arrives(self):
|
||||
self.i.move(operation=MoveOperation.REFLINK)
|
||||
self.assertExists(self.dest)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
@NEEDS_REFLINK
|
||||
def test_force_reflink_does_not_depart(self):
|
||||
self.i.move(operation=MoveOperation.REFLINK)
|
||||
self.assertExists(self.path)
|
||||
|
|
@ -286,7 +283,7 @@ class AlbumFileTest(BeetsTestCase):
|
|||
self.assertExists(oldpath)
|
||||
self.assertExists(self.i.path)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
@NEEDS_REFLINK
|
||||
def test_albuminfo_move_reflinks_file(self):
|
||||
oldpath = self.i.path
|
||||
self.ai.album = "newAlbumName"
|
||||
|
|
@ -571,7 +568,7 @@ class SafeMoveCopyTest(BeetsTestCase):
|
|||
self.assertExists(self.dest)
|
||||
self.assertExists(self.path)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
@NEEDS_REFLINK
|
||||
def test_successful_reflink(self):
|
||||
util.reflink(self.path, self.dest)
|
||||
self.assertExists(self.dest)
|
||||
|
|
@ -585,9 +582,8 @@ class SafeMoveCopyTest(BeetsTestCase):
|
|||
with pytest.raises(util.FilesystemError):
|
||||
util.copy(self.path, self.otherpath)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflink")
|
||||
def test_unsuccessful_reflink(self):
|
||||
with pytest.raises(util.FilesystemError):
|
||||
with pytest.raises(util.FilesystemError, match="target exists"):
|
||||
util.reflink(self.path, self.otherpath)
|
||||
|
||||
def test_self_move(self):
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
"""Tests for the general importer functionality.
|
||||
"""
|
||||
"""Tests for the general importer functionality."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
|
@ -37,6 +37,7 @@ from beets.autotag import AlbumInfo, AlbumMatch, TrackInfo
|
|||
from beets.importer import albums_in_dir
|
||||
from beets.test import _common
|
||||
from beets.test.helper import (
|
||||
NEEDS_REFLINK,
|
||||
AsIsImporterMixin,
|
||||
AutotagStub,
|
||||
BeetsTestCase,
|
||||
|
|
@ -209,7 +210,7 @@ class NonAutotaggedImportTest(AsIsImporterMixin, ImportTestCase):
|
|||
s2[stat.ST_DEV],
|
||||
)
|
||||
|
||||
@unittest.skipUnless(_common.HAVE_REFLINK, "need reflinks")
|
||||
@NEEDS_REFLINK
|
||||
def test_import_reflink_arrives(self):
|
||||
# Detecting reflinks is currently tricky due to various fs
|
||||
# implementations, we'll just check the file exists.
|
||||
|
|
@ -392,7 +393,7 @@ class ImportSingletonTest(ImportTestCase):
|
|||
assert len(self.lib.albums()) == 2
|
||||
|
||||
def test_set_fields(self):
|
||||
genre = "\U0001F3B7 Jazz"
|
||||
genre = "\U0001f3b7 Jazz"
|
||||
collection = "To Listen"
|
||||
|
||||
config["import"]["set_fields"] = {
|
||||
|
|
@ -579,7 +580,7 @@ class ImportTest(ImportTestCase):
|
|||
self.lib.items().get().data_source
|
||||
|
||||
def test_set_fields(self):
|
||||
genre = "\U0001F3B7 Jazz"
|
||||
genre = "\U0001f3b7 Jazz"
|
||||
collection = "To Listen"
|
||||
comments = "managed by beets"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue