This is perfectly fine Python. It outputs
Opening...
Opening...
1337
Closing...
when run, but Mypy complains...
example.py:29: error: Incompatible default for argument "cls" (default has type "Type[Concrete]", argument has type "SupportsOpenClose")
For posterity's sake the answer is that the structure in structural subtyping is important. The initial example doesn't work because the signature of
open
is indeed different from the protocol's definition. The error message from Mypy could be a little less confusing, but it's not wrong. 😅So, in the end, we can write even simpler code and something like
works just fine. The key (no pun intended) is to force the
Concrete.open
signature to match the protocol signature exactly and usekwargs
as a dictionary for communicating keyword arguments. There's an added benefit here thatcls: Callable[[], SupportsOpenClose]
leaves thefn
function even more open for extension. Any callable that resolves to a type that implements theSupportsOpenClose
protocol will satisfy the signature, so it doesn't necessarily need to be aclass
.Many thanks to @RadicalZephyr for helping me puzzle through this.