diff --git a/beetsplug/__init__.py b/beetsplug/__init__.py deleted file mode 100644 index ad573cdb39..0000000000 --- a/beetsplug/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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. - -"""A namespace package for beets plugins.""" - -# Make this a namespace package. -from pkgutil import extend_path - -__path__ = extend_path(__path__, __name__) diff --git a/docs/changelog.rst b/docs/changelog.rst index 3e4266db15..33981468f2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -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: diff --git a/docs/dev/plugins.rst b/docs/dev/plugins.rst index 92a7f870e8..ce19a43c81 100644 --- a/docs/dev/plugins.rst +++ b/docs/dev/plugins.rst @@ -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: @@ -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 ` 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 diff --git a/setup.cfg b/setup.cfg index f694906307..d081275374 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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