Rewrite and speed up query tests (#5813)

Previously:

```sh
Poe => pytest -p no:cov test/test_query.py --durations=10
=============================================================================== test session starts ===============================================================================
platform linux -- Python 3.9.20, pytest-8.3.5, pluggy-1.5.0
cachedir: /tmp/pytest_cache
rootdir: /home/sarunas/repo/beets
configfile: setup.cfg
plugins: anyio-4.9.0, xdist-3.6.1, requests-mock-1.12.1, flask-1.3.0
collected 133 items                                                                                                                                                               

test/test_query.py .....................................................................................................................................                 [133/133]

============================================================================== slowest 10 durations ===============================================================================
0.13s call     test/test_query.py::NotQueryTest::test_type_none
0.12s call     test/test_query.py::NotQueryTest::test_fast_vs_slow
0.11s call     test/test_query.py::GetTest::test_singleton_0
0.11s call     test/test_query.py::NotQueryTest::test_type_substring
0.11s call     test/test_query.py::RelatedQueriesTest::test_filter_items_by_common_field
0.11s call     test/test_query.py::RelatedQueriesTest::test_get_items_filter_by_album_field
0.11s call     test/test_query.py::NotQueryTest::test_type_boolean
0.11s call     test/test_query.py::NotQueryTest::test_type_or
0.11s call     test/test_query.py::NotQueryTest::test_type_numeric
0.11s call     test/test_query.py::NotQueryTest::test_type_true
=============================================================================== 133 passed in 9.94s ===============================================================================
```

Now:
```sh
Poe => pytest -p no:cov test/test_query.py --durations=10
=============================================================================== test session starts ================================================================================
platform linux -- Python 3.9.20, pytest-8.3.5, pluggy-1.5.0
cachedir: /tmp/pytest_cache
rootdir: /home/sarunas/repo/beets
configfile: setup.cfg
plugins: anyio-4.9.0, xdist-3.6.1, requests-mock-1.12.1, flask-1.3.0
collected 129 items                                                                                                                                                                

test/test_query.py .................................................................................................................................                      [129/129]

=============================================================================== slowest 10 durations ===============================================================================
0.10s setup    test/test_query.py::TestRelatedQueries::test_related_query[match-album-with-item-field-query]
0.09s setup    test/test_query.py::TestGet::test_get_query[''-['first', 'second', 'third']]
0.09s setup    test/test_query.py::TestPathQuery::test_explicit[exact-match]
0.09s setup    test/test_query.py::TestQuery::test_value_type[parse-true]
0.08s setup    test/test_query.py::TestDefaultSearchFields::test_search[album-match-album]
0.02s call     test/test_query.py::TestGet::test_query_logic[SubstringQuery('album', 'ba', fast=True)-{'third'}]
0.02s call     test/test_query.py::TestGet::test_query_logic[NoneQuery('rg_track_gain', True)-set()]
0.02s call     test/test_query.py::TestGet::test_query_logic[NumericQuery('year', '2001..2002', fast=True)-{'third'}]
0.02s call     test/test_query.py::TestGet::test_query_logic[RegexpQuery('artist', re.compile('^t'), fast=True)-{'first'}]
0.02s call     test/test_query.py::TestGet::test_query_logic[OrQuery([BooleanQuery('comp', 1, fast=True), NumericQuery('year', '2002', fast=True)])-{'third'}]
=============================================================================== 129 passed in 2.53s ================================================================================
```
This commit is contained in:
Šarūnas Nejus 2025-07-06 16:24:46 +01:00 committed by GitHub
commit d5f87264e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 417 additions and 840 deletions

View file

@ -85,6 +85,7 @@ class Query(ABC):
"""Return a set with field names that this query operates on."""
return set()
@abstractmethod
def clause(self) -> tuple[str | None, Sequence[Any]]:
"""Generate an SQLite expression implementing the query.
@ -95,14 +96,12 @@ class Query(ABC):
The default implementation returns None, falling back to a slow query
using `match()`.
"""
return None, ()
@abstractmethod
def match(self, obj: Model):
"""Check whether this query matches a given Model. Can be used to
perform queries on arbitrary sets of Model.
"""
...
def __and__(self, other: Query) -> AndQuery:
return AndQuery([self, other])
@ -152,7 +151,7 @@ class FieldQuery(Query, Generic[P]):
self.fast = fast
def col_clause(self) -> tuple[str, Sequence[SQLiteType]]:
return self.field, ()
raise NotImplementedError
def clause(self) -> tuple[str | None, Sequence[SQLiteType]]:
if self.fast:
@ -164,7 +163,7 @@ class FieldQuery(Query, Generic[P]):
@classmethod
def value_match(cls, pattern: P, value: Any):
"""Determine whether the value matches the pattern."""
raise NotImplementedError()
raise NotImplementedError
def match(self, obj: Model) -> bool:
return self.value_match(self.pattern, obj.get(self.field_name))
@ -234,7 +233,7 @@ class StringFieldQuery(FieldQuery[P]):
"""Determine whether the value matches the pattern. Both
arguments are strings. Subclasses implement this method.
"""
raise NotImplementedError()
raise NotImplementedError
class StringQuery(StringFieldQuery[str]):

View file

@ -63,8 +63,8 @@ HAVE_SYMLINK = sys.platform != "win32"
HAVE_HARDLINK = sys.platform != "win32"
def item(lib=None):
i = beets.library.Item(
def item(lib=None, **kwargs):
defaults = dict(
title="the title",
artist="the artist",
albumartist="the album artist",
@ -99,6 +99,7 @@ def item(lib=None):
album_id=None,
mtime=12345,
)
i = beets.library.Item(**{**defaults, **kwargs})
if lib:
lib.add(i)
return i

View file

@ -1,7 +1,10 @@
import inspect
import os
import pytest
from beets.dbcore.query import Query
def skip_marked_items(items: list[pytest.Item], marker_name: str, reason: str):
for item in (i for i in items if i.get_closest_marker(marker_name)):
@ -21,3 +24,20 @@ def pytest_collection_modifyitems(
skip_marked_items(
items, "on_lyrics_update", "No change in lyrics source code"
)
def pytest_make_parametrize_id(config, val, argname):
"""Generate readable test identifiers for pytest parametrized tests.
Provides custom string representations for:
- Query classes/instances: use class name
- Lambda functions: show abbreviated source
- Other values: use standard repr()
"""
if inspect.isclass(val) and issubclass(val, Query):
return val.__name__
if inspect.isfunction(val) and val.__name__ == "<lambda>":
return inspect.getsource(val).split("lambda")[-1][:30]
return repr(val)

File diff suppressed because it is too large Load diff