mesa / mesa/mesa-frames

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

Open
#149 2 comments 0 reactions 0 assignees View on GitHub
feature
Dominant language
Python
Stars
42
Forks
18
Avg merge
1m
Merged PRs (30d)
1

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

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

```python
# 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."""

```

```python
# 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`](https://github.com/projectmesa/mesa-frames/blob/main/mesa_frames/abstract/agents.py)
- **Concrete**: [`mesa_frames/concrete/agentset.py`](https://github.com/projectmesa/mesa-frames/blob/main/mesa_frames/concrete/agentset.py)

Contributor guide

Open the contributing guide

Research direction

Start by reading mesa_frames/abstract/agents.py and mesa_frames/concrete/agentset.py, then review the proposed mesa_frames.utils.interface_meta entry point and Beartype's is_subhint behavior. The work is done when ABCs use the new metaclass and incompatible concrete type hints raise TypeError at class-definition time with a clear error message.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.