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", "owner": "sphinx",
"pattern": [ "pattern": [
{ {
"regexp": "^Warning, treated as error:$" "regexp": "^([^:]+):(\\d+): (WARNING: )?(.+)$",
},
{
"regexp": "^(.*?):(\\d+):(.*)$",
"file": 1, "file": 1,
"line": 2, "line": 2,
"message": 3 "message": 4
} }
] ]
} }

View file

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

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

View file

@ -62,33 +62,84 @@ Programming
information in the `“For Developers” section of the information in the `“For Developers” section of the
docs <https://beets.readthedocs.io/en/stable/dev/>`__. 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 Getting the Source
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
The easiest way to get started with the latest beets source is to use The easiest way to get started with the latest beets source is to clone the
`pip`_ to install an “editable” package. This repository and install ``beets`` in a local virtual environment using `poetry`_.
can be done with one command: This can be done with:
.. code-block:: bash
$ pip install -e git+https://github.com/beetbox/beets.git#egg=beets
Or, equivalently:
.. code-block:: bash .. code-block:: bash
$ git clone https://github.com/beetbox/beets.git $ git clone https://github.com/beetbox/beets.git
$ cd beets $ 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 Code Contribution Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
@ -116,6 +167,9 @@ Code Contribution Ideas
Sphinx <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`__ Sphinx <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`__
to, for example, refer to a class name. to, for example, refer to a class name.
.. _poethepoet: https://poethepoet.natn.io/index.html
.. _poetry: https://python-poetry.org/docs/
Your First Contribution Your First Contribution
======================= =======================
@ -153,8 +207,7 @@ request and your code will ship in no time.
listed. listed.
6. Add a changelog entry to ``docs/changelog.rst`` near the top of the 6. Add a changelog entry to ``docs/changelog.rst`` near the top of the
document. document.
7. Run the tests and style checker. The easiest way to run the tests is 7. Run the tests and style checker, see :ref:`testing`.
to use `tox`_. For more information on running tests, see :ref:`testing`.
8. Push to your fork and open a pull request! Well be in touch shortly. 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 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 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`_. We follow `black`_ formatting and `google's docstring format`_.
You can use ``tox -e lint`` to check your code for any style errors. Use ``poe check-format`` and ``poe lint`` to check your code for style and
Running ``tox -e format`` will automatically format your code according linting errors. Running ``poe format`` will automatically format your code
to the specifications required by the project. according to the specifications required by the project.
.. _black: https://black.readthedocs.io/en/stable/ .. _black: https://black.readthedocs.io/en/stable/
.. _google's docstring format: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings .. _google's docstring format: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings
@ -280,45 +333,45 @@ Testing
Running the Tests Running the Tests
----------------- -----------------
To run the tests for multiple Python versions, compile the docs, and Use ``poe`` to run tests::
check style, use `tox`_. Just type ``tox`` or use something like
``tox -e py38`` to test a specific configuration. You can use the $ poe test [pytest options]
``--parallel`` flag to make this go faster.
You can disable a hand-selected set of "slow" tests by setting the 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: $ SKIP_SLOW_TESTS=1 poe test
- ``python testall.py`` (ditto)
- ``python -m unittest discover -p 'test_*'`` (ditto)
- `pytest`_
Coverage Coverage
^^^^^^^^ ^^^^^^^^
``tox -e cov`` will add coverage info for tests: Coverage is pretty low Coverage is measured automatically when running the tests. If you find it takes
still -- see the current status on `Codecov`_. 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 Red Flags
^^^^^^^^^ ^^^^^^^^^
The `pytest-random`_ plugin makes it easy to randomize the order of 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! that reveal ordering dependencies—which are bad news!
Test Dependencies Test Dependencies
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
The tests have a few more dependencies than beets itself. (The The tests have a few more dependencies than beets itself. (The additional
additional dependencies consist of testing utilities and dependencies of dependencies consist of testing utilities and dependencies of non-default
non-default plugins exercised by the test suite.) The dependencies are plugins exercised by the test suite.) The dependencies are listed under the
listed under 'test' in ``extras_require`` in `setup.py`_. ``tool.poetry.group.test.dependencies`` section in `pyproject.toml`_.
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
Writing Tests Writing Tests
------------- -------------
@ -351,13 +404,12 @@ others. See `unittest.mock`_ for more info.
.. _Codecov: https://codecov.io/github/beetbox/beets .. _Codecov: https://codecov.io/github/beetbox/beets
.. _pytest-random: https://github.com/klrmn/pytest-random .. _pytest-random: https://github.com/klrmn/pytest-random
.. _tox: https://tox.readthedocs.io/en/latest/
.. _pytest: https://docs.pytest.org/en/stable/ .. _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 .. _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 .. _`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 .. _unittest: https://docs.python.org/3/library/unittest.html
.. _integration test: https://github.com/beetbox/beets/actions?query=workflow%3A%22integration+tests%22 .. _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 .. _unittest.mock: https://docs.python.org/3/library/unittest.mock.html
.. _documentation: https://beets.readthedocs.io/en/stable/ .. _documentation: https://beets.readthedocs.io/en/stable/
.. _pip: https://pip.pypa.io/en/stable/
.. _vim: https://www.vim.org/ .. _vim: https://www.vim.org/

