Skip to content

Path format configuration matching on genres fails when using operands for exact matches #6598

@twebr

Description

@twebr

Problem

In my config.yaml, I put the following to use a different path format configuration for classical music:

paths:
    ## Special treatment for classical music
    genres:=~Classical: _Classical/$albumartist_sort/[$original_year]$atypes $album%aunique{albumartist album original_year}/$disc_and_track $title
    default: ...

At least up to beets v2.6.2, this worked fine.

But in my current version of beets (v2.10.0), songs that have genre 'Classical' do not match the path query on the left-hand side.
Interestingly, running $ beet list genres:=~Classical still works as expected.
It's just in the path format configuration that the query seems to fail finding any matches.

Removing the operands for an exact match (= or =~) results in classical music matching correctly in the path format configuration, but then I get false positives for genres that contain the substring 'classical'.
(For instance, I have music labelled as genre 'Neoclassical' which I do not want to match with this path format configuration.

I suspect that the bug was introduced when beets added support for multiple genres (deprecating the old genre field), but I am unable to verify this.

I already tried turning off plugins, but this did not resolve the issue.

Setup

  • OS: macOS 15.7.5
  • Python version: 3.13.12
  • beets version: 2.10.0
  • Turning off plugins made problem go away (yes/no): no

My configuration (output of beet config) is:

directory: REDACTED

import:
    copy: yes
    write: yes
    log: beetslog.txt
    timid: yes
    languages: en nl

# --------------- Plugins ---------------

plugins: export albumtypes info inline the lyrics embedart lastgenre badfiles smartplaylist filetote musicbrainz fetchart convert

# --------------- Tagging ---------------

per_disc_numbering: yes
format_album: $albumartist - $album ($original_year)

# --------------- Search ---------------

format_item: $artist - $album ($original_year) - $title
sort_item: artist+ original_year+ album+ disc+ track+

sort_album: albumartist+ original_year+ album+
original_date: yes
asciify_paths: yes

ui:
    colors:
        text_diff_added: [bold, green]
        text_diff_removed: [bold, red]
        text_diff_changed: [bold, yellow]
paths:
    genres:=~Classical: _Classical/$albumartist_sort/[$original_year]$atypes $album%aunique{albumartist album original_year}/$disc_and_track $title
    default: $albumartist_sort/[$original_year]$atypes $album%aunique{albumartist album original_year}/$disc_and_track $title
    singleton: _Singletons/$artist/$title
    comp: _Compilations/$year_reissue$atypes $album%aunique{albumartist album original_year}/$disc_and_track $artist - $title
item_fields:
    year_reissue: "f'[{original_year}\u2190{year}]' if original_year != year else f'[{original_year}]'"
    disc_and_track: f'{disc}-{track:02d}' if disctotal > 1 else f'{track:02d}'
the:
    strip: yes
    the: yes
    a: yes
    format: '{}, {}'
    patterns: []
export:
    csv:
        formatting:
            dialect: unix
            delimiter: ','
    default_format: json
    json:
        formatting:
            ensure_ascii: no
            indent: 4
            separators: &id001 [',', ': ']
            sort_keys: yes
    jsonlines:
        formatting:
            ensure_ascii: no
            separators: *id001
            sort_keys: yes
    xml:
        formatting: {}
albumtypes:
    types:
    -   ep: EP
    -   single: Single
    -   soundtrack: OST
    -   live: Live
    -   compilation: Comp
    -   remix: Remix
    ignore_va: compilation
    bracket: '[]'
fetchart:
    auto: no
    maxwidth: 500
    sources: [filesystem, coverart, itunes]
    minwidth: 0
    quality: 0
    max_filesize: 0
    enforce_ratio: no
    cautious: no
    cover_names:
    - cover
    - front
    - art
    - album
    - folder
    fallback:
    store_source: no
    high_resolution: no
    deinterlace: no
    cover_format:
    google_key: REDACTED
    google_engine: REDACTED
    lastfm_key: REDACTED
    fanarttv_key: REDACTED
embedart:
    auto: no
    maxwidth: 0
    compare_threshold: 0
    ifempty: no
    remove_art_file: no
    quality: 0
    clearart_on_import: no
filetote:
    extensions: .cue .log .png .jpg .pdf
    session:
        operation:
        _beets_lib:
        _library_path:
        import_path:
    filenames: ''
    patterns: {}
    exclude:
        filenames: ''
        extensions: ''
        patterns: {}
    pairing:
        enabled: no
        pairing_only: no
        extensions: .*
    paths: {}
    print_ignored: no
    duplicate_action: merge
edit:
    albumfields: album albumartist albumdisambig albumstatus genres language
lyrics:
    auto: no
    synced: yes
    auto_ignore:
    translate:
        api_key: REDACTED
        from_languages: []
        to_language:
    dist_thresh: 0.11
    google_API_key: REDACTED
    google_engine_ID: REDACTED
    genius_api_key: REDACTED
    fallback:
    force: no
    keep_synced: no
    local: no
    print: no
    sources: [lrclib, google, genius]
lastgenre:
    whitelist: genre_whitelist.txt
    canonical: yes
    force: yes
    keep_existing: no
    min_weight: 10
    count: 1
    fallback:
    cleanup_existing: no
    source: album
    auto: yes
    prefer_specific: no
    title_case: yes
    pretend: no
    ignorelist: {}
badfiles:
    check_on_import: yes
smartplaylist:
    playlist_dir: REDACTED
    relative_to: REDACTED
    playlists: [{name: More-than-CD quality.m3u8, query: 'bitdepth:17.. , samplerate:48000..'}, {name: Classical music.m3u8, query: 'genre:classical albumartist+ album+'}]
    dest_regen: no
    auto: yes
    uri_format:
    fields: []
    forward_slash: no
    prefix: REDACTED
    urlencode: no
    pretend_paths: no
    output: m3u
convert:
    dest: REDACTED
    command: ffmpeg -i $source -y -vn -acodec aac_at -aac_at_mode vbr -aac_at_quality 0 -q:a 7 $dest
    extension: m4a
    pretend: no
    link: no
    hardlink: no
    threads: 8
    format: mp3
    id3v23: inherit
    write_metadata: yes
    formats:
        aac:
            command: ffmpeg -i $source -y -vn -acodec aac -aq 1 $dest
            extension: m4a
        alac:
            command: ffmpeg -i $source -y -vn -acodec alac $dest
            extension: m4a
        flac: ffmpeg -i $source -y -vn -acodec flac $dest
        mp3: ffmpeg -i $source -y -vn -aq 2 $dest
        opus: ffmpeg -i $source -y -vn -acodec libopus -ab 96k $dest
        ogg: ffmpeg -i $source -y -vn -acodec libvorbis -aq 3 $dest
        wma: ffmpeg -i $source -y -vn -acodec wmav2 -vn $dest
    max_bitrate:
    auto: no
    auto_keep: no
    tmpdir:
    quiet: no
    embed: yes
    paths: {}
    no_convert: ''
    never_convert_lossy_files: no
    copy_album_art: no
    album_art_maxwidth: 0
    delete_originals: no
    playlist:
disabled_plugins: []
pathfields: {}
album_fields: {}
musicbrainz:
    search_limit: 5
    data_source_mismatch_penalty: 0.5
    search_query_ascii: no
    genres: no
    genres_tag: genre
    external_ids:
        discogs: no
        bandcamp: no
        spotify: no
        deezer: no
        tidal: no
    extra_tags: []

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions