Replace setup.py packaging by Poetry (#5266)

Migrate `beets` package configuration to Poetry which nowadays seems to
be the gold standard.

I have been using Poetry since 2019 and I have mostly been happy a happy
user: it makes local dev setup easy and has the tools I need to maintain
python packages day to day, including reliable dependency resolution,
versioning and publishing to Pypi.

It's a user-friendly tool, so it should make it more straightforward for
contributors to setup and navigate the codebase, and ultimately,
hopefully facilitate more frequent releases!

Since poetry manages local virtual environment, we do not have much need
for tox any more. Therefore, it was replaced by a task runner
`poethepoet`. Type `poe` in the project directory to see the available
commands.

- [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. (Very much encouraged but not strictly required.)
This commit is contained in:
Šarūnas Nejus 2024-06-12 10:59:24 +01:00 committed by GitHub
commit d7bf28deed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 3448 additions and 618 deletions

View file

@ -1,16 +0,0 @@
{
"problemMatcher": [
{
"owner": "flake8",
"pattern": [
{
"regexp": "^(.*?):(\\d+):(\\d+): (.*)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4
}
]
}
]
}

View file

@ -4,13 +4,10 @@
"owner": "sphinx",
"pattern": [
{
"regexp": "^Warning, treated as error:$"
},
{
"regexp": "^(.*?):(\\d+):(.*)$",
"regexp": "^([^:]+):(\\d+): (WARNING: )?(.+)$",
"file": 1,
"line": 2,
"message": 3
"message": 4
}
]
}

View file

@ -1,104 +1,56 @@
name: ci
name: Test
on:
pull_request:
push:
branches:
- master
pull_request:
branches:
- master
env:
PY_COLORS: 1
jobs:
test:
runs-on: ${{ matrix.platform }}
name: Run tests
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest]
python-version: ["3.8", "3.9", "3.x"]
python-version: ["3.8", "3.9"]
runs-on: ${{ matrix.platform }}
env:
PY_COLORS: 1
IS_MAIN_PYTHON: ${{ matrix.python-version == '3.8' && matrix.platform == 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Install Python tools
uses: BrandonLWhite/pipx-install-action@v0.1.1
- name: Setup Python with poetry caching
# poetry cache requires poetry to already be installed, weirdly
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: poetry
- name: Install base dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox sphinx
- name: Install optional dependencies
if: matrix.platform != 'windows-latest'
- name: Install PyGobject dependencies on Ubuntu
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt update
sudo apt install ffmpeg # For replaygain
sudo apt install ffmpeg gobject-introspection libgirepository1.0-dev
poetry install --extras replaygain
- name: Test older Python versions with tox
if: matrix.python-version != '3.x'
run: |
tox -e py-test
- name: Install Python dependencies
run: poetry install --only=main,test
- name: Upload code coverage
if: matrix.python-version == '3.8' && matrix.platform == 'ubuntu-latest'
run: |
pip install codecov || true
codecov || true
- if: ${{ ! env.IS_MAIN_PYTHON }}
name: Test without coverage
run: poe test --no-cov
- name: Test latest Python version with tox and mypy
if: matrix.python-version == '3.x'
# continue-on-error is not ideal since it doesn't give a visible
# warning, but there doesn't seem to be anything better:
# https://github.com/actions/toolkit/issues/399
- if: ${{ env.IS_MAIN_PYTHON }}
name: Test with coverage
uses: liskin/gh-problem-matcher-wrap@v3
with:
linters: pytest
run: poe test
- if: ${{ env.IS_MAIN_PYTHON }}
name: Upload code coverage
continue-on-error: true
run: |
tox -vv -e py-mypy
test-docs:
runs-on: ubuntu-latest
env:
PY_COLORS: 1
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: "3.x"
- name: Install base dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox sphinx
- name: Add problem matcher
run: echo "::add-matcher::.github/sphinx-problem-matcher.json"
- name: Build and check docs using tox
run: tox -e docs
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: "3.x"
- name: Install base dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox sphinx
- name: Add problem matcher
run: echo "::add-matcher::.github/flake8-problem-matcher.json"
- name: Lint with flake8
run: tox -e py-lint
run: poetry run codecov

View file

@ -1,14 +0,0 @@
name: formatting_check
run-name: Check code formatting
on: [push, pull_request]
jobs:
formatting_check:
runs-on: ubuntu-latest
steps:
- name: Install dependencies
uses: actions/checkout@v3
- name: Run formatting check
uses: paolorechia/pox@v1.0.1
with:
tox_env: "format_check"

View file

@ -2,34 +2,29 @@ name: integration tests
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * SUN' # run every Sunday at midnight
- cron: "0 0 * * SUN" # run every Sunday at midnight
jobs:
test_integration:
runs-on: ubuntu-latest
env:
PY_COLORS: 1
steps:
- uses: actions/checkout@v2
- name: Set up latest Python version
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Install Python tools
uses: BrandonLWhite/pipx-install-action@v0.1.1
- uses: actions/setup-python@v5
with:
python-version: 3.9-dev
python-version: 3.8
cache: poetry
- name: Install base dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox sphinx
- name: Install dependencies
run: poetry install
- name: Test with tox
run: |
tox -e int
- name: Test
env:
INTEGRATION_TEST: 1
run: poe test
- name: Check external links in docs
run: |
tox -e links
run: poe check-docs-links
- name: Notify on failure
if: ${{ failure() }}

128
.github/workflows/lint.yml vendored Normal file
View file

@ -0,0 +1,128 @@
name: Lint check
run-name: Lint code
on:
pull_request:
push:
branches:
- master
env:
PYTHON_VERSION: 3.8
jobs:
changed-files:
runs-on: ubuntu-latest
name: Get changed files
outputs:
any_docs_changed: ${{ steps.changed-doc-files.outputs.any_changed }}
any_python_changed: ${{ steps.changed-python-files.outputs.any_changed }}
changed_doc_files: ${{ steps.changed-doc-files.outputs.all_changed_files }}
changed_python_files: ${{ steps.changed-python-files.outputs.all_changed_files }}
steps:
- uses: actions/checkout@v4
- name: Get changed docs files
id: changed-doc-files
uses: tj-actions/changed-files@v44
with:
files: |
docs/**
- name: Get changed python files
id: changed-python-files
uses: tj-actions/changed-files@v44
with:
files: |
**.py
format:
if: needs.changed-files.outputs.any_python_changed == 'true'
runs-on: ubuntu-latest
name: Check formatting
needs: changed-files
steps:
- uses: actions/checkout@v4
- name: Install Python tools
uses: BrandonLWhite/pipx-install-action@v0.1.1
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry
- name: Install dependencies
run: poetry install --only=format
- name: Check code formatting
# the job output will contain colored diffs with what needs adjusting
run: poe check-format
lint:
if: needs.changed-files.outputs.any_python_changed == 'true'
runs-on: ubuntu-latest
name: Check linting
needs: changed-files
steps:
- uses: actions/checkout@v4
- name: Install Python tools
uses: BrandonLWhite/pipx-install-action@v0.1.1
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry
- name: Install dependencies
run: poetry install --only=lint
- name: Lint code
uses: liskin/gh-problem-matcher-wrap@v3
with:
linters: flake8
run: poe lint ${{ needs.changed-files.outputs.changed_python_files }}
mypy:
if: needs.changed-files.outputs.any_python_changed == 'true'
runs-on: ubuntu-latest
name: Check types with mypy
needs: changed-files
steps:
- uses: actions/checkout@v4
- name: Install Python tools
uses: BrandonLWhite/pipx-install-action@v0.1.1
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry
- name: Install dependencies
run: poetry install --only=typing
- name: Type check code
uses: liskin/gh-problem-matcher-wrap@v3
continue-on-error: true
with:
linters: mypy
run: poe check-types --show-column-numbers --no-error-summary ${{ needs.changed-files.outputs.changed_python_files }}
docs:
if: needs.changed-files.outputs.any_docs_changed == 'true'
runs-on: ubuntu-latest
name: Check docs
needs: changed-files
steps:
- uses: actions/checkout@v4
- name: Install Python tools
uses: BrandonLWhite/pipx-install-action@v0.1.1
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry
- name: Install dependencies
run: poetry install --only=docs
- name: Add Sphinx problem matcher
run: echo "::add-matcher::.github/sphinx-problem-matcher.json"
- name: Build docs
run: |
poe docs |& tee /tmp/output
# fail the job if there are issues
grep -q " WARNING:" /tmp/output && exit 1 || exit 0

1
.gitignore vendored
View file

@ -74,6 +74,7 @@ target/
.env
# virtualenv
env/
venv/
.venv/
ENV/

View file

@ -62,33 +62,84 @@ Programming
information in the `“For Developers” section of the
docs <https://beets.readthedocs.io/en/stable/dev/>`__.
.. _development-tools:
Development Tools
^^^^^^^^^^^^^^^^^
In order to develop beets, you will need a few tools installed:
- `poetry`_ for packaging, virtual environment and dependency management
- `poethepoet`_ to run tasks, such as linting, formatting, testing
Python community recommends using `pipx`_ to install stand-alone command-line
applications such as above. `pipx`_ installs each application in an isolated
virtual environment, where its dependencies will not interfere with your system
and other CLI tools.
If you do not have `pipx`_ installed in your system, follow `pipx-installation-instructions`_ or
.. code-block:: sh
$ python3 -m pip install --user pipx
Install `poetry`_ and `poethepoet`_ using `pipx`_::
$ pipx install poetry poethepoet
.. _pipx: https://pipx.pypa.io/stable
.. _pipx-installation-instructions: https://pipx.pypa.io/stable/installation/
.. _getting-the-source:
Getting the Source
^^^^^^^^^^^^^^^^^^
The easiest way to get started with the latest beets source is to use
`pip`_ to install an “editable” package. This
can be done with one command:
.. code-block:: bash
$ pip install -e git+https://github.com/beetbox/beets.git#egg=beets
Or, equivalently:
The easiest way to get started with the latest beets source is to clone the
repository and install ``beets`` in a local virtual environment using `poetry`_.
This can be done with:
.. code-block:: bash
$ git clone https://github.com/beetbox/beets.git
$ cd beets
$ pip install -e .
$ poetry install
This will install ``beets`` and all development dependencies into its own
virtual environment in your ``$POETRY_CACHE_DIR``. See ``poetry install
--help`` for installation options, including installing ``extra`` dependencies
for plugins.
In order to run something within this virtual environment, start the command
with ``poetry run`` to them, for example ``poetry run pytest``.
On the other hand, it may get tedious to type ``poetry run`` before every
command. Instead, you can activate the virtual environment in your shell with::
$ poetry shell
You should see ``(beets-py38)`` prefix in your shell prompt. Now you can run
commands directly, for example::
$ (beets-py38) pytest
Additionally, `poethepoet`_ task runner assists us with the most common
operations. Formatting, linting, testing are defined as ``poe`` tasks in
`pyproject.toml`_. Run::
$ poe
to see all available tasks. They can be used like this, for example
.. code-block:: sh
$ poe lint # check code style
$ poe format # fix formatting issues
$ poe test # run tests
# ... fix failing tests
$ poe test --lf # re-run failing tests (note the additional pytest option)
$ poe check-types --pretty # check types with an extra option for mypy
If you already have a released version of beets installed, you may need
to remove it first by typing ``pip uninstall beets``. The pip command
above will put the beets source in a ``src/beets`` directory and install
the ``beet`` CLI script to a standard location on your system. You may
want to use the ``--src`` option to specify the parent directory where
the source will be checked out and the ``--user`` option such that the
package will be installed to your home directory (compare with the
output of ``pip install --help``).
Code Contribution Ideas
^^^^^^^^^^^^^^^^^^^^^^^
@ -116,6 +167,9 @@ Code Contribution Ideas
Sphinx <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`__
to, for example, refer to a class name.
.. _poethepoet: https://poethepoet.natn.io/index.html
.. _poetry: https://python-poetry.org/docs/
Your First Contribution
=======================
@ -153,8 +207,7 @@ request and your code will ship in no time.
listed.
6. Add a changelog entry to ``docs/changelog.rst`` near the top of the
document.
7. Run the tests and style checker. The easiest way to run the tests is
to use `tox`_. For more information on running tests, see :ref:`testing`.
7. Run the tests and style checker, see :ref:`testing`.
8. Push to your fork and open a pull request! Well be in touch shortly.
9. If you add commits to a pull request, please add a comment or
re-request a review after you push them since GitHub doesnt
@ -223,9 +276,9 @@ Style
We follow `black`_ formatting and `google's docstring format`_.
You can use ``tox -e lint`` to check your code for any style errors.
Running ``tox -e format`` will automatically format your code according
to the specifications required by the project.
Use ``poe check-format`` and ``poe lint`` to check your code for style and
linting errors. Running ``poe format`` will automatically format your code
according to the specifications required by the project.
.. _black: https://black.readthedocs.io/en/stable/
.. _google's docstring format: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings
@ -280,45 +333,45 @@ Testing
Running the Tests
-----------------
To run the tests for multiple Python versions, compile the docs, and
check style, use `tox`_. Just type ``tox`` or use something like
``tox -e py38`` to test a specific configuration. You can use the
``--parallel`` flag to make this go faster.
Use ``poe`` to run tests::
$ poe test [pytest options]
You can disable a hand-selected set of "slow" tests by setting the
environment variable SKIP_SLOW_TESTS before running them.
environment variable ``SKIP_SLOW_TESTS``, for example::
Other ways to run the tests:
- ``python testall.py`` (ditto)
- ``python -m unittest discover -p 'test_*'`` (ditto)
- `pytest`_
$ SKIP_SLOW_TESTS=1 poe test
Coverage
^^^^^^^^
``tox -e cov`` will add coverage info for tests: Coverage is pretty low
still -- see the current status on `Codecov`_.
Coverage is measured automatically when running the tests. If you find it takes
a while to calculate, disable it::
$ poe test --no-cov
You are welcome to explore coverage by opening the HTML report in
``.reports/html/index.html``.
Note that for each covered line the report shows **which tests cover it**
(expand the list on the right-hand side of the affected line).
You can find project coverage status on `Codecov`_.
Red Flags
^^^^^^^^^
The `pytest-random`_ plugin makes it easy to randomize the order of
tests. ``py.test test --random`` will occasionally turn up failing tests
tests. ``poe test --random`` will occasionally turn up failing tests
that reveal ordering dependencies—which are bad news!
Test Dependencies
^^^^^^^^^^^^^^^^^
The tests have a few more dependencies than beets itself. (The
additional dependencies consist of testing utilities and dependencies of
non-default plugins exercised by the test suite.) The dependencies are
listed under 'test' in ``extras_require`` in `setup.py`_.
To install the test dependencies, run ``python -m pip install .[test]``.
Or, just run a test suite with ``tox`` which will install them
automatically.
.. _setup.py: https://github.com/beetbox/beets/blob/master/setup.py
The tests have a few more dependencies than beets itself. (The additional
dependencies consist of testing utilities and dependencies of non-default
plugins exercised by the test suite.) The dependencies are listed under the
``tool.poetry.group.test.dependencies`` section in `pyproject.toml`_.
Writing Tests
-------------
@ -351,13 +404,12 @@ others. See `unittest.mock`_ for more info.
.. _Codecov: https://codecov.io/github/beetbox/beets
.. _pytest-random: https://github.com/klrmn/pytest-random
.. _tox: https://tox.readthedocs.io/en/latest/
.. _pytest: https://docs.pytest.org/en/stable/
.. _pyproject.toml: https://github.com/beetbox/beets/tree/master/pyproject.toml
.. _test: https://github.com/beetbox/beets/tree/master/test
.. _`https://github.com/beetbox/beets/blob/master/test/test_template.py#L224`: https://github.com/beetbox/beets/blob/master/test/test_template.py#L224
.. _unittest: https://docs.python.org/3/library/unittest.html
.. _integration test: https://github.com/beetbox/beets/actions?query=workflow%3A%22integration+tests%22
.. _unittest.mock: https://docs.python.org/3/library/unittest.mock.html
.. _documentation: https://beets.readthedocs.io/en/stable/
.. _pip: https://pip.pypa.io/en/stable/
.. _vim: https://www.vim.org/

View file

@ -13,7 +13,27 @@ Bug fixes:
For packagers:
* The minimum Python version is now 3.8.
* The minimum supported Python version is now 3.8.
Other changes:
* :doc:`contributing`: The project now uses `poetry` for packaging and
dependency management. This change affects project management and mostly
affects beets developers. Please see updates in :ref:`getting-the-source` and
:ref:`testing` for more information.
* :doc:`contributing`: Since `poetry` now manages local virtual environments,
`tox` has been replaced by a task runner `poethepoet`. This change affects
beets developers and contributors. Please see updates in the
:ref:`development-tools` section for more details. Type ``poe`` while in
the project directory to see the available commands.
* Installation instructions have been made consistent across plugins
documentation. Users should simply install `beets` with an `extra` of the
corresponding plugin name in order to install extra dependencies for that
plugin.
* GitHub workflows have been reorganised for clarity: style, linting, type and
docs checks now live in separate jobs and are named accordingly.
* Added caching for dependency installation in all CI jobs which speeds them up
a bit, especially the tests.
2.0.0 (May 30, 2024)
--------------------

View file

@ -11,8 +11,8 @@ master_doc = "index"
project = "beets"
copyright = "2016, Adrian Sampson"
version = '2.0'
release = '2.0.0'
version = "2.0"
release = "2.0.0"
pygments_style = "sphinx"
@ -60,9 +60,9 @@ man_pages = [
]
# Options for pydata theme
html_theme = 'pydata_sphinx_theme'
html_theme = "pydata_sphinx_theme"
html_theme_options = {
'collapse_navigation': True,
"collapse_navigation": True,
"logo": {
"text": "beets",
},
@ -70,5 +70,5 @@ html_theme_options = {
}
html_title = "beets"
html_logo = "_static/beets_logo_nobg.png"
html_static_path = ['_static']
html_css_files = ['beets.css']
html_static_path = ["_static"]
html_css_files = ["beets.css"]

View file

@ -149,18 +149,19 @@ it's helpful to run on the "bleeding edge". To run the latest source:
and ``python3`` instead of ``pip`` and ``python`` respectively.
- Use ``pip`` to install the latest snapshot tarball. Type:
``pip install https://github.com/beetbox/beets/tarball/master``
- Grab the source using git. First, clone the repository:
``git clone https://github.com/beetbox/beets.git``.
Then, ``cd beets`` and ``python setup.py install``.
- Use ``pip`` to install an "editable" version of beets based on an
automatic source checkout. For example, run
``pip install -e git+https://github.com/beetbox/beets#egg=beets``
to clone beets and install it, allowing you to modify the source
in-place to try out changes.
- Combine the previous two approaches, cloning the source yourself,
and then installing in editable mode:
``git clone https://github.com/beetbox/beets.git`` then
``pip install -e beets``. This approach lets you decide where the
- Clone source code and install it in editable mode
.. code-block:: shell
git clone https://github.com/beetbox/beets.git
poetry install
This approach lets you decide where the
source is stored, with any changes immediately reflected in your
environment.

View file

@ -21,13 +21,12 @@ to run. Its source can be found on `GitHub`_, and while it is possible to
compile the extractor from source, AcousticBrainz would prefer if you used
their binary (see the AcousticBrainz `FAQ`_).
The ``absubmit`` plugin also requires `requests`_, which you can install
using `pip`_ by typing::
Then, install ``beets`` with ``absubmit`` extra
pip install requests
pip install "beets[absubmit]"
Lastly, enable the plugin in your configuration (see :ref:`using-plugins`).
After installing both the extractor binary and requests you can enable
the plugin ``absubmit`` in your configuration (see :ref:`using-plugins`).
Submitting Data
---------------

View file

@ -12,19 +12,10 @@ read the :ref:`aura-issues` section.
Install
-------
The ``aura`` plugin depends on `Flask`_, which can be installed using
``python -m pip install flask``. Then you can enable the ``aura`` plugin in
your configuration (see :ref:`using-plugins`).
To use the ``aura`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``aura`` extra
It is likely that you will need to enable :ref:`aura-cors`, which introduces
an additional dependency: `flask-cors`_. This can be installed with
``python -m pip install flask-cors``.
If `Pillow`_ is installed (``python -m pip install Pillow``) then the optional
``width`` and ``height`` attributes are included in image resource objects.
.. _flask-cors: https://flask-cors.readthedocs.io
.. _Pillow: https://pillow.readthedocs.io
pip install "beets[aura]"
Usage

View file

@ -10,13 +10,12 @@ both MusicBrainz and (to a lesser degree) `Discogs`_ show no matches.
Installation
------------
To use the ``beatport`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install the `requests`_ and `requests_oauthlib`_
libraries (which we need for querying and authorizing with the Beatport API)
by typing::
:ref:`using-plugins`). Then, install ``beets`` with ``beatport`` extra
pip install requests requests_oauthlib
.. code-block:: bash
pip install "beets[beatport]"
You will also need to register for a `Beatport`_ account. The first time you
run the :ref:`import-cmd` command after enabling the plugin, it will ask you
@ -41,6 +40,4 @@ Configuration
This plugin can be configured like other metadata source plugins as described in :ref:`metadata-source-plugin-configuration`.
.. _requests: https://requests.readthedocs.io/en/master/
.. _requests_oauthlib: https://github.com/requests/requests-oauthlib
.. _Beatport: https://www.beatport.com/

View file

@ -26,6 +26,13 @@ You will also need the various GStreamer plugin packages to make everything
work. See the :doc:`/plugins/chroma` documentation for more information on
installing GStreamer plugins.
Once you have system dependencies installed, install ``beets`` with ``bpd``
extra which installs Python bindings for ``GStreamer``:
.. code-block:: console
pip install "beets[bpd]"
.. _GStreamer: https://gstreamer.freedesktop.org/download
.. _Homebrew: https://brew.sh

View file

@ -23,18 +23,23 @@ If you're willing to pay the performance cost for fingerprinting, read on!
Installing Dependencies
-----------------------
To get fingerprinting working, you'll need to install three things: the
`Chromaprint`_ library or command-line tool, an audio decoder, and the
`pyacoustid`_ Python library (version 0.6 or later).
To get fingerprinting working, you'll need to install three things:
First, install pyacoustid itself. You can do this using `pip`_, like so::
1. `pyacoustid`_ Python library (version 0.6 or later). You can install it by
installing ``beets`` with ``chroma`` extra
$ pip install pyacoustid
.. code-block:: bash
.. _pip: https://pip.pypa.io
pip install "beets[chroma]"
Then, you will need to install `Chromaprint`_, either as a dynamic library or
in the form of a command-line tool (``fpcalc``).
2. the `Chromaprint`_ library_ or |command-line-tool|_
3. an |audio-decoder|_
.. |command-line-tool| replace:: command line tool
.. |audio-decoder| replace:: audio decoder
.. _command-line-tool:
Installing the Binary Command-Line Tool
'''''''''''''''''''''''''''''''''''''''
@ -47,6 +52,8 @@ executable somewhere like ``/usr/local/bin``.
.. _download: https://acoustid.org/chromaprint
.. _library:
Installing the Library
''''''''''''''''''''''
@ -58,6 +65,11 @@ chromaprint``.
.. _Homebrew: https://brew.sh/
.. _audio-decoder:
Audio Decoder
'''''''''''''
You will also need a mechanism for decoding audio files supported by the
`audioread`_ library:

View file

@ -15,11 +15,11 @@ Installation
------------
To use the ``discogs`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install the `python3-discogs-client`_ library by typing:
:ref:`using-plugins`). Then, install ``beets`` with ``discogs`` extra
.. code-block:: console
.. code-block:: bash
$ pip install python3-discogs-client
pip install "beets[discogs]"
You will also need to register for a `Discogs`_ account, and provide
authentication credentials via a personal access token or an OAuth2

View file

@ -10,10 +10,15 @@ displaying album art in some media players (iPods, for example).
Embedding Art Automatically
---------------------------
To automatically embed discovered album art into imported files, just enable
the ``embedart`` plugin (see :doc:`/plugins/index`). You'll also want to enable the
:doc:`/plugins/fetchart` to obtain the images to be embedded. Art will be
embedded after each album has its cover art set.
To use the ``embedart`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``embedart`` extra
.. code-block:: bash
pip install "beets[embedart]"
You'll also want to enable the :doc:`/plugins/fetchart` to obtain the images to
be embedded. Art will be embedded after each album has its cover art set.
This behavior can be disabled with the ``auto`` config option (see below).

View file

@ -1,9 +1,20 @@
EmbyUpdate Plugin
=================
``embyupdate`` is a plugin that lets you automatically update `Emby`_'s library whenever you change your beets library.
``embyupdate`` is a plugin that lets you automatically update `Emby`_'s library
whenever you change your beets library.
To use ``embyupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then, you'll want to configure the specifics of your Emby server. You can do that using an ``emby:`` section in your ``config.yaml``, which looks like this::
To use it, first enable the your configuration (see :ref:`using-plugins`).
Then, install ``beets`` with ``embyupdate`` extra
.. code-block:: bash
pip install "beets[embyupdate]"
Then, you'll want to configure the specifics of your Emby server. You can do
that using an ``emby`` section in your ``config.yaml``
.. code-block:: yaml
emby:
host: localhost
@ -11,14 +22,9 @@ To use ``embyupdate`` plugin, enable it in your configuration (see :ref:`using-p
username: user
apikey: apikey
To use the ``embyupdate`` plugin you need to install the `requests`_ library with::
pip install requests
With that all in place, you'll see beets send the "update" command to your Emby server every time you change your beets library.
.. _Emby: https://emby.media/
.. _requests: https://requests.readthedocs.io/en/master/
Configuration
-------------

View file

@ -5,13 +5,11 @@ The ``fetchart`` plugin retrieves album art images from various sources on the
Web and stores them as image files.
To use the ``fetchart`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install the `requests`_ library by typing::
:ref:`using-plugins`). Then, install ``beets`` with ``fetchart`` extra
pip install requests
.. code-block:: bash
The plugin uses `requests`_ to fetch album art from the Web.
.. _requests: https://requests.readthedocs.io/en/master/
pip install "beets[fetchart]"
Fetching Album Art During Import
--------------------------------
@ -260,10 +258,6 @@ the list of sources in your configuration.
Spotify
'''''''
Spotify backend requires `BeautifulSoup`_, which you can install using `pip`_ by typing::
pip install beautifulsoup4
Spotify backend is enabled by default and will update album art if a valid Spotify album id is found.
.. _pip: https://pip.pypa.io

View file

@ -29,18 +29,21 @@ To update multiple Kodi instances, specify them as an array::
pwd: kodi2
To use the ``kodiupdate`` plugin you need to install the `requests`_ library with::
To use the ``kodiupdate`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``kodiupdate`` extra
pip install requests
.. code-block:: bash
pip install "beets[kodiupdate]"
You'll also need to enable JSON-RPC in Kodi.
You'll also need to enable JSON-RPC in Kodi in order the use the plugin.
In Kodi's interface, navigate to System/Settings/Network/Services and choose "Allow control of Kodi via HTTP."
With that all in place, you'll see beets send the "update" command to your Kodi
host every time you change your beets library.
.. _Kodi: https://kodi.tv/
.. _requests: https://requests.readthedocs.io/en/master/
Configuration
-------------

View file

@ -10,12 +10,12 @@ to your albums and items.
Installation
------------
The plugin requires `pylast`_, which you can install using `pip`_ by typing::
To use the ``lastgenre`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``lastgenre`` extra
pip install pylast
.. code-block:: bash
After you have pylast installed, enable the ``lastgenre`` plugin in your
configuration (see :ref:`using-plugins`).
pip install "beets[lastgenre]"
Usage
-----
@ -31,8 +31,6 @@ The genre list file should contain one genre per line. Blank lines are ignored.
For the curious, the default genre list is generated by a `script that scrapes
Wikipedia`_.
.. _pip: https://pip.pypa.io
.. _pylast: https://github.com/pylast/pylast
.. _script that scrapes Wikipedia: https://gist.github.com/1241307
.. _internal whitelist: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres.txt

View file

@ -11,21 +11,18 @@ with this field.
Installation
------------
The plugin requires `pylast`_, which you can install using `pip`_ by typing::
To use the ``lastimport`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``lastimport`` extra
pip install pylast
.. code-block:: bash
After you have pylast installed, enable the ``lastimport`` plugin in your
configuration (see :ref:`using-plugins`).
pip install "beets[lastimport]"
Next, add your Last.fm username to your beets configuration file::
lastfm:
user: beetsfanatic
.. _pip: https://pip.pypa.io
.. _pylast: https://github.com/pylast/pylast
Importing Play Counts
---------------------

View file

@ -13,22 +13,19 @@ and, optionally, the Google custom search API.
Fetch Lyrics During Import
--------------------------
To automatically fetch lyrics for songs you import, enable the ``lyrics``
plugin in your configuration (see :ref:`using-plugins`).
Then, install the `requests`_ library by typing::
To automatically fetch lyrics for songs you import, first enable it in your
configuration (see :ref:`using-plugins`). Then, install ``beets`` with
``lyrics`` extra
pip install requests
.. code-block:: bash
The plugin uses `requests`_ to download lyrics.
pip install "beets[lyrics]"
When importing new files, beets will now fetch lyrics for files that don't
already have them. The lyrics will be stored in the beets database. If the
``import.write`` config option is on, then the lyrics will also be written to
the files' tags.
.. _requests: https://requests.readthedocs.io/en/master/
Configuration
-------------
@ -130,12 +127,7 @@ few suggestions.
Activate Google Custom Search
------------------------------
Using the Google backend requires `BeautifulSoup`_, which you can install
using `pip`_ by typing::
pip install beautifulsoup4
You also need to `register for a Google API key`_. Set the ``google_API_key``
You need to `register for a Google API key`_. Set the ``google_API_key``
configuration option to your key.
Then add ``google`` to the list of sources in your configuration (or use
default list, which includes it as long as you have an API key).
@ -153,17 +145,11 @@ default, beets use a list of sources known to be scrapeable.
Note that the Google custom search API is limited to 100 queries per day.
After that, the lyrics plugin will fall back on other declared data sources.
.. _pip: https://pip.pypa.io
.. _BeautifulSoup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
Activate Genius and Tekstowo.pl Lyrics
--------------------------------------
Using the Genius or Tekstowo.pl backends requires `BeautifulSoup`_, which
you can install using `pip`_ by typing::
pip install beautifulsoup4
These backends are enabled by default.
.. _lyrics-translation:
@ -171,16 +157,10 @@ These backends are enabled by default.
Activate On-the-Fly Translation
-------------------------------
Using the Bing Translation API requires `langdetect`_, which you can install
using `pip`_ by typing::
pip install langdetect
You also need to register for a Microsoft Azure Marketplace free account and
You need to register for a Microsoft Azure Marketplace free account and
to the `Microsoft Translator API`_. Follow the four steps process, specifically
at step 3 enter ``beets`` as *Client ID* and copy/paste the generated
*Client secret* into your ``bing_client_secret`` configuration, alongside
``bing_lang_to`` target `language code`.
.. _langdetect: https://pypi.python.org/pypi/langdetect
.. _Microsoft Translator API: https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-how-to-signup

View file

@ -19,8 +19,12 @@ Installation
Enable the ``metasync`` plugin in your configuration (see
:ref:`using-plugins`).
To synchronize with Amarok, you'll need the `dbus-python`_ library. There are
packages for most major Linux distributions.
To synchronize with Amarok, you'll need the `dbus-python`_ library. In such
case, install ``beets`` with ``metasync`` extra
.. code-block:: bash
pip install "beets[metasync]"
.. _dbus-python: https://dbus.freedesktop.org/releases/dbus-python/

View file

@ -21,13 +21,10 @@ Installing Dependencies
This plugin requires the python-mpd2 library in order to talk to the MPD
server.
Install the library from `pip`_, like so::
To use the ``mpdstats`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``mpdstats`` extra
$ pip install python-mpd2
Add the ``mpdstats`` plugin to your configuration (see :ref:`using-plugins`).
.. _pip: https://pip.pypa.io
pip install "beets[mpdstats]"
Usage
-----

View file

@ -4,11 +4,15 @@ PlexUpdate Plugin
``plexupdate`` is a very simple plugin for beets that lets you automatically
update `Plex`_'s music library whenever you change your beets library.
To use ``plexupdate`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
Then, you'll probably want to configure the specifics of your Plex server.
You can do that using an ``plex:`` section in your ``config.yaml``,
which looks like this:
Firstly, install ``beets`` with ``plexupdate`` extra
.. code-block:: console
pip install "beets[plexupdate]"
Then, enable ``plexupdate`` plugin it in your configuration (see :ref:`using-plugins`).
Optionally, configure the specifics of your Plex server. You can do this using
a ``plex:`` section in your ``config.yaml``:
.. code-block:: yaml
@ -19,17 +23,10 @@ which looks like this:
The ``token`` key is optional: you'll need to use it when in a Plex Home (see Plex's own `documentation about tokens`_).
To use the ``plexupdate`` plugin you need to install the `requests`_ library with:
.. code-block:: console
$ pip install beets[plexupdate]
With that all in place, you'll see beets send the "update" command to your Plex
server every time you change your beets library.
.. _Plex: https://plex.tv/
.. _requests: https://requests.readthedocs.io/en/master/
.. _documentation about tokens: https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token
Configuration

View file

@ -33,8 +33,16 @@ You will need at least GStreamer 1.0 and `PyGObject 3.x`_ (a.k.a. ``python-gi``)
.. _PyGObject 3.x: https://pygobject.readthedocs.io/en/latest/
.. _GStreamer: https://gstreamer.freedesktop.org/
Then, enable the ``replaygain`` plugin (see :ref:`using-plugins`) and specify
the GStreamer backend by adding this to your configuration file::
Then, install ``beets`` with ``replaygain`` extra which installs
``GStreamer`` bindings for Python
.. code-block:: bash
pip install "beets[replaygain]"
Lastly, enable the ``replaygain`` plugin in your configuration (see
:ref:`using-plugins`) and specify the GStreamer backend by adding this to your
configuration file::
replaygain:
backend: gstreamer

View file

@ -10,11 +10,17 @@ also provides a command that lets you manually remove files' tags.
Automatic Scrubbing
-------------------
To automatically remove files' tags before writing new ones, just
enable the ``scrub`` plugin (see :ref:`using-plugins`). When importing new files (with
``import.write`` turned on) or modifying files' tags with the ``beet modify``
command, beets will first strip all types of tags entirely and then write the
database-tracked metadata to the file.
To automatically remove files' tags before writing new ones, enable ``scrub``
plugin in your configuration (see :ref:`using-plugins`) and install ``beets``
with ``scrub`` extra
.. code-block:: bash
pip install "beets[scrub]"
When importing new files (with ``import.write`` turned on) or modifying files'
tags with the ``beet modify`` command, beets will first strip all types of tags
entirely and then write the database-tracked metadata to the file.
This behavior can be disabled with the ``auto`` config option (see below).

View file

@ -7,12 +7,12 @@ library whenever you change your beets library.
To use ``sonosupdate`` plugin, enable it in your configuration
(see :ref:`using-plugins`).
To use the ``sonosupdate`` plugin you need to install the `soco`_ library with::
To use the ``sonosupdate`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``sonosupdate`` extra
pip install soco
pip install "beets[sonosupdate]"
With that all in place, you'll see beets send the "update" command to your Sonos
controller every time you change your beets library.
.. _Sonos: https://sonos.com/
.. _soco: http://python-soco.com

View file

@ -5,11 +5,15 @@ The ``thumbnails`` plugin creates thumbnails for your album folders with the
album cover. This works on freedesktop.org-compliant file managers such as
Nautilus or Thunar, and is therefore POSIX-only.
To use the ``thumbnails`` plugin, enable it (see :doc:`/plugins/index`) as well
as the :doc:`/plugins/fetchart`. You'll need 2 additional python packages:
:pypi:`pyxdg` and :pypi:`pathlib`.
To use the ``thumbnails`` plugin, enable ``thumbnails`` and
:doc:`/plugins/fetchart` in your configuration (see :ref:`using-plugins`) and
install ``beets`` with ``thumbnails`` and ``fetchart`` extras
``thumbnails`` needs to resize the covers, and therefore requires either
.. code-block:: bash
pip install "beets[fetchart,thumbnails]"
``thumbnails`` need to resize the covers, and therefore requires either
`ImageMagick`_ or `Pillow`_.
.. _Pillow: https://github.com/python-pillow/Pillow

View file

@ -15,16 +15,12 @@ drastically increase the number of people who can use beets.
Install
-------
The Web interface depends on `Flask`_. To get it, just run ``pip install
flask``. Then enable the ``web`` plugin in your configuration (see
:ref:`using-plugins`).
To use the ``web`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install ``beets`` with ``web`` extra
If you need CORS (it's disabled by default---see :ref:`web-cors`, below), then
you also need `flask-cors`_. Just type ``pip install flask-cors``.
.. _flask-cors: https://github.com/CoryDolphin/flask-cors
.. _CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
.. code-block:: bash
pip install "beets[web]"
Run the Server
--------------
@ -101,8 +97,7 @@ server as the API. (You will get an arcane error about ``XMLHttpRequest``
otherwise.) A technology called `CORS`_ lets you relax this restriction.
If you want to use an in-browser client hosted elsewhere (or running from a
different server on your machine), first install the `flask-cors`_ plugin by
typing ``pip install flask-cors``. Then set the ``cors`` configuration option to
different server on your machine), set the ``cors`` configuration option to
the "origin" (protocol, host, and optional port number) where the client is
served. Or set it to ``'*'`` to enable access from all origins. Note that there
are security implications if you set the origin to ``'*'``, so please research
@ -118,6 +113,7 @@ For example::
host: 0.0.0.0
cors: 'http://example.com'
.. _CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
.. _reverse-proxy:
Reverse Proxy Support

View file

@ -11,10 +11,11 @@ from pathlib import Path
from typing import Callable
import click
import tomli
from packaging.version import Version, parse
BASE = Path(__file__).parent.parent.absolute()
BEETS_INIT = BASE / "beets" / "__init__.py"
PYPROJECT = BASE / "pyproject.toml"
CHANGELOG = BASE / "docs" / "changelog.rst"
MD_CHANGELOG_SECTION_LIST = re.compile(r"- .+?(?=\n\n###|$)", re.DOTALL)
@ -51,7 +52,11 @@ Changelog goes here! Please add your entry to the bottom of one of the lists bel
UpdateVersionCallable = Callable[[str, Version], str]
FILENAME_AND_UPDATE_TEXT: list[tuple[Path, UpdateVersionCallable]] = [
(
BEETS_INIT,
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
),
@ -65,12 +70,8 @@ def validate_new_version(
ctx: click.Context, param: click.Argument, value: Version
) -> Version:
"""Validate the version is newer than the current one."""
with BEETS_INIT.open() as f:
contents = f.read()
m = re.search(r'(?<=__version__ = ")[^"]+', contents)
assert m, "Current version not found in __init__.py"
current = parse(m.group())
with PYPROJECT.open("rb") as f:
current = parse(tomli.load(f)["tool"]["poetry"]["version"])
if not value > current:
msg = f"version must be newer than {current}"

2755
poetry.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,217 @@
[tool.poetry]
name = "beets"
version = "2.0.0"
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.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: Implementation :: CPython",
]
packages = [
{ include = "beets" },
{ include = "beetsplug" },
]
[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.8,<4"
click = ">=8.1.7"
colorama = { version = "*", markers = "sys_platform == 'win32'" }
confuse = ">=1.5.0"
jellyfish = "*"
mediafile = ">=0.12.0"
munkres = ">=1.0.0"
musicbrainzngs = ">=0.4"
packaging = ">=24.0"
pyyaml = "*"
tomli = ">=2.0.1"
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 }
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 }
requests-oauthlib = { version = ">=0.6.1", optional = true }
soco = { version = "*", optional = true }
[tool.poetry.group.test.dependencies]
beautifulsoup4 = "*"
codecov = ">=2.1.13"
flask = "*"
mock = "*"
pylast = "*"
pytest = "*"
pytest-cov = "*"
pytest-flask = "*"
python-mpd2 = "*"
python3-discogs-client = ">=2.3.15"
py7zr = "*"
pyxdg = "*"
rarfile = "*"
reflink = "*"
requests_oauthlib = "*"
responses = ">=0.3.0"
[tool.poetry.group.format.dependencies]
isort = { version = "<5.14", extras = ["colors"] }
black = "<24.3"
[tool.poetry.group.lint.dependencies]
flake8 = "*"
flake8-docstrings = "*"
pep8-naming = "*"
[tool.poetry.group.typing.dependencies]
mypy = "*"
types-beautifulsoup4 = "*"
types-Flask-Cors = "*"
types-Pillow = "*"
types-PyYAML = "*"
types-requests = "*"
types-urllib3 = "*"
[tool.poetry.group.docs.dependencies]
pydata-sphinx-theme = "*"
sphinx = "*"
[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"]
# badfiles # mp3val and flac
beatport = ["requests-oauthlib"]
bpd = ["PyGObject"] # python-gi and GStreamer 1.0+
chroma = ["pyacoustid"] # chromaprint or fpcalc
# convert # ffmpeg
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"]
thumbnails = ["Pillow", "pyxdg"]
web = ["flask", "flask-cors"]
[tool.poetry.scripts]
beet = "beets.ui:main"
release = "extra.release:cli"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.pipx-install]
poethepoet = ">=0.26"
poetry = ">=1.8"
# We use a default path '.' to make black and isort behave like flake8 and
# mypy do: they act on the entire codebase (flake8 does it by default, and
# mypy follows our configuration) by default. Positional command-line arguments
# override this. Therefore, locally you can run `poe check-format <some-path>`
# to quickly check a specific path.
#
# Note: both tools respect .gitignore, therefore if we see them format
# something unwanted locally, we should add these paths to .gitignore.
[tool.poe.tasks._black]
help = "Run black"
cmd = "black $OPTS $path"
args = { path = { help = "Path to blacken", positional = true, multiple = true, default = "." } }
[tool.poe.tasks._isort]
help = "Run isort"
cmd = "isort $OPTS $path"
args = { path = { help = "Path to isort", positional = true, multiple = true, default = "." } }
[tool.poe.tasks.bump]
help = "Bump project version and update relevant files"
cmd = "release 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 = "release 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"
ref = "format"
env.OPTS = "--check --diff --color"
[tool.poe.tasks.check-types]
help = "Check the code for typing issues. Accepts mypy options."
cmd = "mypy"
[tool.poe.tasks.docs]
help = "Build documentation"
cmd = "make -C docs html"
[tool.poe.tasks.format]
help = "Format the codebase"
ignore_fail = "return_non_zero"
sequence = ["_black $path", "_isort $path"]
args = { path = { help = "Path to format", positional = true, multiple = true, default = "." } }
[tool.poe.tasks.lint]
help = "Check the code for linting issues. Accepts flake8 options."
cmd = "flake8"
[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"
[tool.black]
line-length = 80
target-version = ["py38", "py39", "py310", "py311"]
@ -8,4 +222,3 @@ py_version = 38
multi_line_output = 3
line_length = 80
indent = 4

View file

@ -181,7 +181,7 @@ per-file-ignores =
./beets/mediafile.py:D
[mypy]
files = beets,beetsplug,test
files = beets,beetsplug,test,extra,docs
allow_any_generics = false
# FIXME: Would be better to actually type the libraries (if under our control),
# or write our own stubs. For now, silence errors

189
setup.py
View file

@ -1,189 +0,0 @@
#!/usr/bin/env python
# This file is part of beets.
# Copyright 2016, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
import os
import shutil
import subprocess
import sys
from setuptools import setup
def _read(fn):
path = os.path.join(os.path.dirname(__file__), fn)
return open(path).read()
def build_manpages():
# Go into the docs directory and build the manpage.
docdir = os.path.join(os.path.dirname(__file__), "docs")
curdir = os.getcwd()
os.chdir(docdir)
try:
subprocess.check_call(["make", "man"])
except OSError:
print("Could not build manpages (make man failed)!", file=sys.stderr)
return
finally:
os.chdir(curdir)
# Copy resulting manpages.
mandir = os.path.join(os.path.dirname(__file__), "man")
if os.path.exists(mandir):
shutil.rmtree(mandir)
shutil.copytree(os.path.join(docdir, "_build", "man"), mandir)
# Build manpages if we're making a source distribution tarball.
if "sdist" in sys.argv:
build_manpages()
setup(
name="beets",
version="2.0.0",
description="music tagger and library organizer",
author="Adrian Sampson",
author_email="adrian@radbox.org",
url="https://beets.io/",
license="MIT",
platforms="ALL",
long_description=_read("README.rst"),
test_suite="test.testall.suite",
zip_safe=False,
include_package_data=True, # Install plugin resources.
packages=[
"beets",
"beets.autotag",
"beets.dbcore",
"beets.test",
"beets.ui",
"beets.util",
"beetsplug",
"beetsplug.bpd",
"beetsplug.lastgenre",
"beetsplug.metasync",
"beetsplug.web",
],
entry_points={
"console_scripts": [
"beet = beets.ui:main",
],
},
install_requires=[
"confuse>=1.5.0",
"jellyfish",
"mediafile>=0.12.0",
"munkres>=1.0.0",
"musicbrainzngs>=0.4",
"pyyaml",
"typing_extensions",
"unidecode>=1.3.6",
]
+ (
# Support for ANSI console colors on Windows.
["colorama"]
if (sys.platform == "win32")
else []
),
extras_require={
"test": [
"beautifulsoup4",
"flask",
"mock",
"pylast",
"pytest",
"pytest-cov",
"pytest-flask",
"python-mpd2",
"python3-discogs-client>=2.3.15",
"py7zr",
"pyxdg",
"rarfile",
"reflink",
"requests_oauthlib",
"responses>=0.3.0",
],
"lint": [
"flake8",
"flake8-docstrings",
"pep8-naming",
],
"mypy": [
"mypy",
"types-beautifulsoup4",
"types-Flask-Cors",
"types-Pillow",
"types-PyYAML",
"types-requests",
"types-urllib3",
],
"docs": [
"pydata_sphinx_theme",
"sphinx",
],
# Plugin (optional) dependencies:
"absubmit": ["requests"],
"beatport": ["requests-oauthlib>=0.6.1"],
"bpd": ["PyGObject"],
"chroma": ["pyacoustid"],
"discogs": ["python3-discogs-client>=2.3.15"],
"embedart": ["Pillow"],
"embyupdate": ["requests"],
"fetchart": ["requests", "Pillow", "beautifulsoup4"],
"import": ["rarfile", "py7zr"],
"kodiupdate": ["requests"],
"lastgenre": ["pylast"],
"lastimport": ["pylast"],
"lyrics": ["requests", "beautifulsoup4", "langdetect"],
"metasync": ["dbus-python"],
"mpdstats": ["python-mpd2>=0.4.2"],
"plexupdate": ["requests"],
"reflink": ["reflink"],
"replaygain": ["PyGObject"],
"scrub": ["mutagen>=1.33"],
"sonosupdate": ["soco"],
"thumbnails": ["pyxdg", "Pillow"],
"web": ["flask", "flask-cors"],
},
# Non-Python/non-PyPI plugin dependencies:
# chroma: chromaprint or fpcalc
# convert: ffmpeg
# badfiles: mp3val and flac
# bpd: python-gi and GStreamer 1.0+
# embedart: ImageMagick
# absubmit: extractor binary from https://acousticbrainz.org/download
# keyfinder: KeyFinder
# replaygain: python-gi and GStreamer 1.0+
# or mp3gain/aacgain
# or Python Audio Tools
# or ffmpeg
# ipfs: go-ipfs
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.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: Implementation :: CPython",
],
)

67
tox.ini
View file

@ -1,67 +0,0 @@
# Tox (http://tox.testrun.org/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
[tox]
envlist = py38-{cov,lint,mypy}, docs, format, format_check
[_test]
deps = .[test]
[_lint]
deps = .[lint]
files = beets beetsplug beet test setup.py docs
[_mypy]
deps =
.[mypy]
.[test]
[testenv]
deps =
{test,cov}: {[_test]deps}
lint: {[_lint]deps}
mypy: {[_mypy]deps}
passenv = INTEGRATION_TEST
commands =
test: python -m pytest {posargs}
lint: python -m flake8 {posargs} {[_lint]files}
mypy: mypy
[testenv:docs]
basepython = python3.10
deps =
sphinx>=5
pydata_sphinx_theme
commands = sphinx-build -W -q -b html docs {envtmpdir}/html {posargs}
# checks all links in the docs
[testenv:links]
deps = sphinx
allowlist_externals = /bin/bash
commands = /bin/bash -c '! sphinx-build -b linkcheck docs {envtmpdir}/linkcheck | grep "broken\s"'
[testenv:int]
deps = {[_test]deps}
setenv = INTEGRATION_TEST = 1
passenv = GITHUB_ACTIONS
commands = python -bb -m pytest {posargs}
[testenv:format]
deps =
isort==5.13.2
black==24.2.0
skip_install = True
commands =
isort beets beetsplug test
black beets beetsplug test
[testenv:format_check]
deps =
isort==5.13.2
black==24.2.0
skip_install = True
commands =
isort beets beetsplug test --check --diff
black beets beetsplug test --check --diff