Skip to content

Commit

Permalink
polish how expected errors are printed: rm traceback, add some color
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed Nov 4, 2023
1 parent 0a2c65f commit 98aa352
Show file tree
Hide file tree
Showing 15 changed files with 84 additions and 57 deletions.
17 changes: 16 additions & 1 deletion rose/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
import sys

import click

from rose.cli import cli
from rose.common import RoseExpectedError


def main() -> None:
try:
cli()
except RoseExpectedError as e:
click.secho(f"{e.__class__.__module__}.{e.__class__.__name__}: ", fg="red", nl=False)
click.secho(str(e))
sys.exit(1)


if __name__ == "__main__":
cli()
main()
6 changes: 3 additions & 3 deletions rose/audiotags.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import mutagen.oggvorbis

from rose.artiststr import ArtistMapping, format_artist_string, parse_artist_string
from rose.common import RoseError
from rose.common import RoseError, RoseExpectedError

TAG_SPLITTER_REGEX = re.compile(r" \\\\ | / |; ?| vs\. ")
YEAR_REGEX = re.compile(r"\d{4}$")
Expand Down Expand Up @@ -66,11 +66,11 @@ def _normalize_rtype(x: str | None) -> str:
return "unknown"


class UnsupportedFiletypeError(RoseError):
class UnsupportedFiletypeError(RoseExpectedError):
pass


class UnsupportedTagValueTypeError(RoseError):
class UnsupportedTagValueTypeError(RoseExpectedError):
pass


