Skip to content

Commit 3c2c050

Browse files
committed
docs: Rewrite Handling Paths chapter (pathlib)
1 parent d843378 commit 3c2c050

File tree

1 file changed

+61
-21
lines changed

1 file changed

+61
-21
lines changed

docs/dev/paths.rst

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,64 @@
11
Handling Paths
22
==============
33

4-
A great deal of convention deals with the handling of **paths**. Paths are
5-
stored internally—in the database, for instance—as byte strings (i.e., ``bytes``
6-
instead of ``str`` in Python 3). This is because POSIX operating systems’ path
7-
names are only reliably usable as byte strings—operating systems typically
8-
recommend but do not require that filenames use a given encoding, so violations
9-
of any reported encoding are inevitable. On Windows, the strings are always
10-
encoded with UTF-8; on Unix, the encoding is controlled by the filesystem. Here
11-
are some guidelines to follow:
12-
13-
- If you have a Unicode path or you’re not sure whether something is Unicode or
14-
not, pass it through ``bytestring_path`` function in the ``beets.util`` module
15-
to convert it to bytes.
16-
- Pass every path name through the ``syspath`` function (also in ``beets.util``)
17-
before sending it to any *operating system* file operation (``open``, for
18-
example). This is necessary to use long filenames (which, maddeningly, must be
19-
Unicode) on Windows. This allows us to consistently store bytes in the
20-
database but use the native encoding rule on both POSIX and Windows.
21-
- Similarly, the ``displayable_path`` utility function converts bytestring paths
22-
to a Unicode string for displaying to the user. Every time you want to print
23-
out a string to the terminal or log it with the ``logging`` module, feed it
24-
through this function.
4+
``pathlib`` provides a clean, cross-platform API for working with filesystem
5+
paths.
6+
7+
Use the ``.filepath`` property on ``Item`` and ``Album`` library objects to
8+
access paths as ``pathlib.Path`` objects. This produces a readable, native
9+
representation suitable for printing, logging, or further processing.
10+
11+
Normalize paths using ``Path(...).expanduser().resolve()``, which expands ``~``
12+
and resolves symlinks.
13+
14+
Cross-platform differences—such as path separators, Unicode handling, and
15+
long-path support (Windows) are automatically managed by ``pathlib``.
16+
17+
When storing paths in the database, however, convert them to bytes with
18+
``bytestring_path()``. Paths in Beets are currently stored as bytes, although
19+
there are plans to eventually store ``pathlib.Path`` objects directly. To access
20+
media file paths in their stored form, use the ``.path`` property on ``Item``
21+
and ``Album``.
22+
23+
Legacy utilities
24+
----------------
25+
26+
Historically, Beets used custom utilities to ensure consistent behavior across
27+
Linux, macOS, and Windows before ``pathlib`` became reliable:
28+
29+
- ``syspath()``: worked around Windows Unicode and long-path limitations by
30+
converting to a system-safe string (adding the ``\\?\`` prefix where needed).
31+
- ``normpath()``: normalized slashes and removed ``./`` or ``..`` parts but did
32+
not expand ``~``.
33+
- ``bytestring_path()``: converted paths to bytes for database storage (still
34+
used for that purpose today).
35+
- ``displayable_path()``: converted byte paths to Unicode for display or
36+
logging.
37+
38+
These functions remain safe to use in legacy code, but new code should rely
39+
solely on ``pathlib.Path``.
40+
41+
Examples
42+
--------
43+
44+
Old style
45+
46+
.. code-block:: python
47+
48+
displayable_path(item.path)
49+
normpath("~/Music/../Artist")
50+
syspath(path)
51+
52+
New style
53+
54+
.. code-block:: python
55+
56+
item.filepath
57+
Path("~/Music/../Artist").expanduser().resolve()
58+
Path(path)
59+
60+
When storing paths in the database
61+
62+
.. code-block:: python
63+
64+
path_bytes = bytestring_path(Path("/some/path/to/file.mp3"))

0 commit comments

Comments
 (0)