Skip to content

Fix handling multi valued fields#6387

Merged
snejus merged 4 commits intomasterfrom
fix-handling-multi-valued-fields
Feb 23, 2026
Merged

Fix handling multi valued fields#6387
snejus merged 4 commits intomasterfrom
fix-handling-multi-valued-fields

Conversation

@snejus
Copy link
Copy Markdown
Member

@snejus snejus commented Feb 22, 2026

While working on #6367 I noticed that users are currently required to use our internal separator \␀ in order to edit multi-valued fields, for example beet modify artists='a\␀b'.

Similarly, this separator is used in output, for example, reporting of field changes:

$ beet modify path::aaa artists='a\␀b'
Modifying 8 items.
54898 | 2022 / RAVE SLUTZ: Fallen Shrine & dj Christian NXC - DEEEJAAAY
  artists: Fallen Shrine\␀dj Christian NXC -> a\␀b

This PR replaces \␀ separator with ; for input and formats changes in multi-valued fields clearly:

$ beet modify path::aaa artists='a; b'
54898 | 2022 / RAVE SLUTZ: Fallen Shrine & dj Christian NXC - DEEEJAAAY
  artists:
    - Fallen Shrine
    - dj Christian NXC
    + a
    + b
image

Architecture-level changes

  • DelimitedString now separates concerns between:
    • database serialization via db_delimiter (to_sql)
    • user-facing/template formatting via a fixed '; ' delimiter (format)
    • parsing that accepts both DB and user-facing separators (parse)
  • Field diff rendering now has a dedicated path for list fields:
    • _field_diff detects list values
    • _multi_value_diff computes set-based added/removed entries and renders per-item diff lines
  • Coloring responsibilities were streamlined:
    • raw ANSI application moved to _colorize
    • colorize is now only the feature-flag/environment gate
    • colordiff is reduced to string diff highlighting logic, with redundant wrapper logic removed

High-level impact

  • Multi-valued fields behave consistently between DB storage and CLI/template usage ('; ' for user input/output, DB delimiter internally).
  • Diff output for list fields is much more readable, showing explicit +/- item-level changes instead of generic string diffs.
  • Docs and tests were updated to reflect the new multi-value behavior, including %first usage and beet modify examples.

Copilot AI review requested due to automatic review settings February 22, 2026 01:23
@snejus snejus requested a review from a team as a code owner February 22, 2026 01:23
@github-actions
Copy link
Copy Markdown

Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves multi-valued field handling by separating user-facing and database delimiters, enhancing diff output readability, and refactoring color formatting logic. The change makes beet modify and field display more user-friendly by replacing the internal \␀ separator with ; for user input and output.

Changes:

  • DelimitedString type now uses ; for formatting/user input and \␀ for database serialization
  • Field diffs for list values display per-item changes with +/- prefixes instead of string comparison
  • Color formatting refactored into _colorize (raw ANSI) and colorize (feature-gated wrapper)

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
beets/dbcore/types.py Separated database delimiter (\␀) from user-facing delimiter (; ) in DelimitedString type
beets/ui/init.py Added list-aware diff rendering, refactored colorize/colordiff functions
beets/library/models.py Updated tmpl_first documentation to remove redundant info
docs/reference/pathformat.rst Expanded %first function documentation with examples and clearer parameter descriptions
docs/reference/cli.rst Added guidance for modifying multi-valued fields
docs/conf.py Added semicolon_space RST substitution for consistent documentation
test/ui/test_field_diff.py Added tests for multi-value field diff rendering
test/test_plugins.py Updated test assertion for new delimiter format
test/test_library.py Updated %first function tests to use appropriate field types

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/reference/pathformat.rst Outdated
Comment thread beets/dbcore/types.py
Comment thread beets/dbcore/types.py
Comment thread test/ui/test_field_diff.py
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.17%. Comparing base (940e94c) to head (edfe005).
⚠️ Report is 6 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6387      +/-   ##
==========================================
+ Coverage   69.13%   69.17%   +0.03%     
==========================================
  Files         140      140              
  Lines       18684    18686       +2     
  Branches     3055     3053       -2     
==========================================
+ Hits        12918    12926       +8     
+ Misses       5119     5115       -4     
+ Partials      647      645       -2     
Files with missing lines Coverage Δ
beets/dbcore/types.py 96.01% <100.00%> (+0.03%) ⬆️
beets/library/models.py 87.10% <ø> (ø)
beets/ui/__init__.py 83.60% <100.00%> (+0.90%) ⬆️
beets/ui/commands/import_/display.py 82.59% <100.00%> (ø)
beetsplug/edit.py 85.62% <100.00%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@snejus snejus force-pushed the fix-handling-multi-valued-fields branch 6 times, most recently from 748934b to 03114e1 Compare February 22, 2026 12:06
@snejus
Copy link
Copy Markdown
Member Author

snejus commented Feb 22, 2026

@amogus07 I see you've given the PR a thumbs-up. Would you mind reviewing it as well? 😆

