#6809·beets

Migrate byte-only path contracts to `pathlib.Path`

Author: snejusCreated Jun 30, 2026Updated Sep 1, 2026

Depends on: the generic path utilities and initial test-suite migration sub-issues.

Child issues:

  • Migrate artwork and media path APIs to Path.
  • Make Library.directory and music-directory context Path-based.
  • Migrate importer path APIs and persisted state to Path, including sorted_walk and albums_in_dir.
  • Migrate model filesystem helpers to Path.
  • Replace runtime item.path and album.artpath consumers with filepath and art_filepath.
  • Use Path in models while keeping SQL path storage as bytes.

Problem

Core runtime interfaces still expose filesystem paths as bytes, propagating encoding and byte-valued model fields through import, artwork, plugin, and UI code. The remaining tests therefore cannot adopt Path.

Affected areas

  • Library/database integration: Library.directory, music-directory context, path queries, and byte-valued model backing fields.
  • Import pipeline: ImportSession, task classes and factories, and persisted ImportState.
  • Artwork/media utilities: fetchart.Candidate.path, ArtResizer, extension handling, and shared art helpers.
  • Plugins/UI: direct model-field access, importer paths, and path configuration values.

Expected behavior

  • Use Path for filesystem paths in runtime and plugin APIs.
  • Prefer LibModel.filepath and Album.art_filepath; access their byte-valued backing fields only at the database compatibility boundary.
  • Migrate importer state and APIs, artwork utilities, plugin state, and event payloads to Path, while decoding legacy state.
  • Encode or decode only at explicit boundaries. SQLite path BLOBs and binary file or URI content remain bytes.
  • Preserve undecodable filesystem paths through surrogate-escape round trips.

Acceptance criteria

  • Direct LibModel.path and Album.artpath use is limited to persistence and compatibility code.
  • Filesystem, importer, and artwork APIs accept or return Path without caller-side encoding.
  • Art, importer, core, and plugin tests migrate with their production interfaces.
  • Boundary tests cover database round trips, legacy state, undecodable paths, and platform behavior.
  • poe test and poe lint pass with coverage at or above 80%.