Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use up-to-date namespace package setup for plugins #5505

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions beetsplug/__init__.py

This file was deleted.

2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ For packagers:
* The minimum supported Python version is now 3.8.
* The `beet` script has been removed from the repository.
* The `typing_extensions` is required for Python 3.10 and below.
* External plugin developers: ``beetsplug/__init__.py`` file can be removed
from your plugin as beets now uses native/implicit namespace package setup.

Other changes:

Expand Down
58 changes: 33 additions & 25 deletions docs/dev/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,54 @@
Writing Plugins
---------------

A beets plugin is just a Python module inside the ``beetsplug`` namespace
package. (Check out this `Stack Overflow question about namespace packages`_ if
you haven't heard of them.) So, to make one, create a directory called
``beetsplug`` and put two files in it: one called ``__init__.py`` and one called
``myawesomeplugin.py`` (but don't actually call it that). Your directory
structure should look like this::
A beets plugin is just a Python module or package inside the ``beetsplug``
namespace package. (Check out this `Stack Overflow question about namespace
packages`_ if you haven't heard of them.) So, to make one, create a directory
called ``beetsplug`` and add either your plugin module::

beetsplug/
__init__.py
myawesomeplugin.py

.. _Stack Overflow question about namespace packages:
https://stackoverflow.com/questions/1675734/how-do-i-create-a-namespace-package-in-python/1676069#1676069
or your plugin subpackage::

Then, you'll need to put this stuff in ``__init__.py`` to make ``beetsplug`` a
namespace package::
beetsplug/
myawesomeplugin/
__init__.py
myawesomeplugin.py

.. attention::

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
You must not add a ``__init__.py`` file to the ``beetsplug`` directory.
This ensures that Python treats your plugin as a namespace package. If you
added ``__init__.py`` file, beets would be unable to find any other plugins
in the ``beetsplug`` directory.

That's all for ``__init__.py``; you can can leave it alone. The meat of your
plugin goes in ``myawesomeplugin.py``. There, you'll have to import the
``beets.plugins`` module and define a subclass of the ``BeetsPlugin`` class
found therein. Here's a skeleton of a plugin file::
The meat of your plugin goes in ``myawesomeplugin.py``. There, you'll have to
import ``BeetsPlugin`` from ``beets.plugins`` and subclass it, for example

.. code-block:: python

from beets.plugins import BeetsPlugin

class MyPlugin(BeetsPlugin):
class MyAwesomePlugin(BeetsPlugin):
pass

Once you have your ``BeetsPlugin`` subclass, there's a variety of things your
plugin can do. (Read on!)

To use your new plugin, make sure the directory that contains your
``beetsplug`` directory is in the Python
path (using ``PYTHONPATH`` or by installing in a `virtualenv`_, for example).
Then, as described above, edit your ``config.yaml`` to include
``plugins: myawesomeplugin`` (substituting the name of the Python module
containing your plugin).
``beetsplug`` directory is in the Python path (using ``PYTHONPATH`` or by
installing in a `virtualenv`_, for example). Then, add your plugin to beets configuration

.. code-block:: yaml

# config.yaml
plugins:
- myawesomeplugin

and you're good to go!

.. _Stack Overflow question about namespace packages: https://stackoverflow.com/a/27586272/9582674
.. _virtualenv: https://pypi.org/project/virtualenv

.. _add_subcommands:
Expand Down Expand Up @@ -249,13 +257,13 @@ The events currently available are:
during a ``beet import`` interactive session. Plugins can use this event for
:ref:`appending choices to the prompt <append_prompt_choices>` by returning a
list of ``PromptChoices``. Parameters: ``task`` and ``session``.

* `mb_track_extract`: called after the metadata is obtained from
MusicBrainz. The parameter is a ``dict`` containing the tags retrieved from
MusicBrainz for a track. Plugins must return a new (potentially empty)
``dict`` with additional ``field: value`` pairs, which the autotagger will
apply to the item, as flexible attributes if ``field`` is not a hardcoded
field. Fields already present on the track are overwritten.
field. Fields already present on the track are overwritten.
Parameter: ``data``

* `mb_album_extract`: Like `mb_track_extract`, but for album tags. Overwrites
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ 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
ignore_missing_imports = true
namespace_packages = true
explicit_package_bases = true
Loading