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