Skip to content

Bug in generic typing for SolutionArray #2051

@TimothyEDawson

Description

@TimothyEDawson

Problem description

For context, some passthrough methods on SolutionArray are only available for specific phases. The way I devised to constrain this was to make SolutionArray generic in the underlying phase object type, and then restrict those methods to only be valid when the type of self matches the specific phase type. For example:

@property
def net_production_rates(self: SolutionArray[Kinetics]) -> Array: ...

However, this doesn't seem to properly match against subclasses as I expected:

Image

This error was picked up by my type checkers, as well.

Behavior

My expectation was that the type SolutionArray[Solution] would match against self: SolutionArray[Kinetics] as Solution is a subclass of Kinetics. I thought this worked as expected during my testing while implementing it (see this comment), although it's possible I only tested the negative case (SolutionArray[Solution] does not match against SolutionArray[Interface]) and not the positive case.

System information

  • Cantera version: 3.2.0
  • OS: RHEL 9
  • Python/MATLAB/other software versions: Python 3.13, mypy 1.18.2, basedpyright 1.33.0, pyright 1.1.407

Additional context

I believe the mistake is that, by default, generics are invariant. The fix may thus be as simple as changing

# Generic representing a valid "phase" input
_P = TypeVar("_P", bound=_SolutionBase)

to

# Generic representing a valid "phase" input
_P = TypeVar("_P", bound=_SolutionBase, covariant=True)

in composite.pyi, but I haven't tested this yet.

See: https://typing.python.org/en/latest/reference/generics.html#variance-of-generic-types

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions