Source code for modelly.core.exceptions
"""Modelly-specific exception hierarchy."""
[docs]
class ModellyException(Exception): # noqa: N818
"""Base class for all Modelly-specific exceptions."""
[docs]
class SpaceException(ModellyException):
"""Base exception for errors in the discrete_space module."""
[docs]
def agent_label(agent) -> str:
"""``Sheep 12``: the agent's class and unique_id, as a modeller names it."""
return f"{type(agent).__name__} {getattr(agent, 'unique_id', None)}"
[docs]
def model_time(agent) -> str:
"""`` at time 3.0``, or an empty string when the agent has no model."""
time = getattr(getattr(agent, "model", None), "time", None)
return "" if time is None else f" at time {time}"
[docs]
class CellFullException(SpaceException):
"""Raised when attempting to add an agent to a cell with no available capacity."""
def __init__(self, coordinate, agent=None):
"""Initialize the exception.
Args:
coordinate: The coordinate tuple of the full cell.
agent: The agent moved there, named in the message when given.
"""
self.coordinate = coordinate
self.agent = agent
if agent is None:
super().__init__(f"Cell at coordinate {coordinate} is full.")
return
super().__init__(
f"Cannot move {agent_label(agent)} to the cell at {coordinate}"
f"{model_time(agent)}: the cell is full."
)
[docs]
class AgentMissingException(ModellyException):
"""Raised when attempting to remove an agent that is not in the cell."""
def __init__(self, agent, coordinate):
"""Initialize the exception.
Args:
agent: The agent instance that was expected.
coordinate: The coordinate tuple of the cell.
"""
self.agent = agent
self.coordinate = coordinate
super().__init__(
f"{agent_label(agent)} is not in the cell at {coordinate}{model_time(agent)}."
)
[docs]
class AgentRemovedError(ModellyException, AttributeError):
"""Raised when ``remove()`` is called on an agent that has left its space.
An ``AttributeError``: the type these calls raised before the message named the agent.
"""
def __init__(self, agent, reason: str = "it was already removed"):
"""Initialize the exception.
Args:
agent: The agent ``remove()`` was called on.
reason: Why there is nothing to remove.
"""
self.agent = agent
super().__init__(
f"Cannot remove {agent_label(agent)}{model_time(agent)}: {reason}."
)
[docs]
class ColumnMissingError(ModellyException, AttributeError):
"""Raised when a Column attribute is used on an agent that has no row.
The agent was removed from its model (its row went with it), or its ``__init__``
never called ``super().__init__(model)``. An ``AttributeError``, as before.
"""
def __init__(self, agent, column: str):
"""Initialize the exception.
Args:
agent: The agent whose column was read or written.
column: The name of the Column attribute.
"""
self.agent = agent
self.column = column
if hasattr(agent, "model"):
reason = "it was removed from the model, and its row with it"
else:
reason = "it was never added to a model: call super().__init__(model) first"
super().__init__(
f"{agent_label(agent)} has no {column!r} value{model_time(agent)}: {reason}."
)
[docs]
class CellMissingException(SpaceException):
"""Raised when attempting to access or remove a cell that does not exist."""
def __init__(self, coordinate):
"""Initialize the exception.
Args:
coordinate: The coordinate tuple of the missing cell.
"""
self.coordinate = coordinate
super().__init__(f"Cell at coordinate {coordinate} does not exist.")
[docs]
class ConnectionMissingException(SpaceException):
"""Raised when attempting to disconnect a cell that is not connected."""
def __init__(self, cell, other):
"""Initialize the exception.
Args:
cell: The source cell instance.
other: The target cell instance that was not connected.
"""
self.cell = cell
self.other = other
super().__init__(
f"Connection between {cell.coordinate} and {other.coordinate} does not exist."
)
[docs]
class TableMissingException(ModellyException, ValueError): # noqa: N818
"""Raised when attempting to access a table that does not exist in the DataCollector."""
def __init__(self, table_name):
"""Initialize the exception.
Args:
table_name: The name of the missing table.
"""
self.table_name = table_name
super().__init__(f"Table '{table_name}' does not exist.")
[docs]
class DimensionException(ModellyException, ValueError): # noqa: N818
"""Raised when spatial dimensions do not match expectations or are invalid."""
def __init__(self, message):
"""Initialize the exception.
Args:
message: The error message describing the dimension mismatch.
"""
super().__init__(message)
[docs]
class CheckpointError(ModellyException):
"""Raised when a model cannot be saved to, or loaded from, a checkpoint."""