Skip to content

Commit

Permalink
Merge pull request #72 from akaihola/cmdline-fail-exit-code-3
Browse files Browse the repository at this point in the history
Use different exit codes for various situations
  • Loading branch information
akaihola authored Jul 31, 2024
2 parents dea5f49 + 33f44dc commit 0f96f8e
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ These features will be included in the next release:

Added
-----
- Return exit code 3 if command line parsing fails. We want to reserve 2 for file not
found errors which will make GitHub actions easier. Also define constants for various
exit codes to be used in Darkgraylib and applications which use it.

Fixed
-----
Expand Down
29 changes: 26 additions & 3 deletions src/darkgraylib/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
)
from darkgraylib.version import __version__

EXIT_CODE_FILE_NOT_FOUND = 2
EXIT_CODE_CMDLINE_ERROR = 3
EXIT_CODE_DEPENDENCY = 4
EXIT_CODE_UNKNOWN = 123


def make_argument_parser(
require_src: bool,
Expand Down Expand Up @@ -119,6 +124,24 @@ def __call__(self, require_src: bool) -> ArgumentParser:
...


def parse_args(parser: ArgumentParser, argv: list[str]) -> Namespace:
"""Parse command line arguments, exit with exit code 3 on error.
:param parser: The argument parser object
:param argv: Command line to parse
:return: The parsed command line arguments
"""
try:
return parser.parse_args(argv)
except SystemExit as exc_info:
if exc_info.args == (2,):
# Change all exceptions from argparse to exit code 3 (cmdline error)
sys.exit(EXIT_CODE_CMDLINE_ERROR)
# For other exit codes, exit with the original code
raise


def parse_command_line(
argument_parser_factory: ArgumentParserFactory,
argv: list[str] | None,
Expand Down Expand Up @@ -154,7 +177,7 @@ def parse_command_line(
# 1. Parse the paths of files/directories to process into `args.src`, and the config
# file path into `args.config`.
parser_for_srcs = argument_parser_factory(require_src=False)
args = parser_for_srcs.parse_args(argv)
args = parse_args(parser_for_srcs, argv)

# 2. Locate `pyproject.toml` based on the `-c`/`--config` command line option, or
# if it's not provided, based on the paths to process, or in the current
Expand All @@ -172,14 +195,14 @@ def parse_command_line(
# based on the configuration file and the command line options for all options
# except `src` (the list of files to process).
parser_for_srcs.set_defaults(**config)
args = parser_for_srcs.parse_args(argv)
args = parse_args(parser_for_srcs, argv)

# 5. Make sure an error for missing file/directory paths is thrown if we're not
# running in stdin mode and no file/directory is configured in `pyproject.toml`.
if args.stdin_filename is None and not config.get("src"):
parser = argument_parser_factory(require_src=True)
parser.set_defaults(**config)
args = parser.parse_args(argv)
args = parse_args(parser, argv)

# Make sure there aren't invalid option combinations after merging configuration and
# command line options.
Expand Down
12 changes: 12 additions & 0 deletions src/darkgraylib/tests/test_command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,15 @@ def test_parse_command_line_load_config_hook_called(tmp_path, monkeypatch):
)

hook_mock.assert_called_once_with({"revision": "main"})


def test_parse_command_line_invalid_arguments(capsys):
"""Test that parse_command_line exits with code 3 for invalid arguments."""
with pytest.raises(SystemExit) as excinfo:
parse_command_line(
make_test_argument_parser, ["--invalid-option"], "darkgraylib", BaseConfig
)

assert excinfo.value.code == 3
captured = capsys.readouterr()
assert "error: unrecognized arguments: --invalid-option" in captured.err

0 comments on commit 0f96f8e

Please sign in to comment.