from __future__ import annotations
import inspect
from typing import Any, Dict, Iterable, Tuple
from .almanac_error import AlmanacError
from .generic_errors import AlmanacKeyError
[docs]class BaseArgumentError(AlmanacError):
"""The base exception type for invalid arguments."""
[docs]class ArgumentNameCollisionError(BaseArgumentError):
"""An exception type for when argument names would collide."""
def __init__(
self,
*names: str
) -> None:
if not names:
msg = 'Cannot map multiple arguments with the same identifier.'
elif len(names) == 1:
msg = f'Cannot map multiple arguments with the same identifer {names[0]}.'
elif len(names) == 2:
msg = (
'Cannot map multiple arguments with the same identifiers '
f'{names[0]} and {names[1]}.'
)
else:
joined_names = ','.join(names[:-1]) + f', and {names[-1]}'
msg = f'Cannot map multiple arguments the same identifiers {joined_names}.'
super().__init__(msg)
self._names = names
@property
def names(
self
) -> Tuple[str, ...]:
"""A tuple of the argument names that spawned this error."""
return self._names
[docs]class InvalidArgumentNameError(BaseArgumentError):
"""An exception type for attempting to register invalid argument names."""
[docs]class MissingArgumentsError(BaseArgumentError):
"""An exception type for missing arguments."""
def __init__(
self,
*missing_args: str
) -> None:
self._missing_args = missing_args
if not missing_args:
msg = 'Missing required argument(s).'
elif len(missing_args) == 1:
msg = f'Missing required argument {missing_args[0]}.'
elif len(missing_args) == 2:
msg = f'Missing required arguments {missing_args[0]} and {missing_args[1]}.'
else:
joined_names = ','.join(missing_args[:-1]) + f', and {missing_args[-1]}'
msg = f'Missing required arguments {joined_names}.'
super().__init__(msg)
@property
def missing_args(
self
) -> Tuple[str, ...]:
"""The arguments that were missing."""
return self._missing_args
[docs]class NoSuchArgumentError(BaseArgumentError, AlmanacKeyError):
"""An exception type for resolutions of non-existent arguments."""
def __init__(
self,
*names: str
) -> None:
if not names:
msg = 'No such argument with specified name.'
elif len(names) == 1:
msg = f'No such argument with name {names[0]}.'
elif len(names) == 2:
msg = f'No arguments exist with the name {names[0]} or {names[1]}.'
else:
joined_names = ','.join(names[:-1]) + f', or {names[-1]}'
msg = f'No arguments exist with the name {joined_names}.'
super().__init__(msg)
self._names = names
@property
def names(
self
) -> Tuple[str, ...]:
"""A tuple of the argument names that triggered this error."""
return self._names
[docs]class TooManyPositionalArgumentsError(BaseArgumentError):
"""An exception type for when too many positional arguments are specified."""
def __init__(
self,
*values: Any
) -> None:
if not values:
raise ValueError('Must have at least one positional argument value')
super().__init__(f'{len(values)} too many positional arguments.')
self._values = values
@property
def values(
self
) -> Tuple[Any, ...]:
"""A tuple of the excess positional argument values."""
return self._values
[docs]class UnknownArgumentBindingError(BaseArgumentError):
"""An exception type for unknown issues in argument-binding."""
def __init__(
self,
signature: inspect.Signature,
pos_args: Iterable[Any],
kw_args: Dict[str, Any]
) -> None:
super().__init__('Unknown argument-binding error.')
self._signature = signature
self._pos_args = tuple(pos_args)
self._kw_args = kw_args
@property
def signature(
self
) -> inspect.Signature:
"""The signature that could not be bound to."""
return self._signature
@property
def pos_args(
self
) -> Tuple[Any, ...]:
"""The pos_args that could not be bound to the signature."""
return self._pos_args
@property
def kw_args(
self
) -> Dict[str, Any]:
"""The kw_args that could not be bound to the signature."""
return self._kw_args