Package: pure-interface
pure_interfaceA Python interface library that disallows function body content on interfaces and supports adaption.Jump to theReference.FeaturesPrevents code in method bodies of an interface classEnsures that method overrides have compatible signaturesSupports interface adaption.Supports optional structural type checking.Allows concrete implementations the flexibility to implement abstract properties as instance attributes.Interface.adapt()can return an implementation wrapper that providesonlythe
attributes and methods defined byInterface.Supports python 3.8+A note on the nameThe phrasepure interfaceapplies only to the first design goal - a class that defines only an interface with no
implementation is a pure interface[*].
In every other respect the zen of ‘practicality beats purity’ applies.InstallationYou can install released versions ofpure_interfaceusing pip:pip install pure-interfaceor you can grab the source code fromGitHub.Defining an InterfaceFor simplicity in these examples we assume that the entirepure_interfacenamespace has been importedfrom pure_interface import *To define an interface, simply inherit from the classInterfaceand write aPEP-544Protocol-like class
leaving all method bodies empty:class IAnimal(Interface):
    height: float

    def speak(self):
        passLike Protocols, class annotations are considered part of the interface.
For historical reasons, you can also use the following alternate syntax:class IAnimal(Interface):
    height = None

    def speak(self):
        passThe value assigned to class attributesmustbeNoneand the attribute is removed from the class dictionary
(since annotations are not in the class dictionary).Interfaceis a subtype ofabc.ABCand theabstractmethod,abstractclassmethodandabstractstaticmethoddecorators work as expected.
ABC-style property definitions are also supported (and equivalent):class IAnimal(Interface):
    @property
    @abstractmethod
    def height(self):
        pass

    @abstractmethod
    def speak(self):
        passAgain, the height property is removed from the class dictionary, but, as with the other syntaxes,
all concrete subclasses will be required to have aheightattribute.Note that theabstractmethoddecorator is optional asALLmethods and properties on aInterfacesubclass are abstract.
All the examples above are equivalent, bothheightandspeakare considered abstract and must be overridden by subclasses.Includingabstractmethoddecorators in your code can be useful for reminding yourself (and telling your IDE) that you need
to override those methods.  Another common way of informing an IDE that a method needs to be overridden is for
the method to raiseNotImplementedError.  For this reason methods that justraise NotImplementedErrorare also
considered empty.Interface classes cannot be instantiatedIAnimal()
InterfaceError: Interfaces cannot be instantiated.Including code in a method will result in anInterfaceErrorbeing raised when the module is imported. For example:class BadInterface(Interface):
    def method(self):
        print('hello')

InterfaceError: Function "method" is not emptyMixingInterfacewith non-interface types in a bases list will raise anInterfaceErrorat module load time.
There are two exceptions to this rule.typing.Genericis permitted as well as emptyabc.ABCclasses
that only defines abstract methods
and properties that satisfy the empty method criteria will result in a type that is considered a pure interface.:class ABCInterface(abc.ABC):
    @abstractmethod
    def foo(self):
        pass

class MyInterface(ABCInterface, Interface):
    def bar(self):
        passThedir()function will include all interface attributes so thatmock.Mock(spec=IAnimal)will work as expected:>>> dir(IAnimal)
['__abstractmethods__', '__doc__', ..., 'height', 'speak']Themock_protocolpackage also works well with interfaces.Sub-InterfacesLikeProtocol, to specify a sub-interface you must specify theInterfaceclass again in the base class list.
Only classes that inheritdirectlyfromInterfacewill be considered an interface type.:class IWeightyAnimal(IAnimal, Interface):
    weight: floatConcrete ImplementationsLikeProtocol, simply inherit from an interface class in the normal way and write a concrete class.:class Animal(IAnimal):
    def __init__(self, height):
        self.height = height

    def speak(self):
        print('hello')Concrete implementations may implement interface attributes in any way they like: as instance attributes, properties or
custom descriptors, provided that they all exist at the end of__init__().  Here is another valid implementation:class Animal(IAnimal):
    def __init__(self, height):
        self._height = height

    @property
    def height(self):
        return self._height

    def speak(self):
        print('hello')Method SignaturesMethod overrides are checked for compatibility with the interface.
This means that argument names must match exactly and that no new non-optional
arguments are present in the override.  This enforces that calling the method
with interface parameters will aways work.
For example, given the interface method:def speak(self, volume):Then these overrides will all fail the checks and raise anInterfaceError:def speak(self):  # too few parameters
def speak(self, loudness):  # name does not match
def speak(self, volume, language):  # extra required argumentHowever new optional parameters are permitted, as are*argsand**kwargs:def speak(self, volume, language='doggy speak')
def speak(self, *args, **kwargs)Implementation WarningsAs withabc.ABC, the abstract method checking for a class is done when an object is instantiated.
However it is useful to know about missing methods sooner than that.  For this reasonpure_interfacewill issue
a warning during module import when methods are missing from a concrete subclass.  For example:class SilentAnimal(IAnimal):
    def __init__(self, height):
        self.height = heightwill issue this warning:readme.py:28: UserWarning: Incomplete Implementation: SilentAnimal does not implement speak
class SilentAnimal(IAnimal):Trying to create aSilentAnimalwill fail in the standard abc way:SilentAnimal()
InterfaceError: Can't instantiate abstract class SilentAnimal with abstract methods speakIf you have a mixin class that implements part of an interface you can suppress the warnings by adding an class attribute
calledpi_partial_implementation.  The value of the attribute is ignored, and the attribute itself is removed from
the class.  For example:class HeightMixin(IAnimal):
    pi_partial_implementation = True

    def __init__(self, height):
        self.height = heightwill not issue any warnings.The warning messages are also stored irrespective of any warning module filters (but only ifget_is_development() returns True).
The existence of warnings can be tested with waringing messages can be fetched usingget_missing_method_warningsThis provides an alternative to raising warnings as errors.
When all your imports are complete you can check if this list is empty.:if warnings := pure_iterface.get_missing_method_warnings():
    for warning in warnings:
        print(warning)
    exit(1)Note that missing properties are NOT checked for as they may be provided by instance attributes.Interface SubsetsSometimes your code only uses a small part of a large interface.  It can be useful (eg. for test mocking) to specify
the sub part of the interface that your code requires.  This can be done with thesub_interface_ofdecorator.:@sub_interface_of(IAnimal)
class IHeight(Interface):
    height: float

def my_code(h: IHeight):
    return "That's tall" if h.height > 100 else "Not so tall"Thesub_interface_ofdecorator checks that the attributes and methods of the smaller interface match the larger interface.
If the larger interface is changed and no longer matches the smaller interface thenInterfaceErroris raised during import.
Function signatures must match exactly (not just be compatible).  The decorator will also register the larger interface as
a sub-type of the smaller interface (usingabc.register) so thatisinstance(Animal(),IHeight)returnsTrue.AdaptionRegistering AdaptersAdapters for an interface are registered with theadaptsdecorator or with
theregister_adapterfunction. Take for example an interfaceISpeakerand a
classTalkerand an adapter classTalkerToSpeaker:class ISpeaker(Interface):
    def speak(self):
        pass

class Talker(object):
    def talk(self):
        return 'talk'

@adapts(Talker)
class TalkerToSpeaker(ISpeaker):
    def __init__(self, talker):
        self._talker = talker

    def speak(self):
        return self._talker.talk()Theadaptsdecorator call above is equivalent to:register_adapter(TalkerToSpeaker, Talker, ISpeaker)TheISpeakerparameter passed toregister_adapteris the first interface in the MRO of the class being decorated (TalkerToSpeaker).
