|
from __future__ import annotations |
|
|
|
from typing import Collection |
|
|
|
|
|
class TOMLKitError(Exception): |
|
pass |
|
|
|
|
|
class ParseError(ValueError, TOMLKitError): |
|
""" |
|
This error occurs when the parser encounters a syntax error |
|
in the TOML being parsed. The error references the line and |
|
location within the line where the error was encountered. |
|
""" |
|
|
|
def __init__(self, line: int, col: int, message: str | None = None) -> None: |
|
self._line = line |
|
self._col = col |
|
|
|
if message is None: |
|
message = "TOML parse error" |
|
|
|
super().__init__(f"{message} at line {self._line} col {self._col}") |
|
|
|
@property |
|
def line(self): |
|
return self._line |
|
|
|
@property |
|
def col(self): |
|
return self._col |
|
|
|
|
|
class MixedArrayTypesError(ParseError): |
|
""" |
|
An array was found that had two or more element types. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Mixed types found in array" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidNumberError(ParseError): |
|
""" |
|
A numeric field was improperly specified. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Invalid number" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidDateTimeError(ParseError): |
|
""" |
|
A datetime field was improperly specified. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Invalid datetime" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidDateError(ParseError): |
|
""" |
|
A date field was improperly specified. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Invalid date" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidTimeError(ParseError): |
|
""" |
|
A date field was improperly specified. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Invalid time" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidNumberOrDateError(ParseError): |
|
""" |
|
A numeric or date field was improperly specified. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Invalid number or date format" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidUnicodeValueError(ParseError): |
|
""" |
|
A unicode code was improperly specified. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Invalid unicode value" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class UnexpectedCharError(ParseError): |
|
""" |
|
An unexpected character was found during parsing. |
|
""" |
|
|
|
def __init__(self, line: int, col: int, char: str) -> None: |
|
message = f"Unexpected character: {char!r}" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class EmptyKeyError(ParseError): |
|
""" |
|
An empty key was found during parsing. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Empty key" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class EmptyTableNameError(ParseError): |
|
""" |
|
An empty table name was found during parsing. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Empty table name" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidCharInStringError(ParseError): |
|
""" |
|
The string being parsed contains an invalid character. |
|
""" |
|
|
|
def __init__(self, line: int, col: int, char: str) -> None: |
|
message = f"Invalid character {char!r} in string" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class UnexpectedEofError(ParseError): |
|
""" |
|
The TOML being parsed ended before the end of a statement. |
|
""" |
|
|
|
def __init__(self, line: int, col: int) -> None: |
|
message = "Unexpected end of file" |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InternalParserError(ParseError): |
|
""" |
|
An error that indicates a bug in the parser. |
|
""" |
|
|
|
def __init__(self, line: int, col: int, message: str | None = None) -> None: |
|
msg = "Internal parser error" |
|
if message: |
|
msg += f" ({message})" |
|
|
|
super().__init__(line, col, message=msg) |
|
|
|
|
|
class NonExistentKey(KeyError, TOMLKitError): |
|
""" |
|
A non-existent key was used. |
|
""" |
|
|
|
def __init__(self, key): |
|
message = f'Key "{key}" does not exist.' |
|
|
|
super().__init__(message) |
|
|
|
|
|
class KeyAlreadyPresent(TOMLKitError): |
|
""" |
|
An already present key was used. |
|
""" |
|
|
|
def __init__(self, key): |
|
key = getattr(key, "key", key) |
|
message = f'Key "{key}" already exists.' |
|
|
|
super().__init__(message) |
|
|
|
|
|
class InvalidControlChar(ParseError): |
|
def __init__(self, line: int, col: int, char: int, type: str) -> None: |
|
display_code = "\\u00" |
|
|
|
if char < 16: |
|
display_code += "0" |
|
|
|
display_code += hex(char)[2:] |
|
|
|
message = ( |
|
"Control characters (codes less than 0x1f and 0x7f)" |
|
f" are not allowed in {type}, " |
|
f"use {display_code} instead" |
|
) |
|
|
|
super().__init__(line, col, message=message) |
|
|
|
|
|
class InvalidStringError(ValueError, TOMLKitError): |
|
def __init__(self, value: str, invalid_sequences: Collection[str], delimiter: str): |
|
repr_ = repr(value)[1:-1] |
|
super().__init__( |
|
f"Invalid string: {delimiter}{repr_}{delimiter}. " |
|
f"The character sequences {invalid_sequences} are invalid." |
|
) |
|
|
|
|
|
class ConvertError(TypeError, ValueError, TOMLKitError): |
|
"""Raised when item() fails to convert a value. |
|
It should be a TypeError, but due to historical reasons |
|
it needs to subclass ValueError as well. |
|
""" |
|
|