Skip to content

Commit

Permalink
Merge pull request #1093 from carmenbianca/refactor-exceptions
Browse files Browse the repository at this point in the history
Refactor exceptions
  • Loading branch information
carmenbianca authored Oct 17, 2024
2 parents d942142 + 0af6fb6 commit d6a8b11
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 93 deletions.
8 changes: 0 additions & 8 deletions src/reuse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,3 @@ def __bool__(self) -> bool:

def __or__(self, value: "ReuseInfo") -> "ReuseInfo":
return self.union(value)


class ReuseException(Exception):
"""Base exception."""


class IdentifierNotFound(ReuseException):
"""Could not find SPDX identifier for license file."""
6 changes: 3 additions & 3 deletions src/reuse/_annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
)
from .comment import (
NAME_STYLE_MAP,
CommentCreateError,
CommentStyle,
EmptyCommentStyle,
get_comment_style,
)
from .header import MissingReuseInfo, add_new_header, find_and_replace_header
from .exceptions import CommentCreateError, MissingReuseInfoError
from .header import add_new_header, find_and_replace_header
from .i18n import _
from .project import Project
from .types import StrPath
Expand Down Expand Up @@ -152,7 +152,7 @@ def add_header_to_file(
)
out.write("\n")
result = 1
except MissingReuseInfo:
except MissingReuseInfoError:
out.write(
_(
"Error: Generated comment header for '{path}' is missing"
Expand Down
6 changes: 3 additions & 3 deletions src/reuse/cli/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
from license_expression import ExpressionError

from .._util import _LICENSING
from ..global_licensing import GlobalLicensingParseError
from ..exceptions import GlobalLicensingConflictError, GlobalLicensingParseError
from ..i18n import _
from ..project import GlobalLicensingConflict, Project
from ..project import Project
from ..vcs import find_root


Expand Down Expand Up @@ -60,7 +60,7 @@ def project(self) -> Project:
).format(path=error.source, message=str(error))
) from error

except (GlobalLicensingConflict, OSError) as error:
except (GlobalLicensingConflictError, OSError) as error:
raise click.UsageError(str(error)) from error

self._project = project
Expand Down
9 changes: 1 addition & 8 deletions src/reuse/comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,12 @@
from textwrap import dedent
from typing import NamedTuple, Optional, Type, cast

from .exceptions import CommentCreateError, CommentParseError
from .types import StrPath

_LOGGER = logging.getLogger(__name__)


class CommentParseError(Exception):
"""An error occurred during the parsing of a comment."""


class CommentCreateError(Exception):
"""An error occurred during the creation of a comment."""


class MultiLineSegments(NamedTuple):
"""Components that make up a multi-line comment style, e.g. '/*', '*', and
'*/'.
Expand Down
61 changes: 61 additions & 0 deletions src/reuse/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# SPDX-FileCopyrightText: 2017 Free Software Foundation Europe e.V. <https://fsfe.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""All exceptions owned by :mod:`reuse`. These exceptions all inherit
:class:`ReuseError`.
"""

from typing import Any, Optional


class ReuseError(Exception):
"""Base exception."""


class SpdxIdentifierNotFoundError(ReuseError):
"""Could not find SPDX identifier for license file."""


class GlobalLicensingParseError(ReuseError):
"""An exception representing any kind of error that occurs when trying to
parse a :class:`reuse.global_licensing.GlobalLicensing` file.
"""

def __init__(self, *args: Any, source: Optional[str] = None):
super().__init__(*args)
self.source = source


class GlobalLicensingParseTypeError(GlobalLicensingParseError, TypeError):
"""An exception representing a type error while trying to parse a
:class:`reuse.global_licensing.GlobalLicensing` file.
"""


class GlobalLicensingParseValueError(GlobalLicensingParseError, ValueError):
"""An exception representing a value error while trying to parse a
:class:`reuse.global_licensing.GlobalLicensing` file.
"""


class GlobalLicensingConflictError(ReuseError):
"""There are two global licensing files in the project that are not
compatible.
"""


class MissingReuseInfoError(ReuseError):
"""Some REUSE information is missing from the result."""


