|
3 | 3 | Writing Plugins
|
4 | 4 | ---------------
|
5 | 5 |
|
6 |
| -A beets plugin is just a Python module inside the ``beetsplug`` namespace |
7 |
| -package. (Check out this `Stack Overflow question about namespace packages`_ if |
8 |
| -you haven't heard of them.) So, to make one, create a directory called |
9 |
| -``beetsplug`` and put two files in it: one called ``__init__.py`` and one called |
10 |
| -``myawesomeplugin.py`` (but don't actually call it that). Your directory |
11 |
| -structure should look like this:: |
| 6 | +A beets plugin is just a Python module or package inside the ``beetsplug`` |
| 7 | +namespace package. (Check out `this article`_ and `this Stack Overflow |
| 8 | +question`_ if you haven't heard about namespace packages.) So, to make one, |
| 9 | +create a directory called ``beetsplug`` and add either your plugin module:: |
12 | 10 |
|
13 | 11 | beetsplug/
|
14 |
| - __init__.py |
15 | 12 | myawesomeplugin.py
|
16 | 13 |
|
17 |
| -.. _Stack Overflow question about namespace packages: |
18 |
| - https://stackoverflow.com/questions/1675734/how-do-i-create-a-namespace-package-in-python/1676069#1676069 |
| 14 | +or your plugin subpackage:: |
19 | 15 |
|
20 |
| -Then, you'll need to put this stuff in ``__init__.py`` to make ``beetsplug`` a |
21 |
| -namespace package:: |
| 16 | + beetsplug/ |
| 17 | + myawesomeplugin/ |
| 18 | + __init__.py |
| 19 | + myawesomeplugin.py |
| 20 | + |
| 21 | +.. attention:: |
22 | 22 |
|
23 |
| - from pkgutil import extend_path |
24 |
| - __path__ = extend_path(__path__, __name__) |
| 23 | + You do not anymore need to add a ``__init__.py`` file to the ``beetsplug`` |
| 24 | + directory. Python treats your plugin as a namespace package automatically, |
| 25 | + thus we do not depend on ``pkgutil``-based setup in the ``__init__.py`` |
| 26 | + file anymore. |
25 | 27 |
|
26 |
| -That's all for ``__init__.py``; you can can leave it alone. The meat of your |
27 |
| -plugin goes in ``myawesomeplugin.py``. There, you'll have to import the |
28 |
| -``beets.plugins`` module and define a subclass of the ``BeetsPlugin`` class |
29 |
| -found therein. Here's a skeleton of a plugin file:: |
| 28 | +The meat of your plugin goes in ``myawesomeplugin.py``. There, you'll have to |
| 29 | +import ``BeetsPlugin`` from ``beets.plugins`` and subclass it, for example |
| 30 | + |
| 31 | +.. code-block:: python |
30 | 32 |
|
31 | 33 | from beets.plugins import BeetsPlugin
|
32 | 34 |
|
33 |
| - class MyPlugin(BeetsPlugin): |
| 35 | + class MyAwesomePlugin(BeetsPlugin): |
34 | 36 | pass
|
35 | 37 |
|
36 | 38 | Once you have your ``BeetsPlugin`` subclass, there's a variety of things your
|
37 | 39 | plugin can do. (Read on!)
|
38 | 40 |
|
39 |
| -To use your new plugin, make sure the directory that contains your |
40 |
| -``beetsplug`` directory is in the Python |
41 |
| -path (using ``PYTHONPATH`` or by installing in a `virtualenv`_, for example). |
42 |
| -Then, as described above, edit your ``config.yaml`` to include |
43 |
| -``plugins: myawesomeplugin`` (substituting the name of the Python module |
44 |
| -containing your plugin). |
| 41 | +To use your new plugin, package your plugin (see how to do this with `poetry`_ |
| 42 | +or `setuptools`_, for example) and install it into your ``beets`` virtual |
| 43 | +environment. Then, add your plugin to beets configuration |
45 | 44 |
|
46 |
| -.. _virtualenv: https://pypi.org/project/virtualenv |
| 45 | +.. code-block:: yaml |
| 46 | +
|
| 47 | + # config.yaml |
| 48 | + plugins: |
| 49 | + - myawesomeplugin |
| 50 | +
|
| 51 | +and you're good to go! |
| 52 | + |
| 53 | +.. _this article: https://realpython.com/python-namespace-package/#setting-up-some-namespace-packages |
| 54 | +.. _this Stack Overflow question: https://stackoverflow.com/a/27586272/9582674 |
| 55 | +.. _poetry: https://python-poetry.org/docs/pyproject/#packages |
| 56 | +.. _setuptools: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#finding-simple-packages |
47 | 57 |
|
48 | 58 | .. _add_subcommands:
|
49 | 59 |
|
@@ -249,13 +259,13 @@ The events currently available are:
|
249 | 259 | during a ``beet import`` interactive session. Plugins can use this event for
|
250 | 260 | :ref:`appending choices to the prompt <append_prompt_choices>` by returning a
|
251 | 261 | list of ``PromptChoices``. Parameters: ``task`` and ``session``.
|
252 |
| - |
| 262 | + |
253 | 263 | * `mb_track_extract`: called after the metadata is obtained from
|
254 | 264 | MusicBrainz. The parameter is a ``dict`` containing the tags retrieved from
|
255 | 265 | MusicBrainz for a track. Plugins must return a new (potentially empty)
|
256 | 266 | ``dict`` with additional ``field: value`` pairs, which the autotagger will
|
257 | 267 | apply to the item, as flexible attributes if ``field`` is not a hardcoded
|
258 |
| - field. Fields already present on the track are overwritten. |
| 268 | + field. Fields already present on the track are overwritten. |
259 | 269 | Parameter: ``data``
|
260 | 270 |
|
261 | 271 | * `mb_album_extract`: Like `mb_track_extract`, but for album tags. Overwrites
|
|
0 commit comments