Implement an Interface¶
There are several ways to indicate that instances of a class provide an interface. These are listed here, and for performance reasons, should typically be considered in the order that they appear.
Register a class that implements the interface¶
For classes that define all attributes of an interface, decorate the class with
jute.implements.
@jute.implements(BufferedWritable)
class OutputWriter:
def write(self, buf):
sys.stdout.write(buf)
def flush(self):
sys.stdout.flush()
If it is not possible to decorate the class, use the interface’s
register_implementation method to specify a class as an implementation of the
interface.
BufferedWritable.register_implementation(file)
In either of the above cases, the interface is verified once, during class definition or registration.
Register a class whose instances provide the interface¶
Sometimes a class does not define all interface attributes, but instances of
the class will, typically through the __init__ or __getattr__ methods. In
this case, decorate the class with jute.provides.
@jute.provides(BufferedWritable)
class ErrorWriter:
def __init__(self):
self.write = sys.stderr.write
def __getattr__(self, name):
if name == 'flush':
def flush(buf):
sys.stderr.flush(buf)
return flush
raise AttributeError(name)
If it is not possible to decorate the class, use the interface’s
register_provider method to specify that class instances will provide the
interface. Note that register_provider takes the class whose instances will
provide the interface, not a class instance.
Writable.register_provider(ssl.SSLSocket)
This particular class could also have been registered using register_implementation.
The claim to provide an interface is verified during each conversion to the interface, and hence is slower than registering an implementation.
Dynamically indicate that an instance provides the interface¶
Sometimes, especially for wrapper classes, it is useful to declare support for
an interface dynamically. Dynamic implementations are declared using the
jute.Dynamic interface, which provides a single method provides_interface:
@implements(jute.Dynamic)
class PrintAttributeAccessWrapper:
def __init__(self, wrapped):
self.wrapped = wrapped
def __getattr__(self, name):
# return the wrapped object's attributes
print('Accessing attribute {}'.format(name))
return getattr(self.wrapped, name)
def provides_interface(self, interface):
# Check wrapped object's support for interface.
return interface.provided_by(self.wrapped)
Note, this object may print “Accessing attribute write” twice. The first time
is during interface verification, which will not actually call the function.
This may be an issue if __getattr__ performs non-trivial work to resolve the
attribute.