Open
Description
🤔 Problem Description
After merging PR #143, we will have Beartype on every method, but nothing automatically verifies that each concrete class still honors the abstract class’s type hints.
A small drift—e.g. changing an add(...)
signature—can silently break downstream code or introduce subtle variance bugs that only fail at runtime.
💡 Proposed Solution
- Add a new metaclass (e.g.
InterfaceMeta
) in a util module (saymesa_frames.utils.interface_meta
) that, in its__init__
, walks everyABC
base and uses Beartype’sis_subhint
to compare each abstract method’s type hints against the override in the subclass—raising aTypeError
at class‐definition time on mismatch. - Switch our ABCs (like
AgentContainer
) to usemetaclass=InterfaceMeta
instead of plainABCMeta
. Any drop-in mismatch inAgentSetPolars
(or any other subclass) will now fail immediately when Python imports the module, giving a clear error message.
Example in mesa-frames
# mesa_frames/abstract/agents.py
from abc import abstractmethod
from typing import get_type_hints
from typing_extensions import Self
from mesa_frames.types_ import DataFrameInput
from collections.abc import Collection
…
class AgentSetDF(AgentContainer, DataFrameMixin):
@abstractmethod
def add(
self,
agents: DataFrameInput,
inplace: bool = True,
) -> Self:
"""Add agents to the container."""
…
# mesa_frames/concrete/agentset.py
import polars as pl
from typing import Sequence, Any
from mesa_frames.abstract.agents import AgentSetDF
from mesa_frames.utils.interface_meta import InterfaceMeta
class AgentSetPolars(AgentSetDF, PolarsMixin, metaclass=InterfaceMeta):
def add(
self,
agents: pl.DataFrame | Sequence[Any] | dict[str, Any],
inplace: bool = True,
) -> Self:
"""Polars-backed add implementation."""
…
Here, the metaclass check would ensure that the concrete add
’s agents:
hint (pl.DataFrame | Sequence[Any] | dict[str,Any]
) is a valid superhint of the abstract DataFrameInput
alias (dict[str, Any] | Sequence[Sequence] | pl.DataFrame
), and would error out at class‐definition time if someone ever drifted one side out of alignment.
🔄 Alternatives Considered
- Decorator (opt-in per class), but easy to forget.
- CI test to compare signatures, but that only catches errors later in testing.
➕ Additional Context
- Abstract:
mesa_frames/abstract/agents.py
- Concrete:
mesa_frames/concrete/agentset.py