OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

How do I safely type a function that accpets a Generic container class, in python?

  • Thread starter Thread starter takeshi2010
  • Start date Start date
T

takeshi2010

Guest
Code:
from __future__ import annotations

from datetime import datetime, UTC
from typing import Any, Generic, Self, TypeVar

from pydantic import AwareDatetime, BaseModel


EventDataT_co = TypeVar('EventDataT_co', covariant=True)


class Event(BaseModel, Generic[EventDataT_co]):
    raised_at: AwareDatetime
    data: tuple[EventDataT_co, ...]

    @classmethod
    def from_data(cls, *data: EventDataT_co) -> Self:  
        return cls(raised_at=datetime.now(UTC), data=data)


def save_events(*events: Event): ...  # not type-safe (someone might make unsafe assumption on `.data`)
def save_events(*events: Event[Any]): ...  # same
def save_events(*events: Event[object]): ...  # Only allowed if Event is covariant, but then I can't have a custom constructor
def save_events(*events: Event[EventDataT_co]): ...  # It implies this is a generic function, when it's more `.data`-agnostic

Mypy throws error: Cannot use a covariant type variable as a parameter [misc] on the def from_data(...) constructor line.

I have no idea how to solve this. I'll admit, I'm new to the concept of variance, and it's not clear to me whether I'm doing something wrong (is Event even covariant to begin with) or if mypy is not allowing something it should. I'm trying to avoid using Any here, because save_events is actually a method of a different class that might be subclassed, and I wouldn't want the dev that inherits from it to get bitten by my use of Any. Event[object] seems like the safest, but it requires covariance. Not only does that mean no custom constructor (I think), it also means actual covariance and I'm not sure my event class is covariant outside of this specific usage with object (i.e.: I don't see a use case where a function handle_foo_created(event: Event[FooParent]) should ever accept Event[FooChild], nor do I think event: FooParentEvent = FooParentEvent.from_data(FooChild()) is a use-case I want to support, but it's possible I'm wrong there too).
<pre class="lang-py prettyprint-override"><code>from __future__ import annotations

from datetime import datetime, UTC
from typing import Any, Generic, Self, TypeVar

from pydantic import AwareDatetime, BaseModel


EventDataT_co = TypeVar('EventDataT_co', covariant=True)


class Event(BaseModel, Generic[EventDataT_co]):
raised_at: AwareDatetime
data: tuple[EventDataT_co, ...]

@classmethod
def from_data(cls, *data: EventDataT_co) -> Self:
return cls(raised_at=datetime.now(UTC), data=data)


def save_events(*events: Event): ... # not type-safe (someone might make unsafe assumption on `.data`)
def save_events(*events: Event[Any]): ... # same
def save_events(*events: Event[object]): ... # Only allowed if Event is covariant, but then I can't have a custom constructor
def save_events(*events: Event[EventDataT_co]): ... # It implies this is a generic function, when it's more `.data`-agnostic
</code></pre>
<p>Mypy throws <code>error: Cannot use a covariant type variable as a parameter [misc]</code> on the <code>def from_data(...)</code> constructor line.</p>
<p>I have no idea how to solve this. I'll admit, I'm new to the concept of variance, and it's not clear to me whether I'm doing something wrong (is <code>Event</code> even covariant to begin with) or if <code>mypy</code> is not allowing something it should. I'm trying to avoid using <code>Any</code> here, because <code>save_events</code> is actually a method of a different class that might be subclassed, and I wouldn't want the dev that inherits from it to get bitten by my use of <code>Any</code>. <code>Event[object]</code> seems like the safest, but it requires covariance. Not only does that mean no custom constructor (<a href="https://github.com/python/mypy/issues/6178" rel="nofollow noreferrer">I think</a>), it also means actual covariance and I'm not sure my event class is covariant outside of this specific usage with <code>object</code> (i.e.: I don't see a use case where a function <code>handle_foo_created(event: Event[FooParent])</code> should ever accept <code>Event[FooChild]</code>, nor do I think <code>event: FooParentEvent = FooParentEvent.from_data(FooChild())</code> is a use-case I want to support, but it's possible I'm wrong there too).</p>
 

Latest posts

B
Replies
0
Views
1
Blundering Ecologist
B
Top