Streamlined auto api referencing for documentation (#5795)

## Description

The current developer documentation feels somewhat cluttered due to
inline auto-generated API references for certain classes. To improve
readability and maintainability, this PR introduces a more streamlined
approach that aligns better with best practices observed in other PyData
ecosystem documentation.

Specifically, this PR:
- Adds a dedicated `api/` folder to the documentation structure.
- Moves all auto-generated references (classes, methods, etc.) to this
folder.
- Enables clean, concise linking to API elements from the narrative
documentation—without interrupting human-written content with large
autogenerated blocks.

This separation makes the documentation easier to navigate and maintain,
while still providing full API reference coverage where needed.

- [x] Documentation
- [x] Changelog
This commit is contained in:
Sebastian Mohr 2025-05-22 11:35:40 +02:00 committed by GitHub
parent 5356e6e5ea
commit 9584216209
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 204 additions and 129 deletions

2
docs/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
_build
generated/

View file

@ -6,6 +6,7 @@ SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
SOURCEDIR = .
# When both are available, use Sphinx 2.x for autodoc compatibility.
ifeq ($(shell which sphinx-build2 >/dev/null 2>&1 ; echo $$?),0)
@ -39,7 +40,7 @@ help:
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
-rm -rf $(BUILDDIR)/* $(SOURCEDIR)/api/generated/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html

3
docs/_templates/autosummary/base.rst vendored Normal file
View file

@ -0,0 +1,3 @@
{{ fullname | escape | underline}}
.. currentmodule:: {{ module }}
.. auto{{ objtype }}:: {{ objname }}

28
docs/_templates/autosummary/class.rst vendored Normal file
View file

@ -0,0 +1,28 @@
{{ fullname | escape | underline}}
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
:members: <-- add at least this line
:private-members:
:show-inheritance: <-- plus I want to show inheritance...
:inherited-members: <-- ...and inherited members too
{% block methods %}
.. automethod:: __init__
{% if methods %}
.. rubric:: {{ _('Public methods summary') }}
.. autosummary::
{% for item in methods %}
~{{ name }}.{{ item }}
{%- endfor %}
{% for item in _methods %}
~{{ name }}.{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
.. rubric:: {{ _('Methods definition') }}

11
docs/_templates/autosummary/module.rst vendored Normal file
View file

@ -0,0 +1,11 @@
{{ fullname | escape | underline}}
{% block modules %}
{% if modules %}
.. rubric:: Modules
{% for item in modules %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}

47
docs/api/database.rst Normal file
View file

@ -0,0 +1,47 @@
Database
--------
.. currentmodule:: beets.library
Library
'''''''
.. autosummary::
:toctree: generated/
Library
Models
''''''
.. autosummary::
:toctree: generated/
LibModel
Album
Item
Transactions
''''''''''''
.. currentmodule:: beets.dbcore.db
.. autosummary::
:toctree: generated/
Transaction
Queries
'''''''
.. currentmodule:: beets.dbcore.query
.. autosummary::
:toctree: generated/
Query
FieldQuery
AndQuery

11
docs/api/plugins.rst Normal file
View file

@ -0,0 +1,11 @@
Plugins
-------
.. currentmodule:: beets.plugins
.. autosummary::
:toctree: generated/
BeetsPlugin

View file

@ -43,16 +43,21 @@ For plugin developers:
Other changes:
* Documentation structure for auto generated API references changed slightly.
Autogenerated API references are now located in the `docs/api` subdirectory.
2.3.1 (May 14, 2025)
--------------------
Bug fixes:
* :doc:`/reference/pathformat`: Fixed a regression where path legalization
incorrectly removed parts of user-configured path formats that followed a dot
(**.**).
:bug:`5771`
For packagers:
* Force ``poetry`` version below 2 to avoid it mangling file modification times
in ``sdist`` package.
:bug:`5770`

View file

@ -1,19 +1,35 @@
AUTHOR = "Adrian Sampson"
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# General configuration
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
extensions = ["sphinx.ext.autodoc", "sphinx.ext.extlinks"]
exclude_patterns = ["_build"]
source_suffix = {".rst": "restructuredtext"}
master_doc = "index"
project = "beets"
AUTHOR = "Adrian Sampson"
copyright = "2016, Adrian Sampson"
master_doc = "index"
language = "en"
version = "2.3"
release = "2.3.1"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.extlinks",
]
autosummary_generate = True
exclude_patterns = ["_build"]
templates_path = ["_templates"]
source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
pygments_style = "sphinx"
# External links to the bug tracker and other sites.
@ -59,10 +75,24 @@ man_pages = [
),
]
# Options for pydata theme
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = "pydata_sphinx_theme"
html_theme_options = {"collapse_navigation": True, "logo": {"text": "beets"}}
html_title = "beets"
html_logo = "_static/beets_logo_nobg.png"
html_static_path = ["_static"]
html_css_files = ["beets.css"]
def skip_member(app, what, name, obj, skip, options):
if name.startswith("_"):
return True
return skip
def setup(app):
app.connect("autodoc-skip-member", skip_member)

View file

@ -10,8 +10,18 @@ and write metadata tags in media files.
.. _MediaFile: https://mediafile.readthedocs.io/en/latest/
.. toctree::
:maxdepth: 1
plugins
library
importer
cli
.. toctree::
:maxdepth: 1
:caption: API Reference
../api/plugins
../api/database

View file

@ -20,30 +20,18 @@ invocation of beets usually has only one :class:`Library`. It's powered by
abstraction, something like a very minimal `ORM`_. The library is also
responsible for handling queries to retrieve stored objects.
.. autoclass:: Library(path, directory[, path_formats[, replacements]])
Overview
''''''''
.. automethod:: __init__
You can add new items or albums to the library via the
:py:meth:`Library.add` and :py:meth:`Library.add_album` methods.
You can add new items or albums to the library:
You may also query the library for items and albums using the
:py:meth:`Library.items`, :py:meth:`Library.albums`, :py:meth:`Library.get_item` and :py:meth:`Library.get_album` methods.
.. automethod:: add
.. automethod:: add_album
And there are methods for querying the database:
.. automethod:: items
.. automethod:: albums
.. automethod:: get_item
.. automethod:: get_album
Any modifications must go through a :class:`Transaction` which you get can
using this method:
.. automethod:: transaction
Any modifications to the library must go through a
:class:`Transaction` object, which you can get using the
:py:meth:`Library.transaction` context manager.
.. _SQLite: https://sqlite.org/index.html
.. _ORM: https://en.wikipedia.org/wiki/Object-relational_mapping
@ -54,7 +42,7 @@ Model Classes
The two model entities in beets libraries, :class:`Item` and :class:`Album`,
share a base class, :class:`LibModel`, that provides common functionality. That
class itself specialises :class:`dbcore.Model` which provides an ORM-like
class itself specialises :class:`beets.dbcore.Model` which provides an ORM-like
abstraction.
To get or change the metadata of a model (an item or album), either access its
@ -68,42 +56,25 @@ Model base
Models use dirty-flags to track when the object's metadata goes out of
sync with the database. The dirty dictionary maps field names to booleans
indicating whether the field has been written since the object was last
synchronized (via load or store) with the database.
synchronized (via load or store) with the database. This logic is implemented
in the model base class :class:`LibModel` and is inherited by both
:class:`Item` and :class:`Album`.
.. autoclass:: LibModel
We provide CRUD-like methods for interacting with the database:
.. automethod:: all_keys
* :py:meth:`LibModel.store`
* :py:meth:`LibModel.load`
* :py:meth:`LibModel.remove`
* :py:meth:`LibModel.add`
.. automethod:: __init__
The base class :class:`beets.dbcore.Model` has a ``dict``-like interface, so
normal the normal mapping API is supported:
.. autoattribute:: _types
* :py:meth:`LibModel.keys`
* :py:meth:`LibModel.update`
* :py:meth:`LibModel.items`
* :py:meth:`LibModel.get`
.. autoattribute:: _fields
There are CRUD-like methods for interacting with the database:
.. automethod:: store
.. automethod:: load
.. automethod:: remove
.. automethod:: add
The base class :class:`dbcore.Model` has a ``dict``-like interface, so
normal the normal mapping API is supported:
.. automethod:: keys
.. automethod:: update
.. automethod:: items
.. note::
The :py:meth:`Album.items` method is not inherited from
:py:meth:`LibModel.items` for historical reasons.
.. automethod:: get
Item
''''
@ -155,38 +126,6 @@ This leads to the following implementation policy:
* On every modification to DB metadata (``item.field = ...``), the DB mtime
is reset to zero.
.. autoclass:: Item
.. automethod:: __init__
.. automethod:: from_path
.. automethod:: get_album
.. automethod:: destination
.. automethod:: current_mtime
The methods ``read()`` and ``write()`` are complementary: one reads a
file's tags and updates the item's metadata fields accordingly while the
other takes the item's fields and writes them to the file's tags.
.. automethod:: read
.. automethod:: write
.. automethod:: try_write
.. automethod:: try_sync
The :class:`Item` class supplements the normal model interface so that they
interacting with the filesystem as well:
.. automethod:: move
.. automethod:: remove
Album
'''''
@ -205,35 +144,10 @@ For those fields that are both item-level and album-level (e.g., ``year`` or
use an SQLite table called ``albums``, in which each column is an album
metadata field.
.. autoclass:: Album
.. automethod:: __init__
.. automethod:: item_dir
.. automethod:: items
Albums extend the normal model interface to also forward changes to their
items:
.. autoattribute:: item_keys
.. automethod:: store
.. automethod:: try_sync
.. automethod:: move
.. automethod:: remove
Albums also manage album art, image files that are associated with each
album:
.. automethod:: set_art
.. automethod:: move_art
.. automethod:: art_destination
.. note::
The :py:meth:`Album.items` method is not inherited from
:py:meth:`LibModel.items` for historical reasons.
Transactions
''''''''''''
@ -241,24 +155,30 @@ Transactions
The :class:`Library` class provides the basic methods necessary to access and
manipulate its contents. To perform more complicated operations atomically, or
to interact directly with the underlying SQLite database, you must use a
*transaction* (see this `blog post`_ for motivation). For example::
*transaction* (see this `blog post`_ for motivation). For example
.. code-block:: python
lib = Library()
with lib.transaction() as tx:
items = lib.items(query)
lib.add_album(list(items))
.. _blog post: https://beets.io/blog/sqlite-nightmare.html
.. currentmodule:: beets.dbcore.db
.. autoclass:: Transaction
:members:
The :class:`Transaction` class is a context manager that provides a
transactional interface to the underlying SQLite database. It is
responsible for managing the transaction's lifecycle, including
beginning, committing, and rolling back the transaction if
an error occurs.
.. _blog post: https://beets.io/blog/sqlite-nightmare.html
Queries
-------
.. currentmodule:: beets.dbcore.query
To access albums and items in a library, we use :doc:`/reference/query`.
In beets, the :class:`Query` abstract base class represents a criterion that
matches items or albums in the database.

View file

@ -1,3 +1,11 @@
Plugin Development Guide
========================
Beets plugins are Python modules or packages that extend the core functionality
of beets. The plugin system is designed to be flexible, allowing developers to
add virtually any type of features.
.. _writing-plugins:
Writing Plugins
@ -413,9 +421,8 @@ to extend the kinds of metadata that they can easily manage.
The ``MediaFile`` class uses ``MediaField`` descriptors to provide
access to file tags. If you have created a descriptor you can add it through
your plugins ``add_media_field()`` method.
your plugins :py:meth:`beets.plugins.BeetsPlugin.add_media_field()`` method.
.. automethod:: beets.plugins.BeetsPlugin.add_media_field
.. _MediaFile: https://mediafile.readthedocs.io/en/latest/