working on changing position in import process - may consider options for pre or post import

This commit is contained in:
Henry 2025-10-19 16:33:08 -07:00
parent 57641ad9d2
commit a9f7ee8d1e
4 changed files with 58 additions and 31 deletions

View file

@ -20,10 +20,8 @@ from beets.dbcore import types
from beets import ui
from titlecase import titlecase
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from beets.importer import ImportSession, ImportTask
from beets.library import Item
from beets.library import Item
from beets.importer import ImportSession, ImportTask
__author__ = "henryoberholtzer@gmail.com"
__version__ = "1.0"
@ -58,6 +56,7 @@ class TitlecasePlugin(BeetsPlugin):
self.config.add(
{
"auto": True,
"preserve": [],
"small_first_last": True,
"titlecase_metadata": True,
@ -66,6 +65,7 @@ class TitlecasePlugin(BeetsPlugin):
}
)
"""
auto - automatically apply to new imports
preserve - provide a list of words/acronyms with specific case requirements
small_first_last - if small characters should be title cased at beginning
titlecase_metadata - if metadata fields should have title case applied
@ -98,6 +98,8 @@ class TitlecasePlugin(BeetsPlugin):
self.preserve[word.upper()] = word
self.__init_field_list__()
self.import_stages = [self.imported]
def __init_field_list__(self) -> None:
""" Creates the set for fields to process in tagging.
If we have include_fields from config, the shared fields will be used.
@ -106,17 +108,16 @@ class TitlecasePlugin(BeetsPlugin):
Last, the EXCLUDED_INFO_FIELDS are removed to prevent unitentional modification.
"""
initial_field_list = set([
k for k, v in Item()._fields.items() if
isinstance(v, types.STRING) or
isinstance(v, types.SEMICOLONS_SPACE_DSV) or
isinstance(v, types.MULTI_VALUE_DSV)
)
k for k, v in Item()._fields.items() if
isinstance(v, types.String) or
isinstance(v, types.DelimitedString)
])
if (incl := self.config["include_fields"].as_str_seq()):
initial_field_list = initial_field_list.intersection(set(incl))
if (excl := self.config["exclude_fields"].as_str_seq()):
initial_field_list -= set(excl)
initial_field_list -= set(EXCLUDED_INFO_FIELDS)
self.fields_to_process = basic_fields_list
self.fields_to_process = initial_field_list
def __preserved__(self, word, **kwargs) -> str | None:
""" Callback function for words to preserve case of."""

4
poetry.lock generated
View file

@ -3413,7 +3413,7 @@ files = [
name = "titlecase"
version = "2.4.1"
description = "Python Port of John Gruber's titlecase.pl"
optional = true
optional = false
python-versions = ">=3.7"
files = [
{file = "titlecase-2.4.1.tar.gz", hash = "sha256:7d83a277ccbbda11a2944e78a63e5ccaf3d32f828c594312e4862f9a07f635f5"},
@ -3688,4 +3688,4 @@ web = ["flask", "flask-cors"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.9,<4"
content-hash = "1db39186aca430ef6f1fd9e51b9dcc3ed91880a458bc21b22d950ed8589fdf5a"
content-hash = "fab72aa11a8622829c1f4b5d6d76ab87632f1649a04602bba26202a16a02d482"

View file

@ -76,8 +76,7 @@ requests = { version = "*", optional = true }
resampy = { version = ">=0.4.3", optional = true }
requests-oauthlib = { version = ">=0.6.1", optional = true }
soco = { version = "*", optional = true }
titlecase = { version = ">=2.4.1", optional = true }
titlecase = "^2.4.1"
pydata-sphinx-theme = { version = "*", optional = true }
sphinx = { version = "*", optional = true }
sphinx-design = { version = "^0.6.1", optional = true }

View file

@ -17,8 +17,8 @@
import pytest
from beets import config
from beets.test.helper import BeetsTestCase
from beetsplug.titlecase import TitlecasePlugin
from beets.test.helper import PluginTestCase
from beetsplug.titlecase import TitlecasePlugin, EXCLUDED_INFO_FIELDS
@pytest.mark.parametrize("given, expected",
[("a", "A"),
@ -35,30 +35,57 @@ def test_basic_titlecase(given, expected):
assert TitlecasePlugin().titlecase(given) == expected
class TitlecasePluginTest(BeetsTestCase):
class TitlecasePluginTest(PluginTestCase):
plugin = "titlecase"
preload_plugin = False
def test_preserved_case(self):
""" Test using given strings to preserve case """
names_to_preserve = ["easyFun", "A.D.O.R.",
"D.R.", "ABBA", "LaTeX"]
config["titlecase"]["preserve"] = names_to_preserve
for name in names_to_preserve:
assert TitlecasePlugin().titlecase(
name.lower()) == name
names_to_preserve = ["easyFun", "A.D.O.R.", "D.R.", "ABBA", "LaTeX"]
with self.configure_plugin({
"preserve": names_to_preserve}):
config["titlecase"]["preserve"] = names_to_preserve
for name in names_to_preserve:
assert TitlecasePlugin().titlecase(
name.lower()) == name
def test_small_first_last(self):
config["titlecase"]["small_first_last"] = False
assert TitlecasePlugin().titlecase(
"A Simple Trial") == "a Simple Trial"
config["titlecase"]["small_first_last"] = True
assert TitlecasePlugin().titlecase(
"A simple Trial") == "A Simple Trial"
with self.configure_plugin({
"small_first_last": False}):
assert TitlecasePlugin().titlecase(
"A Simple Trial") == "a Simple Trial"
with self.configure_plugin({
"small_first_last": True}):
assert TitlecasePlugin().titlecase(
"A simple Trial") == "A Simple Trial"
def test_ui_command(self):
assert 1 == 3
def test_imported(self):
assert 1 == 3
item = self.add_item(
artist="A poorly cased artist",
albumartist="not vEry good tItle caSE",
mb_artistid="case sensitive field")
assert item.artist == "A Poorly Cased Artist"
assert item.albumartist == "Not Very Good Title Case"
def test_init_field_list(self):
def test_field_list_default_excluded(self):
excluded = list(EXCLUDED_INFO_FIELDS)
config["titlecase"]["include_fields"] = excluded
t = TitlecasePlugin()
for field in excluded:
assert field not in t.fields_to_process
def test_field_list_included(self):
config["titlecase"]["include_fields"] = ["album", "albumartist"]
t = TitlecasePlugin()
t.fields_to_process == ["album", "albumartist"]
def test_field_list_exclude(self):
excluded = ["album", "albumartist"]
config["titlecase"]["exclude_fields"] = excluded
t = TitlecasePlugin()
for field in excluded:
assert field not in t.fields_to_process