Standardisation des scripts
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import traceback
|
||||
from collections.abc import Callable, Sequence
|
||||
from enum import IntEnum
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from .workspace import (
|
||||
EvaluationWorkspace,
|
||||
WorkspaceNotFoundError,
|
||||
WorkspaceValidationError,
|
||||
)
|
||||
|
||||
|
||||
class ExitCode(IntEnum):
|
||||
SUCCESS = 0
|
||||
FAILURE = 1
|
||||
INVALID_ARGUMENTS = 2
|
||||
INVALID_WORKSPACE = 3
|
||||
PARTIAL = 4
|
||||
INTERRUPTED = 130
|
||||
|
||||
|
||||
class CliError(Exception):
|
||||
def __init__(self, message: str, exit_code: ExitCode = ExitCode.FAILURE) -> None:
|
||||
self.exit_code = exit_code
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
def evaluation_parser(description: str) -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument(
|
||||
"evaluation",
|
||||
type=Path,
|
||||
help="Evaluation directory",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="Show a traceback when an unexpected error occurs",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def evaluation_workspace(
|
||||
path: str | Path,
|
||||
*,
|
||||
repository: str | Path | None = None,
|
||||
) -> EvaluationWorkspace:
|
||||
root = Path(path).expanduser().resolve()
|
||||
if not root.exists():
|
||||
raise CliError(
|
||||
f"Evaluation directory does not exist: {root}",
|
||||
ExitCode.INVALID_WORKSPACE,
|
||||
)
|
||||
if not root.is_dir():
|
||||
raise CliError(
|
||||
f"Evaluation path is not a directory: {root}",
|
||||
ExitCode.INVALID_WORKSPACE,
|
||||
)
|
||||
return EvaluationWorkspace(root, Path(repository) if repository is not None else None)
|
||||
|
||||
|
||||
def workspace_from_args(
|
||||
args: argparse.Namespace,
|
||||
*,
|
||||
repository: str | Path | None = None,
|
||||
) -> EvaluationWorkspace:
|
||||
return evaluation_workspace(args.evaluation, repository=repository)
|
||||
|
||||
|
||||
def execute(
|
||||
parser: argparse.ArgumentParser,
|
||||
argv: Sequence[str] | None,
|
||||
handler: Callable[[argparse.Namespace], int | ExitCode | None],
|
||||
) -> int:
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
result = handler(args)
|
||||
except CliError as exc:
|
||||
print(f"Error: {exc}", file=sys.stderr)
|
||||
return int(exc.exit_code)
|
||||
except (WorkspaceNotFoundError, WorkspaceValidationError) as exc:
|
||||
print(f"Error: {exc}", file=sys.stderr)
|
||||
return int(ExitCode.INVALID_WORKSPACE)
|
||||
except KeyboardInterrupt:
|
||||
print("Interrupted by user.", file=sys.stderr)
|
||||
return int(ExitCode.INTERRUPTED)
|
||||
except Exception as exc: # noqa: BLE001 - executable boundary
|
||||
if getattr(args, "verbose", False):
|
||||
traceback.print_exc()
|
||||
else:
|
||||
print(f"Error: {exc}", file=sys.stderr)
|
||||
return int(ExitCode.FAILURE)
|
||||
return int(ExitCode.SUCCESS if result is None else result)
|
||||
|
||||
|
||||
def stderr(message: Any) -> None:
|
||||
print(message, file=sys.stderr)
|
||||
Reference in New Issue
Block a user