Generic Mapper in python

Hi,

Goal

I’d like to create a generic mapper in Python that enforces type relationships between keys and values in a dictionary. I’m looking for a way to enforce these key-value type relationships in Python, similar to how generics work in TypeScript. Would this be possible with Python’s typing system?

Example: Nullable Dictionary

For instance, I want to define a NullableDict where:

  • If the key is of type T,
  • Then the value must be either T or None.
from typing import TypeVar 
T = TypeVar("T") 
NullableDict = dict[T, T | None]  # Key: T → Value: T or None

This ensures that if a key is a str, its value can only be a str or None.


Real-World Use Case: SQLAlchemy Updates

A practical example is in SQLAlchemy, where we want to prevent incorrect column updates using the toolkit (not ORM).

Problem

Currently, this doesn’t raise a type error during type check, but it’s logically wrong:

sa.update(User).values({User.created_at: True}) # created_at is datetime, but we pass a bool!

Desired Solution

If we could define a dictionary with generic constraints:

dict[InstrumentedAttribute[T], T]

* The key is `InstrumentedAttribute[datetime]` (e.g., `User.created_at`).
* The value **must** be `datetime` (not `bool` or other types).

This would help catch type mismatches at type check time (with a type checker like mypy).

dict[IntstrumentedAttribute[T], T], though, would only allow a dict with date-related keys that map to datetime values. It’s not enough to specify the full kind of “column type determines value type” that you seem to want. For example, TypedDict kind of does what you want, but restricts the key types to specific literal strings, rather than arbitrary types.

1 Like

As you mentioned, key would be literal and their type would not be generic or as you said “column type determines value type”

I don’t think this would actually even does what you said, it doesn’t do anything. it’s wrong, this thread is suggesting the idea of having generic on mapper.

I could even implement something very basic, that kinda does what i want to do, but would be nicer to have this on python. Other languages already support this, like typescript and java if i’m not wrong.

from typing import TypeVar

from sqlalchemy.orm import InstrumentedAttribute

T = TypeVar("T")


class GenericMapper:
    def __init__(self):
        self._data = {}

    def __get__(self, item: InstrumentedAttribute[T]):
        return self._data[item]

    def __set__[T](self, item: InstrumentedAttribute[T], value: T):
        self._data[item] = value
        return self

I don’t know about TypeScript, but Java doesn’t really have that. java.util.Map::values is a collection, so U can’t require specific value to be of different type. Also, java.util.HashMap doesn’t accept a hasher, but it is using polymorphic call, so the key type is (relatively) invariant.

Regardless, I have never seen it in any language. It seems like a special case, not fit for std lib.

from typing import TypeVar, Any, Protocol
from collections.abc import MutableMapping

_V = TypeVar("_V")
class GenericKey(Protocol[_V]):
    V: type[_V]

class GenericKeyMapping(MutableMapping[
    GenericKey[Any], Any #Not generic.
]):
    def __init__(self):
        self._raw = {}

    def __getitem__(self, key: GenericKey[_V]) -> _V:
        return self._raw[key]

    def __setitem__(self, key: GenericKey[_V], value: _V):
        self._raw[key] = value

    def __delitem__(self, key: GenericKey[Any]):
        del self._raw[key]

    def __len__(self):
        return len(self._raw)

    def __iter__(self):
        return iter(self._raw)

To make it generic, I can see only 1 solution: make TypeVar (bound by subscript-able type) subscript-able.