How do I test whether two structural types are subtypes of each other?

30 Views Asked by At

I have two Protocols in different modules.

class TooComplexProtocolInNeedOfRefactoring(Protocol):
    @property
    def useful(self) -> int:
        ...
    @property
    def irrelevant1(self) -> int:
        ...
    @property
    def irrelevant2(self) -> int:
        ...
    @property
    def irrelevant3(self) -> int:
        ...

and

class SpecificSubProtocol(Protocol):
    @property
    def useful(self) -> int:
        ...

I want to check that all classes that implement TooComplexProtocolInNeedOfRefactoring can be used for SpecificSubProtocol, so the former is a subtype of the latter.

All the tricks for checking structural subtypes I have found need instantiation or at least concrete classes, like

test_subtype: Type[SpecificSubProtocol] = TooComplexProtocolInNeedOfRefactoring

(“Can only assign concrete classes to a variable of type "type[SpecificSubProtocol]"”)

How can I test whether two protocols are structural subtypes of each other?

1

There are 1 best solutions below

0
InSync On

You don't actually have to instantiate the protocol (at runtime or not). Just declare a type-checking-only variable whose type is that protocol:

(playground links: Mypy, Pyright)

from typing import TYPE_CHECKING

if TYPE_CHECKING:
  # For Mypy, which is probably what you are using
  instance: TooComplexProtocolInNeedOfRefactoring
  # For Pyright
  instance: TooComplexProtocolInNeedOfRefactoring = ...  # type: ignore

  test_subtype: SpecificSubProtocol = instance  # this is fine

If the protocols didn't match (try removing one of the useful() methods) you would get a "Incompatible types in assignment" error or similar.