Skip to content

Commit

Permalink
Clean up after big refactoring
Browse files Browse the repository at this point in the history
Having refactored argparse to click, this is just cleanup afterwards.

Signed-off-by: Carmen Bianca BAKKER <[email protected]>
  • Loading branch information
carmenbianca committed Oct 10, 2024
1 parent d17dde5 commit 95d5e3c
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 47 deletions.
7 changes: 3 additions & 4 deletions src/reuse/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

"""Entry module for reuse."""

import sys

if __name__ == "__main__":
from ._main import main
from .cli.main import main

sys.exit(main())
# pylint: disable=no-value-for-parameter
main()
2 changes: 2 additions & 0 deletions src/reuse/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""All command-line functionality."""

from . import (
annotate,
convert_dep5,
Expand Down
9 changes: 4 additions & 5 deletions src/reuse/cli/annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
)
from ..i18n import _
from ..project import Project
from .common import ClickObj, MutexOption, spdx_identifier
from .common import ClickObj, MutexOption, requires_project, spdx_identifier
from .main import main

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -284,6 +284,7 @@ def get_reuse_info(
)


@requires_project
@main.command(name="annotate", help=_HELP)
@click.option(
"--copyright",
Expand Down Expand Up @@ -323,7 +324,7 @@ def get_reuse_info(
"--style",
"-s",
cls=MutexOption,
mutually_exclusive=["skip_unrecognised"], # FIXME: test
mutually_exclusive=["skip_unrecognised"],
type=click.Choice(list(NAME_STYLE_MAP)),
help=_("Comment style to use."),
)
Expand Down Expand Up @@ -359,8 +360,6 @@ def get_reuse_info(
@click.option(
"--single-line",
cls=MutexOption,
# FIXME: This results in an ugly error message that shows 'multi_line'
# instead of '--multi-line'.
mutually_exclusive=_LINE_MUTEX,
is_flag=True,
help=_("Force single-line comment style."),
Expand Down Expand Up @@ -407,7 +406,6 @@ def get_reuse_info(
@click.option(
"--skip-unrecognized",
"skip_unrecognised",
# FIXME: test if mutex is applied.
is_flag=True,
hidden=True,
)
Expand Down Expand Up @@ -444,6 +442,7 @@ def annotate(
skip_existing: bool,
paths: Sequence[Path],
) -> None:
# pylint: disable=too-many-arguments,too-many-locals,missing-function-docstring
project = cast(Project, obj.project)

test_mandatory_option_required(copyrights, licenses, contributors)
Expand Down
12 changes: 11 additions & 1 deletion src/reuse/cli/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""Utilities that are common to multiple CLI commands."""

from dataclasses import dataclass
from typing import Any, Mapping, Optional
from typing import Any, Callable, Mapping, Optional, TypeVar

import click
from boolean.boolean import Expression, ParseError
Expand All @@ -15,6 +15,16 @@
from ..i18n import _
from ..project import Project

F = TypeVar("F", bound=Callable)


def requires_project(f: F) -> F:
"""A decorator to mark subcommands that require a :class:`Project` object.
Make sure to apply this decorator _first_.
"""
setattr(f, "requires_project", True)
return f


@dataclass(frozen=True)
class ClickObj:
Expand Down
4 changes: 3 additions & 1 deletion src/reuse/cli/convert_dep5.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ..global_licensing import ReuseDep5
from ..i18n import _
from ..project import Project
from .common import ClickObj
from .common import ClickObj, requires_project
from .main import main

_HELP = _(
Expand All @@ -23,9 +23,11 @@
)


@requires_project
@main.command(name="convert-dep5", help=_HELP)
@click.pass_obj
def convert_dep5(obj: ClickObj) -> None:
# pylint: disable=missing-function-docstring
project = cast(Project, obj.project)
if not (project.root / ".reuse/dep5").exists():
raise click.UsageError(_("no '.reuse/dep5' file"))
Expand Down
5 changes: 3 additions & 2 deletions src/reuse/cli/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from ..project import Project
from ..report import ProjectReport
from ..types import StrPath
from .common import ClickObj, MutexOption
from .common import ClickObj, MutexOption, requires_project
from .main import main

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -113,6 +113,7 @@ def _successfully_downloaded(destination: StrPath) -> None:
)


