Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add print/print-all for artists,genres,labels&descriptors #119

Merged
merged 4 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading