Handling Paths#

pathlib provides a clean, cross-platform API for working with filesystem paths.

Use the .filepath property on Item and Album library objects to access paths as pathlib.Path objects. This produces a readable, native representation suitable for printing, logging, or further processing.

Normalize paths using Path(...).expanduser().resolve(), which expands ~ and resolves symlinks.

Cross-platform differences—such as path separators, Unicode handling, and long-path support (Windows) are automatically managed by pathlib.

When storing paths in the database, however, convert them to bytes with bytestring_path(). Paths in Beets are currently stored as bytes, although there are plans to eventually store pathlib.Path objects directly. To access media file paths from library objects, use .path for the absolute path as bytes or .filepath for the absolute path as a pathlib.Path. The database still stores these paths relative to the configured library root.

Legacy utilities#

Historically, Beets used custom utilities to ensure consistent behavior across Linux, macOS, and Windows before pathlib became reliable:

  • syspath(): worked around Windows Unicode and long-path limitations by converting to a system-safe string (adding the \\?\ prefix where needed).

  • normpath(): normalized slashes and removed ./ or .. parts but did not expand ~.

  • bytestring_path(): converted paths to bytes for database storage (still used for that purpose today).

  • displayable_path(): converted byte paths to Unicode for display or logging.

These functions remain safe to use in legacy code, but new code should rely solely on pathlib.Path.

Examples#

Old style

displayable_path(item.path)
normpath("~/Music/../Artist")
syspath(path)

New style

item.filepath
Path("~/Music/../Artist").expanduser().resolve()
Path(path)

When storing paths in the database

path_bytes = bytestring_path(Path("/some/path/to/file.mp3"))