66from .compat import raise_from , with_metaclass
77from .default import default , warn_if_defaults_use_non_interface_members
88from .formatting import bulleted_list
9- from .functional import complement , keyfilter , valfilter
9+ from .functional import complement , keyfilter , merge , valfilter
1010from .typecheck import compatible
1111from .typed_signature import TypedSignature
1212from .utils import is_a , unique
@@ -21,8 +21,22 @@ class InvalidImplementation(TypeError):
2121 """
2222
2323
24+ class InvalidSubInterface (TypeError ):
25+ """
26+ Raised when on attempt to define a subclass of an interface that's not
27+ compatible with the parent definition.
28+ """
29+
30+
2431CLASS_ATTRIBUTE_WHITELIST = frozenset (
25- ["__doc__" , "__module__" , "__name__" , "__qualname__" , "__weakref__" ]
32+ [
33+ "__doc__" ,
34+ "__module__" ,
35+ "__name__" ,
36+ "__qualname__" ,
37+ "__weakref__" ,
38+ "_INTERFACE_IGNORE_MEMBERS" ,
39+ ]
2640)
2741
2842is_interface_field_name = complement (CLASS_ATTRIBUTE_WHITELIST .__contains__ )
@@ -72,6 +86,14 @@ def _conflicting_defaults(typename, conflicts):
7286 return InvalidImplementation (message )
7387
7488
89+ def _merge_parent_signatures (bases ):
90+ return merge (filter (None , (getattr (b , "_signatures" ) for b in bases )))
91+
92+
93+ def _merge_parent_defaults (bases ):
94+ return merge (filter (None , (getattr (b , "_defaults" ) for b in bases )))
95+
96+
7597class InterfaceMeta (type ):
7698 """
7799 Metaclass for interfaces.
@@ -80,22 +102,43 @@ class InterfaceMeta(type):
80102 """
81103
82104 def __new__ (mcls , name , bases , clsdict ):
83- signatures = {}
84- defaults = {}
85- for k , v in keyfilter (is_interface_field_name , clsdict ).items ():
105+ signatures = _merge_parent_signatures (bases )
106+ defaults = _merge_parent_defaults (bases )
107+ ignored = clsdict .get ("_INTERFACE_IGNORE_MEMBERS" , set ())
108+
109+ for field , v in keyfilter (is_interface_field_name , clsdict ).items ():
110+ if field in ignored :
111+ continue
112+
86113 try :
87- signatures [ k ] = TypedSignature (v )
114+ signature = TypedSignature (v )
88115 except TypeError as e :
89116 errmsg = (
90117 "Couldn't parse signature for field "
91118 "{iface_name}.{fieldname} of type {attrtype}." .format (
92- iface_name = name , fieldname = k , attrtype = getname (type (v )),
119+ iface_name = name , fieldname = field , attrtype = getname (type (v )),
93120 )
94121 )
95122 raise_from (TypeError (errmsg ), e )
96123
124+ # If we already have a signature for this field from a parent, then
125+ # our new signature must be a subtype of the parent signature, so
126+ # that any valid call to the new signature must also be a valid
127+ # call to the parent signature.
128+ if field in signatures and not compatible (signature , signatures [field ]):
129+ conflicted = signatures [field ]
130+ raise InvalidSubInterface (
131+ "\n Interface field {new}.{field} conflicts with inherited field of "
132+ "the same name.\n "
133+ " - {field}{new_sig} != {field}{old_sig}" .format (
134+ new = name , field = field , new_sig = signature , old_sig = conflicted ,
135+ )
136+ )
137+ else :
138+ signatures [field ] = signature
139+
97140 if isinstance (v , default ):
98- defaults [k ] = v
141+ defaults [field ] = v
99142
100143 warn_if_defaults_use_non_interface_members (
101144 name , defaults , set (signatures .keys ())
@@ -139,7 +182,7 @@ def _diff_signatures(self, type_):
139182 if not issubclass (impl_sig .type , iface_sig .type ):
140183 mistyped [name ] = impl_sig .type
141184
142- if not compatible (impl_sig . signature , iface_sig . signature ):
185+ if not compatible (impl_sig , iface_sig ):
143186 mismatched [name ] = impl_sig
144187
145188 return missing , mistyped , mismatched
@@ -258,6 +301,9 @@ def _format_mismatched_methods(self, mismatched):
258301 )
259302
260303
304+ empty_set = frozenset ([])
305+
306+
261307class Interface (with_metaclass (InterfaceMeta )):
262308 """
263309 Base class for interface definitions.
@@ -313,6 +359,10 @@ def delete(self, key):
313359 :func:`implements`
314360 """
315361
362+ # Don't consider these members part of the interface definition for
363+ # children of `Interface`.
364+ _INTERFACE_IGNORE_MEMBERS = {"__new__" , "from_class" }
365+
316366 def __new__ (cls , * args , ** kwargs ):
317367 raise TypeError ("Can't instantiate interface %s" % getname (cls ))
318368
@@ -349,7 +399,10 @@ def from_class(cls, existing_class, subset=None, name=None):
349399 )
350400
351401
352- empty_set = frozenset ([])
402+ # Signature requirements are inherited, so make sure the base interface doesn't
403+ # require any methods of children.
404+ assert Interface ._signatures == {}
405+ assert Interface ._defaults == {}
353406
354407
355408class ImplementsMeta (type ):
0 commit comments