mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
This plugin aims to address the shortcomings of the %title function, as brought up in issues #152, #3298 and an initial look to improvement with #3411. It supplies a new string format command, `%titlecase` which doesn't interfere with any prior expected behavior of the `%title` format command. It also adds the ability to apply titlecase logic to metadata fields that a user selects, which is useful if you, like me, are looking for stylistic consistency and the minor stylistic differences between Musizbrainz, Discogs, Deezer etc, with title case are slightly infuriating. This will add an optional dependency of [titlecase](https://pypi.org/project/titlecase/), which allows the titlecase core logic to be externally maintained. If there's not enough draw to have this as a core plugin, I can also spin this into an independent one, but it seemed like a recurring theme that the %title string format didn't really behave as expected, and I wanted my metadata to match too. - [x] 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.) - [x] Tests. - Not 100% coverage, but didn't see a lot of other plugins with testing for import stages.
337 lines
9.4 KiB
TOML
337 lines
9.4 KiB
TOML
[tool.poetry]
|
|
name = "beets"
|
|
version = "2.5.1"
|
|
description = "music tagger and library organizer"
|
|
authors = ["Adrian Sampson <adrian@radbox.org>"]
|
|
maintainers = ["Serene-Arc"]
|
|
license = "MIT"
|
|
readme = "README.rst"
|
|
homepage = "https://beets.io/"
|
|
repository = "https://github.com/beetbox/beets"
|
|
documentation = "https://beets.readthedocs.io/en/stable/"
|
|
classifiers = [
|
|
"Topic :: Multimedia :: Sound/Audio",
|
|
"Topic :: Multimedia :: Sound/Audio :: Players :: MP3",
|
|
"License :: OSI Approved :: MIT License",
|
|
"Environment :: Console",
|
|
"Environment :: Web Environment",
|
|
"Programming Language :: Python",
|
|
"Programming Language :: Python :: 3",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
]
|
|
packages = [
|
|
{ include = "beets" },
|
|
{ include = "beetsplug" },
|
|
]
|
|
include = [ # extra files to include in the sdist
|
|
{ path = "docs", format = "sdist" },
|
|
{ path = "extra", format = "sdist" },
|
|
{ path = "man/**/*", format = "sdist" },
|
|
{ path = "test/*.py", format = "sdist" },
|
|
{ path = "test/rsrc/**/*", format = "sdist" },
|
|
]
|
|
exclude = ["docs/_build", "docs/modd.conf", "docs/**/*.css"]
|
|
|
|
[tool.poetry.urls]
|
|
Changelog = "https://github.com/beetbox/beets/blob/master/docs/changelog.rst"
|
|
"Bug Tracker" = "https://github.com/beetbox/beets/issues"
|
|
|
|
[tool.poetry.dependencies]
|
|
python = ">=3.10,<4"
|
|
|
|
colorama = { version = "*", markers = "sys_platform == 'win32'" }
|
|
confuse = ">=2.1.0"
|
|
jellyfish = "*"
|
|
lap = ">=0.5.12"
|
|
mediafile = ">=0.12.0"
|
|
musicbrainzngs = ">=0.4"
|
|
numpy = [
|
|
{ python = "<3.13", version = ">=2.0.2" },
|
|
{ python = ">=3.13", version = ">=2.3.4" },
|
|
]
|
|
platformdirs = ">=3.5.0"
|
|
pyyaml = "*"
|
|
typing_extensions = "*"
|
|
unidecode = ">=1.3.6"
|
|
|
|
beautifulsoup4 = { version = "*", optional = true }
|
|
dbus-python = { version = "*", optional = true }
|
|
flask = { version = "*", optional = true }
|
|
flask-cors = { version = "*", optional = true }
|
|
langdetect = { version = "*", optional = true }
|
|
librosa = { version = ">=0.11", optional = true }
|
|
scipy = [ # for librosa
|
|
{ python = "<3.13", version = ">=1.13.1", optional = true },
|
|
{ python = ">=3.13", version = ">=1.16.1", optional = true },
|
|
]
|
|
numba = [ # for librosa
|
|
{ python = "<3.13", version = ">=0.60", optional = true },
|
|
{ python = ">=3.13", version = ">=0.62.1", optional = true },
|
|
]
|
|
mutagen = { version = ">=1.33", optional = true }
|
|
Pillow = { version = "*", optional = true }
|
|
py7zr = { version = "*", optional = true }
|
|
pyacoustid = { version = "*", optional = true }
|
|
PyGObject = { version = "*", optional = true }
|
|
pylast = { version = "*", optional = true }
|
|
python-mpd2 = { version = ">=0.4.2", optional = true }
|
|
python3-discogs-client = { version = ">=2.3.15", optional = true }
|
|
pyxdg = { version = "*", optional = true }
|
|
rarfile = { version = "*", optional = true }
|
|
reflink = { version = "*", optional = true }
|
|
requests = { version = "*", optional = true }
|
|
resampy = { version = ">=0.4.3", optional = true }
|
|
requests-oauthlib = { version = ">=0.6.1", optional = true }
|
|
soco = { version = "*", optional = true }
|
|
|
|
docutils = { version = ">=0.20.1", optional = true }
|
|
pydata-sphinx-theme = { version = "*", optional = true }
|
|
sphinx = { version = "*", optional = true }
|
|
sphinx-design = { version = ">=0.6.1", optional = true }
|
|
sphinx-copybutton = { version = ">=0.5.2", optional = true }
|
|
titlecase = {version = "^2.4.1", optional = true}
|
|
|
|
[tool.poetry.group.test.dependencies]
|
|
beautifulsoup4 = "*"
|
|
codecov = ">=2.1.13"
|
|
flask = "*"
|
|
langdetect = "*"
|
|
mock = "*"
|
|
pylast = "*"
|
|
pytest = "*"
|
|
pytest-cov = "*"
|
|
pytest-flask = "*"
|
|
python-mpd2 = "*"
|
|
python3-discogs-client = ">=2.3.15"
|
|
py7zr = "*"
|
|
pyxdg = "*"
|
|
rarfile = "*"
|
|
requests-mock = ">=1.12.1"
|
|
requests_oauthlib = "*"
|
|
responses = ">=0.3.0"
|
|
titlecase = "^2.4.1"
|
|
|
|
[tool.poetry.group.lint.dependencies]
|
|
docstrfmt = ">=1.11.1"
|
|
ruff = ">=0.6.4"
|
|
sphinx-lint = ">=1.0.0"
|
|
|
|
[tool.poetry.group.typing.dependencies]
|
|
mypy = "*"
|
|
types-beautifulsoup4 = "*"
|
|
types-docutils = ">=0.22.2.20251006"
|
|
types-mock = "*"
|
|
types-Flask-Cors = "*"
|
|
types-Pillow = "*"
|
|
types-PyYAML = "*"
|
|
types-requests = "*"
|
|
types-urllib3 = "*"
|
|
|
|
[tool.poetry.group.release.dependencies]
|
|
click = ">=8.1.7"
|
|
packaging = ">=24.0"
|
|
tomli = ">=2.0.1"
|
|
|
|
[tool.poetry.extras]
|
|
# inline comments note required external / non-python dependencies
|
|
absubmit = ["requests"] # extractor binary from https://acousticbrainz.org/download
|
|
aura = ["flask", "flask-cors", "Pillow"]
|
|
autobpm = ["librosa", "resampy"]
|
|
# badfiles # mp3val and flac
|
|
beatport = ["requests-oauthlib"]
|
|
bpd = ["PyGObject"] # gobject-introspection, gstreamer1.0-plugins-base, python3-gst-1.0
|
|
chroma = ["pyacoustid"] # chromaprint or fpcalc
|
|
# convert # ffmpeg
|
|
docs = [
|
|
"docutils",
|
|
"pydata-sphinx-theme",
|
|
"sphinx",
|
|
"sphinx-lint",
|
|
"sphinx-design",
|
|
"sphinx-copybutton",
|
|
]
|
|
discogs = ["python3-discogs-client"]
|
|
embedart = ["Pillow"] # ImageMagick
|
|
embyupdate = ["requests"]
|
|
fetchart = ["beautifulsoup4", "langdetect", "Pillow", "requests"]
|
|
import = ["py7zr", "rarfile"]
|
|
# ipfs # go-ipfs
|
|
# keyfinder # KeyFinder
|
|
kodiupdate = ["requests"]
|
|
lastgenre = ["pylast"]
|
|
lastimport = ["pylast"]
|
|
lyrics = ["beautifulsoup4", "langdetect", "requests"]
|
|
metasync = ["dbus-python"]
|
|
mpdstats = ["python-mpd2"]
|
|
plexupdate = ["requests"]
|
|
reflink = ["reflink"]
|
|
replaygain = [
|
|
"PyGObject",
|
|
] # python-gi and GStreamer 1.0+ or mp3gain/aacgain or Python Audio Tools or ffmpeg
|
|
scrub = ["mutagen"]
|
|
sonosupdate = ["soco"]
|
|
titlecase = ["titlecase"]
|
|
thumbnails = ["Pillow", "pyxdg"]
|
|
web = ["flask", "flask-cors"]
|
|
|
|
[tool.poetry.scripts]
|
|
beet = "beets.ui:main"
|
|
|
|
[build-system]
|
|
requires = ["poetry-core>=1.0.0"]
|
|
build-backend = "poetry.core.masonry.api"
|
|
|
|
[tool.pipx-install]
|
|
poethepoet = ">=0.26"
|
|
poetry = ">=1.8,<2"
|
|
|
|
[tool.poe.tasks.build]
|
|
help = "Build the package"
|
|
shell = """
|
|
make -C docs man
|
|
rm -rf man
|
|
mv docs/_build/man .
|
|
poetry build
|
|
"""
|
|
|
|
[tool.poe.tasks.bump]
|
|
help = "Bump project version and update relevant files"
|
|
cmd = "python ./extra/release.py bump $version"
|
|
args = { version = { help = "The new version to set", positional = true, required = true } }
|
|
|
|
[tool.poe.tasks.changelog]
|
|
help = "Print the latest version's changelog in Markdown"
|
|
cmd = "python ./extra/release.py changelog"
|
|
|
|
[tool.poe.tasks.check-docs-links]
|
|
help = "Check the documentation for broken URLs"
|
|
cmd = "make -C docs linkcheck"
|
|
|
|
[tool.poe.tasks.check-format]
|
|
help = "Check the code for style issues"
|
|
cmd = "ruff format --check --diff"
|
|
|
|
[tool.poe.tasks.check-types]
|
|
help = "Check the code for typing issues. Accepts mypy options."
|
|
cmd = "mypy"
|
|
|
|
[tool.poe.tasks.docs]
|
|
help = "Build documentation"
|
|
args = [{ name = "COMMANDS", positional = true, multiple = true, default = "html" }]
|
|
cmd = "make -C docs $COMMANDS"
|
|
|
|
[tool.poe.tasks.format]
|
|
help = "Format the codebase"
|
|
cmd = "ruff format"
|
|
|
|
[tool.poe.tasks.format-docs]
|
|
help = "Format the documentation"
|
|
cmd = "docstrfmt docs *.rst"
|
|
|
|
[tool.poe.tasks.lint]
|
|
help = "Check the code for linting issues. Accepts ruff options."
|
|
cmd = "ruff check"
|
|
|
|
[tool.poe.tasks.lint-docs]
|
|
help = "Lint the documentation"
|
|
shell = "sphinx-lint --enable all --disable default-role $(git ls-files '*.rst')"
|
|
|
|
[tool.poe.tasks.update-dependencies]
|
|
help = "Update dependencies to their latest versions."
|
|
cmd = "poetry update -vv"
|
|
|
|
[tool.poe.tasks.test]
|
|
help = "Run tests with pytest"
|
|
cmd = "pytest $OPTS"
|
|
env.OPTS.default = "-p no:cov"
|
|
|
|
[tool.poe.tasks.test-with-coverage]
|
|
help = "Run tests and record coverage"
|
|
ref = "test"
|
|
# record coverage in beets and beetsplug packages
|
|
# save xml for coverage upload to coveralls
|
|
# save html report for local dev use
|
|
# measure coverage across logical branches
|
|
# show which tests cover specific lines in the code (see the HTML report)
|
|
env.OPTS = """
|
|
--cov=beets
|
|
--cov=beetsplug
|
|
--cov-report=xml:.reports/coverage.xml
|
|
--cov-report=html:.reports/html
|
|
--cov-branch
|
|
--cov-context=test
|
|
"""
|
|
|
|
[tool.poe.tasks.check-temp-files]
|
|
help = "Run each test module one by one and check for leftover temp files"
|
|
shell = """
|
|
setopt nullglob
|
|
for file in test/**/*.py; do
|
|
print Temp files created by $file && poe test $file &>/dev/null
|
|
tempfiles=(/tmp/**/tmp* /tmp/beets/**/*)
|
|
if (( $#tempfiles )); then
|
|
print -l $'\t'$^tempfiles
|
|
rm -r --interactive=never $tempfiles &>/dev/null
|
|
fi
|
|
done
|
|
"""
|
|
interpreter = "zsh"
|
|
|
|
[tool.docstrfmt]
|
|
line-length = 80
|
|
extend-exclude = [
|
|
"docs/_templates/**/*",
|
|
"docs/api/**/*",
|
|
"README_kr.rst",
|
|
]
|
|
|
|
[tool.ruff]
|
|
target-version = "py39"
|
|
line-length = 80
|
|
|
|
[tool.ruff.lint]
|
|
select = [
|
|
# "ARG", # flake8-unused-arguments
|
|
# "C4", # flake8-comprehensions
|
|
"E", # pycodestyle
|
|
"F", # pyflakes
|
|
# "B", # flake8-bugbear
|
|
"G", # flake8-logging-format
|
|
"I", # isort
|
|
"ISC", # flake8-implicit-str-concat
|
|
"N", # pep8-naming
|
|
"PT", # flake8-pytest-style
|
|
# "RUF", # ruff
|
|
"UP", # pyupgrade
|
|
"TCH", # flake8-type-checking
|
|
"W", # pycodestyle
|
|
]
|
|
ignore = [
|
|
"TC006", # no need to quote 'cast's since we use 'from __future__ import annotations'
|
|
]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"beets/**" = ["PT"]
|
|
"test/test_util.py" = ["E501"]
|
|
|
|
[tool.ruff.lint.isort]
|
|
split-on-trailing-comma = false
|
|
|
|
[tool.ruff.lint.pycodestyle]
|
|
max-line-length = 88
|
|
|
|
[tool.ruff.lint.flake8-pytest-style]
|
|
fixture-parentheses = false
|
|
mark-parentheses = false
|
|
parametrize-names-type = "csv"
|
|
|
|
[tool.ruff.lint.flake8-unused-arguments]
|
|
ignore-variadic-names = true
|
|
|
|
[tool.ruff.lint.pep8-naming]
|
|
classmethod-decorators = ["cached_classproperty"]
|
|
extend-ignore-names = ["assert*", "cached_classproperty"]
|