From a5df44a5ea3a8cffd9ea5b550e173940fd4683cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Tue, 13 May 2025 06:07:38 +0100 Subject: [PATCH] Cache album and item lookups --- beets/library.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/beets/library.py b/beets/library.py index 8fd1c8022..d027dc11b 100644 --- a/beets/library.py +++ b/beets/library.py @@ -23,7 +23,7 @@ import string import sys import time import unicodedata -from functools import cached_property +from functools import cache, cached_property from pathlib import Path from typing import TYPE_CHECKING @@ -1284,6 +1284,7 @@ class Album(LibModel): getters["albumtotal"] = Album._albumtotal return getters + @cache def items(self): """Return an iterable over the items associated with this album. @@ -1541,6 +1542,7 @@ class Album(LibModel): # Query construction helpers. +@cache def parse_query_parts(parts, model_cls): """Given a beets query string as a list of components, return the `Query` and `Sort` they represent. @@ -1582,7 +1584,7 @@ def parse_query_string(s, model_cls): parts = shlex.split(s) except ValueError as exc: raise dbcore.InvalidQueryError(s, exc) - return parse_query_parts(parts, model_cls) + return parse_query_parts(tuple(parts), model_cls) # The Library: interface to the database. @@ -1652,6 +1654,7 @@ class Library(dbcore.Database): # Querying. + @cache def _fetch(self, model_cls, query, sort=None): """Parse a query and fetch. @@ -1664,7 +1667,7 @@ class Library(dbcore.Database): if isinstance(query, str): query, parsed_sort = parse_query_string(query, model_cls) elif isinstance(query, (list, tuple)): - query, parsed_sort = parse_query_parts(query, model_cls) + query, parsed_sort = parse_query_parts(tuple(query), model_cls) except dbcore.query.InvalidQueryArgumentValueError as exc: raise dbcore.InvalidQueryError(query, exc) @@ -1691,11 +1694,19 @@ class Library(dbcore.Database): def albums(self, query=None, sort=None) -> Results[Album]: """Get :class:`Album` objects matching the query.""" - return self._fetch(Album, query, sort or self.get_default_album_sort()) + return self._fetch( + Album, + tuple(query) if isinstance(query, list) else query, + sort or self.get_default_album_sort(), + ) def items(self, query=None, sort=None) -> Results[Item]: """Get :class:`Item` objects matching the query.""" - return self._fetch(Item, query, sort or self.get_default_item_sort()) + return self._fetch( + Item, + tuple(query) if isinstance(query, list) else query, + sort or self.get_default_item_sort(), + ) # Convenience accessors.