- Document the genre alias normalization feature and the default aliases
we ship with the plugin (by using rst "literalinclude" referring to
aliases.yaml directly)
- Clarify what canonicalization acutually does when used without a
whitelist enabled.
- New docs chapter "Using the right tool"
This fixes some inconsistencies in spelling in the data files we ship
with the plugin as well as adds some new genres to both files that
seem to be returned often by last.fm.
Personal note: Of course changes like this always are somewhat
opinionated but it is still better to fix and streamline whatever data
files we used to ship with beets so far instead of ignoring unusable
data in them forever.
For some changes the default aliases feature helps to streamline
inconsistencies that come from last.fm already.
- Genre alias normalization feature implementation
- Extend and simplify _filter_valid()
- Remove drop_ignored_genres()
- More smaller ignorelist related refactoring
I've started working on migrating the codebase to `pathlib.Path` and
this is the very first step: fully type `beets.util` and
`beets.test.helper`. Next, I will me migrating tests to use
`pathlib.Path`.
First half of #6808.
- Extracts shared path/temp-directory behavior into `PathsMixin`, and
splits import-specific test setup into `ImporterMixin`. This makes
`beets.test.helper` more modular and gives test helpers a clearer
inheritance structure.
- Updates `TestHelper` and import helpers to use those smaller mixins,
while keeping existing test behavior intact. The main architectural
effect is better separation between core test setup, filesystem helpers,
and importer-specific utilities.
- Tightens typing across `beets.test.helper` and `beets.util`,
especially around path handling. `beets.util` now accepts a broader set
of path types through `PathLike`/`AnyPath`, which reduces friction
between `bytes`, `str`, and `Path` usage.
- Aligns helper internals with the typed interfaces by normalizing path
handling in methods like `touch`, using typed `template(...)` entries
for importer path formats, and fixing a few return-type/inheritance edge
cases.
- High-level impact: this is mainly a typing and test-infrastructure
cleanup. It improves maintainability and type-checker accuracy without
changing production architecture or intended runtime behavior.
- Moves the expensive config setup into `ConfigMixin`, which now caches
a default `config.sources` baseline once and rebuilds isolated test
config from that baseline for each test instead of re-reading full
config every time.
- Changes the shared test config flow so the `config` fixture is now
function-scoped, giving each test and parametrized case a fresh config
by default.
- Updates affected tests such as `test/autotag/test_distance.py`,
`test/plugins/test_lastgenre.py`, and `test/plugins/test_lyrics.py` to
use the new isolated flow, since per-test config setup is no longer too
expensive.
**High-level impact**
- Improves test isolation by preventing shared config state from leaking
across tests.
- Makes the suite easier to reason about because config lifecycle is
handled in one place.
- Speeds up tests up to `2x` by avoiding repeated full config reads
while keeping fresh per-test state.
See two test modules, for example, where `ConfigMixin` is used
extensively:
### Before
```sh
$ pytest test/test_library.py
...
test/test_library.py ...............ss........................................................................................... [148/174]
.......................... [174/174]
...
================================= 172 passed, 2 skipped in 10.42s ==========================================================================
$ pytest test/test_importer.py
...
test/test_importer.py ..s.ss.........................................s.......s......................................... [137/137]
...
================================= 129 passed, 8 skipped in 12.90s ==========================================================================
```
### After
```sh
$ pytest test/test_library.py
...
test/test_library.py ...............ss........................................................................................... [148/174]
.......................... [174/174]
...
================================== 172 passed, 2 skipped in 4.98s ==========================================================================
$ pytest test/test_importer.py
...
test/test_importer.py ..s.ss.........................................s.......s......................................... [137/137]
...
================================== 129 passed, 8 skipped in 9.27s ==========================================================================
```
- This change moves path Unicode normalization and separator cleanup
into `beets.util.asciify_path()`, so path shaping now lives in one place
instead of being split between `beets.library.models` and `util`.
- Callers in `Item.destination()`, `art_destination()`, and
`tmpl_asciify()` now use the same `util.asciify_path()` flow. This makes
path generation more consistent and removes duplicate platform-specific
normalization logic from the library layer.
- High-level impact: when `asciify_paths` is enabled, all asciified
paths now get the same normalization, transliteration, and
separator-replacement behavior through one shared utility. This should
make path handling easier to reason about and safer to change later.
- Test coverage follows the architecture change: focused asciify
behavior tests move from `test/test_library.py` to `test/test_util.py`,
so `asciify_path()` is tested directly where the behavior now lives.
Fixes#840.
When `importfeeds` is configured with `formats: link`, it creates a
symlink for each imported track. If that symlink can't be created — on
Windows without the privilege to make symlinks (the original report),
but also on any OS when the destination directory isn't writable or the
filesystem doesn't support symlinks — `beets.util.link()` raises
`FilesystemError`. That exception wasn't caught, so it propagated out of
the import pipeline and aborted the entire `beet import` run, even
though the tracks had already been imported into the library.
This wraps the `link()` call in `ImportFeedsPlugin._record_items()` in
`try/except FilesystemError`, logs a per-item warning, and continues
with the remaining items — so a failed symlink is skipped rather than
fatal. This is the "catch and skip" behaviour suggested in the issue
thread. It catches `FilesystemError` (not `OSError`, which `util.link()`
wraps) and mirrors the existing handling in `beetsplug/playlist.py` and
the fetchart fix (#6193).
Adds five regression tests (warn-and-continue, that remaining items are
still linked, that only `FilesystemError` is caught, and that a
successful link still creates the symlink). Also verified manually: with
a read-only feeds directory, `beet import` now finishes with a warning
(exit `0`) instead of aborting (exit `1`), and the track is still
imported.
When `formats` includes `link`, importfeeds creates a symlink per imported
item. A failed symlink (lacking privilege on Windows, a read-only directory, or
a filesystem without symlink support) raised beets.util.FilesystemError out of
the import pipeline and aborted the whole `beet import` run, even though the
tracks were already imported.
Catch FilesystemError around the link() call, log a per-item warning, and
continue with the remaining items. Add regression tests for the
warn-and-continue behaviour, that only FilesystemError is caught, and that a
successful link still creates the symlink. Add a changelog entry.
Fixes#840.
- Move test files from the top-level `test/` directory into
package-specific folders like `test/dbcore/`, `test/plugins/`,
`test/util/`, and `test/extra/`.
- Keep test coverage the same, but make the test suite match the
codebase structure more closely. This makes ownership and navigation
clearer, and helps reviewers find related tests faster.
- Add the large file-move commit to `.git-blame-ignore-revs` so `git
blame` stays useful and points at real logic changes instead of this
mechanical reorganization.
#### What changed
- Reorganized tests so they live closer to the subsystem they cover:
- query parsing tests moved from `test/test_dbcore.py` to
`test/test_queryparse.py`
- utility/path tests moved from `test/test_files.py` to
`test/test_util.py`
- Added shared lightweight db test fixtures in `beets/test/fixtures.py`,
and updated tests to import `ModelFixture1` and `SortFixture` from
there.
- Added the related refactor commits to `.git-blame-ignore-revs` so `git
blame` stays focused on real logic changes.
#### Why this matters
- The test suite is now structured by responsibility instead of growing
large mixed-purpose test files.
- Shared fixtures remove duplicate dbcore test setup and make cross-file
reuse simpler.
- This lowers coupling between test modules and makes future test
changes easier to find and review.
#### High-level impact
- Test-only refactor; no production behavior changes.
- Improves maintainability, readability, and ownership of the test
architecture.
- Keeps blame history cleaner after the test file split.
This PR refactors configuration and logging initialization in the beets
UI layer.
Logging is no longer implicitly configured as a side effect of import;
it is now initialized explicitly during UI startup. This allows library
users to fully control logging configuration themselves, and enables
more granular logging setup based on user configuration (future PR).
It also clarifies startup order by deferring heavier initialization
until after logging is available for proper error reporting.
---
This is related to the multi-step efforts to improve logging in beets
https://github.com/beetbox/beets/issues/6553