Fixes#5441
This small change explicitly passes the `for_artist` keyword to the
`plugins.feat_tokens` function that constructs the regex for matching
existing "feat. X" parts in song titles.
Previously, it was not passed and set to the default (`True`), which
caused using the pattern intended for the artist field to also be used
for the title field.
This caused some false positives as shown in #5441
Since the `for_artist` keyword has been removed from
`ftintitle.contains_feat`, the unit tests need to be updated.
This includes the deletion of the test cases that test the
`for_artist=True` delimiters.
Remove the optional `for_artist` keyword in the
`ftintitle.contains_feat` function and hardcode it to False, since it is
always used like this in the ftintitle plugin.
The old version of the `ftintitle.contains_feat` function could lead to
false positives by matching words like "and" and "with" in the title,
even if there was no "feat. X" part.
With this commit, the `for_artist` keyword is explicitly passed to the
`plugins.feat_tokens` function to disable these matches when matching a
title (and not an artist).
The previous version of the `plugins.feat_tokens` regular expression
only matched "feat. X" parts if preceded by a space. This caused missed
detections in the `ftintitle.contains_feat` function.
This commit adds unit tests for the updated regex that also matches
"feat. X" parts within parentheses and brackets
When checking whether a title or artist contains a feature, it now also
detects them when they are in parentheses or brackets, i.e., "Song Name
(feat. XYZ)" will return true.
#### Context
I noticed one of recently merged PRs used `unittest` assertions that we
are migrating from. Thus, I thought it would be a good idea to configure
our linting to catch such issues in the future. Since I was here, I
replaced our multiple linting and formatting tools with a single tool,
Ruff, to simplify and speed up our development workflow.
#### Summary
This PR migrates the codebase from using isort, Black and Flake8 to Ruff
for code formatting and linting. The changes include updates to the
GitHub Actions workflow, pre-commit configuration, and documentation to
reflect the new tooling.
#### Changes
1. **GitHub Actions Workflow**
- Updated `.github/workflows/lint.yml` to use `poetry install
--only=lint` and `poe lint --output-format=github`.
2. **Pre-commit Configuration**
- Replaced Black and Isort with Ruff in `.pre-commit-config.yaml`.
3. **Documentation**
- Updated `CONTRIBUTING.rst` to reflect the use of Ruff for formatting
and linting.
- Modified instructions for running tests and handling external API
requests.
4. **Poetry Configuration**
- Removed Black, Isort, Flake8, and related dependencies from
`poetry.lock` and `pyproject.toml`.
- Added Ruff as the new linter and formatter in `pyproject.toml`.
5. **Setup Configuration**
- Removed Flake8 configuration from `setup.cfg`.
6. **Git blame**
- Introduced `.git-blame-ignore-revs` file to keep git blame clean from
formatting
changes. Configure your local `beets` repository to use this file by
running:
```fish
$ git config --local blame.ignoreRevsFile .git-blame-ignore-revs
```
#### Benefits
- **Performance**: Ruff is known for its speed and efficiency, which
should improve the developer experience.
- **Consolidation**: Using a single tool for both formatting and linting
simplifies the development workflow.
#### How to Test
1. **Linting and Formatting**
- Run `poe check-format` to check for formatting issues.
- Run `poe format` to format the codebase.
- Run `poe lint` to check for linting issues.
2. **Pre-commit Hooks**
- Ensure pre-commit hooks are working correctly by running `pre-commit
run --all-files`.
3. **CI Pipeline**
- Verify that the GitHub Actions workflow completes successfully.
#### Notes
- Contributions migrating existing tests from `unittest` to `pytest` are
welcome.
- External API requests should be mocked using `requests_mock` and
tested weekly in the integration test suite.
#### References
- [Ruff Documentation](https://docs.astral.sh/ruff/)
- [Pre-commit Hooks](https://pre-commit.com/hooks.html)
---
This PR aims to streamline our development process by adopting Ruff, a
modern and efficient tool for Python code formatting and linting.
This commit introduces a `.git-blame-ignore-revs` file to the
repository. The purpose of this file is to list specific commit hashes
that should be ignored when using the `git blame` command. This is
useful for ignoring commits that involve large-scale formatting changes,
refactoring, or other non-functional changes that would otherwise
clutter the blame history.
I added a couple of previous commit hashes which reformatted the code.
Configure this repository to use this file:
git config --local blame.ignoreRevsFile .git-blame-ignore-revs
The variable in `test_ordered_enum` was flagged for naming issues, and
I noticed that `OrderedEnum` is essentially `enum.IntEnum`.
I guess `OrderedEnum` exists because it was created before
`enum.IntEnum` was made available in Python 3.4. We do not need it
anymore though, so it's now gone.
* Replace `noqa` comments in `assert...` method definitions with
a configuration option to ignore these names.
* Use the `__all__` variable to specify importable items from the
module, replacing `*` imports and `noqa` comments for unused imports.
* Address issues with poorly named variables and methods by renaming
them appropriately.
- Fix imports
- Fix pytest issues
- Do not assign lambda as variable
- Use isinstance instead of type to check type
- Rename ambiguously named variables
- Name custom errors with Error suffix
This PR is Part 1 of the work #5215 that fixes typing issues in
`beets.util.__init__` module.
It addresses simple-to-fix / most of the issues in this module.
## Description
This PR adds gracefully handling requests error in teh Deezer plugin. Right now, it errors out when it receives error:
```bash
Traceback (most recent call last):
File "/home/arsaboo/.local/bin/beet", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/__init__.py", line 1865, in main
_raw_main(args)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/__init__.py", line 1852, in _raw_main
subcommand.func(lib, suboptions, subargs)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/commands.py", line 1395, in import_func
import_files(lib, paths, query)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/commands.py", line 1326, in import_files
session.run()
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/importer.py", line 360, in run
pl.run_parallel(QUEUE_SIZE)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/util/pipeline.py", line 447, in run_parallel
raise exc_info[1].with_traceback(exc_info[2])
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/util/pipeline.py", line 312, in run
out = self.coro.send(msg)
^^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/util/pipeline.py", line 195, in coro
func(*(args + (task,)))
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/importer.py", line 1497, in lookup_candidates
task.lookup_candidates()
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/importer.py", line 688, in lookup_candidates
artist, album, prop = autotag.tag_album(
^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/autotag/match.py", line 548, in tag_album
for matched_candidate in hooks.album_candidates(
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/plugins.py", line 593, in decorated
for v in generator(*args, **kwargs):
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/autotag/hooks.py", line 759, in album_candidates
yield from plugins.candidates(items, artist, album, va_likely, extra_tags)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/plugins.py", line 390, in candidates
yield from plugin.candidates(
^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/plugins.py", line 772, in candidates
results = self._search_api(query_type="album", filters=query_filters)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beetsplug/deezer.py", line 282, in _search_api
response.raise_for_status()
File "/home/arsaboo/.local/lib/python3.12/site-packages/requests/models.py", line 1024, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://api.deezer.com/search/album?q=album%3A%22Y+Hate+%3F%22+artist%3A%22Parmish+Verma%22
```
## To Do
- [ ] Documentation. (If you've added a new command-line flag, for example, find the appropriate page under `docs/` to describe it.)
- [x] Changelog. (Add an entry to `docs/changelog.rst` to the bottom of one of the lists near the top of the document.)
- [ ] Tests. (Very much encouraged but not strictly required.)
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.