Define replacements for commonly used classes

This commit is contained in:
Šarūnas Nejus 2025-09-04 10:23:52 +01:00
parent 67dd355968
commit 33feb0348d
No known key found for this signature in database
GPG key ID: DD28F6704DBE3435
3 changed files with 73 additions and 84 deletions

View file

@ -75,6 +75,17 @@ man_pages = [
), ),
] ]
# Global substitutions that can be used anywhere in the documentation.
rst_epilog = """
.. |Album| replace:: :class:`~beets.library.models.Album`
.. |AlbumInfo| replace:: :class:`beets.autotag.hooks.AlbumInfo`
.. |ImportSession| replace:: :class:`~beets.importer.session.ImportSession`
.. |ImportTask| replace:: :class:`~beets.importer.tasks.ImportTask`
.. |Item| replace:: :class:`~beets.library.models.Item`
.. |Library| replace:: :class:`~beets.library.library.Library`
.. |Model| replace:: :class:`~beets.dbcore.db.Model`
.. |TrackInfo| replace:: :class:`beets.autotag.hooks.TrackInfo`
"""
# -- Options for HTML output ------------------------------------------------- # -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

View file

@ -7,18 +7,18 @@ This page describes the internal API of beets' core database features. It
doesn't exhaustively document the API, but is aimed at giving an overview of the doesn't exhaustively document the API, but is aimed at giving an overview of the
architecture to orient anyone who wants to dive into the code. architecture to orient anyone who wants to dive into the code.
The :class:`Library` object is the central repository for data in beets. It The |Library| object is the central repository for data in beets. It represents
represents a database containing songs, which are :class:`Item` instances, and a database containing songs, which are |Item| instances, and groups of items,
groups of items, which are :class:`Album` instances. which are |Album| instances.
The Library Class The Library Class
----------------- -----------------
The :class:`Library` is typically instantiated as a singleton. A single The |Library| is typically instantiated as a singleton. A single invocation of
invocation of beets usually has only one :class:`Library`. It's powered by beets usually has only one |Library|. It's powered by :class:`dbcore.Database`
:class:`dbcore.Database` under the hood, which handles the SQLite_ abstraction, under the hood, which handles the SQLite_ abstraction, something like a very
something like a very minimal ORM_. The library is also responsible for handling minimal ORM_. The library is also responsible for handling queries to retrieve
queries to retrieve stored objects. stored objects.
Overview Overview
~~~~~~~~ ~~~~~~~~
@ -40,10 +40,9 @@ which you can get using the :py:meth:`Library.transaction` context manager.
Model Classes Model Classes
------------- -------------
The two model entities in beets libraries, :class:`Item` and :class:`Album`, The two model entities in beets libraries, |Item| and |Album|, share a base
share a base class, :class:`LibModel`, that provides common functionality. That class, :class:`LibModel`, that provides common functionality. That class itself
class itself specialises :class:`beets.dbcore.Model` which provides an ORM-like specialises :class:`beets.dbcore.Model` which provides an ORM-like abstraction.
abstraction.
To get or change the metadata of a model (an item or album), either access its To get or change the metadata of a model (an item or album), either access its
attributes (e.g., ``print(album.year)`` or ``album.year = 2012``) or use the attributes (e.g., ``print(album.year)`` or ``album.year = 2012``) or use the
@ -56,8 +55,7 @@ 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 the database. The dirty dictionary maps field names to booleans indicating
whether the field has been written since the object was last synchronized (via whether the field has been written since the object was last synchronized (via
load or store) with the database. This logic is implemented in the model base 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 :class:`LibModel` and is inherited by both |Item| and |Album|.
:class:`Album`.
We provide CRUD-like methods for interacting with the database: We provide CRUD-like methods for interacting with the database:
@ -77,10 +75,10 @@ normal the normal mapping API is supported:
Item Item
~~~~ ~~~~
Each :class:`Item` object represents a song or track. (We use the more generic Each |Item| object represents a song or track. (We use the more generic term
term item because, one day, beets might support non-music media.) An item can item because, one day, beets might support non-music media.) An item can either
either be purely abstract, in which case it's just a bag of metadata fields, or be purely abstract, in which case it's just a bag of metadata fields, or it can
it can have an associated file (indicated by ``item.path``). have an associated file (indicated by ``item.path``).
In terms of the underlying SQLite database, items are backed by a single table In terms of the underlying SQLite database, items are backed by a single table
called items with one column per metadata fields. The metadata fields currently called items with one column per metadata fields. The metadata fields currently
@ -97,12 +95,12 @@ become out of sync with on-disk metadata, mainly to speed up the
:ref:`update-cmd` (which needs to check whether the database is in sync with the :ref:`update-cmd` (which needs to check whether the database is in sync with the
filesystem). This feature turns out to be sort of complicated. filesystem). This feature turns out to be sort of complicated.
For any :class:`Item`, there are two mtimes: the on-disk mtime (maintained by For any |Item|, there are two mtimes: the on-disk mtime (maintained by the OS)
the OS) and the database mtime (maintained by beets). Correspondingly, there is and the database mtime (maintained by beets). Correspondingly, there is on-disk
on-disk metadata (ID3 tags, for example) and DB metadata. The goal with the metadata (ID3 tags, for example) and DB metadata. The goal with the mtime is to
mtime is to ensure that the on-disk and DB mtimes match when the on-disk and DB ensure that the on-disk and DB mtimes match when the on-disk and DB metadata are
metadata are in sync; this lets beets do a quick mtime check and avoid rereading in sync; this lets beets do a quick mtime check and avoid rereading files in
files in some circumstances. some circumstances.
Specifically, beets attempts to maintain the following invariant: Specifically, beets attempts to maintain the following invariant:
@ -126,14 +124,14 @@ This leads to the following implementation policy:
Album Album
~~~~~ ~~~~~
An :class:`Album` is a collection of Items in the database. Every item in the An |Album| is a collection of Items in the database. Every item in the database
database has either zero or one associated albums (accessible via has either zero or one associated albums (accessible via ``item.album_id``). An
``item.album_id``). An item that has no associated album is called a singleton. item that has no associated album is called a singleton. Changing fields on an
Changing fields on an album (e.g. ``album.year = 2012``) updates the album album (e.g. ``album.year = 2012``) updates the album itself and also changes the
itself and also changes the same field in all associated items. same field in all associated items.
An :class:`Album` object keeps track of album-level metadata, which is (mostly) An |Album| object keeps track of album-level metadata, which is (mostly) a
a subset of the track-level metadata. The album-level metadata fields are listed subset of the track-level metadata. The album-level metadata fields are listed
in ``Album._fields``. For those fields that are both item-level and album-level in ``Album._fields``. For those fields that are both item-level and album-level
(e.g., ``year`` or ``albumartist``), every item in an album should share the (e.g., ``year`` or ``albumartist``), every item in an album should share the
same value. Albums use an SQLite table called ``albums``, in which each column same value. Albums use an SQLite table called ``albums``, in which each column
@ -147,7 +145,7 @@ is an album metadata field.
Transactions Transactions
~~~~~~~~~~~~ ~~~~~~~~~~~~
The :class:`Library` class provides the basic methods necessary to access and The |Library| class provides the basic methods necessary to access and
manipulate its contents. To perform more complicated operations atomically, or manipulate its contents. To perform more complicated operations atomically, or
to interact directly with the underlying SQLite database, you must use a 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
@ -181,8 +179,8 @@ matching items/albums.
The ``clause()`` method should return an SQLite ``WHERE`` clause that matches The ``clause()`` method should return an SQLite ``WHERE`` clause that matches
appropriate albums/items. This allows for efficient batch queries. appropriate albums/items. This allows for efficient batch queries.
Correspondingly, the ``match(item)`` method should take an :class:`Item` object Correspondingly, the ``match(item)`` method should take an |Item| object and
and return a boolean, indicating whether or not a specific item matches the return a boolean, indicating whether or not a specific item matches the
criterion. This alternate implementation allows clients to determine whether criterion. This alternate implementation allows clients to determine whether
items that have already been fetched from the database match the query. items that have already been fetched from the database match the query.
@ -194,4 +192,4 @@ together, matching only albums/items that match all constituent queries.
Beets has a human-writable plain-text query syntax that can be parsed into Beets has a human-writable plain-text query syntax that can be parsed into
:class:`Query` objects. Calling ``AndQuery.from_strings`` parses a list of query :class:`Query` objects. Calling ``AndQuery.from_strings`` parses a list of query
parts into a query object that can then be used with :class:`Library` objects. parts into a query object that can then be used with |Library| objects.

View file

@ -52,166 +52,146 @@ registration process in this case:
command starts. command starts.
``import`` ``import``
:Parameters: :py:class:`lib <beets.library.Library>`, ``paths`` (list of :Parameters: ``lib`` (|Library|), ``paths`` (list of path strings)
path strings)
:Description: Called after the ``import`` command finishes. :Description: Called after the ``import`` command finishes.
``album_imported`` ``album_imported``
:Parameters: :py:class:`lib <beets.library.Library>`, :py:class:`album :Parameters: ``lib`` (|Library|), ``album`` (|Album|)
<beets.library.Album>`
:Description: Called every time the importer finishes adding an album to the :Description: Called every time the importer finishes adding an album to the
library. library.
``album_removed`` ``album_removed``
:Parameters: :py:class:`lib <beets.library.Library>`, :py:class:`album :Parameters: ``lib`` (|Library|), ``album`` (|Album|)
<beets.library.Album>`
:Description: Called every time an album is removed from the library (even :Description: Called every time an album is removed from the library (even
when its files are not deleted from disk). when its files are not deleted from disk).
``item_copied`` ``item_copied``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called whenever an item file is copied. :Description: Called whenever an item file is copied.
``item_imported`` ``item_imported``
:Parameters: :py:class:`lib <beets.library.Library>`, :py:class:`item :Parameters: ``lib`` (|Library|), ``item`` (|Item|)
<beets.library.Item>`
:Description: Called every time the importer adds a singleton to the library :Description: Called every time the importer adds a singleton to the library
(not called for full-album imports). (not called for full-album imports).
``before_item_imported`` ``before_item_imported``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called with an ``Item`` object immediately before it is :Description: Called with an ``Item`` object immediately before it is
imported. imported.
``before_item_moved`` ``before_item_moved``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called with an ``Item`` object immediately before its file is :Description: Called with an ``Item`` object immediately before its file is
moved. moved.
``item_moved`` ``item_moved``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called with an ``Item`` object whenever its file is moved. :Description: Called with an ``Item`` object whenever its file is moved.
``item_linked`` ``item_linked``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called with an ``Item`` object whenever a symlink is created :Description: Called with an ``Item`` object whenever a symlink is created
for a file. for a file.
``item_hardlinked`` ``item_hardlinked``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called with an ``Item`` object whenever a hardlink is created :Description: Called with an ``Item`` object whenever a hardlink is created
for a file. for a file.
``item_reflinked`` ``item_reflinked``
:Parameters: :py:class:`item <beets.library.Item>`, ``source`` (path), :Parameters: ``item`` (|Item|), ``source`` (path), ``destination`` (path)
``destination`` (path)
:Description: Called with an ``Item`` object whenever a reflink is created :Description: Called with an ``Item`` object whenever a reflink is created
for a file. for a file.
``item_removed`` ``item_removed``
:Parameters: :py:class:`item <beets.library.Item>` :Parameters: ``item`` (|Item|)
:Description: Called with an ``Item`` object every time an item (singleton :Description: Called with an ``Item`` object every time an item (singleton
or part of an album) is removed from the library (even when its file is or part of an album) is removed from the library (even when its file is
not deleted from disk). not deleted from disk).
``write`` ``write``
:Parameters: :py:class:`item <beets.library.Item>`, ``path`` (path), :Parameters: ``item`` (|Item|), ``path`` (path), ``tags`` (dict)
``tags`` (dict)
:Description: Called just before a file's metadata is written to disk. :Description: Called just before a file's metadata is written to disk.
Handlers may modify ``tags`` or raise ``library.FileOperationError`` to Handlers may modify ``tags`` or raise ``library.FileOperationError`` to
abort. abort.
``after_write`` ``after_write``
:Parameters: :py:class:`item <beets.library.Item>` :Parameters: ``item`` (|Item|)
:Description: Called after a file's metadata is written to disk. :Description: Called after a file's metadata is written to disk.
``import_task_created`` ``import_task_created``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called immediately after an import task is initialized. May :Description: Called immediately after an import task is initialized. May
return a list (possibly empty) of replacement tasks. return a list (possibly empty) of replacement tasks.
``import_task_start`` ``import_task_start``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called before an import task begins processing. :Description: Called before an import task begins processing.
``import_task_apply`` ``import_task_apply``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called after metadata changes have been applied in an import :Description: Called after metadata changes have been applied in an import
task (on the UI thread; keep fast). Prefer a pipeline stage otherwise task (on the UI thread; keep fast). Prefer a pipeline stage otherwise
(see :ref:`plugin-stage`). (see :ref:`plugin-stage`).
``import_task_before_choice`` ``import_task_before_choice``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called after candidate search and before deciding how to :Description: Called after candidate search and before deciding how to
import. May return an importer action (only one handler may return import. May return an importer action (only one handler may return
non-None). non-None).
``import_task_choice`` ``import_task_choice``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called after a decision has been made about an import task. :Description: Called after a decision has been made about an import task.
Use ``task.choice_flag`` to inspect or change the action. Use ``task.choice_flag`` to inspect or change the action.
``import_task_files`` ``import_task_files``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called after filesystem manipulation (copy/move/write) for an :Description: Called after filesystem manipulation (copy/move/write) for an
import task. import task.
``library_opened`` ``library_opened``
:Parameters: :py:class:`lib <beets.library.Library>` :Parameters: ``lib`` (|Library|)
:Description: Called after beets starts and initializes the main Library :Description: Called after beets starts and initializes the main Library
object. object.
``database_change`` ``database_change``
:Parameters: :py:class:`lib <beets.library.Library>`, :py:class:`model :Parameters: ``lib`` (|Library|), ``model`` (|Model|)
<beets.library.Model>`
:Description: A modification has been made to the library database (may not :Description: A modification has been made to the library database (may not
yet be committed). yet be committed).
``cli_exit`` ``cli_exit``
:Parameters: :py:class:`lib <beets.library.Library>` :Parameters: ``lib`` (|Library|)
:Description: Called just before the ``beet`` command-line program exits. :Description: Called just before the ``beet`` command-line program exits.
``import_begin`` ``import_begin``
:Parameters: :py:class:`session <beets.importer.ImportSession>` :Parameters: ``session`` (|ImportSession|)
:Description: Called just before a ``beet import`` session starts. :Description: Called just before a ``beet import`` session starts.
``trackinfo_received`` ``trackinfo_received``
:Parameters: :py:class:`info <beets.autotag.TrackInfo>` :Parameters: ``info`` (|TrackInfo|)
:Description: Called after metadata for a track is fetched (e.g., from :Description: Called after metadata for a track is fetched (e.g., from
MusicBrainz). Handlers can modify the tags seen by later pipeline stages MusicBrainz). Handlers can modify the tags seen by later pipeline stages
or adjustments (e.g., ``mbsync``). or adjustments (e.g., ``mbsync``).
``albuminfo_received`` ``albuminfo_received``
:Parameters: :py:class:`info <beets.autotag.AlbumInfo>` :Parameters: ``info`` (|AlbumInfo|)
:Description: Like ``trackinfo_received`` but for album-level metadata. :Description: Like ``trackinfo_received`` but for album-level metadata.
``before_choose_candidate`` ``before_choose_candidate``
:Parameters: :py:class:`task <beets.importer.ImportTask>`, :Parameters: ``task`` (|ImportTask|), ``session`` (|ImportSession|)
:py:class:`session <beets.importer.ImportSession>`
:Description: Called before prompting the user during interactive import. :Description: Called before prompting the user during interactive import.
May return a list of ``PromptChoices`` to append to the prompt (see May return a list of ``PromptChoices`` to append to the prompt (see
:ref:`append_prompt_choices`). :ref:`append_prompt_choices`).
``mb_track_extract`` ``mb_track_extract``
:Parameters: :py:class:`data <dict>` :Parameters: ``data`` (dict)
:Description: Called after metadata is obtained from MusicBrainz for a :Description: Called after metadata is obtained from MusicBrainz for a
track. Must return a (possibly empty) dict of additional ``field: track. Must return a (possibly empty) dict of additional ``field:
value`` pairs to apply (overwriting existing fields). value`` pairs to apply (overwriting existing fields).
``mb_album_extract`` ``mb_album_extract``
:Parameters: :py:class:`data <dict>` :Parameters: ``data`` (dict)
:Description: Like ``mb_track_extract`` but for album tags. Overwrites tags :Description: Like ``mb_track_extract`` but for album tags. Overwrites tags
set at the track level with the same field. set at the track level with the same field.