class CommentError(ReuseError):
"""An error occurred during an interaction with a comment."""


class CommentCreateError(Exception):
"""An error occurred during the creation of a comment."""


class CommentParseError(Exception):
"""An error occurred during the parsing of a comment."""
29 changes: 6 additions & 23 deletions src/reuse/global_licensing.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@
from debian.copyright import Error as DebianError
from license_expression import ExpressionError

from . import ReuseException, ReuseInfo, SourceType
from . import ReuseInfo, SourceType
from ._util import _LICENSING
from .covered_files import iter_files
from .exceptions import (
GlobalLicensingParseError,
GlobalLicensingParseTypeError,
GlobalLicensingParseValueError,
)
from .i18n import _
from .types import StrPath
from .vcs import VCSStrategy
Expand Down Expand Up @@ -72,28 +77,6 @@ class PrecedenceType(Enum):
OVERRIDE = "override"


class GlobalLicensingParseError(ReuseException):
"""An exception representing any kind of error that occurs when trying to
parse a :class:`GlobalLicensing` file.
"""

def __init__(self, *args: Any, source: Optional[str] = None):
super().__init__(*args)
self.source = source


class GlobalLicensingParseTypeError(GlobalLicensingParseError, TypeError):
"""An exception representing a type error while trying to parse a
:class:`GlobalLicensing` file.
"""


class GlobalLicensingParseValueError(GlobalLicensingParseError, ValueError):
"""An exception representing a value error while trying to parse a
:class:`GlobalLicensing` file.
"""


