|
1 | 1 | Handling Paths |
2 | 2 | ============== |
3 | 3 |
|
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