I am working on making stubs for an external ORM library, I have encountered an issue that I am not sure how to overcome though. So the example bellow technically passes the mypy check, but only after expecting the library user to tediously repeat themselves during class declaration.
# Library stubs:
from typing import Generic, TypeVar, Type, Any, Optional
from collections.abc import Collection, Sequence
from abc import ABC
T = TypeVar('T', bound='BaseItem')
K = TypeVar('K')
class ItemSet(Generic[K]):
def get_or_none(self, **kwargs: Any) -> Optional[K]: ...
def first(self) -> K: ...
def all(self) -> Collection[K]: ...
def order_by(self, *args: Any) -> Sequence[K]: ...
class BaseItem(ABC, Generic[T]):
@classmethod
def set(cls: Type[T]) -> ItemSet[T]: ...
# User's model:
from library import BaseItem
class FooItem(BaseItem['FooItem']):
name: str
class BarItem(BaseItem['BarItem']):
size: float
class BazItem(BaseItem['BazItem']):
id_: int
reveal_type(FooItem.set())
reveal_type(FooItem.set().all())
This generates this output:
main.py:32: note: Revealed type is "__main__.ItemSet[__main__.FooItem*]"
main.py:33: note: Revealed type is "typing.Collection[__main__.FooItem*]"
Which is exactly what you would expect, however this only works because the user had to pass the class name as a type on every class definition. The omission of type leads to it having the Any
type
class FooItem(BaseItem):
name: str
main.py:32: note: Revealed type is "__main__.ItemSet[Any]"
main.py:33: note: Revealed type is "typing.Collection[Any]"
So my question is how to make so this type inference is invisible to the user?