Expand Down
28 changes: 16 additions & 12 deletions rose/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
remove_release_from_collage,
rename_collage,
)
from rose.common import RoseError, valid_uuid
from rose.common import RoseExpectedError, valid_uuid
from rose.config import Config
from rose.playlists import (
add_track_to_playlist,
Expand Down Expand Up @@ -61,15 +61,15 @@
logger = logging.getLogger(__name__)


class InvalidReleaseArgError(RoseError):
class InvalidReleaseArgError(RoseExpectedError):
pass


class InvalidTrackArgError(RoseError):
class InvalidTrackArgError(RoseExpectedError):
pass


class DaemonAlreadyRunningError(RoseError):
class DaemonAlreadyRunningError(RoseExpectedError):
pass


Expand Down Expand Up @@ -506,11 +506,13 @@ def parse_release_argument(r: str) -> str:
return m[1]
raise InvalidReleaseArgError(
f"""\
{r} is not a valid release argument. Release arguments must be:
{r} is not a valid release argument.
1. The release UUID
2. The path of the source directory of a release
3. The path of the release in the virtual filesystem (from any view)
Release arguments must be:
1. The release UUID
2. The path of the source directory of a release
3. The path of the release in the virtual filesystem (from any view)
{r} is not recognized as any of the above.
"""
Expand All @@ -530,11 +532,13 @@ def parse_track_argument(t: str) -> str:
return af.id
raise InvalidTrackArgError(
f"""\
{t} is not a valid track argument. Track arguments must be:
{t} is not a valid track argument.
Track arguments must be:
1. The track UUID
2. The path of the track in the source directory
3. The path of the track in the virtual filesystem (from any view)
1. The track UUID
2. The path of the track in the source directory
3. The path of the track in the virtual filesystem (from any view)
{t} is not recognized as any of the above.
"""
Expand Down
8 changes: 4 additions & 4 deletions rose/collages.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@
update_cache_evict_nonexistent_collages,
update_cache_for_collages,
)
from rose.common import RoseError
from rose.common import RoseExpectedError
from rose.config import Config
from rose.releases import resolve_release_ids

logger = logging.getLogger(__name__)


class DescriptionMismatchError(RoseError):
class DescriptionMismatchError(RoseExpectedError):
pass


class CollageDoesNotExistError(RoseError):
class CollageDoesNotExistError(RoseExpectedError):
pass


class CollageAlreadyExistsError(RoseError):
class CollageAlreadyExistsError(RoseExpectedError):
pass


Expand Down
4 changes: 3 additions & 1 deletion rose/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ class RoseError(Exception):
pass


class InvalidCoverArtFileError(RoseError):
class RoseExpectedError(RoseError):
"""These errors are printed without traceback."""

pass


Expand Down
10 changes: 5 additions & 5 deletions rose/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import appdirs
import tomllib

from rose.common import RoseError, sanitize_filename
from rose.common import RoseExpectedError, sanitize_filename
from rose.rule_parser import MetadataRule, RuleSyntaxError

XDG_CONFIG_ROSE = Path(appdirs.user_config_dir("rose"))
Expand All @@ -25,19 +25,19 @@
XDG_CACHE_ROSE.mkdir(parents=True, exist_ok=True)


class ConfigNotFoundError(RoseError):
class ConfigNotFoundError(RoseExpectedError):
pass


class ConfigDecodeError(RoseError):
class ConfigDecodeError(RoseExpectedError):
pass


class MissingConfigKeyError(RoseError):
class MissingConfigKeyError(RoseExpectedError):
pass


class InvalidConfigValueError(RoseError, ValueError):
class InvalidConfigValueError(RoseExpectedError, ValueError):
pass


Expand Down
3 changes: 2 additions & 1 deletion rose/config_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import tempfile
from pathlib import Path

import click
import pytest

from rose.config import Config, ConfigNotFoundError, InvalidConfigValueError, MissingConfigKeyError
Expand Down Expand Up @@ -422,7 +423,7 @@ def write(x: str) -> None:
with pytest.raises(InvalidConfigValueError) as excinfo:
Config.parse(config_path_override=path)
assert (
str(excinfo.value)
click.unstyle(str(excinfo.value))
== f"""\
Failed to parse stored_metadata_rules in configuration file ({path}): rule {{'matcher': 'tracktitle:hi', 'actions': ['delete:hi']}}: Failed to parse action 1, invalid syntax:
Expand Down
14 changes: 9 additions & 5 deletions rose/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,29 @@
update_cache_evict_nonexistent_playlists,
update_cache_for_playlists,
)
from rose.common import InvalidCoverArtFileError, RoseError
from rose.common import RoseExpectedError
from rose.config import Config

logger = logging.getLogger(__name__)


class DescriptionMismatchError(RoseError):
class InvalidCoverArtFileError(RoseExpectedError):
pass


class PlaylistDoesNotExistError(RoseError):
class DescriptionMismatchError(RoseExpectedError):
pass


class TrackDoesNotExistError(RoseError):
class PlaylistDoesNotExistError(RoseExpectedError):
pass


class PlaylistAlreadyExistsError(RoseError):
class TrackDoesNotExistError(RoseExpectedError):
pass


class PlaylistAlreadyExistsError(RoseExpectedError):
pass


Expand Down
14 changes: 9 additions & 5 deletions rose/releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,31 @@
update_cache_for_collages,
update_cache_for_releases,
)
from rose.common import InvalidCoverArtFileError, RoseError, valid_uuid
from rose.common import RoseError, RoseExpectedError, valid_uuid
from rose.config import Config
from rose.rule_parser import MetadataAction
from rose.rules import execute_metadata_actions

logger = logging.getLogger(__name__)


class ReleaseDoesNotExistError(RoseError):
class InvalidCoverArtFileError(RoseExpectedError):
pass


class ReleaseEditFailedError(RoseError):
class ReleaseDoesNotExistError(RoseExpectedError):
pass


class InvalidReleaseEditResumeFileError(RoseError):
class ReleaseEditFailedError(RoseExpectedError):
pass


class UnknownArtistRoleError(RoseError):
class InvalidReleaseEditResumeFileError(RoseExpectedError):
pass


class UnknownArtistRoleError(RoseExpectedError):
pass


Expand Down
10 changes: 6 additions & 4 deletions rose/rule_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
from dataclasses import dataclass
from typing import Literal

from rose.common import RoseError
import click

from rose.common import RoseError, RoseExpectedError

logger = logging.getLogger(__name__)


class InvalidRuleError(RoseError):
class InvalidRuleError(RoseExpectedError):
pass


Expand All @@ -35,8 +37,8 @@ def __str__(self) -> str:
Failed to parse {self.rule_name}, invalid syntax:
{self.rule}
{" " * self.index}^
{" " * self.index}{self.feedback}
{" " * self.index}{click.style("^", fg="red")}
{" " * self.index}{click.style(self.feedback, bold=True)}
"""


Expand Down
5 changes: 3 additions & 2 deletions rose/rule_parser_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re

import click
import pytest

from rose.rule_parser import (
Expand Down Expand Up @@ -93,7 +94,7 @@ def test_rule_parse_matcher() -> None:
def test_err(rule: str, err: str) -> None:
with pytest.raises(RuleSyntaxError) as exc:
MetadataMatcher.parse(rule)
assert str(exc.value) == err
assert click.unstyle(str(exc.value)) == err

test_err(
"tracknumber^Track$",
Expand Down Expand Up @@ -234,7 +235,7 @@ def test_rule_parse_action() -> None:
def test_err(rule: str, err: str, matcher: MetadataMatcher | None = None) -> None:
with pytest.raises(RuleSyntaxError) as exc:
MetadataAction.parse(rule, 1, matcher)
assert str(exc.value) == err
assert click.unstyle(str(exc.value)) == err

test_err(
"haha::delete",
Expand Down
12 changes: 5 additions & 7 deletions rose/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
get_release_source_paths_from_ids,
update_cache_for_releases,
)
from rose.common import RoseError, uniq
from rose.common import RoseError, RoseExpectedError, uniq
from rose.config import Config
from rose.rule_parser import (
AddAction,
Expand All @@ -34,11 +34,7 @@
logger = logging.getLogger(__name__)


class InvalidRuleActionError(RoseError):
pass


class InvalidReplacementValueError(RoseError):
class InvalidReplacementValueError(RoseExpectedError):
pass


Expand Down Expand Up @@ -389,7 +385,9 @@ def execute_single_action(action: MetadataAction, value: str | int | None) -> st
return bhv.src.sub(bhv.dst, strvalue)
elif isinstance(bhv, DeleteAction):
return None
raise InvalidRuleActionError(f"Invalid action {type(bhv)} for single-value tag")
raise RoseError(
f"Invalid action {type(bhv)} for single-value tag: Should have been caught in parsing"
)


def execute_multi_value_action(
Expand Down
4 changes: 2 additions & 2 deletions rose/tracks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
from rose.cache import (
get_track,
)
from rose.common import RoseError
from rose.common import RoseExpectedError
from rose.config import Config
from rose.rule_parser import MetadataAction
from rose.rules import execute_metadata_actions

logger = logging.getLogger(__name__)


class TrackDoesNotExistError(RoseError):
class TrackDoesNotExistError(RoseExpectedError):
pass


Expand Down
4 changes: 0 additions & 4 deletions rose/virtualfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,6 @@ def label(self, label: str) -> bool:
return True


class UnknownFileHandleError(RoseError):
pass


class FileHandleManager:
"""
FileDescriptorGenerator generates file descriptors and handles wrapping so that we do not go
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
author="blissful",
author_email="blissful@sunsetglow.net",
license="Apache-2.0",
entry_points={"console_scripts": ["rose = rose.__main__:cli"]},
entry_points={"console_scripts": ["rose = rose.__main__:main"]},
packages=setuptools.find_namespace_packages(where="."),
package_data={"rose": ["*.sql", ".version"]},
install_requires=[
Expand Down

0 comments on commit 98aa352

Please sign in to comment.