[Python] custom urllib2 opener

from urllib2 import *

class MyHttpHandler(HTTPErrorProcessor):
    #parent = OpenerDirector()
    handler_order = 1

    def http_request(self, request):
        return request

    https_request = http_request

    def default_open(self, request):
        """return None for propagation"""
        return None

    def http_open(self, request):
        """return None for propagation"""
        return None

    https_open = http_open

    def unknown_open(self, request):
        """return None for propagation"""
        return None

    def http_response(self, request, response):
        response = self.parent.error('http', request, response, response.code,
                                     response.msg, response.info())
        return response

    https_response = http_response

    def http_error_default(self, request, fp, code, msg, headers):
        """return None for propagation"""
        raise HTTPError(request.get_full_url(), code, msg, headers, fp)

    def http_error_XXX(self, request, fp, code, msg, headers):
        """return None for propagation"""
        return None

urlopen = build_opener(MyHttpHandler).open

build_opener はデフォルトで [ProxyHandler, UnknownHandler, HTTPHandler, HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor] を組み込む。これらの動作を変更したいならそのクラスから導出したクラスを引数に指定する。
ハンドラはマルチスレッドで呼ばれる可能性があるので self ではなく、request で状態を保持する。

メソッドの呼ばれる順

  • http_request
  • default_open
  • http_open
  • unknown_open
  • http_response

以下は HTTPErrorProcessor.http_response が呼ぶ

  • http_error_XXX
  • http_error_default

戻り値

*_request は request オブジェクトを必ず返さなければならない。
*_response は response オブジェクトを必ず返さなければならない。
他は assert(bool(result)) な値を返せばハンドラの伝搬は停止する。None を返すと他のハンドラが呼ばれる。例外は好きに投げろ。


割と良くできてると思います。またしても classic class ではありますが。