@requires_project
@main.command(name="download", help=_HELP)
@click.option(
"--all",
Expand Down Expand Up @@ -152,7 +153,7 @@ def download(
output: Optional[Path],
source: Optional[Path],
) -> None:

# pylint: disable=missing-function-docstring
if all_ and license_:
raise click.UsageError(
_(
Expand Down
4 changes: 3 additions & 1 deletion src/reuse/cli/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from ..lint import format_json, format_lines, format_plain
from ..project import Project
from ..report import ProjectReport
from .common import ClickObj, MutexOption
from .common import ClickObj, MutexOption, requires_project
from .main import main

_OUTPUT_MUTEX = ["quiet", "json", "plain", "lines"]
Expand Down Expand Up @@ -61,6 +61,7 @@
)


@requires_project
@main.command(name="lint", help=_HELP)
@click.option(
"--quiet",
Expand Down Expand Up @@ -98,6 +99,7 @@
def lint(
obj: ClickObj, quiet: bool, json: bool, plain: bool, lines: bool
) -> None:
# pylint: disable=missing-function-docstring
report = ProjectReport.generate(
cast(Project, obj.project),
do_checksum=False,
Expand Down
4 changes: 3 additions & 1 deletion src/reuse/cli/lint_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ..lint import format_lines_subset
from ..project import Project
from ..report import ProjectSubsetReport
from .common import ClickObj, MutexOption
from .common import ClickObj, MutexOption, requires_project
from .main import main

_OUTPUT_MUTEX = ["quiet", "lines"]
Expand All @@ -29,6 +29,7 @@
)


@requires_project
@main.command(name="lint-file", help=_HELP)
@click.option(
"--quiet",
Expand Down Expand Up @@ -56,6 +57,7 @@
def lint_file(
obj: ClickObj, quiet: bool, lines: bool, files: Collection[Path]
) -> None:
# pylint: disable=missing-function-docstring
project = cast(Project, obj.project)
subset_files = {Path(file_) for file_ in files}
for file_ in subset_files:
Expand Down
52 changes: 28 additions & 24 deletions src/reuse/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
+ "\n\n"
+ _("Support the FSFE's work:")
+ "\n\n"
# FIXME: Indent this.
# Indent next paragraph.
+ " "
+ _(
"Donations are critical to our strength and autonomy. They enable us"
" to continue working for Free Software wherever necessary. Please"
Expand Down Expand Up @@ -133,6 +134,7 @@ def main(
no_multiprocessing: bool,
root: Optional[Path],
) -> None:
# pylint: disable=missing-function-docstring,too-many-arguments
setup_logging(level=logging.DEBUG if debug else logging.WARNING)

# Very stupid workaround to not print a DEP5 deprecation warning in the
Expand All @@ -143,29 +145,31 @@ def main(
if not suppress_deprecation:
warnings.filterwarnings("default", module="reuse")

# FIXME: Not needed for all subcommands.
if root is None:
root = find_root()
if root is None:
root = Path.cwd()

# FIXME: Not needed for all subcommands.
try:
project = Project.from_directory(root)
# FileNotFoundError and NotADirectoryError don't need to be caught because
# argparse already made sure of these things.
except GlobalLicensingParseError as error:
raise click.UsageError(
_(
"'{path}' could not be parsed. We received the following error"
" message: {message}"
).format(path=error.source, message=str(error))
) from error

except (GlobalLicensingConflict, OSError) as error:
raise click.UsageError(str(error)) from error
project.include_submodules = include_submodules
project.include_meson_subprojects = include_meson_subprojects
project: Optional[Project] = None
if ctx.invoked_subcommand:
cmd = main.get_command(ctx, ctx.invoked_subcommand)
if getattr(cmd, "requires_project", False):
if root is None:
root = find_root()
if root is None:
root = Path.cwd()

try:
project = Project.from_directory(root)
# FileNotFoundError and NotADirectoryError don't need to be caught
# because argparse already made sure of these things.
except GlobalLicensingParseError as error:
raise click.UsageError(
_(
"'{path}' could not be parsed. We received the"
" following error message: {message}"
).format(path=error.source, message=str(error))
) from error

except (GlobalLicensingConflict, OSError) as error:
raise click.UsageError(str(error)) from error
project.include_submodules = include_submodules
project.include_meson_subprojects = include_meson_subprojects

ctx.obj = ClickObj(
no_multiprocessing=no_multiprocessing,
Expand Down
11 changes: 7 additions & 4 deletions src/reuse/cli/spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,24 @@

import contextlib
import logging
from typing import Optional, cast
import sys
from typing import Optional, cast

import click

from ..project import Project
from .. import _IGNORE_SPDX_PATTERNS
from ..report import ProjectReport
from ..i18n import _
from .common import ClickObj
from ..project import Project
from ..report import ProjectReport
from .common import ClickObj, requires_project
from .main import main

_LOGGER = logging.getLogger(__name__)

_HELP = _("Generate an SPDX bill of materials.")


@requires_project
@main.command(name="spdx", help=_HELP)
@click.option(
"--output",
Expand Down Expand Up @@ -68,6 +69,8 @@ def spdx(
creator_person: Optional[str],
creator_organization: Optional[str],
) -> None:
# pylint: disable=missing-function-docstring

# The SPDX spec mandates that a creator must be specified when a license
# conclusion is made, so here we enforce that. More context:
# https://github.com/fsfe/reuse-tool/issues/586#issuecomment-1310425706
Expand Down
1 change: 1 addition & 0 deletions src/reuse/cli/supported_licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

@main.command(name="supported-licenses", help=_HELP)
def supported_licenses() -> None:
# pylint: disable=missing-function-docstring
licenses = _load_license_list(_LICENSES)[1]

for license_id, license_info in licenses.items():
Expand Down
4 changes: 2 additions & 2 deletions src/reuse/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ def _generate_file_reports(

def _process_error(error: Exception, path: StrPath) -> None:
# Facilitate better debugging by being able to quit the program.
if isinstance(error, bdb.BdbQuit):
raise bdb.BdbQuit() from error
if isinstance(error, (bdb.BdbQuit, KeyboardInterrupt)):
raise error
if isinstance(error, (OSError, UnicodeError)):
_LOGGER.error(
_("Could not read '{path}'").format(path=path),
Expand Down
9 changes: 7 additions & 2 deletions tests/test_cli_annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,12 @@ def test_skip_unrecognised(self, fake_repository, skip_unrecognised):
assert result.exit_code == 0
assert "Skipped unrecognised file 'foo.foo'" in result.output

def test_skip_unrecognised_and_style_mutex(self, fake_repository):
@pytest.mark.parametrize(
"skip_unrecognised", ["--skip-unrecognised", "--skip-unrecognized"]
)
def test_skip_unrecognised_and_style_mutex(
self, fake_repository, skip_unrecognised
):
"""--skip-unrecognised and --style are mutually exclusive."""
simple_file = fake_repository / "foo.foo"
simple_file.write_text("pass")
Expand All @@ -635,7 +640,7 @@ def test_skip_unrecognised_and_style_mutex(self, fake_repository):
"--copyright",
"Jane Doe",
"--style=c",
"--skip-unrecognised",
skip_unrecognised,
"foo.foo",
],
)
Expand Down
2 changes: 2 additions & 0 deletions tests/test_cli_convert_dep5.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from reuse._util import cleandoc_nl
from reuse.cli.main import main

# pylint: disable=unused-argument


class TestConvertDep5:
"""Tests for convert-dep5."""
Expand Down
2 changes: 2 additions & 0 deletions tests/test_cli_spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

from reuse.cli.main import main

# pylint: disable=unused-argument


class TestSpdx:
"""Tests for spdx."""
Expand Down

0 comments on commit 95d5e3c

Please sign in to comment.