Skip to content

Commit

Permalink
switch to snapshottest
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed May 6, 2024
1 parent d7099c0 commit cfe0dc5
Show file tree
Hide file tree
Showing 11 changed files with 2,037 additions and 1,178 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
.pytest_cache
.mypy_cache
result
snapshots
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ test-seq:
pytest .
coverage html

snapshot:
pytest --snapshot-update .

lintcheck:
ruff format --check .
ruff check .
Expand Down
37 changes: 25 additions & 12 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dataclasses
import hashlib
import logging
import shutil
Expand Down Expand Up @@ -100,6 +101,17 @@ def config(isolated_dir: Path) -> Config:

@pytest.fixture()
def seeded_cache(config: Config) -> None:
_seed_cache(config, True)


@pytest.fixture()
def static_cache(config: Config) -> None:
"""A variant of the seeded cache with static hardcoded (fake) paths. Useful for snapshot tests."""
config = dataclasses.replace(config, music_source_dir=Path("/dummy"))
_seed_cache(config, False)


def _seed_cache(config: Config, mkfiles: bool) -> None:
dirpaths = [
config.music_source_dir / "r1",
config.music_source_dir / "r2",
Expand Down Expand Up @@ -246,18 +258,19 @@ def seeded_cache(config: Config) -> None:
""",
)

(config.music_source_dir / "!collages").mkdir()
(config.music_source_dir / "!playlists").mkdir()

for d in dirpaths:
d.mkdir()
(d / f".rose.{d.name}.toml").touch()
for f in musicpaths + imagepaths:
f.touch()
for cn in ["Rose Gold", "Ruby Red"]:
(config.music_source_dir / "!collages" / f"{cn}.toml").touch()
for pn in ["Lala Lisa", "Turtle Rabbit"]:
(config.music_source_dir / "!playlists" / f"{pn}.toml").touch()
if mkfiles:
(config.music_source_dir / "!collages").mkdir()
(config.music_source_dir / "!playlists").mkdir()

for d in dirpaths:
d.mkdir()
(d / f".rose.{d.name}.toml").touch()
for f in musicpaths + imagepaths:
f.touch()
for cn in ["Rose Gold", "Ruby Red"]:
(config.music_source_dir / "!collages" / f"{cn}.toml").touch()
for pn in ["Lala Lisa", "Turtle Rabbit"]:
(config.music_source_dir / "!playlists" / f"{pn}.toml").touch()


@pytest.fixture()
Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
pytest-timeout
pytest-cov
pytest-xdist
snapshottest
];
dev-cli = pkgs.writeShellScriptBin "rose" ''
cd $ROSE_ROOT
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ exclude = [
".mypy_cache",
".ruff_cache",
".venv",
"snapshots",
]

[tool.ruff.lint]
Expand Down
8 changes: 8 additions & 0 deletions rose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@
from rose.common import (
VERSION,
Artist,
ArtistDoesNotExistError,
ArtistMapping,
DescriptorDoesNotExistError,
GenreDoesNotExistError,
LabelDoesNotExistError,
RoseError,
RoseExpectedError,
initialize_logging,
Expand Down Expand Up @@ -207,18 +211,22 @@
"artist_exists",
"list_artists",
"UnknownArtistRoleError",
"ArtistDoesNotExistError",
# Genres
"GenreEntry",
"list_genres",
"genre_exists",
"GenreDoesNotExistError",
# Descriptors
"DescriptorEntry",
"list_descriptors",
"descriptor_exists",
"DescriptorDoesNotExistError",
# Labels
"LabelEntry",
"list_labels",
"label_exists",
"LabelDoesNotExistError",
# Collages
"Collage",
"add_release_to_collage",
Expand Down
16 changes: 16 additions & 0 deletions rose/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ class RoseExpectedError(RoseError):
pass


class GenreDoesNotExistError(RoseExpectedError):
pass


class LabelDoesNotExistError(RoseExpectedError):
pass


class DescriptorDoesNotExistError(RoseExpectedError):
pass


class ArtistDoesNotExistError(RoseExpectedError):
pass


@dataclasses.dataclass
class Artist:
name: str
Expand Down
100 changes: 100 additions & 0 deletions rose_cli/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
from rose import (
CollageDoesNotExistError,
Config,
DescriptorDoesNotExistError,
GenreDoesNotExistError,
LabelDoesNotExistError,
MetadataMatcher,
PlaylistDoesNotExistError,
Release,
ReleaseDoesNotExistError,
Track,
TrackDoesNotExistError,
descriptor_exists,
find_releases_matching_rule,
find_tracks_matching_rule,
genre_exists,
get_collage,
get_collage_releases,
get_playlist,
Expand All @@ -20,11 +25,17 @@
get_track,
get_tracks_of_release,
get_tracks_of_releases,
label_exists,
list_collages,
list_descriptors,
list_genres,
list_labels,
list_playlists,
list_releases,
list_tracks,
)
from rose.cache import artist_exists, list_artists, list_releases_delete_this
from rose.common import ArtistDoesNotExistError


def release_to_json(r: Release) -> dict[str, Any]:
Expand Down Expand Up @@ -129,6 +140,95 @@ def dump_all_tracks(c: Config, matcher: MetadataMatcher | None = None) -> str:
return json.dumps([track_to_json(t) for t in tracks])


def dump_artist(c: Config, artist_name: str) -> str:
if not artist_exists(c, artist_name):
raise ArtistDoesNotExistError(f"artist {artist_name} does not exist")
artist_releases = list_releases_delete_this(c, artist_filter=artist_name)
roles = _partition_releases_by_role(artist_name, artist_releases)
roles_json = {k: [release_to_json(x) for x in v] for k, v in roles.items()}
return json.dumps({"name": artist_name, "roles": roles_json})


def dump_all_artists(c: Config) -> str:
out: list[dict[str, Any]] = []
for name in list_artists(c):
artist_releases = list_releases_delete_this(c, artist_filter=name)
roles = _partition_releases_by_role(name, artist_releases)
roles_json = {k: [release_to_json(x) for x in v] for k, v in roles.items()}
out.append({"name": name, "roles": roles_json})
return json.dumps(out)


def _partition_releases_by_role(artist: str, releases: list[Release]) -> dict[str, list[Release]]:
rval: dict[str, list[Release]] = {
"main": [],
"guest": [],
"remixer": [],
"producer": [],
"composer": [],
"conductor": [],
"djmixer": [],
}
for release in releases:
# It is possible for a release to end up in multiple roles. That's intentional.
for role, names in release.releaseartists.items():
if any(artist == x.name for x in names):
rval[role].append(release)
break
return rval


def dump_genre(c: Config, genre_name: str) -> str:
if not genre_exists(c, genre_name):
raise GenreDoesNotExistError(f"Genre {genre_name} does not exist")
genre_releases = list_releases_delete_this(c, genre_filter=genre_name)
releases = [release_to_json(r) for r in genre_releases]
return json.dumps({"name": genre_name, "releases": releases})


def dump_all_genres(c: Config) -> str:
out: list[dict[str, Any]] = []
for name in list_genres(c):
genre_releases = list_releases_delete_this(c, genre_filter=name.genre)
releases = [release_to_json(r) for r in genre_releases]
out.append({"name": name, "releases": releases})
return json.dumps(out)


def dump_label(c: Config, label_name: str) -> str:
if not label_exists(c, label_name):
raise LabelDoesNotExistError(f"label {label_name} does not exist")
label_releases = list_releases_delete_this(c, label_filter=label_name)
releases = [release_to_json(r) for r in label_releases]
return json.dumps({"name": label_name, "releases": releases})


def dump_all_labels(c: Config) -> str:
out: list[dict[str, Any]] = []
for name in list_labels(c):
label_releases = list_releases_delete_this(c, label_filter=name.label)
releases = [release_to_json(r) for r in label_releases]
out.append({"name": name, "releases": releases})
return json.dumps(out)


def dump_descriptor(c: Config, descriptor_name: str) -> str:
if not descriptor_exists(c, descriptor_name):
raise DescriptorDoesNotExistError(f"descriptor {descriptor_name} does not exist")
descriptor_releases = list_releases_delete_this(c, descriptor_filter=descriptor_name)
releases = [release_to_json(r) for r in descriptor_releases]
return json.dumps({"name": descriptor_name, "releases": releases})


def dump_all_descriptors(c: Config) -> str:
out: list[dict[str, Any]] = []
for name in list_descriptors(c):
descriptor_releases = list_releases_delete_this(c, descriptor_filter=name.descriptor)
releases = [release_to_json(r) for r in descriptor_releases]
out.append({"name": name, "releases": releases})
return json.dumps(out)


def dump_collage(c: Config, collage_name: str) -> str:
collage = get_collage(c, collage_name)
if collage is None:
Expand Down
Loading

0 comments on commit cfe0dc5

Please sign in to comment.