@attrs.define
class _CollectionOfValidator:
collection_type: Type[Collection] = attrs.field()
Expand Down
28 changes: 13 additions & 15 deletions src/reuse/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@
extract_reuse_info,
merge_copyright_lines,
)
from .comment import (
from .comment import CommentStyle, EmptyCommentStyle, PythonCommentStyle
from .exceptions import (
CommentCreateError,
CommentParseError,
CommentStyle,
EmptyCommentStyle,
PythonCommentStyle,
MissingReuseInfoError,
)
from .i18n import _

Expand All @@ -53,10 +52,6 @@ class _TextSections(NamedTuple):
after: str


class MissingReuseInfo(Exception):
"""Some REUSE information is missing from the result."""


def _create_new_header(
reuse_info: ReuseInfo,
template: Optional[Template] = None,
Expand All @@ -68,7 +63,8 @@ def _create_new_header(
Raises:
CommentCreateError: if a comment could not be created.
MissingReuseInfo: if the generated comment is missing SPDX information.
MissingReuseInfoError: if the generated comment is missing SPDX
information.
"""
if template is None:
template = DEFAULT_TEMPLATE
Expand Down Expand Up @@ -101,7 +97,7 @@ def _create_new_header(
)
)
_LOGGER.debug(result)
raise MissingReuseInfo()
raise MissingReuseInfoError()

return result

Expand All @@ -125,7 +121,8 @@ def create_header(
Raises:
CommentCreateError: if a comment could not be created.
MissingReuseInfo: if the generated comment is missing SPDX information.
MissingReuseInfoError: if the generated comment is missing SPDX
information.
"""
if template is None:
template = DEFAULT_TEMPLATE
Expand Down Expand Up @@ -186,7 +183,7 @@ def _find_first_spdx_comment(
preceding the comment, the comment itself, and everything following it.
Raises:
MissingReuseInfo: if no REUSE info can be found in any comment
MissingReuseInfoError: if no REUSE info can be found in any comment.
"""
if style is None:
style = PythonCommentStyle
Expand All @@ -203,7 +200,7 @@ def _find_first_spdx_comment(
text[:index], comment + "\n", text[index + len(comment) + 1 :]
)

raise MissingReuseInfo()
raise MissingReuseInfoError()


def _extract_shebang(prefix: str, text: str) -> tuple[str, str]:
Expand Down Expand Up @@ -248,14 +245,15 @@ def find_and_replace_header(
Raises:
CommentCreateError: if a comment could not be created.
MissingReuseInfo: if the generated comment is missing SPDX information.
MissingReuseInfoError: if the generated comment is missing SPDX
information.
"""
if style is None:
style = PythonCommentStyle

try:
before, header, after = _find_first_spdx_comment(text, style=style)
except MissingReuseInfo:
except MissingReuseInfoError:
before, header, after = "", "", text

# Workaround. EmptyCommentStyle should always be completely replaced.
Expand Down
28 changes: 13 additions & 15 deletions src/reuse/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import attrs
from binaryornot.check import is_binary

from . import IdentifierNotFound, ReuseInfo
from . import ReuseInfo
from ._licenses import EXCEPTION_MAP, LICENSE_MAP
from ._util import (
_LICENSEREF_PATTERN,
Expand All @@ -30,6 +30,10 @@
reuse_info_of_file,
)
from .covered_files import iter_files
from .exceptions import (
GlobalLicensingConflictError,
SpdxIdentifierNotFoundError,
)
from .global_licensing import (
GlobalLicensing,
NestedReuseTOML,
Expand All @@ -44,12 +48,6 @@
_LOGGER = logging.getLogger(__name__)


class GlobalLicensingConflict(Exception):
"""There are two global licensing files in the project that are not
compatible.
"""


class GlobalLicensingFound(NamedTuple):
path: Path
cls: Type[GlobalLicensing]
Expand Down Expand Up @@ -111,8 +109,8 @@ def from_directory(
decoded.
GlobalLicensingParseError: if the global licensing config file could
not be parsed.
GlobalLicensingConflict: if more than one global licensing config
file is present.
GlobalLicensingConflictError: if more than one global licensing
config file is present.
"""
root = Path(root)
if not root.exists():
Expand Down Expand Up @@ -323,8 +321,8 @@ def find_global_licensing(
:class:`GlobalLicensing`.
Raises:
GlobalLicensingConflict: if more than one global licensing config
file is present.
GlobalLicensingConflictError: if more than one global licensing
config file is present.
"""
candidates: list[GlobalLicensingFound] = []
dep5_path = root / ".reuse/dep5"
Expand Down Expand Up @@ -352,7 +350,7 @@ def find_global_licensing(
]
if reuse_toml_candidates:
if candidates:
raise GlobalLicensingConflict(
raise GlobalLicensingConflictError(
_(
"Found both '{new_path}' and '{old_path}'. You"
" cannot keep both files simultaneously; they are"
Expand Down Expand Up @@ -384,13 +382,13 @@ def _identifier_of_license(self, path: Path) -> str:
License Identifier.
"""
if not path.suffix:
raise IdentifierNotFound(f"{path} has no file extension")
raise SpdxIdentifierNotFoundError(f"{path} has no file extension")
if path.stem in self.license_map:
return path.stem
if _LICENSEREF_PATTERN.match(path.stem):
return path.stem

raise IdentifierNotFound(
raise SpdxIdentifierNotFoundError(
f"Could not find SPDX License Identifier for {path}"
)

Expand Down Expand Up @@ -418,7 +416,7 @@ def _find_licenses(self) -> dict[str, Path]:

try:
identifier = self._identifier_of_license(path)
except IdentifierNotFound:
except SpdxIdentifierNotFoundError:
if path.name in self.license_map:
_LOGGER.info(
_("{path} does not have a file extension").format(
Expand Down
3 changes: 1 addition & 2 deletions tests/test_comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
import pytest

from reuse.comment import (
CommentCreateError,
CommentParseError,
CommentStyle,
CppCommentStyle,
HtmlCommentStyle,
LispCommentStyle,
PythonCommentStyle,
_all_style_classes,
)
from reuse.exceptions import CommentCreateError, CommentParseError


@pytest.fixture(
Expand Down
6 changes: 4 additions & 2 deletions tests/test_global_licensing.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@

from reuse import ReuseInfo, SourceType
from reuse._util import _LICENSING
from reuse.global_licensing import (
AnnotationsItem,
from reuse.exceptions import (
GlobalLicensingParseError,
GlobalLicensingParseTypeError,
GlobalLicensingParseValueError,
)
from reuse.global_licensing import (
AnnotationsItem,
NestedReuseTOML,
PrecedenceType,
ReuseDep5,
Expand Down
Loading

0 comments on commit d6a8b11

Please sign in to comment.