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:
Šarūnas Nejus 2024-09-08 12:31:02 +01:00 committed by GitHub
commit 54b2435c72
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 803 additions and 742 deletions

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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:
raise FilesystemError(
"OS/filesystem does not support reflinks.",
"link",
(path, dest),
traceback.format_exc(),
)
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(
msg, "reflink", (path, dest), traceback.format_exc()
) from exc
def unique_path(path: bytes) -> bytes:

View file

@ -600,13 +600,13 @@ Defaults to ``no``.
This kind of clone is only available on certain filesystems: for example,
btrfs and APFS. For more details on filesystem support, see the `pyreflink`_
documentation. Note that you need to install ``pyreflink``, either through
documentation. Note that you need to install ``pyreflink``, either through
``python -m pip install beets[reflink]`` or ``python -m pip install reflink``.
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

File diff suppressed because it is too large Load diff

View file

@ -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"

View file

@ -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):

View file

@ -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"