Skip to content

Commit

Permalink
add print/print-all for artists,genres,labels&descriptors (#119)
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline authored May 6, 2024
1 parent d7099c0 commit 3f88f5f
Show file tree
Hide file tree
Showing 15 changed files with 3,839 additions and 1,189 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
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,15 +222,20 @@ Options:
-c, --config PATH Override the config file location.
--help Show this message and exit.


Commands:
cache Manage the read cache.
collages Manage collages.
config Utilites for configuring Rosé.
fs Manage the virtual filesystem.
playlists Manage playlists.
releases Manage releases.
rules Run metadata upda
artists Manage artists.
cache Manage the read cache.
collages Manage collages.
config Utilites for configuring Rosé.
descriptors Manage descriptors.
fs Manage the virtual filesystem.
genres Manage genres.
labels Manage labels.
playlists Manage playlists.
releases Manage releases.
rules Run metadata update rules on the entire library.
tracks Manage tracks.
version Print version.
```

> [!NOTE]
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
12 changes: 12 additions & 0 deletions docs/AVAILABLE_COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ resource they effect. Most commands are of the structure `rose {resource} {actio
- `playlists remove-track`: Remove a track from a playlist.
- `playlists set-cover`: Set the cover art for a playlist. Replaces any existing cover art.
- `playlists delete-cover`: Remove the cover art of a playlist.
- artists/
- `artists print`: Print a single artist's metadata and releases in JSON.
- `artists print-all`: Print all artists' metadata and releases in JSON.
- genres/
- `genres print`: Print a single genre's metadata and releases in JSON.
- `genres print-all`: Print all genres' metadata and releases in JSON.
- labels/
- `labels print`: Print a single label's metadata and releases in JSON.
- `labels print-all`: Print all labels' metadata and releases in JSON.
- descriptors/
- `descriptors print`: Print a single descriptor's metadata and releases in JSON.
- `descriptors print-all`: Print all descriptors' metadata and releases in JSON.
- rules/ _(see [Improving Your Music Metadata](./METADATA_TOOLS.md))_
- `rules run`: Run an ad hoc rule in the command line interface. You can also easily test rules
with the `--dry-run` flag.
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
4 changes: 4 additions & 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 Expand Up @@ -82,6 +83,9 @@ ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "setuptools"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "snapshottest"
ignore_missing_imports = true

[tool.pytest.ini_options]
addopts = [
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
7 changes: 4 additions & 3 deletions rose/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,9 +564,10 @@ def parse(cls, config_path_override: Path | None = None) -> Config:
dfs_state.append((child_accessor, v))
continue
unrecognized_accessors.append(accessor)
logger.warning(
f"Unrecognized options found in configuration file: {', '.join(unrecognized_accessors)}"
)
if unrecognized_accessors:
logger.warning(
f"Unrecognized options found in configuration file: {', '.join(unrecognized_accessors)}"
)

return Config(
music_source_dir=music_source_dir,
Expand Down
88 changes: 88 additions & 0 deletions rose_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,19 @@
update_cache,
)
from rose_cli.dump import (
dump_all_artists,
dump_all_collages,
dump_all_descriptors,
dump_all_genres,
dump_all_labels,
dump_all_playlists,
dump_all_releases,
dump_all_tracks,
dump_artist,
dump_collage,
dump_descriptor,
dump_genre,
dump_label,
dump_playlist,
dump_release,
dump_track,
Expand Down Expand Up @@ -523,6 +531,86 @@ def delete_cover_playlist(ctx: Context, playlist: str) -> None:
delete_playlist_cover_art(ctx.config, playlist)


@cli.group()
def artists() -> None:
"""Manage artists."""


@artists.command(name="print")
@click.argument("artist", type=str, nargs=1)
@click.pass_obj
def print_artist(ctx: Context, artist: str) -> None:
"""Print a artist (in JSON). Accepts a artist's name."""
click.echo(dump_artist(ctx.config, artist))


@artists.command(name="print-all")
@click.pass_obj
def print_all_artists(ctx: Context) -> None:
"""Print all artists (in JSON)."""
click.echo(dump_all_artists(ctx.config))


@cli.group()
def genres() -> None:
"""Manage genres."""


@genres.command(name="print")
@click.argument("genre", type=str, nargs=1)
@click.pass_obj
def print_genre(ctx: Context, genre: str) -> None:
"""Print a genre (in JSON). Accepts a genre's name."""
click.echo(dump_genre(ctx.config, genre))


@genres.command(name="print-all")
@click.pass_obj
def print_all_genres(ctx: Context) -> None:
"""Print all genres (in JSON)."""
click.echo(dump_all_genres(ctx.config))


@cli.group()
def labels() -> None:
"""Manage labels."""


@labels.command(name="print")
@click.argument("label", type=str, nargs=1)
@click.pass_obj
def print_label(ctx: Context, label: str) -> None:
"""Print a label (in JSON). Accepts a label's name."""
click.echo(dump_label(ctx.config, label))


@labels.command(name="print-all")
@click.pass_obj
def print_all_labels(ctx: Context) -> None:
"""Print all labels (in JSON)."""
click.echo(dump_all_labels(ctx.config))


@cli.group()
def descriptors() -> None:
"""Manage descriptors."""


@descriptors.command(name="print")
@click.argument("descriptor", type=str, nargs=1)
@click.pass_obj
def print_descriptor(ctx: Context, descriptor: str) -> None:
"""Print a descriptor (in JSON). Accepts a descriptor's name."""
click.echo(dump_descriptor(ctx.config, descriptor))


@descriptors.command(name="print-all")
@click.pass_obj
def print_all_descriptors(ctx: Context) -> None:
"""Print all descriptors (in JSON)."""
click.echo(dump_all_descriptors(ctx.config))


@cli.group()
def rules() -> None:
"""Run metadata update rules on the entire library."""
Expand Down
Loading

0 comments on commit 3f88f5f

Please sign in to comment.