@snejus snejus mentioned this pull request Feb 22, 2026
@amogus07
Copy link
Copy Markdown
Contributor

amogus07 commented Feb 22, 2026

@amogus07 I see you've given the PR a thumbs-up. Would you mind reviewing it as well? 😆

I'm not that familiar with these parts of the codebase, unfortunately... I'm just glad this is finally being addressed

@JOJ0
Copy link
Copy Markdown
Member

JOJ0 commented Feb 22, 2026

I will review and test this later today!

@snejus snejus force-pushed the fix-handling-multi-valued-fields branch from 03114e1 to 54a46bd Compare February 22, 2026 15:57
- Use '\␀' as the DB delimiter while formatting lists with '; ' for
templates.
- Update DelimitedString parsing to accept both separators:
  * '\␀' for the values from the DB
  * '; ' for the rest of parsed values (for example `beet modify genres="eletronic; jazz"`)
- Refresh %first docs and tests to reflect multi-value field behavior.
@snejus snejus force-pushed the fix-handling-multi-valued-fields branch from 54a46bd to 4699958 Compare February 22, 2026 16:17
Comment thread beets/dbcore/types.py
Comment thread beets/dbcore/types.py
Comment thread beets/ui/__init__.py
Comment thread beets/ui/__init__.py
Comment thread beets/ui/__init__.py
Comment thread docs/reference/pathformat.rst
Comment thread docs/reference/pathformat.rst
Comment thread test/ui/test_field_diff.py
Comment thread beets/dbcore/types.py
Copy link
Copy Markdown
Member

@JOJ0 JOJ0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damnit forgot to add my final message in my previous review: Overall many many thanks! Great stuff here!. When testing add-multiple-genres I had similar thoughts: We need to find a way to make delimiters passing more user friendly. This null character is only suitable for actual storing. Well done, great solution you provided here!

Also adding a tiny test idea here in this subseuqent review. Not sure. What do you say?

Comment thread test/test_plugins.py
@JOJ0
Copy link
Copy Markdown
Member

JOJ0 commented Feb 22, 2026

@snejus
Copy link
Copy Markdown
Member Author

snejus commented Feb 22, 2026

Actually, I thinkw we'd also like to adjust edit plugin:

Currently we have:

album: RAVE SLUTZ
album_id: 11492
albumartist: Fallen Shrine & dj Christian NXC
albumstatus: Official
albumtype: album
albumtypes: album
artist: Fallen Shrine & dj Christian NXC
artist_sort: ''
artists: Fallen Shrine; dj Christian NXC

While I imagine we'd instead like to have:

album: RAVE SLUTZ
album_id: 11492
albumartist: Fallen Shrine & dj Christian NXC
albumstatus: Official
albumtype: album
albumtypes:
- album
artist: Fallen Shrine & dj Christian NXC
artist_sort: ''
artists:
- Fallen Shrine
- dj Christian NXC

Copy link
Copy Markdown
Member

@JOJ0 JOJ0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go ahead then 😍

@JOJ0
Copy link
Copy Markdown
Member

JOJ0 commented Feb 22, 2026

Actually, I thinkw we'd also like to adjust edit plugin:

Currently we have:

album: RAVE SLUTZ

album_id: 11492

albumartist: Fallen Shrine & dj Christian NXC

albumstatus: Official

albumtype: album

albumtypes: album

artist: Fallen Shrine & dj Christian NXC

artist_sort: ''

artists: Fallen Shrine; dj Christian NXC

While I imagine we'd instead like to have:

album: RAVE SLUTZ

album_id: 11492

albumartist: Fallen Shrine & dj Christian NXC

albumstatus: Official

albumtype: album

albumtypes:

- album

artist: Fallen Shrine & dj Christian NXC

artist_sort: ''

artists:

- Fallen Shrine

- dj Christian NXC

Hmm interesting idea, since it's yaml...

Do this in a subsequent PR? For now it's good enough in my opinion. Played with edit before and didn't miss anything, but yeah would be a great and self-explanatory feature!

@snejus
Copy link
Copy Markdown
Member Author

snejus commented Feb 23, 2026

It kinds of belongs here, what do you think? The change was just two lines, so I added it here:

asciicast

Note: I use edit quite a lot 😅

Treat DelimitedString as a safe YAML-editable type in the edit plugin,
allowing multi-valued fields to be edited as native lists.
@snejus snejus force-pushed the fix-handling-multi-valued-fields branch from d5abe35 to edfe005 Compare February 23, 2026 00:33
@snejus snejus merged commit 2ea7886 into master Feb 23, 2026
22 checks passed
@snejus snejus deleted the fix-handling-multi-valued-fields branch February 23, 2026 01:14
@JOJ0
Copy link
Copy Markdown
Member

JOJ0 commented Feb 24, 2026

sure! edit! sorry was busy this weekend orherwise. good you included it! thanks!

Morikko added a commit to Morikko/beets-multivalue that referenced this pull request Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants