Pythonic Interface Definitions
The `python-interface` library provides a Pythonic way to define and enforce interfaces. It helps in creating clear contracts for classes, ensuring that implementations adhere to a specified structure. Currently at version 1.6.1, the library has a moderate release cadence, with updates addressing bugs, adding minor features like subinterfaces, and improving internal tooling.
Warnings
- breaking Version 1.3.0 contained a bug in the implementation of the `@default` decorator, leading to incorrect behavior. Users should upgrade to 1.4.0 or later to avoid this issue.
- gotcha When combining `@default` and `@property` decorators, versions prior to 1.5.2 had a bug that could cause unexpected behavior. This was fixed in 1.5.2.
- gotcha Overriding a class's `__new__` method in an implementation class without explicitly calling the parent/interface's `__new__` method will bypass the interface enforcement checks.
- gotcha The library enforces strict method signature matching (name and argument names) for interface methods. While keyword argument *values* can differ, argument *names* must be identical to the interface definition.
Install
-
pip install python-interface
Imports
- Interface
from interface import Interface
- abstractmethod
from interface import abstractmethod
- implements
from interface import implements
Quickstart
from interface import Interface, abstractmethod, implements
class MyInterface(Interface):
"""An example interface.
Requires a 'required_method' with specific arguments.
"""
@abstractmethod
def required_method(self, required_argument: str) -> bool:
"""This method must be implemented by any class implementing MyInterface."""
pass
class MyImplementation(implements(MyInterface)):
"""A class correctly implementing MyInterface."""
def required_method(self, required_argument: str) -> bool:
if isinstance(required_argument, str) and len(required_argument) > 0:
return True
return False
# Attempting to instantiate a class that doesn't implement all methods will raise an error
class IncompleteImplementation(implements(MyInterface)):
pass
try:
print("Attempting to instantiate IncompleteImplementation...")
IncompleteImplementation()
except TypeError as e:
print(f"Error as expected for incomplete implementation: {e}")
# Demonstrate successful implementation
impl = MyImplementation()
print(f"MyImplementation.required_method('test'): {impl.required_method('test')}")
print(f"MyImplementation.required_method(''): {impl.required_method('')}")
# New in 1.6.0: Interface Subclassing
class ExtendedInterface(MyInterface):
"""An interface extending MyInterface with an additional method."""
@abstractmethod
def another_required_method(self) -> int:
pass
class ExtendedImplementation(implements(ExtendedInterface)):
"""A class correctly implementing ExtendedInterface."""
def required_method(self, required_argument: str) -> bool:
return True
def another_required_method(self) -> int:
return 42
extended_impl = ExtendedImplementation()
print(f"ExtendedImplementation.another_required_method(): {extended_impl.another_required_method()}")