From: Luca De Vitis Date: Thu, 1 Sep 2011 16:22:12 +0000 (+0200) Subject: Reverted hooks from sub-package to module. X-Git-Tag: v0.8.0~94^2~4^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=07dd324e2f78ee208e35d3faa963ebab237ff95f;p=services%2Fpython-requests.git Reverted hooks from sub-package to module. --- diff --git a/requests/hooks.py b/requests/hooks.py new file mode 100644 index 0000000..e2980ac --- /dev/null +++ b/requests/hooks.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- + +""" +requests.hooks +~~~~~~~~~~~~~~ + +This module provides the capabilities for the Requests hooks system. + +Available hooks: + +``args``: + A dictionary of the arguments being sent to Request(). + +``pre_request``: + The Request object, directly before being sent. + +``post_request``: + The Request object, directly after being sent. + +``response``: + The response generated from a Request. + +""" + +import warnings +from collections import Iterable +import config +import zlib +import bz2 +from cgi import parse_header + +def setup_hooks(supplied): + """Setup a hooks mapping, based on the supplied argument. Eache mapping + value will be list of hooks that will extend the **default_hooks**. + + :param supplied: a dictionary of hooks. Each value can either be a callable + or a list of callables. + :type supplied: dict + :returns: a dictionary of hooks that extends the **default_hooks** dictionary. + :rtype: dict + """ + + # Copy the default hooks settings. + default = config.settings.default_hooks + dispatching = dict([(k, v[:]) for k, v in default.items()]) + + # I abandoned the idea of a dictionary of sets because sets may not keep + # insertion order, while it may be important. Also, there is no real reason + # to force hooks to run once. + for hooks, values in supplied.items(): + hook_list = values if isinstance(values, Iterable) else [values] + dispatching[hooks].extend(hook_list) + + # If header is set by config, maybe response is encoded. + if config.settings.base_headers.get('Accept-Encoding', ''): + if not decode_encoding in dispatching['response']: + # It's safer to put decoding as first hook. + dispatching['response'].insert(0, decode_encoding) + + if config.settings.decode_unicode: + try: + # Try unicode encoding just after content decoding... + index = dispatching['response'].index(decode_encoding) + 1 + except ValueError: + # ... Or as first hook + index = 0 + dispatching['response'].insert(index, decode_unicode) + + return dispatching + +def dispatch_hooks(hooks, data): + """Dispatches multiple hooks on a given piece of data. + + :param key: the hooks group to lookup + :type key: str + :param hooks: the hooks dictionary. The value of each key can be a callable + object, or a list of callable objects. + :type hooks: dict + :param data: the object on witch the hooks should be applied + :type data: object + """ + for hook in hooks: + try: + # hook must be a callable. + data = hook(data) + + except Exception, why: + + # Letting users to choose a policy may be an idea. It can be as + # simple as "be gracefull, or not": + # + # config.settings.gracefull_hooks = True | False + if not config.settings.gracefull_hooks: raise + + warnings.warn(str(why)) + + return data + +#: Example response hook that turns a JSON formatted +#: :py:class:`requests.models.Response.content` into a dumped data structure:: +#: +#: try: +#: import json +#: except ImportError: +#: try: +#: import simplejson as json +#: except ImportError: +#: json = False +#: +#: if json: +#: def json_content(r): +#: """Turns content into a dumped JSON structure.""" +#: r._content = json.dumps(r.content) +#: return r +#: +#: Example response hook that turns an XML formatted +#: :py:class:`requests.models.Response.content` into an ElementTree:: +#: +#: try: +#: from lxml import etree +#: except ImportError: +#: try: +#: import xml.etree.cElementTree as etree +#: except ImportError: +#: try: +#: import xml.etree.ElementTree as etree +#: except ImportError: +#: try: +#: import cElementTree as etree +#: except ImportError: +#: try: +#: import elementtree.ElementTree as etree +#: except ImportError: +#: etree = False +#: +#: if etree: +#: def etree_content(r): +#: """Turns content into an ElementTree structure.""" +#: r._content = etree.fromstring(r.content) +#: return r + +def decode_unicode(r): + """Encode content into unicode string. + + :param r: response object + :type r: :py:class:`requests.models.Response` + :returns: the same input object. + :rtype: :py:class:`requests.models.Response` + """ + content_type, params = parse_header(r.headers['content-type']) + charset = params.get('charset', '').strip("'\"") + r._content = unicode(r.content, charset) if charset else unicode(r.content) + return r + +def decode_encoding(r): + """Decode content using Contetn-Encoding header. + + :param r: response object + :type r: :py:class:`requests.models.Response` + :returns: the same input object. + :rtype: :py:class:`requests.models.Response` + """ + + # Dictionary of content decoders. + decode = { + # No decoding applied. + 'identity': lambda content: content, + # Decode Response content compressed with deflate. + 'deflate': lambda content: zlib.decompress(content), + # Decode Response content compressed with gzip. + 'gzip': lambda content: zlib.decompress(content, 16+zlib.MAX_WBITS), + # Decode Response content compressed with bz2. + # Not a standard Content-Encoding value, but.. + 'bzip2': lambda content: bz2.decompress(content), + } + # Decode Response content compressed with compress. + # If I understood zlib... + decode['compress'] = decode['deflate'] + + # Apply decoding only if the header is set. + encoding = r.headers['content-encoding'] + if encoding: + r._content = decode[encoding](r.content) + return r diff --git a/requests/hooks/__init__.py b/requests/hooks/__init__.py deleted file mode 100644 index e737bff..0000000 --- a/requests/hooks/__init__.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.hooks -~~~~~~~~~~~~~~ - -This module provides the capabilities for the Requests hooks system. - -Available hooks: - -``args``: - A dictionary of the arguments being sent to Request(). - -``pre_request``: - The Request object, directly before being sent. - -``post_request``: - The Request object, directly after being sent. - -``response``: - The response generated from a Request. - -""" - -import warnings -from collections import Iterable -from .. import config -from . import args -from . import pre_request -from . import post_request -from . import response - -def setup_hooks(supplied): - """Setup the supplied dictionary of hooks. - Each value is a list of hooks and will extend **default_hooks**. - - :param supplied: a dictionary of hooks. Each value can either be a callable - or a list of callables. - :type supplied: dict - :returns: a dictionary of hooks that extends the **default_hooks** dictionary. - :rtype: dict - """ - - # Copy the default hooks settings. - default = config.settings.default_hooks - dispatching = dict([(k, v[:]) for k, v in default.items()]) - - # I abandoned the idea of a dictionary of sets because sets may not keep - # insertion order, while it may be important. Also, there is no real reason - # to force hooks to run once. - for hooks, values in supplied.items(): - hook_list = values if isinstance(values, Iterable) else [values] - dispatching[hooks].extends(hook_list) - - # If header is set, maybe response is encoded. Whatever hook you want to - # run on response, content decoding should be first. - if config.settings.base_headers.get('Accept-Encoding', ''): - dispatching['response'].insert(0, response.decode_encoding) - - if config.settings.decode_unicode: - try: - # Try unicode encoding just after content decoding... - index = dispatching['response'].index(response.decode_encoding) + 1 - except ValueError: - # ... Or as first hook - index = 0 - dispatching['response'].insert(index, response.decode_unicode) - - return dispatching - -def dispatch_hooks(hooks, data): - """Dispatches multiple hooks on a given piece of data. - - :param key: the hooks group to lookup - :type key: str - :param hooks: the hooks dictionary. The value of each key can be a callable - object, or a list of callable objects. - :type hooks: dict - :param data: the object on witch the hooks should be applied - :type data: object - """ - for hook in hooks: - try: - # hook must be a callable. - data = hook(data) - - except Exception, why: - - # Letting users to choose a policy may be an idea. It can be as - # simple as "be gracefull, or not": - # - # config.settings.gracefull_hooks = True | False - if not config.settings.gracefull_hooks: raise - - warnings.warn(str(why)) - - return data diff --git a/requests/hooks/args.py b/requests/hooks/args.py deleted file mode 100644 index 6ac6fb6..0000000 --- a/requests/hooks/args.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -request.hooks.args -~~~~~~~~~~~~~~~~~~ - -This module provide a collection of args hooks. -""" - diff --git a/requests/hooks/post_request.py b/requests/hooks/post_request.py deleted file mode 100644 index 3a4ff54..0000000 --- a/requests/hooks/post_request.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -request.hooks.post_request -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This module provide a collection of post_request hooks. -""" - diff --git a/requests/hooks/pre_request.py b/requests/hooks/pre_request.py deleted file mode 100644 index ca1e715..0000000 --- a/requests/hooks/pre_request.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -request.hooks.pre_request -~~~~~~~~~~~~~~~~~~~~~~~~~ - -This module provide a collection of pre_request hooks. -""" - diff --git a/requests/hooks/response.py b/requests/hooks/response.py deleted file mode 100644 index beec248..0000000 --- a/requests/hooks/response.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -request.hooks.response -~~~~~~~~~~~~~~~~~~~~~~ - -This module provide a collection of response hooks. -""" -import zlib -import bz2 -from cgi import parse_header - -try: - import json -except ImportError: - try: - import simplejson as json - except ImportError: - json = False -try: - from lxml import etree -except ImportError: - try: - import xml.etree.cElementTree as etree - except ImportError: - try: - import xml.etree.ElementTree as etree - except ImportError: - try: - import cElementTree as etree - except ImportError: - try: - import elementtree.ElementTree as etree - except ImportError: - etree = False - -#: Dictionary of content decoders. -content_decoders = { - # No decoding applied. - 'identity': lambda content: content, - # Decode Response file object compressed with deflate. - 'deflate': lambda content: zlib.decompress(content), - # Decode Response file object compressed with gzip. - 'gzip': lambda content: zlib.decompress(content, 16+zlib.MAX_WBITS), - # Decode Response file object compressed with bz2. - # Not a standard Content-Encoding value, but.. - 'bzip2': lambda content: bz2.decompress(content), -} - -# Decode Response file object compressed with compress. -content_decoders['compress'] = content_decoders['deflate'] - -def decode_unicode(r): - """Encode a :py:class:`requests.models.Response` file object in unicode.""" - content_type, params = parse_header(r.headers['content-type']) - charset = params.get('charset', '').strip("'\"") - r._content = unicode(r.content, charset) if charset else unicode(r.content) - return r - -def decode_encoding(r): - """ - Decode a :py:class:`requests.models.Response` content using - Contetn-Encoding header. - """ - # Apply decoding only if the header is set. - encoding = r.headers['content-encoding'] - if encoding: - r._content = content_decoders[encoding](r.content) - return r - -if json: - def json_content(r): - """ - Turns :py:class:`requests.models.Response` content into a dumped - JSON structure. - """ - r._content = json.dumps(r.content) - return r - -if etree: - def etree_content(r): - """ - Turns :py:class:`requests.models.Response` content into an - ElementTree structure. - """ - r._content = etree.fromstring(r.content) - return r