View file

@ -13,7 +13,27 @@ Bug fixes:
For packagers: 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) 2.0.0 (May 30, 2024)
-------------------- --------------------

View file

@ -11,8 +11,8 @@ master_doc = "index"
project = "beets" project = "beets"
copyright = "2016, Adrian Sampson" copyright = "2016, Adrian Sampson"
version = '2.0' version = "2.0"
release = '2.0.0' release = "2.0.0"
pygments_style = "sphinx" pygments_style = "sphinx"
@ -60,9 +60,9 @@ man_pages = [
] ]
# Options for pydata theme # Options for pydata theme
html_theme = 'pydata_sphinx_theme' html_theme = "pydata_sphinx_theme"
html_theme_options = { html_theme_options = {
'collapse_navigation': True, "collapse_navigation": True,
"logo": { "logo": {
"text": "beets", "text": "beets",
}, },
@ -70,5 +70,5 @@ html_theme_options = {
} }
html_title = "beets" html_title = "beets"
html_logo = "_static/beets_logo_nobg.png" html_logo = "_static/beets_logo_nobg.png"
html_static_path = ['_static'] html_static_path = ["_static"]
html_css_files = ['beets.css'] 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. and ``python3`` instead of ``pip`` and ``python`` respectively.
- Use ``pip`` to install the latest snapshot tarball. Type: - Use ``pip`` to install the latest snapshot tarball. Type:
``pip install https://github.com/beetbox/beets/tarball/master`` ``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 - Use ``pip`` to install an "editable" version of beets based on an
automatic source checkout. For example, run automatic source checkout. For example, run
``pip install -e git+https://github.com/beetbox/beets#egg=beets`` ``pip install -e git+https://github.com/beetbox/beets#egg=beets``
to clone beets and install it, allowing you to modify the source to clone beets and install it, allowing you to modify the source
in-place to try out changes. in-place to try out changes.
- Combine the previous two approaches, cloning the source yourself, - Clone source code and install it in editable mode
and then installing in editable mode:
``git clone https://github.com/beetbox/beets.git`` then .. code-block:: shell
``pip install -e beets``. This approach lets you decide where the
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 source is stored, with any changes immediately reflected in your
environment. 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 compile the extractor from source, AcousticBrainz would prefer if you used
their binary (see the AcousticBrainz `FAQ`_). their binary (see the AcousticBrainz `FAQ`_).
The ``absubmit`` plugin also requires `requests`_, which you can install Then, install ``beets`` with ``absubmit`` extra
using `pip`_ by typing::
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 Submitting Data
--------------- ---------------

View file

@ -12,19 +12,10 @@ read the :ref:`aura-issues` section.
Install Install
------- -------
The ``aura`` plugin depends on `Flask`_, which can be installed using To use the ``aura`` plugin, first enable it in your configuration (see
``python -m pip install flask``. Then you can enable the ``aura`` plugin in :ref:`using-plugins`). Then, install ``beets`` with ``aura`` extra
your configuration (see :ref:`using-plugins`).
It is likely that you will need to enable :ref:`aura-cors`, which introduces pip install "beets[aura]"
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
Usage Usage

View file

@ -10,13 +10,12 @@ both MusicBrainz and (to a lesser degree) `Discogs`_ show no matches.
Installation Installation
------------ ------------
To use the ``beatport`` plugin, first enable it in your configuration (see To use the ``beatport`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install the `requests`_ and `requests_oauthlib`_ :ref:`using-plugins`). Then, install ``beets`` with ``beatport`` extra
libraries (which we need for querying and authorizing with the Beatport API)
by typing::
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 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 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`. 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/ .. _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 work. See the :doc:`/plugins/chroma` documentation for more information on
installing GStreamer plugins. 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 .. _GStreamer: https://gstreamer.freedesktop.org/download
.. _Homebrew: https://brew.sh .. _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 Installing Dependencies
----------------------- -----------------------
To get fingerprinting working, you'll need to install three things: the To get fingerprinting working, you'll need to install three things:
`Chromaprint`_ library or command-line tool, an audio decoder, and the
`pyacoustid`_ Python library (version 0.6 or later).
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 2. the `Chromaprint`_ library_ or |command-line-tool|_
in the form of a command-line tool (``fpcalc``). 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 Installing the Binary Command-Line Tool
''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''
@ -47,6 +52,8 @@ executable somewhere like ``/usr/local/bin``.
.. _download: https://acoustid.org/chromaprint .. _download: https://acoustid.org/chromaprint
.. _library:
Installing the Library Installing the Library
'''''''''''''''''''''' ''''''''''''''''''''''
@ -58,6 +65,11 @@ chromaprint``.
.. _Homebrew: https://brew.sh/ .. _Homebrew: https://brew.sh/
.. _audio-decoder:
Audio Decoder
'''''''''''''
You will also need a mechanism for decoding audio files supported by the You will also need a mechanism for decoding audio files supported by the
`audioread`_ library: `audioread`_ library:

View file

@ -15,11 +15,11 @@ Installation
------------ ------------
To use the ``discogs`` plugin, first enable it in your configuration (see 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 You will also need to register for a `Discogs`_ account, and provide
authentication credentials via a personal access token or an OAuth2 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 Embedding Art Automatically
--------------------------- ---------------------------
To automatically embed discovered album art into imported files, just enable To use the ``embedart`` plugin, first enable it in your configuration (see
the ``embedart`` plugin (see :doc:`/plugins/index`). You'll also want to enable the :ref:`using-plugins`). Then, install ``beets`` with ``embedart`` extra
:doc:`/plugins/fetchart` to obtain the images to be embedded. Art will be
embedded after each album has its cover art set. .. 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). This behavior can be disabled with the ``auto`` config option (see below).

View file

@ -1,9 +1,20 @@
EmbyUpdate Plugin 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: emby:
host: localhost host: localhost
@ -11,14 +22,9 @@ To use ``embyupdate`` plugin, enable it in your configuration (see :ref:`using-p
username: user username: user
apikey: apikey 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. 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/ .. _Emby: https://emby.media/
.. _requests: https://requests.readthedocs.io/en/master/
Configuration 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. Web and stores them as image files.
To use the ``fetchart`` plugin, first enable it in your configuration (see 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. pip install "beets[fetchart]"
.. _requests: https://requests.readthedocs.io/en/master/
Fetching Album Art During Import Fetching Album Art During Import
-------------------------------- --------------------------------
@ -260,10 +258,6 @@ the list of sources in your configuration.
Spotify 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. Spotify backend is enabled by default and will update album art if a valid Spotify album id is found.
.. _pip: https://pip.pypa.io .. _pip: https://pip.pypa.io

View file

@ -29,18 +29,21 @@ To update multiple Kodi instances, specify them as an array::
pwd: kodi2 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." 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 With that all in place, you'll see beets send the "update" command to your Kodi
host every time you change your beets library. host every time you change your beets library.
.. _Kodi: https://kodi.tv/ .. _Kodi: https://kodi.tv/
.. _requests: https://requests.readthedocs.io/en/master/
Configuration Configuration
------------- -------------

View file

@ -10,12 +10,12 @@ to your albums and items.
Installation 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 pip install "beets[lastgenre]"
configuration (see :ref:`using-plugins`).
Usage 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 For the curious, the default genre list is generated by a `script that scrapes
Wikipedia`_. Wikipedia`_.
.. _pip: https://pip.pypa.io
.. _pylast: https://github.com/pylast/pylast
.. _script that scrapes Wikipedia: https://gist.github.com/1241307 .. _script that scrapes Wikipedia: https://gist.github.com/1241307
.. _internal whitelist: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres.txt .. _internal whitelist: https://raw.githubusercontent.com/beetbox/beets/master/beetsplug/lastgenre/genres.txt

View file

@ -11,21 +11,18 @@ with this field.
Installation 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 pip install "beets[lastimport]"
configuration (see :ref:`using-plugins`).
Next, add your Last.fm username to your beets configuration file:: Next, add your Last.fm username to your beets configuration file::
lastfm: lastfm:
user: beetsfanatic user: beetsfanatic
.. _pip: https://pip.pypa.io
.. _pylast: https://github.com/pylast/pylast
Importing Play Counts Importing Play Counts
--------------------- ---------------------

View file

@ -13,22 +13,19 @@ and, optionally, the Google custom search API.
Fetch Lyrics During Import Fetch Lyrics During Import
-------------------------- --------------------------
To automatically fetch lyrics for songs you import, enable the ``lyrics`` To automatically fetch lyrics for songs you import, first enable it in your
plugin in your configuration (see :ref:`using-plugins`). configuration (see :ref:`using-plugins`). Then, install ``beets`` with
Then, install the `requests`_ library by typing:: ``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 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 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 ``import.write`` config option is on, then the lyrics will also be written to
the files' tags. the files' tags.
.. _requests: https://requests.readthedocs.io/en/master/
Configuration Configuration
------------- -------------
@ -130,12 +127,7 @@ few suggestions.
Activate Google Custom Search Activate Google Custom Search
------------------------------ ------------------------------
Using the Google backend requires `BeautifulSoup`_, which you can install You need to `register for a Google API key`_. Set the ``google_API_key``
using `pip`_ by typing::
pip install beautifulsoup4
You also need to `register for a Google API key`_. Set the ``google_API_key``
configuration option to your key. configuration option to your key.
Then add ``google`` to the list of sources in your configuration (or use 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). 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. 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. 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/ .. _BeautifulSoup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
Activate Genius and Tekstowo.pl Lyrics 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. These backends are enabled by default.
.. _lyrics-translation: .. _lyrics-translation:
@ -171,16 +157,10 @@ These backends are enabled by default.
Activate On-the-Fly Translation Activate On-the-Fly Translation
------------------------------- -------------------------------
Using the Bing Translation API requires `langdetect`_, which you can install You need to register for a Microsoft Azure Marketplace free account and
using `pip`_ by typing::
pip install langdetect
You also need to register for a Microsoft Azure Marketplace free account and
to the `Microsoft Translator API`_. Follow the four steps process, specifically to the `Microsoft Translator API`_. Follow the four steps process, specifically
at step 3 enter ``beets`` as *Client ID* and copy/paste the generated at step 3 enter ``beets`` as *Client ID* and copy/paste the generated
*Client secret* into your ``bing_client_secret`` configuration, alongside *Client secret* into your ``bing_client_secret`` configuration, alongside
``bing_lang_to`` target `language code`. ``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 .. _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 Enable the ``metasync`` plugin in your configuration (see
:ref:`using-plugins`). :ref:`using-plugins`).
To synchronize with Amarok, you'll need the `dbus-python`_ library. There are To synchronize with Amarok, you'll need the `dbus-python`_ library. In such
packages for most major Linux distributions. case, install ``beets`` with ``metasync`` extra
.. code-block:: bash
pip install "beets[metasync]"
.. _dbus-python: https://dbus.freedesktop.org/releases/dbus-python/ .. _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 This plugin requires the python-mpd2 library in order to talk to the MPD
server. 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 pip install "beets[mpdstats]"
Add the ``mpdstats`` plugin to your configuration (see :ref:`using-plugins`).
.. _pip: https://pip.pypa.io
Usage Usage
----- -----

View file

@ -4,11 +4,15 @@ PlexUpdate Plugin
``plexupdate`` is a very simple plugin for beets that lets you automatically ``plexupdate`` is a very simple plugin for beets that lets you automatically
update `Plex`_'s music library whenever you change your beets library. update `Plex`_'s music library whenever you change your beets library.
To use ``plexupdate`` plugin, enable it in your configuration Firstly, install ``beets`` with ``plexupdate`` extra
(see :ref:`using-plugins`).
Then, you'll probably want to configure the specifics of your Plex server. .. code-block:: console
You can do that using an ``plex:`` section in your ``config.yaml``,
which looks like this: 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 .. 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`_). 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 With that all in place, you'll see beets send the "update" command to your Plex
server every time you change your beets library. server every time you change your beets library.
.. _Plex: https://plex.tv/ .. _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 .. _documentation about tokens: https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token
Configuration 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/ .. _PyGObject 3.x: https://pygobject.readthedocs.io/en/latest/
.. _GStreamer: https://gstreamer.freedesktop.org/ .. _GStreamer: https://gstreamer.freedesktop.org/
Then, enable the ``replaygain`` plugin (see :ref:`using-plugins`) and specify Then, install ``beets`` with ``replaygain`` extra which installs
the GStreamer backend by adding this to your configuration file:: ``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: replaygain:
backend: gstreamer backend: gstreamer

View file

@ -10,11 +10,17 @@ also provides a command that lets you manually remove files' tags.
Automatic Scrubbing Automatic Scrubbing
------------------- -------------------
To automatically remove files' tags before writing new ones, just To automatically remove files' tags before writing new ones, enable ``scrub``
enable the ``scrub`` plugin (see :ref:`using-plugins`). When importing new files (with plugin in your configuration (see :ref:`using-plugins`) and install ``beets``
``import.write`` turned on) or modifying files' tags with the ``beet modify`` with ``scrub`` extra
command, beets will first strip all types of tags entirely and then write the
database-tracked metadata to the file. .. 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). 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 To use ``sonosupdate`` plugin, enable it in your configuration
(see :ref:`using-plugins`). (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 With that all in place, you'll see beets send the "update" command to your Sonos
controller every time you change your beets library. controller every time you change your beets library.
.. _Sonos: https://sonos.com/ .. _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 album cover. This works on freedesktop.org-compliant file managers such as
Nautilus or Thunar, and is therefore POSIX-only. Nautilus or Thunar, and is therefore POSIX-only.
To use the ``thumbnails`` plugin, enable it (see :doc:`/plugins/index`) as well To use the ``thumbnails`` plugin, enable ``thumbnails`` and
as the :doc:`/plugins/fetchart`. You'll need 2 additional python packages: :doc:`/plugins/fetchart` in your configuration (see :ref:`using-plugins`) and
:pypi:`pyxdg` and :pypi:`pathlib`. 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`_. `ImageMagick`_ or `Pillow`_.
.. _Pillow: https://github.com/python-pillow/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 Install
------- -------
The Web interface depends on `Flask`_. To get it, just run ``pip install To use the ``web`` plugin, first enable it in your configuration (see
flask``. Then enable the ``web`` plugin in your configuration (see :ref:`using-plugins`). Then, install ``beets`` with ``web`` extra
:ref:`using-plugins`).
If you need CORS (it's disabled by default---see :ref:`web-cors`, below), then .. code-block:: bash
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
pip install "beets[web]"
Run the Server 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. 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 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 different server on your machine), set the ``cors`` configuration option to
typing ``pip install flask-cors``. Then set the ``cors`` configuration option to
the "origin" (protocol, host, and optional port number) where the client is 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 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 are security implications if you set the origin to ``'*'``, so please research
@ -118,6 +113,7 @@ For example::
host: 0.0.0.0 host: 0.0.0.0
cors: 'http://example.com' cors: 'http://example.com'
.. _CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
.. _reverse-proxy: .. _reverse-proxy:
Reverse Proxy Support Reverse Proxy Support

View file

@ -11,10 +11,11 @@ from pathlib import Path
from typing import Callable from typing import Callable
import click import click
import tomli
from packaging.version import Version, parse from packaging.version import Version, parse
BASE = Path(__file__).parent.parent.absolute() BASE = Path(__file__).parent.parent.absolute()
BEETS_INIT = BASE / "beets" / "__init__.py" PYPROJECT = BASE / "pyproject.toml"
CHANGELOG = BASE / "docs" / "changelog.rst" CHANGELOG = BASE / "docs" / "changelog.rst"
MD_CHANGELOG_SECTION_LIST = re.compile(r"- .+?(?=\n\n###|$)", re.DOTALL) 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] UpdateVersionCallable = Callable[[str, Version], str]
FILENAME_AND_UPDATE_TEXT: list[tuple[Path, UpdateVersionCallable]] = [ 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( lambda text, new: re.sub(
r"(?<=__version__ = )[^\n]+", f'"{new}"', text r"(?<=__version__ = )[^\n]+", f'"{new}"', text
), ),
@ -65,12 +70,8 @@ def validate_new_version(
ctx: click.Context, param: click.Argument, value: Version ctx: click.Context, param: click.Argument, value: Version
) -> Version: ) -> Version:
"""Validate the version is newer than the current one.""" """Validate the version is newer than the current one."""
with BEETS_INIT.open() as f: with PYPROJECT.open("rb") as f:
contents = f.read() current = parse(tomli.load(f)["tool"]["poetry"]["version"])
m = re.search(r'(?<=__version__ = ")[^"]+', contents)
assert m, "Current version not found in __init__.py"
current = parse(m.group())
if not value > current: if not value > current:
msg = f"version must be newer than {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] [tool.black]
line-length = 80 line-length = 80
target-version = ["py38", "py39", "py310", "py311"] target-version = ["py38", "py39", "py310", "py311"]
@ -8,4 +222,3 @@ py_version = 38
multi_line_output = 3 multi_line_output = 3
line_length = 80 line_length = 80
indent = 4 indent = 4

View file

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