Skip to content

Commit 829e3ca

Browse files
committed
feat!(io): filename uses id instead of name
Signed-off-by: Juan Rubio <jcrubio@gmail.com>
1 parent efefd77 commit 829e3ca

3 files changed

Lines changed: 93 additions & 9 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ test-e2e: ## 🧪 Run end-to-end tests
111111
rm -f "playlists/Greatest Film Themes of All Time.yaml"
112112
mkdir -p playlists
113113
uv run listify download --id "6LFObuU0EvpaQLj1iueTHO"
114-
test -f "playlists/Greatest Film Themes of All Time.yaml"
115-
yq .owner_id "playlists/Greatest Film Themes of All Time.yaml" | grep "bbcmusicmagazine" || (echo "Owner ID does not match expected value" && exit 1)
114+
test -f "playlists/playlist_6LFObuU0EvpaQLj1iueTHO.yaml"
115+
yq .owner_id "playlists/playlist_6LFObuU0EvpaQLj1iueTHO.yaml" | grep "bbcmusicmagazine" || (echo "Owner ID does not match expected value" && exit 1)
116116

117117
# ----------------------------------------------------------
118118
# Build

src/spotify_lists/io.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@
66

77

88
def save_playlist(playlist: Playlist, directory: Path) -> None:
9-
"""Saves a playlist to a YAML file in the specified directory."""
9+
"""Saves a playlist as a YAML file.
10+
11+
The filename uses the format "playlist_{playlist_id}.yaml".
12+
The function ensures the directory exists and overwrites
13+
any existing file with the same name.
14+
15+
Returns:
16+
None
17+
"""
1018
directory.mkdir(parents=True, exist_ok=True)
1119

12-
# Sanitize filename
13-
safe_name = "".join([c for c in playlist.name if c.isalpha() or c.isdigit() or c == " "]).strip()
14-
if not safe_name:
15-
safe_name = f"playlist_{playlist.id}"
16-
filename = directory / f"{safe_name}.yaml"
20+
# Name is "playlist_{id}.yaml"
21+
filename = f"playlist_{playlist.id}.yaml"
22+
filepath = directory / filename
1723

18-
with open(filename, "w", encoding="utf-8") as f:
24+
with open(filepath, "w", encoding="utf-8") as f:
1925
yaml.dump(playlist.to_dict(), f, sort_keys=False, allow_unicode=True)

tests/test_io.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""Unit tests for io.py."""
2+
3+
from pathlib import Path
4+
5+
import pytest
6+
import yaml
7+
8+
from spotify_lists.io import save_playlist
9+
from spotify_lists.models import Playlist, Track
10+
11+
# ---------------------------------------------------------------------------
12+
# Fixtures
13+
# ---------------------------------------------------------------------------
14+
15+
16+
@pytest.fixture()
17+
def playlist() -> Playlist:
18+
return Playlist(
19+
id="pl-id-1",
20+
owner_id="owner-1",
21+
name="My Playlist",
22+
description="A test playlist",
23+
public=True,
24+
tracks=[
25+
Track(id="t-1", name="Song A", artists="Artist A", uri="spotify:track:t-1", album="Album A"),
26+
],
27+
)
28+
29+
30+
# ---------------------------------------------------------------------------
31+
# save_playlist
32+
# ---------------------------------------------------------------------------
33+
34+
35+
class TestSavPlaylist:
36+
def test_creates_yaml_file(self, playlist: Playlist, tmp_path: Path) -> None:
37+
save_playlist(playlist, tmp_path)
38+
assert (tmp_path / "playlist_pl-id-1.yaml").exists()
39+
40+
def test_creates_directory_if_missing(self, playlist: Playlist, tmp_path: Path) -> None:
41+
target = tmp_path / "nested" / "dir"
42+
save_playlist(playlist, target)
43+
assert (target / "playlist_pl-id-1.yaml").exists()
44+
45+
def test_yaml_content_matches_playlist(self, playlist: Playlist, tmp_path: Path) -> None:
46+
save_playlist(playlist, tmp_path)
47+
with open(tmp_path / "playlist_pl-id-1.yaml", encoding="utf-8") as f:
48+
data = yaml.safe_load(f)
49+
assert data["id"] == "pl-id-1"
50+
assert data["name"] == "My Playlist"
51+
assert data["description"] == "A test playlist"
52+
assert data["public"] is True
53+
assert data["owner_id"] == "owner-1"
54+
assert len(data["tracks"]) == 1
55+
assert data["tracks"][0]["name"] == "Song A"
56+
57+
def test_overwrites_existing_file(self, playlist: Playlist, tmp_path: Path) -> None:
58+
save_playlist(playlist, tmp_path)
59+
playlist.description = "updated"
60+
save_playlist(playlist, tmp_path)
61+
with open(tmp_path / "playlist_pl-id-1.yaml", encoding="utf-8") as f:
62+
data = yaml.safe_load(f)
63+
assert data["description"] == "updated"
64+
65+
def test_playlist_with_no_tracks(self, tmp_path: Path) -> None:
66+
playlist = Playlist(id="pl-empty", owner_id="o-1", name="Empty")
67+
save_playlist(playlist, tmp_path)
68+
with open(tmp_path / "playlist_pl-empty.yaml", encoding="utf-8") as f:
69+
data = yaml.safe_load(f)
70+
assert data["tracks"] == []
71+
72+
def test_unicode_name_preserved_in_content(self, tmp_path: Path) -> None:
73+
# Non-ASCII letters pass isalpha(), so the full name is kept in the filename
74+
playlist = Playlist(id="pl-unicode", owner_id="o-1", name="Café")
75+
save_playlist(playlist, tmp_path)
76+
with open(tmp_path / "playlist_pl-unicode.yaml", encoding="utf-8") as f:
77+
data = yaml.safe_load(f)
78+
assert data["name"] == "Café"

0 commit comments

Comments
 (0)