Skip to content

CharmType TypeVar used by _CharmSpec should probably be covariant #2242

@james-garner-canonical

Description

@james-garner-canonical

The CharmType type variable used in the _CharmSpec generic is invariant (the default). The variable is defined here. It's probably intended to be covariant, at least as far as _CharmSpec is concerned. That is, anywhere a _CharmSpec[ops.CharmBase] is required, the more specific _CharmSpec[MyCharmBaseSubClass] should be fine.

Invariance is problematic in cases like this one in #2230, which looks like this:

def f(c: _CharmSpec[ops.CharmBase]):
    ...

charm_spec = _CharmSpec(MyCharmClass, ...)   # typed as _CharmSpec[MyCharmClass]
f(charm_spec)  # error because f needs exactly a _CharmSpec[ops.CharmBase]

It seems pretty clear that _CharmSpec[Specific] should be fine where _CharmSpec[Base] is declared since _CharmSpec is essentially an immutable container here (it's a frozen dataclass). I believe that moving from invariant to covariant here would be backwards compatible. However, we need to check all the uses of the existing TypeVar, or make a new one for this, in case there are any uses that should be invariant (or contravariant).

Metadata

Metadata

Assignees

No one assigned

    Labels

    26.04An item we hope to do in the 26.04 cyclerainy daySmall items done in ~10% of each week's timetestsRelated to tests or testing

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions