diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 2ee64a97d..14b50859f 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -72,4 +72,4 @@ d93ddf8dd43e4f9ed072a03829e287c78d2570a2 # Moved plugin docs Further Reading chapter 33f1a5d0bef8ca08be79ee7a0d02a018d502680d # Moved art.py utility module from beets into beetsplug -28aee0fde463f1e18dfdba1994e2bdb80833722f \ No newline at end of file +28aee0fde463f1e18dfdba1994e2bdb80833722f diff --git a/.gitignore b/.gitignore index 90ef7387d..102e1c3e4 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,6 @@ ENV/ # pyright pyrightconfig.json + +# Versioning +beets/_version.py diff --git a/beets/__init__.py b/beets/__init__.py index 10b0f58b0..5f4c6657d 100644 --- a/beets/__init__.py +++ b/beets/__init__.py @@ -17,10 +17,26 @@ from sys import stderr import confuse -__version__ = "2.4.0" +# Version management using poetry-dynamic-versioning +from ._version import __version__, __version_tuple__ +from .util import deprecate_imports + __author__ = "Adrian Sampson " +def __getattr__(name: str): + """Handle deprecated imports.""" + return deprecate_imports( + old_module=__name__, + new_module_by_name={ + "art": "beetsplug._utils", + "vfs": "beetsplug._utils", + }, + name=name, + version="3.0.0", + ) + + class IncludeLazyConfig(confuse.LazyConfig): """A version of Confuse's LazyConfig that also merges in data from YAML files specified in an `include` setting. @@ -39,3 +55,6 @@ class IncludeLazyConfig(confuse.LazyConfig): config = IncludeLazyConfig("beets", __name__) + + +__all__ = ["__version__", "__version_tuple__", "config"] diff --git a/beets/_version.py b/beets/_version.py new file mode 100644 index 000000000..4dea56035 --- /dev/null +++ b/beets/_version.py @@ -0,0 +1,7 @@ +# This file is auto-generated during the build process. +# Do not edit this file directly. +# Placeholders are replaced during substitution. +# Run `git update-index --assume-unchanged beets/_version.py` +# to ignore local changes to this file. +__version__ = "0.0.0" +__version_tuple__ = (0, 0, 0) diff --git a/beetsplug/_utils/__init__.py b/beetsplug/_utils/__init__.py index e69de29bb..7453f88bf 100644 --- a/beetsplug/_utils/__init__.py +++ b/beetsplug/_utils/__init__.py @@ -0,0 +1,3 @@ +from . import art, vfs + +__all__ = ["art", "vfs"] diff --git a/beets/vfs.py b/beetsplug/_utils/vfs.py similarity index 82% rename from beets/vfs.py rename to beetsplug/_utils/vfs.py index 4fd133f5a..6294b644c 100644 --- a/beets/vfs.py +++ b/beetsplug/_utils/vfs.py @@ -16,17 +16,25 @@ libraries. """ -from typing import Any, NamedTuple +from __future__ import annotations + +from typing import TYPE_CHECKING, NamedTuple from beets import util +if TYPE_CHECKING: + from beets.library import Library + class Node(NamedTuple): - files: dict[str, Any] - dirs: dict[str, Any] + files: dict[str, int] + # Maps filenames to Item ids. + + dirs: dict[str, Node] + # Maps directory names to child nodes. -def _insert(node, path, itemid): +def _insert(node: Node, path: list[str], itemid: int): """Insert an item into a virtual filesystem node.""" if len(path) == 1: # Last component. Insert file. @@ -40,7 +48,7 @@ def _insert(node, path, itemid): _insert(node.dirs[dirname], rest, itemid) -def libtree(lib): +def libtree(lib: Library) -> Node: """Generates a filesystem-like directory tree for the files contained in `lib`. Filesystem nodes are (files, dirs) named tuples in which both components are dictionaries. The first diff --git a/beetsplug/bench.py b/beetsplug/bench.py index cf72527e8..d77f1f92a 100644 --- a/beetsplug/bench.py +++ b/beetsplug/bench.py @@ -17,10 +17,11 @@ import cProfile import timeit -from beets import importer, library, plugins, ui, vfs +from beets import importer, library, plugins, ui from beets.autotag import match from beets.plugins import BeetsPlugin from beets.util.functemplate import Template +from beetsplug._utils import vfs def aunique_benchmark(lib, prof): diff --git a/beetsplug/bpd/__init__.py b/beetsplug/bpd/__init__.py index aa7013150..1a4f505dd 100644 --- a/beetsplug/bpd/__init__.py +++ b/beetsplug/bpd/__init__.py @@ -30,10 +30,11 @@ from typing import TYPE_CHECKING import beets import beets.ui -from beets import dbcore, logging, vfs +from beets import dbcore, logging from beets.library import Item from beets.plugins import BeetsPlugin from beets.util import as_string, bluelet +from beetsplug._utils import vfs if TYPE_CHECKING: from beets.dbcore.query import Query diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 0f6e0012b..7cb9e330d 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -694,12 +694,10 @@ class SpotifyPlugin( audio_features = self.track_audio_features(spotify_track_id) if audio_features is None: self._log.info("No audio features found for: {}", item) - continue - for feature in audio_features.keys(): - if feature in self.spotify_audio_features.keys(): - item[self.spotify_audio_features[feature]] = audio_features[ - feature - ] + else: + for feature, value in audio_features.items(): + if feature in self.spotify_audio_features: + item[self.spotify_audio_features[feature]] = value item["spotify_updated"] = time.time() item.store() if write: diff --git a/docs/changelog.rst b/docs/changelog.rst index 464ce36fd..942477003 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -26,6 +26,8 @@ New features: Bug fixes: +- :doc:`plugins/spotify` Ensure ``spotifysync`` keeps popularity, ISRC, and + related fields current even when audio features requests fail. :bug:`6061` - :doc:`plugins/spotify` Fixed an issue where track matching and lookups could return incorrect or misleading results when using the Spotify plugin. The problem occurred primarily when no album was provided or when the album field @@ -53,8 +55,13 @@ Other changes: - Moved ``art.py`` utility module from ``beets`` into ``beetsplug`` namespace as it is not used in the core beets codebase. It can now be found in ``beetsplug._utils``. +- Moved ``vfs.py`` utility module from ``beets`` into ``beetsplug`` namespace as + it is not used in the core beets codebase. It can now be found in + ``beetsplug._utils``. - :class:`beets.metadata_plugin.MetadataSourcePlugin`: Remove discogs specific disambiguation stripping. +- When installing ``beets`` via git or locally the version string now reflects + the current git branch and commit hash. :bug:`4448` For developers and plugin authors: diff --git a/extra/release.py b/extra/release.py index 647cc49c9..b47de8966 100755 --- a/extra/release.py +++ b/extra/release.py @@ -174,12 +174,6 @@ FILENAME_AND_UPDATE_TEXT: list[tuple[Path, UpdateVersionCallable]] = [ PYPROJECT, lambda text, new: re.sub(r"(?<=\nversion = )[^\n]+", f'"{new}"', text), ), - ( - BASE / "beets" / "__init__.py", - lambda text, new: re.sub( - r"(?<=__version__ = )[^\n]+", f'"{new}"', text - ), - ), (CHANGELOG, update_changelog), (BASE / "docs" / "conf.py", update_docs_config), ] diff --git a/pyproject.toml b/pyproject.toml index 2546360ad..8338ce1c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -156,9 +156,18 @@ web = ["flask", "flask-cors"] [tool.poetry.scripts] beet = "beets.ui:main" + +[tool.poetry-dynamic-versioning] +enable = true +vcs = "git" +format = "{base}.dev{distance}+{commit}" + +[tool.poetry-dynamic-versioning.files."beets/_version.py"] +persistent-substitution = true + [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] +build-backend = "poetry_dynamic_versioning.backend" [tool.pipx-install] poethepoet = ">=0.26" diff --git a/test/test_vfs.py b/test/plugins/utils/test_vfs.py similarity index 97% rename from test/test_vfs.py rename to test/plugins/utils/test_vfs.py index 7f75fbd83..9505075f9 100644 --- a/test/test_vfs.py +++ b/test/plugins/utils/test_vfs.py @@ -14,9 +14,9 @@ """Tests for the virtual filesystem builder..""" -from beets import vfs from beets.test import _common from beets.test.helper import BeetsTestCase +from beetsplug._utils import vfs class VFSTest(BeetsTestCase):