If there are no interface types in the MRO of the decorated class anInterfaceErrorexception is raised.Adapter factory functions can be decorated too, in which case the interface being adapted to needs to be specified:@adapts(Talker, ISpeaker)
def talker_to_speaker(talker):
    return TalkerToSpeaker(talker)The decorated adapter (whether class for function) must be callable with a single parameter - the object to adapt.Adapting ObjectsTheInterface.adaptmethod will adapt an object to the given interface
such thatInterface.provided_byisTrueor raiseAdaptionErrorif no adapter could be found.  For example:speaker = ISpeaker.adapt(talker)
isinstance(speaker, ISpeaker)  --> TrueIf you want to getNonerather than an exception then use:speaker = ISpeaker.adapt_or_none(talker)You can filter a list of objects returning those objects that provide an interface
usingfilter_adapt(objects):list(ISpeaker.filter_adapt([None, Talker(), a_speaker, 'text']) --> [TalkerToSpeaker, a_speaker]To adapt an object only if it is notNonethen use:ISpeaker.optional_adapt(optional_talker)This is equivalent to:ISpeaker.adapt(optional_talker) if optional_talker is not None else NoneBy default the adaption functions will return an object which providesonlythe functions and properties specified by the interface.  For example given the
following implementation of theISpeakerinterface above:class TopicSpeaker(ISpeaker):
    def __init__(self, topic):
        self.topic = topic

    def speak(self):
        return 'lets talk about {}'.format(self.topic)

topic_speaker = TopicSpeaker('python')Then:speaker = ISpeaker.adapt(topic_speaker)
speaker is topic_speaker  --> False
speaker.topic --> AttributeError("ISpeaker interface has no attribute topic")This is controlled by the optionalinterface_onlyparameter toadaptwhich defaults toTrue.
Passinterface_only=Falseif you want the actual adapted object rather than a wrapper:speaker = ISpeaker.adapt(topic_speaker, interface_only=False)
speaker is topic_speaker  --> True
speaker.topic --> 'Python'Accessing thetopicattribute on anISpeakermay work for all current implementations
ofISpeaker, but this code will likely break at some inconvenient time in the future.Adapters from sub-interfaces may be used to perform adaption if necessary. For example:class IA(Interface):
   foo = None

class IB(IA, Interface):
    bar = None

@adapts(int):
class IntToB(IB):
    def __init__(self, x):
        self.foo = self.bar = xThenIA.adapt(4)will use theIntToBadapter to adapt4toIA(unless there is already an adapter
frominttoIA)Further, if an interface is decorated withsub_interface_of, adapters for the larger interface will be used if
a direct adapter is not found.Structural Type CheckingStructuraltype checking checks if an object has the attributes and methods defined by the interface.As interfaces are inherited, you can usually useisinstance(obj, MyInterface)to check if an interface is provided.
An alternative toisinstance()is theInterface.provided_by(obj)classmethod which will fall back to structural type
checking if the instance is not an actual subclass. The structural type-checking does not check function signatures.
Pure interface is stricter than aruntime_checkabledecoratedProtocolin that it differentiates between attributes and methods.:class Parrot(object):
    def __init__(self):
        self._height = 43

    @property
    def height(self):
        return self._height

    def speak(self):
        print('hello')

p = Parrot()
isinstance(p, IAnimal) --> False
IAnimal.provided_by(p) --> TrueThe structural type checking makes working with data transfer objects (DTO’s) much easier.:class IMyDataType(Interface):
    thing: str

class DTO(object):
    pass

d = DTO()
d.thing = 'hello'
IMyDataType.provided_by(d) --> True
e = DTO()
e.something_else = True
IMyDataType.provided_by(e) --> FalseAdaption also supports structural typing by passingallow_implicit=True(but this is not the default):speaker = ISpeaker.adapt(Parrot(), allow_implicit=True)
ISpeaker.provided_by(speaker)  --> TrueWhen usingadapt()withallow_implicit=True, a warning may be issued informing you that
the structurally typed object should inherit the interface.  The warning is only issued if the interface is implemented by the
class (and not by instance attributes as in the DTO case above) and the warning is only issued once for each
class, interface pair.  For example:s = ISpeaker.adapt(Parrot(), allow_implicit=True)
UserWarning: Class Parrot implements ISpeaker.
Consider inheriting ISpeaker or using ISpeaker.register(Parrot)This warning is issued becauseprovided_byfirst does an isinstance check and will be faster in this situation.Dataclass SupportInterfacescan be decorated with the standard librarydataclasses.dataclassdecorator.
This will create a dataclass that implements an interface.  For example:class IAnimal2(Interface):
    height: float
    species: str

    def speak(self):
        pass

@dataclasses.dataclass
class Animal2(IAnimal2):
    def speak(self):
        print('Hello, I am a {} metre tall {}', self.height, self.species)

a = Animal2(height=4.5, species='Giraffe')Interface Type InformationThepure_interfacemodule provides these functions for returning information about interface types.type_is_interface(cls)ReturnTrueifclsis a pure interface,Falseotherwise or ifclsis not a class.get_type_interfaces(cls)Returns all interfaces in theclsmro includingclsitself if it is an interfaceget_interface_names(cls)Returns afrozensetof names (methods and attributes) defined by the interface.
Ifinterfaceis not aInterfacesubtype then an empty set is returned.get_interface_method_names(interface)Returns afrozensetof names of methods defined by the interface.
Ifinterfaceis not aInterfacesubtype then an empty set is returnedget_interface_attribute_names(interface)Returns afrozensetof names of attributes defined by the interface.
Ifinterfaceis not aInterfacesubtype then an empty set is returnedAutomatic AdaptionThe function decoratoradapt_argsadapts arguments to a decorated function to the types given.
For example:@adapt_args(foo=IFoo, bar=IBar)
def my_func(foo, bar=None):
    passThe types can also be taken from the argument annotations.:@adapt_args
def my_func(foo: IFoo, bar: IBar | None = None):
    passThis would adapt thefooparameter toIFoo(withIFoo.optional_adapt(foo))andbartoIBar (using ``IBar.optional_adapt(bar))
before passing them to my_func.Nonevalues are never adapted, somy_func(foo, None)will work, otherwiseAdaptionErroris raised if the parameter is not adaptable.
All arguments toadapt_argsmust be specified as keyword arguments:@adapt_args(IFoo, IBar)   # NOT ALLOWED
def other_func(foo, bar):
    passDelegation and CompositionSometimes when adapting objects to an interface the adapter has to route attributes and methods to another object.
theDelegateclass assists with this task reducing boiler plate code such as:def method(self):
    return self.impl.method()TheDelegateclass provides 3 special attributes to route attributes to a child object.  Only attributes and mothods
not defined on the class (or super-classes) are routed.  (Attributes and methods defined on an interface sub-class are not
considered part of the implementation and these attributes are routed.)
Any one or combination of attributes is allowed.pi_attr_delegatespi_attr_delegatesis a dictionary mapping the attribute name of the delegate to either an interface or a list
of attribute names to delegate.
If an interface is given then the list returned byget_interface_names()is used for the attribute names to route to the delegate object.
For example suppose we want to extend an Animal with a new methodprice:class ExtendedAnimal(Delegate, IAnimal):
    pi_attr_delegates = {'a': IAnimal}

    def __init__(self, a):
        self.a

    def price(self):
        return 'lots'

a = Animal(5)
ea = ExtendedAnimal(a)

ea.height -> 5  # height is in IAnimal and routed to 'ea.a.height'
ea.speak() -> 'hello'  # speak is in IAnimal and routed to 'ea.a.speak()'
ea.price() -> 'lots'The following code is equivalent but won’t update with changes to IAnimal:class ExtendedAnimal(Delegate):
    pi_attr_delegates = {'a': ['height', 'speak']}

    def __init__(self, a):
        self.a
    ...pi_attr_mappingThe above works when the attribute names match. When they don’t, you can use thepi_attr_mappingspecial attribute.pi_attr_mappingtakes the reverse approach, the key is the attribute and the value is a dotted name of how to route
the lookup.  This provides a lot of flexibility as any number of dots are permitted.
This example is again equivalent to the first Delegate:class ExtendedAnimal(Delegate):
    pi_attr_mapping = {'height': 'a.height',
                       'talk': 'a.talk'}

    def __init__(self, a):
        self.a

    def price(self):
        return 'lots'pi_attr_fallbackpi_attr_fallback, if notNone, is treated a delegate for all attributes defined by base interfaces of the class
if there is no delegate, mapping or implementation for that attribute. Again, this is equivalent to the first Delegate.:class ExtendedAnimal(Delegate, IAnimal):
    pi_attr_fallback = 'a'

    def __init__(self, a):
        self.a

    def price(self):
        return 'lots'Note that method and attribute names for all interface classes inExtendAnimal.mro()are routed toa.
Methods and properties defined on the delegating class itself take precedence (as one would expect):class MyDelegate(Delegate, IAnimal):
    pi_attr_delegates = {'impl': IAnimal}

    def __init__(self, impl):
        self.impl = impl

    @property
    def height(self):
        return 10

    def speak(self):
        return 'I speak on behalf of the animal'

d = MyDelegate(a)
d.height -> 10  # height defined on MyDelegate
d.speak() -> 'I speak on behalf of the animal'  # speak is defined on MyDelegateHowever, attempting to set an instance attribute as an override will just set the attribute on the underlying delegate
instead.  If you want to override an interface attribute using an instance attribute, first define it as a class attribute:class MyDelegate(Delegate, IAnimal):
    pi_attr_delegates = {'impl': IAnimal}
    height = None  # prevents delegation of height to `impl`

    def __init__(self, impl):
        self.impl = impl
        self.height = 10If you supply more than one delegation rule (e.g. bothpi_attr_mappingandpi_attr_fallack) thenpi_attr_delegatesdelegation rules have priority overpi_attr_mappingdelegation rules which have priority overpi_attr_fallback.Type CompositionA special case where all delegated attributes are defined in anInterfaceis handled by thecomposed_typefactory function.composed_typetakes 2 or more interfaces and returns a new type that inherits from all the interfaces with a
constructor that takes instances that implement those interfaces (in the same order).  For exmaple:AT = composed_type(IAnimal, ITalker)

a = Animal(5)
t = Talker()
a_t = AT(a, t)

a_t.height
a_t.talk

# AT(t, a) -> ValueError - arguments in wrong order.If the same arguments are passed tocomposed_typeagain the same type is returned. For example:AT = composed_type(IAnimal, ITalker)
AT2 = composed_type(IAnimal, ITalker)

AT is AT2 -> TrueIf the interfaces share method or attribute names, then the attribute is routed to the first encountered interface.
For example:class Speaker(ISpeaker):
    def speak(self):
        return 'speaker speak'

SA = composed_type(ISpeaker, IAnimal)
s = Speaker()
a = Animal(5)

sa = SA(s, a)
sa.speak(3) -> 'speaker speak'  # from s.speakTypes created withcomposed_typeareDelegatesubclasses with aprovided_bymethod which returnsTrueif the
argument provides all the interfaces in the type (even if the argument is not aDelegatesubclasses).:AT = composed_type(IAnimal, ITalker)
TA = composed_type(ITalker, IAnimal)

a_t = AT(Animal(5), Talker())

isinstance(a_t, AT) -> True
isinstance(a_t, TA) -> False
AT.provided_by(a_t) -> True
TA.provided_by(a_t) -> True

class X(IAnimal, ITalker):
    ...

AT.provided_by(X()) -> True
TA.provided_by(X()) -> TrueMyPypure_interfacedoes some things that mypy does not understand.  For example mypy does not understand that
all methods in an interface are abstract and will complain about incorrect return types.
For this reasonpure_interfacehas a mypy plugin.  Unfortunately this plugin does not completely cover all
the capabilities ofpure_interfaceand some# type: ignorecomments will be required to get a clean mypy run.To use thepure_interfaceplugin add the following to yourmypy configurationfile.:[mypy]
plugins = pure_interface.mypy_pluginOr your pyproject.toml file:[tool.mypy]
plugins = "pure_interface.mypy_plugin"Development FlagMuch of the empty function and other checking is awesome whilst writing your code but
ultimately slows down production code.
For this reason thepure_interfacemodule has anis_developmentswitch with accessor functions.:get_is_development()
set_is_development(is_dev)is_developmentdefaults toTrueif running from source and defaults toFalseif bundled into an executable bypy2exe,cx_Freezeor similar tools.If you callset_is_developmentto change this flag it must be set before modules using theInterfacetype
are imported or else the change will not have any effect.Ifis_developmentisFalsethen:Signatures of overriding methods are not checkedNo warnings are issued by the adaption functionsNo incomplete implementation warnings are issuedThe default value ofinterface_onlyis set toFalse, so that interface wrappers are not created.ReferenceClassesInterfaceType(abc.ABCMeta)Metaclass for checking interface and implementation classes.
AddingInterfaceTypeas a meta-class to a class will not make that class an interface, you need to
inherit fromInterfaceclass to define an interface.In addition to theregistermethod provided byABCMeta, the following functions are defined onInterfaceTypeand can be accessed directly when theInterfacemethods are overridden
for other purposes.adapt(cls, obj, allow_implicit=False, interface_only=None)SeeInterface.adaptfor a description.adapt_or_none(cls, obj, allow_implicit=False, interface_only=None)SeeInterface.adapt_or_nonefor a descriptionoptional_adapt(cls, obj, allow_implicit=False, interface_only=None)SeeInterface.optional_adaptfor a descriptioncan_adapt(cls, obj, allow_implicit=False)SeeInterface.can_adaptfor a descriptionfilter_adapt(cls, objects, allow_implicit=False, interface_only=None)SeeInterface.filter_adaptfor a descriptioninterface_only(cls, implementation)SeeInterface.interface_onlyfor a descriptionprovided_by(cls, obj, allow_implicit=True)SeeInterface.provided_byfor a descriptionClasses created with a metaclass ofInterfaceTypewill have the following property:_piThis contains information about the class that is used by this meta-class.
This attribute is reserved for use bypure_interfaceand must not be overridden.InterfaceBase class for defining interfaces.  The following methods are provided:adapt(obj, allow_implicit=False, interface_only=None)Adaptsobjto this interface. Ifallow_implicitisTruepermit structural adaptions.
Ifinterface_onlyisNonethe it is set to the value ofis_development.
Ifinterface_onlyresolves toTruea wrapper object that provides
the properties and methods defined by the interface and nothing else is returned.
RaisesAdaptionErrorif no adaption is possible or a registered adapter returns an object not providing
this interface.adapt_or_none(obj, allow_implicit=False, interface_only=None)As peradapt()except returnsNoneinstead of raising aAdaptionErroroptional_adapt(obj, allow_implicit=False, interface_only=None)Adapts obj to this interface if it is notNonereturningNoneotherwise.
Short-cut foradapt(obj) if obj is not None else Nonecan_adapt(obj, allow_implicit=False)ReturnsTrueifadapt(obj, allow_implicit)will succeed.  Short-cut foradapt_or_none(obj) is not Nonefilter_adapt(objects, allow_implicit=False, interface_only=None)Generates adaptions of each item inobjectsthat provide this interface.allow_implicitandinterface_onlyare as foradapt.
Objects that cannot be adapted to this interface are silently skipped.interface_only(implementation)Returns a wrapper aroundimplementationthat provides the properties and methods defined by
the interface and nothing else.provided_by(obj)ReturnsTrueifobjprovides this interface (either by inheritance or structurally).DelegateHelper class for delegating attribute access to one or more objects.  Attribute delegation is defined by
using one or more special call attributespi_attr_delegates,pi_attr_mappingorpi_attr_fallback.pi_attr_delegatesA dictionary mapping implementation attribute to either a list of attributes to delegate to that implementation,
or anInterfacesubclass.  If anInterfacesubclass is specifed the names returned byget_interface_namesare used instead. For example:pi_attr_delegates = {'_impl': ['foo', 'bar']}creates implmentations ofobj.fooasobj._impl.fooandobj.barasobj._impl.bar.pi_attr_mappingA dictionary mapping attribute name to dotted lookup path.  Use this if the exposed attribute does not match
the attribute name on the delegatee or if multiple levels of indirection are requried.  For example:pi_attr_mapping = {'foo': '_impl.x',
                   'bar': '_impl.z.y'}creates implmentations ofobj.fooasobj._impl.xandobj.barasobj._impl.z.y.pi_attr_fallbackWhen a delegate class implements an interface (or interfaces),pi_attr_fallbackmay be used to specify the name the
implementation attribute for all attributes not otherwise defined on the class or by the methods above.  For example:class MyDelgate(Delegate, IAnimal):
    pi_attr_fallback = 'impl'

    def __init__(self, animal):
        self.impl = animalIf the delegate does not inherit from an interface thenpi_attr_fallbackdoes nothing.provided_by(obj)Interface.provided_byequivalent for delegates created bycomposed_type.  It returnsTrueif obj provides all the interfaces in the composed type andFalseotherwise.Functionsadapts(from_type, to_interface=None)Class or function decorator for declaring an adapter fromfrom_typetoto_interface.
The class or function being decorated must take a single argument (an instance offrom_type) and
provide (or return and object providing)to_interface.  The adapter may return an object that provides
the interface structurally only, howeveradaptmust be called withallow_implicit=Truefor this to work.
If decorating a class,to_interfacemay beNoneto use the first interface in the class’s MRO.register_adapter(adapter, from_type, to_interface)Registers an adapter to convert instances offrom_typeto objects that provideto_interfacefor theto_interface.adapt()method.adaptermust be a callable that takes a single argument
(an instance offrom_type) and returns and object providingto_interface.type_is_interface(cls)ReturnTrueifclsis a pure interface andFalseotherwiseget_type_interfaces(cls)Returns all interfaces in theclsmro including cls itself if it is an interfaceget_interface_names(cls)Returns afrozensetof names (methods and attributes) defined by the interface.
if interface is not aInterfacesubtype then an empty set is returned.get_interface_method_names(cls)Returns afrozensetof names of methods defined by the interface.
Ifclsis not aInterfacesubtype then an empty set is returned.get_interface_attribute_names(cls)Returns afrozensetof names of class attributes and annotations defined by the interface
Ifclsis not aInterfacesubtype then an empty set is returned.dataclass(…)This function is a re-implementation of the standard Pythondataclasses.dataclassdecorator.
In addition to the fields on the decorated class, all annotations on interface base classes are added as fields.
See the Pythondataclassesdocumentation for details on the arguments, they are exactly the same.get_is_development()Returns the current value of the “is development” flag.set_is_devlopment(is_dev)Set toTrueto enable all checks and warnings.
If set toFalsethen:Signatures of overriding methods are not checkedNo warnings are issued by the adaption functionsNo incomplete implementation warnings are issuedThe default value ofinterface_onlyis set toFalse, so that interface wrappers are not created.get_missing_method_warnings()The list of warning messages for concrete classes with missing interface (abstract) method overrides.
Note that missing properties are NOT checked for as they may be provided by instance attributes.composed_type(*interface_types)Type factory function that creates aDelegatesubclass that implements all the interfaces via delegates.ExceptionsPureInterfaceErrorBase exception class for all exceptions raised bypure_interface.InterfaceErrorException raised for problems with interfacesAdaptionErrorException raised for problems with adapters or adapting.[*]We don’t talk about the methods on the baseInterfaceclass.  In earlier versions they
were all on the meta class but then practicality (mainly type-hinting) got in the way.