Tag names have leading and trailing whitespace stripped

A padded name now finds the existing Tag instead of creating a
near-duplicate, and a whitespace-only name is rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Roland 2026-10-25 15:26:12 -06:00
parent c3e25b84d6
commit 57107f678e
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
2 changed files with 30 additions and 1 deletions

View file

@ -166,7 +166,9 @@ class Tag(ModelHelper, Base):
# Replace forward-slash (linux directories) with Unicode Big Solidus (U+29F8)
name = name.replace('/', '⧸')
name = INVALID_FILE_CHARS.sub('', name)
name = INVALID_FILE_CHARS.sub('', name).strip()
if not name:
raise InvalidTag('Tag name cannot be empty')
if (other := self.get_by_name(session, name)) and other.id != self.id:
raise InvalidTag('Tag name already taken')
@ -266,6 +268,7 @@ class Tag(ModelHelper, Base):
@warning: does not commit"""
if name and id_:
raise RuntimeError('Tag name and id cannot be used together')
name = name.strip() if name else name
if tag := session.query(Tag).filter(Tag.id == id_).one_or_none():
return tag

View file

@ -406,6 +406,32 @@ async def test_invalid_tag(async_client, test_session, test_directory):
with pytest.raises(UnknownTag):
await tags.upsert_tag(test_session, 'Tag ID does not exist', '#fff', 1)
with pytest.raises(InvalidTag):
await tags.upsert_tag(test_session, ' ', '#fff')
with pytest.raises(InvalidTag):
tags.Tag.get_or_create_tag(test_session, ' \t')
@pytest.mark.asyncio
async def test_tag_name_whitespace_stripped(test_session, test_directory, tag_factory):
"""Leading and trailing whitespace is never part of a Tag's name."""
await tags.upsert_tag(test_session, ' one ', '#fff')
tag = tags.Tag.find_by_name(test_session, 'one')
assert tag.name == 'one'
# Renaming strips too.
await tags.upsert_tag(test_session, '\ttwo\n', '#fff', tag.id)
assert tag.name == 'two'
# A padded name finds the existing Tag rather than creating a near-duplicate.
assert tags.Tag.get_or_create_tag(test_session, 'two ').id == tag.id
assert tags.Tag.get_or_create_tag(test_session, ' three ').name == 'three'
assert {i.name for i in test_session.query(tags.Tag)} == {'two', 'three'}
# A padded name conflicts with an existing Tag.
with pytest.raises(InvalidTag):
await tags.upsert_tag(test_session, 'three ', '#fff', tag.id)
@pytest.mark.asyncio
async def test_tags_directory(test_session, test_directory, tag_factory, video_factory, example_pdf, await_switches,