mypy-zope
mypy-zope copied to clipboard
A way to express "A type which implements these N interfaces"
Let's say I have two interfaces IA
and IB
. They're completely independent of each other. I implement both in some type C
.
from zope.interface import Interface, implementer
class IA(Interface):
def do_a(): ...
class IB(Interface):
def do_b(): ...
@implementer(IA, IB)
class C:
def do_a(): ...
def do_b(): ...
I can assign a C
instance to a variable marked against either interface.
a: IA = C # ok
b: IB = C # ok
I can also pass a C
instance to a function requiring either interface.
def needs_IA(a: IA): ...
def needs_IB(b: IB): ...
needs_IA(c) # ok
needs_IB(c) # ok
Suppose I have another function which requires both interfaces.
def needs_IA_and_IB(arg): ...
needs_IA_and_IB(c) # want this to be checked as ok
needs_IA_and_IB(object()) # want this to be checked as not okay
If I know that I'm only going to use C
s, I can mark arg: C
and call it a day.
But this doesn't work if I have a second type D
that implements both interfaces.
@implementer(IA, IB)
class D:
def do_a(): ...
def do_b(): ...
d = D()
needs_IA_and_IB(d) # want this to also be okay
How should I annotate arg
? What I'd like is a way to describe "a type that implements each of these interfaces". Is there a way to do this at present? There's no notion of an intersection type; maybe there'd need to be a new Type spelt Implements[IA, IB, ...]
for this purpose?
Example
To give a concrete example: Twisted's HostnameEndpoint.__init__
expects a reactor
argument which should be
provider of
IReactorTCP
,IReactorTime
and eitherIReactorPluggableNameResolver
orIReactorPluggableResolver
.
I don't think that can be currently expressed in the type system. I'd want to spell it as something like
Implements[
IReactorTCP,
IReactorTime,
Union[IReactorPluggableNameResolver, IReactorPluggableResolver]
]
The inner Union
might make things harder; even being able to express one of the two choices like
Implements[IReactorTCP, IReactorTime, IReactorPluggableNameResolver]
would be helpful!
I don't know if this is something in the remit of mypy-zope as opposed to the zope project itself. I'm hopingthis is a good to ask fo suggestions or feedback though!