mirror of
https://github.com/beetbox/beets.git
synced 2026-01-18 06:05:06 +01:00
Merge pull request #4191 from katecoded/master
Updates docstrings and some comments in library.py
This commit is contained in:
commit
5df2914db1
1 changed files with 163 additions and 132 deletions
295
beets/library.py
295
beets/library.py
|
|
@ -53,8 +53,9 @@ class PathQuery(dbcore.FieldQuery):
|
|||
"""
|
||||
|
||||
def __init__(self, field, pattern, fast=True, case_sensitive=None):
|
||||
"""Create a path query. `pattern` must be a path, either to a
|
||||
file or a directory.
|
||||
"""Create a path query.
|
||||
|
||||
`pattern` must be a path, either to a file or a directory.
|
||||
|
||||
`case_sensitive` can be a bool or `None`, indicating that the
|
||||
behavior should depend on the filesystem.
|
||||
|
|
@ -140,8 +141,10 @@ class DateType(types.Float):
|
|||
|
||||
|
||||
class PathType(types.Type):
|
||||
"""A dbcore type for filesystem paths. These are represented as
|
||||
`bytes` objects, in keeping with the Unix filesystem abstraction.
|
||||
"""A dbcore type for filesystem paths.
|
||||
|
||||
These are represented as `bytes` objects, in keeping with
|
||||
the Unix filesystem abstraction.
|
||||
"""
|
||||
|
||||
sql = 'BLOB'
|
||||
|
|
@ -149,8 +152,9 @@ class PathType(types.Type):
|
|||
model_type = bytes
|
||||
|
||||
def __init__(self, nullable=False):
|
||||
"""Create a path type object. `nullable` controls whether the
|
||||
type may be missing, i.e., None.
|
||||
"""Create a path type object.
|
||||
|
||||
`nullable` controls whether the type may be missing, i.e., None.
|
||||
"""
|
||||
self.nullable = nullable
|
||||
|
||||
|
|
@ -282,7 +286,8 @@ PF_KEY_DEFAULT = 'default'
|
|||
|
||||
# Exceptions.
|
||||
class FileOperationError(Exception):
|
||||
"""Indicates an error when interacting with a file on disk.
|
||||
"""Indicate an error when interacting with a file on disk.
|
||||
|
||||
Possibilities include an unsupported media type, a permissions
|
||||
error, and an unhandled Mutagen exception.
|
||||
"""
|
||||
|
|
@ -296,8 +301,10 @@ class FileOperationError(Exception):
|
|||
self.reason = reason
|
||||
|
||||
def text(self):
|
||||
"""Get a string representing the error. Describes both the
|
||||
underlying reason and the file path in question.
|
||||
"""Get a string representing the error.
|
||||
|
||||
Describe both the underlying reason and the file path
|
||||
in question.
|
||||
"""
|
||||
return '{}: {}'.format(
|
||||
util.displayable_path(self.path),
|
||||
|
|
@ -310,16 +317,14 @@ class FileOperationError(Exception):
|
|||
|
||||
|
||||
class ReadError(FileOperationError):
|
||||
"""An error while reading a file (i.e. in `Item.read`).
|
||||
"""
|
||||
"""An error while reading a file (i.e. in `Item.read`)."""
|
||||
|
||||
def __str__(self):
|
||||
return 'error reading ' + super().text()
|
||||
|
||||
|
||||
class WriteError(FileOperationError):
|
||||
"""An error while writing a file (i.e. in `Item.write`).
|
||||
"""
|
||||
"""An error while writing a file (i.e. in `Item.write`)."""
|
||||
|
||||
def __str__(self):
|
||||
return 'error writing ' + super().text()
|
||||
|
|
@ -328,12 +333,10 @@ class WriteError(FileOperationError):
|
|||
# Item and Album model classes.
|
||||
|
||||
class LibModel(dbcore.Model):
|
||||
"""Shared concrete functionality for Items and Albums.
|
||||
"""
|
||||
"""Shared concrete functionality for Items and Albums."""
|
||||
|
||||
# Config key that specifies how an instance should be formatted.
|
||||
_format_config_key = None
|
||||
"""Config key that specifies how an instance should be formatted.
|
||||
"""
|
||||
|
||||
def _template_funcs(self):
|
||||
funcs = DefaultTemplateFunctions(self, self._db).functions()
|
||||
|
|
@ -410,6 +413,7 @@ class FormattedItemMapping(dbcore.db.FormattedMapping):
|
|||
|
||||
def _get(self, key):
|
||||
"""Get the value for a key, either from the album or the item.
|
||||
|
||||
Raise a KeyError for invalid keys.
|
||||
"""
|
||||
if self.for_path and key in self.album_keys:
|
||||
|
|
@ -422,8 +426,10 @@ class FormattedItemMapping(dbcore.db.FormattedMapping):
|
|||
raise KeyError(key)
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Get the value for a key. `artist` and `albumartist`
|
||||
are fallback values for each other when not set.
|
||||
"""Get the value for a key.
|
||||
|
||||
`artist` and `albumartist` are fallback values for each other
|
||||
when not set.
|
||||
"""
|
||||
value = self._get(key)
|
||||
|
||||
|
|
@ -448,6 +454,7 @@ class FormattedItemMapping(dbcore.db.FormattedMapping):
|
|||
|
||||
|
||||
class Item(LibModel):
|
||||
"""Represent a song or track."""
|
||||
_table = 'items'
|
||||
_flex_table = 'item_attributes'
|
||||
_fields = {
|
||||
|
|
@ -539,22 +546,18 @@ class Item(LibModel):
|
|||
'data_source': types.STRING,
|
||||
}
|
||||
|
||||
# Set of item fields that are backed by `MediaFile` fields.
|
||||
# Any kind of field (fixed, flexible, and computed) may be a media
|
||||
# field. Only these fields are read from disk in `read` and written in
|
||||
# `write`.
|
||||
_media_fields = set(MediaFile.readable_fields()) \
|
||||
.intersection(_fields.keys())
|
||||
"""Set of item fields that are backed by `MediaFile` fields.
|
||||
|
||||
Any kind of field (fixed, flexible, and computed) may be a media
|
||||
field. Only these fields are read from disk in `read` and written in
|
||||
`write`.
|
||||
"""
|
||||
|
||||
# Set of item fields that are backed by *writable* `MediaFile` tag
|
||||
# fields.
|
||||
# This excludes fields that represent audio data, such as `bitrate` or
|
||||
# `length`.
|
||||
_media_tag_fields = set(MediaFile.fields()).intersection(_fields.keys())
|
||||
"""Set of item fields that are backed by *writable* `MediaFile` tag
|
||||
fields.
|
||||
|
||||
This excludes fields that represent audio data, such as `bitrate` or
|
||||
`length`.
|
||||
"""
|
||||
|
||||
_formatter = FormattedItemMapping
|
||||
|
||||
|
|
@ -562,8 +565,8 @@ class Item(LibModel):
|
|||
|
||||
_format_config_key = 'format_item'
|
||||
|
||||
# Cached album object. Read-only.
|
||||
__album = None
|
||||
"""Cached album object. Read-only."""
|
||||
|
||||
@property
|
||||
def _cached_album(self):
|
||||
|
|
@ -594,8 +597,7 @@ class Item(LibModel):
|
|||
|
||||
@classmethod
|
||||
def from_path(cls, path):
|
||||
"""Creates a new item from the media file at the specified path.
|
||||
"""
|
||||
"""Create a new item from the media file at the specified path."""
|
||||
# Initiate with values that aren't read from files.
|
||||
i = cls(album_id=None)
|
||||
i.read(path)
|
||||
|
|
@ -603,8 +605,7 @@ class Item(LibModel):
|
|||
return i
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""Set the item's value for a standard field or a flexattr.
|
||||
"""
|
||||
"""Set the item's value for a standard field or a flexattr."""
|
||||
# Encode unicode paths and read buffers.
|
||||
if key == 'path':
|
||||
if isinstance(value, str):
|
||||
|
|
@ -621,7 +622,9 @@ class Item(LibModel):
|
|||
|
||||
def __getitem__(self, key):
|
||||
"""Get the value for a field, falling back to the album if
|
||||
necessary. Raise a KeyError if the field is not available.
|
||||
necessary.
|
||||
|
||||
Raise a KeyError if the field is not available.
|
||||
"""
|
||||
try:
|
||||
return super().__getitem__(key)
|
||||
|
|
@ -641,8 +644,9 @@ class Item(LibModel):
|
|||
)
|
||||
|
||||
def keys(self, computed=False, with_album=True):
|
||||
"""Get a list of available field names. `with_album`
|
||||
controls whether the album's fields are included.
|
||||
"""Get a list of available field names.
|
||||
|
||||
`with_album` controls whether the album's fields are included.
|
||||
"""
|
||||
keys = super().keys(computed=computed)
|
||||
if with_album and self._cached_album:
|
||||
|
|
@ -653,7 +657,9 @@ class Item(LibModel):
|
|||
|
||||
def get(self, key, default=None, with_album=True):
|
||||
"""Get the value for a given key or `default` if it does not
|
||||
exist. Set `with_album` to false to skip album fallback.
|
||||
exist.
|
||||
|
||||
Set `with_album` to false to skip album fallback.
|
||||
"""
|
||||
try:
|
||||
return self._get(key, default, raise_=with_album)
|
||||
|
|
@ -663,8 +669,9 @@ class Item(LibModel):
|
|||
return default
|
||||
|
||||
def update(self, values):
|
||||
"""Set all key/value pairs in the mapping. If mtime is
|
||||
specified, it is not reset (as it might otherwise be).
|
||||
"""Set all key/value pairs in the mapping.
|
||||
|
||||
If mtime is specified, it is not reset (as it might otherwise be).
|
||||
"""
|
||||
super().update(values)
|
||||
if self.mtime == 0 and 'mtime' in values:
|
||||
|
|
@ -690,10 +697,10 @@ class Item(LibModel):
|
|||
"""Read the metadata from the associated file.
|
||||
|
||||
If `read_path` is specified, read metadata from that file
|
||||
instead. Updates all the properties in `_media_fields`
|
||||
instead. Update all the properties in `_media_fields`
|
||||
from the media file.
|
||||
|
||||
Raises a `ReadError` if the file could not be read.
|
||||
Raise a `ReadError` if the file could not be read.
|
||||
"""
|
||||
if read_path is None:
|
||||
read_path = self.path
|
||||
|
|
@ -769,10 +776,10 @@ class Item(LibModel):
|
|||
plugins.send('after_write', item=self, path=path)
|
||||
|
||||
def try_write(self, *args, **kwargs):
|
||||
"""Calls `write()` but catches and logs `FileOperationError`
|
||||
"""Call `write()` but catch and log `FileOperationError`
|
||||
exceptions.
|
||||
|
||||
Returns `False` an exception was caught and `True` otherwise.
|
||||
Return `False` an exception was caught and `True` otherwise.
|
||||
"""
|
||||
try:
|
||||
self.write(*args, **kwargs)
|
||||
|
|
@ -782,7 +789,7 @@ class Item(LibModel):
|
|||
return False
|
||||
|
||||
def try_sync(self, write, move, with_album=True):
|
||||
"""Synchronize the item with the database and, possibly, updates its
|
||||
"""Synchronize the item with the database and, possibly, update its
|
||||
tags on disk and its path (by moving the file).
|
||||
|
||||
`write` indicates whether to write new tags into the file. Similarly,
|
||||
|
|
@ -806,7 +813,7 @@ class Item(LibModel):
|
|||
# Files themselves.
|
||||
|
||||
def move_file(self, dest, operation=MoveOperation.MOVE):
|
||||
"""Move, copy, link or hardlink the item's depending on `operation`,
|
||||
"""Move, copy, link or hardlink the item depending on `operation`,
|
||||
updating the path value if the move succeeds.
|
||||
|
||||
If a file exists at `dest`, then it is slightly modified to be unique.
|
||||
|
|
@ -848,7 +855,7 @@ class Item(LibModel):
|
|||
self.path = dest
|
||||
|
||||
def current_mtime(self):
|
||||
"""Returns the current mtime of the file, rounded to the nearest
|
||||
"""Return the current mtime of the file, rounded to the nearest
|
||||
integer.
|
||||
"""
|
||||
return int(os.path.getmtime(syspath(self.path)))
|
||||
|
|
@ -867,9 +874,12 @@ class Item(LibModel):
|
|||
# Model methods.
|
||||
|
||||
def remove(self, delete=False, with_album=True):
|
||||
"""Removes the item. If `delete`, then the associated file is
|
||||
removed from disk. If `with_album`, then the item's album (if
|
||||
any) is removed if it the item was the last in the album.
|
||||
"""Remove the item.
|
||||
|
||||
If `delete`, then the associated file is removed from disk.
|
||||
|
||||
If `with_album`, then the item's album (if any) is removed
|
||||
if the item was the last in the album.
|
||||
"""
|
||||
super().remove()
|
||||
|
||||
|
|
@ -892,9 +902,10 @@ class Item(LibModel):
|
|||
def move(self, operation=MoveOperation.MOVE, basedir=None,
|
||||
with_album=True, store=True):
|
||||
"""Move the item to its designated location within the library
|
||||
directory (provided by destination()). Subdirectories are
|
||||
created as needed. If the operation succeeds, the item's path
|
||||
field is updated to reflect the new location.
|
||||
directory (provided by destination()).
|
||||
|
||||
Subdirectories are created as needed. If the operation succeeds,
|
||||
the item's path field is updated to reflect the new location.
|
||||
|
||||
Instead of moving the item it can also be copied, linked or hardlinked
|
||||
depending on `operation` which should be an instance of
|
||||
|
|
@ -908,8 +919,8 @@ class Item(LibModel):
|
|||
By default, the item is stored to the database if it is in the
|
||||
database, so any dirty fields prior to the move() call will be written
|
||||
as a side effect.
|
||||
If `store` is `False` however, the item won't be stored and you'll
|
||||
have to manually store it after invoking this method.
|
||||
If `store` is `False` however, the item won't be stored and it will
|
||||
have to be manually stored after invoking this method.
|
||||
"""
|
||||
self._check_db()
|
||||
dest = self.destination(basedir=basedir)
|
||||
|
|
@ -939,12 +950,13 @@ class Item(LibModel):
|
|||
|
||||
def destination(self, fragment=False, basedir=None, platform=None,
|
||||
path_formats=None, replacements=None):
|
||||
"""Returns the path in the library directory designated for the
|
||||
item (i.e., where the file ought to be). fragment makes this
|
||||
method return just the path fragment underneath the root library
|
||||
directory; the path is also returned as Unicode instead of
|
||||
encoded as a bytestring. basedir can override the library's base
|
||||
directory for the destination.
|
||||
"""Return the path in the library directory designated for the
|
||||
item (i.e., where the file ought to be).
|
||||
|
||||
fragment makes this method return just the path fragment underneath
|
||||
the root library directory; the path is also returned as Unicode
|
||||
instead of encoded as a bytestring. basedir can override the library's
|
||||
base directory for the destination.
|
||||
"""
|
||||
self._check_db()
|
||||
platform = platform or sys.platform
|
||||
|
|
@ -1016,9 +1028,10 @@ class Item(LibModel):
|
|||
|
||||
|
||||
class Album(LibModel):
|
||||
"""Provides access to information about albums stored in a
|
||||
library. Reflects the library's "albums" table, including album
|
||||
art.
|
||||
"""Provide access to information about albums stored in a
|
||||
library.
|
||||
|
||||
Reflects the library's "albums" table, including album art.
|
||||
"""
|
||||
_table = 'albums'
|
||||
_flex_table = 'album_attributes'
|
||||
|
|
@ -1076,6 +1089,7 @@ class Album(LibModel):
|
|||
'artist': SmartArtistSort,
|
||||
}
|
||||
|
||||
# List of keys that are set on an album's items.
|
||||
item_keys = [
|
||||
'added',
|
||||
'albumartist',
|
||||
|
|
@ -1113,8 +1127,6 @@ class Album(LibModel):
|
|||
'original_month',
|
||||
'original_day',
|
||||
]
|
||||
"""List of keys that are set on an album's items.
|
||||
"""
|
||||
|
||||
_format_config_key = 'format_album'
|
||||
|
||||
|
|
@ -1128,16 +1140,19 @@ class Album(LibModel):
|
|||
return getters
|
||||
|
||||
def items(self):
|
||||
"""Returns an iterable over the items associated with this
|
||||
"""Return an iterable over the items associated with this
|
||||
album.
|
||||
"""
|
||||
return self._db.items(dbcore.MatchQuery('album_id', self.id))
|
||||
|
||||
def remove(self, delete=False, with_items=True):
|
||||
"""Removes this album and all its associated items from the
|
||||
library. If delete, then the items' files are also deleted
|
||||
from disk, along with any album art. The directories
|
||||
containing the album are also removed (recursively) if empty.
|
||||
"""Remove this album and all its associated items from the
|
||||
library.
|
||||
|
||||
If delete, then the items' files are also deleted from disk,
|
||||
along with any album art. The directories containing the album are
|
||||
also removed (recursively) if empty.
|
||||
|
||||
Set with_items to False to avoid removing the album's items.
|
||||
"""
|
||||
super().remove()
|
||||
|
|
@ -1208,8 +1223,8 @@ class Album(LibModel):
|
|||
|
||||
By default, the album is stored to the database, persisting any
|
||||
modifications to its metadata. If `store` is `False` however,
|
||||
the album is not stored automatically, and you'll have to manually
|
||||
store it after invoking this method.
|
||||
the album is not stored automatically, and it will have to be manually
|
||||
stored after invoking this method.
|
||||
"""
|
||||
basedir = basedir or self._db.directory
|
||||
|
||||
|
|
@ -1230,7 +1245,7 @@ class Album(LibModel):
|
|||
self.store()
|
||||
|
||||
def item_dir(self):
|
||||
"""Returns the directory containing the album's first item,
|
||||
"""Return the directory containing the album's first item,
|
||||
provided that such an item exists.
|
||||
"""
|
||||
item = self.items().get()
|
||||
|
|
@ -1239,8 +1254,7 @@ class Album(LibModel):
|
|||
return os.path.dirname(item.path)
|
||||
|
||||
def _albumtotal(self):
|
||||
"""Return the total number of tracks on all discs on the album
|
||||
"""
|
||||
"""Return the total number of tracks on all discs on the album."""
|
||||
if self.disctotal == 1 or not beets.config['per_disc_numbering']:
|
||||
return self.items()[0].tracktotal
|
||||
|
||||
|
|
@ -1260,8 +1274,10 @@ class Album(LibModel):
|
|||
return total
|
||||
|
||||
def art_destination(self, image, item_dir=None):
|
||||
"""Returns a path to the destination for the album art image
|
||||
for the album. `image` is the path of the image that will be
|
||||
"""Return a path to the destination for the album art image
|
||||
for the album.
|
||||
|
||||
`image` is the path of the image that will be
|
||||
moved there (used for its extension).
|
||||
|
||||
The path construction uses the existing path of the album's
|
||||
|
|
@ -1289,11 +1305,12 @@ class Album(LibModel):
|
|||
return bytestring_path(dest)
|
||||
|
||||
def set_art(self, path, copy=True):
|
||||
"""Sets the album's cover art to the image at the given path.
|
||||
"""Set the album's cover art to the image at the given path.
|
||||
|
||||
The image is copied (or moved) into place, replacing any
|
||||
existing art.
|
||||
|
||||
Sends an 'art_set' event with `self` as the sole argument.
|
||||
Send an 'art_set' event with `self` as the sole argument.
|
||||
"""
|
||||
path = bytestring_path(path)
|
||||
oldart = self.artpath
|
||||
|
|
@ -1320,10 +1337,12 @@ class Album(LibModel):
|
|||
plugins.send('art_set', album=self)
|
||||
|
||||
def store(self, fields=None):
|
||||
"""Update the database with the album information. The album's
|
||||
tracks are also updated.
|
||||
:param fields: The fields to be stored. If not specified, all fields
|
||||
will be.
|
||||
"""Update the database with the album information.
|
||||
|
||||
The album's tracks are also updated.
|
||||
|
||||
`fields` represents the fields to be stored. If not specified,
|
||||
all fields will be.
|
||||
"""
|
||||
# Get modified track fields.
|
||||
track_updates = {}
|
||||
|
|
@ -1408,10 +1427,11 @@ def parse_query_string(s, model_cls):
|
|||
|
||||
def _sqlite_bytelower(bytestring):
|
||||
""" A custom ``bytelower`` sqlite function so we can compare
|
||||
bytestrings in a semi case insensitive fashion. This is to work
|
||||
around sqlite builds are that compiled with
|
||||
``-DSQLITE_LIKE_DOESNT_MATCH_BLOBS``. See
|
||||
``https://github.com/beetbox/beets/issues/2172`` for details.
|
||||
bytestrings in a semi case insensitive fashion.
|
||||
|
||||
This is to work around sqlite builds are that compiled with
|
||||
``-DSQLITE_LIKE_DOESNT_MATCH_BLOBS``. See
|
||||
``https://github.com/beetbox/beets/issues/2172`` for details.
|
||||
"""
|
||||
return bytestring.lower()
|
||||
|
||||
|
|
@ -1419,8 +1439,7 @@ def _sqlite_bytelower(bytestring):
|
|||
# The Library: interface to the database.
|
||||
|
||||
class Library(dbcore.Database):
|
||||
"""A database of music containing songs and albums.
|
||||
"""
|
||||
"""A database of music containing songs and albums."""
|
||||
_models = (Item, Album)
|
||||
|
||||
def __init__(self, path='library.blb',
|
||||
|
|
@ -1446,7 +1465,9 @@ class Library(dbcore.Database):
|
|||
|
||||
def add(self, obj):
|
||||
"""Add the :class:`Item` or :class:`Album` object to the library
|
||||
database. Return the object's new id.
|
||||
database.
|
||||
|
||||
Return the object's new id.
|
||||
"""
|
||||
obj.add(self)
|
||||
self._memotable = {}
|
||||
|
|
@ -1482,8 +1503,10 @@ class Library(dbcore.Database):
|
|||
# Querying.
|
||||
|
||||
def _fetch(self, model_cls, query, sort=None):
|
||||
"""Parse a query and fetch. If a order specification is present
|
||||
in the query string the `sort` argument is ignored.
|
||||
"""Parse a query and fetch.
|
||||
|
||||
If an order specification is present in the query string
|
||||
the `sort` argument is ignored.
|
||||
"""
|
||||
# Parse the query, if necessary.
|
||||
try:
|
||||
|
|
@ -1506,40 +1529,38 @@ class Library(dbcore.Database):
|
|||
|
||||
@staticmethod
|
||||
def get_default_album_sort():
|
||||
"""Get a :class:`Sort` object for albums from the config option.
|
||||
"""
|
||||
"""Get a :class:`Sort` object for albums from the config option."""
|
||||
return dbcore.sort_from_strings(
|
||||
Album, beets.config['sort_album'].as_str_seq())
|
||||
|
||||
@staticmethod
|
||||
def get_default_item_sort():
|
||||
"""Get a :class:`Sort` object for items from the config option.
|
||||
"""
|
||||
"""Get a :class:`Sort` object for items from the config option."""
|
||||
return dbcore.sort_from_strings(
|
||||
Item, beets.config['sort_item'].as_str_seq())
|
||||
|
||||
def albums(self, query=None, sort=None):
|
||||
"""Get :class:`Album` objects matching the query.
|
||||
"""
|
||||
"""Get :class:`Album` objects matching the query."""
|
||||
return self._fetch(Album, query, sort or self.get_default_album_sort())
|
||||
|
||||
def items(self, query=None, sort=None):
|
||||
"""Get :class:`Item` objects matching the query.
|
||||
"""
|
||||
"""Get :class:`Item` objects matching the query."""
|
||||
return self._fetch(Item, query, sort or self.get_default_item_sort())
|
||||
|
||||
# Convenience accessors.
|
||||
|
||||
def get_item(self, id):
|
||||
"""Fetch an :class:`Item` by its ID. Returns `None` if no match is
|
||||
found.
|
||||
"""Fetch a :class:`Item` by its ID.
|
||||
|
||||
Return `None` if no match is found.
|
||||
"""
|
||||
return self._get(Item, id)
|
||||
|
||||
def get_album(self, item_or_id):
|
||||
"""Given an album ID or an item associated with an album, return
|
||||
an :class:`Album` object for the album. If no such album exists,
|
||||
returns `None`.
|
||||
a :class:`Album` object for the album.
|
||||
|
||||
If no such album exists, return `None`.
|
||||
"""
|
||||
if isinstance(item_or_id, int):
|
||||
album_id = item_or_id
|
||||
|
|
@ -1554,30 +1575,37 @@ class Library(dbcore.Database):
|
|||
|
||||
def _int_arg(s):
|
||||
"""Convert a string argument to an integer for use in a template
|
||||
function. May raise a ValueError.
|
||||
function.
|
||||
|
||||
May raise a ValueError.
|
||||
"""
|
||||
return int(s.strip())
|
||||
|
||||
|
||||
class DefaultTemplateFunctions:
|
||||
"""A container class for the default functions provided to path
|
||||
templates. These functions are contained in an object to provide
|
||||
templates.
|
||||
|
||||
These functions are contained in an object to provide
|
||||
additional context to the functions -- specifically, the Item being
|
||||
evaluated.
|
||||
"""
|
||||
_prefix = 'tmpl_'
|
||||
|
||||
def __init__(self, item=None, lib=None):
|
||||
"""Parametrize the functions. If `item` or `lib` is None, then
|
||||
some functions (namely, ``aunique``) will always evaluate to the
|
||||
empty string.
|
||||
"""Parametrize the functions.
|
||||
|
||||
If `item` or `lib` is None, then some functions (namely, ``aunique``)
|
||||
will always evaluate to the empty string.
|
||||
"""
|
||||
self.item = item
|
||||
self.lib = lib
|
||||
|
||||
def functions(self):
|
||||
"""Returns a dictionary containing the functions defined in this
|
||||
object. The keys are function names (as exposed in templates)
|
||||
"""Return a dictionary containing the functions defined in this
|
||||
object.
|
||||
|
||||
The keys are function names (as exposed in templates)
|
||||
and the values are Python functions.
|
||||
"""
|
||||
out = {}
|
||||
|
|
@ -1592,7 +1620,7 @@ class DefaultTemplateFunctions:
|
|||
|
||||
@staticmethod
|
||||
def tmpl_upper(s):
|
||||
"""Covert a string to upper case."""
|
||||
"""Convert a string to upper case."""
|
||||
return s.upper()
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -1630,21 +1658,20 @@ class DefaultTemplateFunctions:
|
|||
|
||||
@staticmethod
|
||||
def tmpl_asciify(s):
|
||||
"""Translate non-ASCII characters to their ASCII equivalents.
|
||||
"""
|
||||
"""Translate non-ASCII characters to their ASCII equivalents."""
|
||||
return util.asciify_path(s, beets.config['path_sep_replace'].as_str())
|
||||
|
||||
@staticmethod
|
||||
def tmpl_time(s, fmt):
|
||||
"""Format a time value using `strftime`.
|
||||
"""
|
||||
"""Format a time value using `strftime`."""
|
||||
cur_fmt = beets.config['time_format'].as_str()
|
||||
return time.strftime(fmt, time.strptime(s, cur_fmt))
|
||||
|
||||
def tmpl_aunique(self, keys=None, disam=None, bracket=None):
|
||||
"""Generate a string that is guaranteed to be unique among all
|
||||
albums in the library who share the same set of keys. A fields
|
||||
from "disam" is used in the string if one is sufficient to
|
||||
albums in the library who share the same set of keys.
|
||||
|
||||
A fields from "disam" is used in the string if one is sufficient to
|
||||
disambiguate the albums. Otherwise, a fallback opaque value is
|
||||
used. Both "keys" and "disam" should be given as
|
||||
whitespace-separated lists of field names, while "bracket" is a
|
||||
|
|
@ -1735,14 +1762,15 @@ class DefaultTemplateFunctions:
|
|||
|
||||
@staticmethod
|
||||
def tmpl_first(s, count=1, skip=0, sep='; ', join_str='; '):
|
||||
""" Gets the item(s) from x to y in a string separated by something
|
||||
and join then with something
|
||||
"""Get the item(s) from x to y in a string separated by something
|
||||
and join then with something.
|
||||
|
||||
:param s: the string
|
||||
:param count: The number of items included
|
||||
:param skip: The number of items skipped
|
||||
:param sep: the separator. Usually is '; ' (default) or '/ '
|
||||
:param join_str: the string which will join the items, default '; '.
|
||||
Args:
|
||||
s: the string
|
||||
count: The number of items included
|
||||
skip: The number of items skipped
|
||||
sep: the separator. Usually is '; ' (default) or '/ '
|
||||
join_str: the string which will join the items, default '; '.
|
||||
"""
|
||||
skip = int(skip)
|
||||
count = skip + int(count)
|
||||
|
|
@ -1752,10 +1780,13 @@ class DefaultTemplateFunctions:
|
|||
""" If field exists return trueval or the field (default)
|
||||
otherwise, emit return falseval (if provided).
|
||||
|
||||
:param field: The name of the field
|
||||
:param trueval: The string if the condition is true
|
||||
:param falseval: The string if the condition is false
|
||||
:return: The string, based on condition
|
||||
Args:
|
||||
field: The name of the field
|
||||
trueval: The string if the condition is true
|
||||
falseval: The string if the condition is false
|
||||
|
||||
Returns:
|
||||
The string, based on condition.
|
||||
"""
|
||||
if field in self.item:
|
||||
return trueval if trueval else self.item.formatted().get(field)
|
||||
|
|
|
|||
Loading…
Reference in a new issue