1.1.5 Interfaces Used by the Declaration API
Description: Interfaces Used by the Declaration API
Keywords: ref

##
1.1.5 Interfaces Used by the Declaration API

Like any other API, the `protocols` declaration API has certain expectations regarding its parameters. These expectations are documented and referenced in code using interfaces defined in the `protocols.interfaces` module. (The interfaces are also exported directly from the top level of the `protocols` package.)

You will rarely use or subclass any of these interface objects, unless you are customizing or extending the system. Four of the interfaces exist exclusively for documentation purposes, while the rest are used in `adapt()` calls made by the API.

First, let's look at the documentation-only interfaces. It is not necessary for you to declare that an object supports these interfaces, and the `protocols` package never tries to `adapt()` objects to them.

IAdapterFactory
  Up until this point, we've been talking about ``adapters'' rather loosely. The `IAdapterFactory` interface formalizes the concept. An adapter factory is a callable object that accepts an object to be adapted, and returns an object that provides the protocol on behalf of the passed-in object. Declaration API functions that take ``adapter'' or ``factory'' arguments must be adapter factories.

  The `protocols` package supplies two functions that provide this interface: `NO_ADAPTER_NEEDED` and `DOES_NOT_SUPPORT`. `NO_ADAPTER_NEEDED` is used to declare that an object provides a protocol directly, and thus it returns the object passed into it, rather than some kind of adapter. `DOES_NOT_SUPPORT` is used to declare that an object does not support a protocol, even with an adapter. (Since this is the default case, `DOES_NOT_SUPPORT` is rarely used, except to indicate that a subclass does not support an interface that one of its superclasses does.)

IProtocol
  This interface formalizes the idea of a ``protocol object''. As you will recall from section 1.1.2, a protocol object is any object that can be used as a Python dictionary key. The second argument to `adapt()` must be a protocol object according to this definition.

IAdaptingProtocol
  This interface formalizes the idea of an ``adapting protocol'', specifically that it is a protocol object (i.e., it provides `IProtocol`) that also has an `__adapt__` method as described in section 1.1.3. `IAdaptingProtocol` is a subclass of `IProtocol`, so of course `adapt()` accepts such objects as protocols.

IImplicationListener
  This interface is for objects that want to receive notification when new implication relationships (i.e. adapters) are registered between two protocols. If you have objects that want to keep track of what interfaces they support, you may want those object to implement this interface so they can be kept informed of new protocol-to-protocol adapters.

The other three interfaces are critical to the operation of the declaration API, and thus must be supported by objects supplied to it. The `protocols` package supplies and registers various adapter classes that provide these interfaces on behalf of many commonly used Python object types. So, for each interface, we will list ``known supporters'' of that interface, whether they are classes supplied by `protocols`, or built-in types that are automatically adapted to the interface.

We will not, however, go into details here about the methods and behavior required by each interface. (Those details can be found in section 1.1.9.)

IOpenProtocol
  This interface formalizes the ``open protocol'' concept that was introduced in section 1.1.2. An `IOpenProtocol` is an `IAdaptingProtocol` that can also accept declarations made by the `protocols` declaration API.

  The `protocols` package supplies two implementations of this interface: `Protocol` and `InterfaceClass`. Thus, any `Interface` subclass or `Protocol` instance is automatically considered to provide `IOpenProtocol`. Note: `Interface` is an instance of `InterfaceClass`, and thus provides `IOpenProtocol`. But if you create an instance of an `Interface`, that object does not provide `IOpenProtocol`, because the interfaces provided by an object and its class (or its instances) can be different.

  In addition to its built-in implementations, the `protocols` package also supplies and can declare adapter factories that adapt Zope X3 and Twisted's interface objects to the `IOpenProtocol` interface, thus allowing you to use Zope and Twisted interfaces in calls to the declaration API. Similar adapters for other frameworks' interfaces may be added, if there is sufficient demand and/or contributed code, and the frameworks' authors do not add the adapters to their frameworks.

IOpenImplementor
  An `IOpenImplementor` is a class or type that can be told (via the declaration API) what protocols its instances provide (or support via an `IAdapterFactory`). Note that this implies that the instances have a `__conform__` method, or else they would not be able to tell `adapt()` about the declared support!

  Support for this interface is optional, since types that don't support it can still have their instances be adapted by `IOpenProtocol` objects. The `protocols` package does not supply any implementations or adapters for this interface, either. It is intended primarily as a hook for classes to be able to receive notification about protocol declarations for their instances.

IOpenProvider
  Because objects' behavior usually comes from a class definition, it's not that often that you will declare that a specific object provides or supports an interface. But objects like functions and modules do not have a class definition, and classes themselves sometimes provide an interface. (For example, one could say that class objects provide an `IClass` interface.) So, the declaration API needs to also be able to declare what protocols an individual object (such as a function, module, or class) supports or provides.

  That's what the `IOpenProvider` interface is for. An `IOpenProvider` is an object with a `__conform__` method, that can be told (via the declaration API) what protocols it provides (or supports via an `IAdapterFactory`).

  Notice that this is different from `IOpenImplementor`, which deals with an class or type's instances. `IOpenProvider` deals with the object itself. A single object can potentially be both an `IOpenProvider` and an `IOpenImplementor`, if it is a class or type.

  The `protocols` package supplies and declares an adapter factory that can adapt most Python objects to support this interface, assuming that they have a `__dict__` attribute. Thus, it is acceptable to pass a Python function, module, or instance of a ``classic'' class to any declaration API that expects an `IOpenProvider` argument.

  We'll talk more about making protocol declarations for individual objects (as opposed to types) in section 1.1.6, ``Protocol Declarations for Individual Objects''.