##
18.6.2 OpenerDirector Objects

`OpenerDirector` instances have the following methods:

`add_handler`( | handler)

  handler should be an instance of `BaseHandler`. The following methods are searched, and added to the possible chains (note that HTTP errors are a special case).

  - `protocol_open()` -- signal that the handler knows how to open protocol URLs.
  - `http_error_type()` -- signal that the handler knows how to handle HTTP errors with HTTP error code type.
  - `protocol_error()` -- signal that the handler knows how to handle errors from (non-`http`) protocol.
  - `protocol_request()` -- signal that the handler knows how to pre-process protocol requests.
  - `protocol_response()` -- signal that the handler knows how to post-process protocol responses.

`open`( | url[, data])

  Open the given url (which can be a request object or a string), optionally passing the given data. Arguments, return values and exceptions raised are the same as those of `urlopen()` (which simply calls the `open()` method on the currently installed global `OpenerDirector`).

`error`( | proto[, arg[, ...]])

  Handle an error of the given protocol. This will call the registered error handlers for the given protocol with the given arguments (which are protocol specific). The HTTP protocol is a special case which uses the HTTP response code to determine the specific error handler; refer to the `http_error_*()` methods of the handler classes.

  Return values and exceptions raised are the same as those of `urlopen()`.

OpenerDirector objects open URLs in three stages:

The order in which these methods are called within each stage is determined by sorting the handler instances.

1. Every handler with a method named like `protocol_request()` has that method called to pre-process the request.

2. Handlers with a method named like `protocol_open()` are called to handle the request. This stage ends when a handler either returns a non-`None` value (ie. a response), or raises an exception (usually `URLError`). Exceptions are allowed to propagate.

   In fact, the above algorithm is first tried for methods named `default_open`. If all such methods return `None`, the algorithm is repeated for methods named like `protocol_open()`. If all such methods return `None`, the algorithm is repeated for methods named `unknown_open()`.

   Note that the implementation of these methods may involve calls of the parent `OpenerDirector` instance's `.open()` and `.error()` methods.

3. Every handler with a method named like `protocol_response()` has that method called to post-process the response.