Skip to content

[Feature]: Enforce Abstract↔Concrete type-hint coherence via a metaclass #149

@adamamer20

Description

@adamamer20

🤔 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

  1. Add a new metaclass (e.g. InterfaceMeta) in a util module (say mesa_frames.utils.interface_meta) that, in its __init__, walks every ABC base and uses Beartype’s is_subhint to compare each abstract method’s type hints against the override in the subclass—raising a TypeError at class‐definition time on mismatch.
  2. Switch our ABCs (like AgentContainer) to use metaclass=InterfaceMeta instead of plain ABCMeta. Any drop-in mismatch in AgentSetPolars (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 Collectionclass 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew functionality added to the project.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions