• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import dataclasses as dc
2from typing import Literal,  NoReturn, overload
3
4
5@dc.dataclass
6class ClinicError(Exception):
7    message: str
8    _: dc.KW_ONLY
9    lineno: int | None = None
10    filename: str | None = None
11
12    def __post_init__(self) -> None:
13        super().__init__(self.message)
14
15    def report(self, *, warn_only: bool = False) -> str:
16        msg = "Warning" if warn_only else "Error"
17        if self.filename is not None:
18            msg += f" in file {self.filename!r}"
19        if self.lineno is not None:
20            msg += f" on line {self.lineno}"
21        msg += ":\n"
22        msg += f"{self.message}\n"
23        return msg
24
25
26class ParseError(ClinicError):
27    pass
28
29
30@overload
31def warn_or_fail(
32    *args: object,
33    fail: Literal[True],
34    filename: str | None = None,
35    line_number: int | None = None,
36) -> NoReturn: ...
37
38@overload
39def warn_or_fail(
40    *args: object,
41    fail: Literal[False] = False,
42    filename: str | None = None,
43    line_number: int | None = None,
44) -> None: ...
45
46def warn_or_fail(
47    *args: object,
48    fail: bool = False,
49    filename: str | None = None,
50    line_number: int | None = None,
51) -> None:
52    joined = " ".join([str(a) for a in args])
53    error = ClinicError(joined, filename=filename, lineno=line_number)
54    if fail:
55        raise error
56    else:
57        print(error.report(warn_only=True))
58
59
60def warn(
61    *args: object,
62    filename: str | None = None,
63    line_number: int | None = None,
64) -> None:
65    return warn_or_fail(*args, filename=filename, line_number=line_number, fail=False)
66
67def fail(
68    *args: object,
69    filename: str | None = None,
70    line_number: int | None = None,
71) -> NoReturn:
72    warn_or_fail(*args, filename=filename, line_number=line_number, fail=True)
73