mirror of
https://github.com/beetbox/beets.git
synced 2026-07-22 02:06:50 -04:00
Read sort case sensitivity in FieldSort
Move sort case-sensitivity config lookup into `FieldSort` as a cached class property instead of threading a `case_insensitive` flag through query parsing helpers. This centralizes sort behavior at the sort implementation boundary and simplifies parse/orchestration call paths while preserving configurable case-sensitive ordering.
This commit is contained in:
@@ -171,15 +171,11 @@ def query_from_strings(
|
||||
return query_cls(subqueries)
|
||||
|
||||
|
||||
def construct_sort_part(
|
||||
model_cls: type[LibModel], part: str, case_insensitive: bool = True
|
||||
) -> sort.Sort:
|
||||
def construct_sort_part(model_cls: type[LibModel], part: str) -> sort.FieldSort:
|
||||
"""Create a `Sort` from a single string criterion.
|
||||
|
||||
`model_cls` is the `Model` being queried. `part` is a single string
|
||||
ending in ``+`` or ``-`` indicating the sort. `case_insensitive`
|
||||
indicates whether or not the sort should be performed in a case
|
||||
sensitive manner.
|
||||
ending in ``+`` or ``-`` indicating the sort.
|
||||
"""
|
||||
assert part, "part must be a field name and + or -"
|
||||
field = part[:-1]
|
||||
@@ -197,27 +193,25 @@ def construct_sort_part(
|
||||
# Flexible or computed.
|
||||
sort_cls = sort.SlowFieldSort
|
||||
|
||||
return sort_cls(field, is_ascending, case_insensitive)
|
||||
return sort_cls(field, is_ascending)
|
||||
|
||||
|
||||
def sort_from_strings(
|
||||
model_cls: type[LibModel],
|
||||
sort_parts: Sequence[str],
|
||||
case_insensitive: bool = True,
|
||||
model_cls: type[LibModel], sort_parts: Sequence[str]
|
||||
) -> sort.Sort:
|
||||
"""Create a `Sort` from a list of sort criteria (strings)."""
|
||||
if not sort_parts:
|
||||
return sort.NullSort()
|
||||
if len(sort_parts) == 1:
|
||||
return construct_sort_part(model_cls, sort_parts[0], case_insensitive)
|
||||
return construct_sort_part(model_cls, sort_parts[0])
|
||||
s = sort.MultipleSort()
|
||||
for part in sort_parts:
|
||||
s.add_sort(construct_sort_part(model_cls, part, case_insensitive))
|
||||
s.add_sort(construct_sort_part(model_cls, part))
|
||||
return s
|
||||
|
||||
|
||||
def parse_sorted_query(
|
||||
model_cls: type[LibModel], parts: list[str], case_insensitive: bool = True
|
||||
model_cls: type[LibModel], parts: list[str]
|
||||
) -> tuple[query.Query, sort.Sort]:
|
||||
"""Given a list of strings, create the `Query` and `Sort` that they
|
||||
represent.
|
||||
@@ -251,5 +245,5 @@ def parse_sorted_query(
|
||||
|
||||
# Avoid needlessly wrapping single statements in an OR
|
||||
q = query.OrQuery(query_parts) if len(query_parts) > 1 else query_parts[0]
|
||||
s = sort_from_strings(model_cls, sort_parts, case_insensitive)
|
||||
s = sort_from_strings(model_cls, sort_parts)
|
||||
return q, s
|
||||
|
||||
@@ -4,6 +4,9 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import beets
|
||||
from beets.util import cached_classproperty
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from beets.dbcore.db import AnyModel, Model
|
||||
|
||||
@@ -103,12 +106,13 @@ class FieldSort(Sort):
|
||||
any kind).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, field: str, ascending: bool = True, case_insensitive: bool = True
|
||||
):
|
||||
def __init__(self, field: str, ascending: bool = True):
|
||||
self.field = field
|
||||
self.ascending = ascending
|
||||
self.case_insensitive = case_insensitive
|
||||
|
||||
@cached_classproperty
|
||||
def case_insensitive(cls) -> bool:
|
||||
return beets.config["sort_case_insensitive"].get(bool)
|
||||
|
||||
def sort(self, objs: list[AnyModel]) -> list[AnyModel]:
|
||||
# TODO: Support flexible attributes with different types (e.g. a mix
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
import shlex
|
||||
|
||||
import beets
|
||||
from beets import dbcore, logging
|
||||
|
||||
log = logging.getLogger("beets")
|
||||
@@ -25,9 +24,7 @@ def parse_query_parts(parts, model_cls):
|
||||
for s in parts
|
||||
]
|
||||
|
||||
case_insensitive = beets.config["sort_case_insensitive"].get(bool)
|
||||
|
||||
query, sort = dbcore.parse_sorted_query(model_cls, parts, case_insensitive)
|
||||
query, sort = dbcore.parse_sorted_query(model_cls, parts)
|
||||
log.debug("Parsed query: {!r}", query)
|
||||
log.debug("Parsed sort: {!r}", sort)
|
||||
return query, sort
|
||||
|
||||
@@ -160,6 +160,23 @@ class TestCaseSensitivity:
|
||||
helper.add_item(artist="artist", flex1="flex1", track=10)
|
||||
helper.add_item(artist="Artist", flex1="Flex1", track=2)
|
||||
|
||||
@pytest.fixture
|
||||
def config(self, monkeypatch, config):
|
||||
"""Monkeypatch the config to clear the cached sort settings.
|
||||
|
||||
This is needed because ``FieldSort`` is accessed multiple times during
|
||||
the test.
|
||||
"""
|
||||
|
||||
def _set_config(_, key, value):
|
||||
"""Invalidate cached sort settings before updating the config."""
|
||||
if key == "sort_case_insensitive":
|
||||
util.cached_classproperty.cache.clear()
|
||||
config.set({key: value})
|
||||
|
||||
monkeypatch.setattr("confuse.core.ConfigView.__setitem__", _set_config)
|
||||
return config
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"getter,query,attr,expected_insensitive,expected_sensitive",
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user