mirror of
https://github.com/kennethreitz/requests.git
synced 2026-06-05 22:50:18 +00:00
Fix errors introduced by merging an outdated pull request.
Don't do that anymore, OK?
This commit is contained in:
+8
-8
@@ -14,7 +14,7 @@ This module implements the Requests API.
|
||||
from ._config import get_config
|
||||
from .models import Request, Response
|
||||
from .status_codes import codes
|
||||
from hooks import setup_hooks, dispatch_hooks
|
||||
from .hooks import dispatch_hooks
|
||||
from .utils import cookiejar_from_dict, header_expand
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ def request(method, url,
|
||||
method = str(method).upper()
|
||||
config = get_config(config)
|
||||
|
||||
# cookies = cookiejar_from_dict(cookies if cookies is not None else dict())
|
||||
if cookies is None:
|
||||
cookies = {}
|
||||
|
||||
# cookies = cookiejar_from_dict(cookies)
|
||||
|
||||
# Expand header values
|
||||
@@ -70,16 +72,14 @@ def request(method, url,
|
||||
_pools=_pools
|
||||
)
|
||||
|
||||
hooks = setup_hooks(hooks if hooks is not None else dict())
|
||||
|
||||
# Arguments manipulation hook.
|
||||
args = dispatch_hooks(hooks['args'], args)
|
||||
args = dispatch_hooks('args', hooks, args)
|
||||
|
||||
# Create Request object.
|
||||
r = Request(**args)
|
||||
|
||||
# Pre-request hook.
|
||||
r = dispatch_hooks(hooks['pre_request'], r)
|
||||
r = dispatch_hooks('pre_request', hooks, r)
|
||||
|
||||
# Only construct the request (for async)
|
||||
if _return_request:
|
||||
@@ -90,10 +90,10 @@ def request(method, url,
|
||||
|
||||
# TODO: Add these hooks inline.
|
||||
# Post-request hook.
|
||||
r = dispatch_hooks(hooks['post_request'], r)
|
||||
r = dispatch_hooks('post_request', hooks, r)
|
||||
|
||||
# Response manipulation hook.
|
||||
r.response = dispatch_hooks(hooks['response'], r.response)
|
||||
r.response = dispatch_hooks('response', hooks, r.response)
|
||||
|
||||
return r.response
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
requests.config
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This module provides the Requests settings feature set.
|
||||
|
||||
"""
|
||||
|
||||
class Settings(object):
|
||||
_singleton = {}
|
||||
|
||||
# attributes with defaults
|
||||
__attrs__ = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Settings, self).__init__()
|
||||
|
||||
self.__dict__ = self._singleton
|
||||
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
# new instance of class to call
|
||||
r = self.__class__()
|
||||
|
||||
# cache previous settings for __exit__
|
||||
r.__cache = self.__dict__.copy()
|
||||
map(self.__cache.setdefault, self.__attrs__)
|
||||
|
||||
# set new settings
|
||||
self.__dict__.update(*args, **kwargs)
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
|
||||
def __exit__(self, *args):
|
||||
|
||||
# restore cached copy
|
||||
self.__dict__.update(self.__cache.copy())
|
||||
del self.__cache
|
||||
|
||||
|
||||
def __getattribute__(self, key):
|
||||
if key in object.__getattribute__(self, '__attrs__'):
|
||||
try:
|
||||
return object.__getattribute__(self, key)
|
||||
except AttributeError:
|
||||
return None
|
||||
return object.__getattribute__(self, key)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
||||
settings.base_headers = {
|
||||
'User-Agent': 'python-requests.org',
|
||||
'Accept-Encoding': ', '.join([ 'identity', 'deflate', 'compress', 'gzip' ]),
|
||||
}
|
||||
settings.accept_gzip = True
|
||||
settings.proxies = None
|
||||
settings.verbose = None
|
||||
settings.timeout = None
|
||||
settings.max_redirects = 30
|
||||
settings.decode_unicode = False
|
||||
settings.gracefull_hooks = True
|
||||
|
||||
#: A dictionary of default hooks to be applied, based on settings.
|
||||
settings.default_hooks = {
|
||||
'args': list(),
|
||||
'pre_request': list(),
|
||||
'post_request': list(),
|
||||
'response': list()
|
||||
}
|
||||
|
||||
#: Use socket.setdefaulttimeout() as fallback?
|
||||
settings.timeout_fallback = True
|
||||
+7
-150
@@ -23,162 +23,19 @@ Available hooks:
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from collections import Iterable
|
||||
import config
|
||||
import zlib
|
||||
import bz2
|
||||
from cgi import parse_header
|
||||
import collections
|
||||
|
||||
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
|
||||
"""
|
||||
def dispatch_hooks(key, hooks, hook_data):
|
||||
"""Dipatches a hook dictionary on a given peice of data."""
|
||||
|
||||
# Copy the default hooks settings.
|
||||
default = config.settings.default_hooks
|
||||
dispatching = dict([(k, v[:]) for k, v in default.items()])
|
||||
hooks = (hooks or {}).get(key, [])
|
||||
hooks = hooks if isinstance(hooks, collections.Iterable) else [hooks]
|
||||
|
||||
# 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)
|
||||
|
||||
hook_data = hook(hook_data) or 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
|
||||
return hook_data
|
||||
|
||||
+3
-23
@@ -453,21 +453,14 @@ class Response(object):
|
||||
(if available).
|
||||
"""
|
||||
|
||||
if self._content is None:
|
||||
# Read the contents.
|
||||
self._content = self.fo.read()
|
||||
if self._content is not None:
|
||||
return self._content
|
||||
|
||||
if self._content_consumed:
|
||||
raise RuntimeError(
|
||||
'The content for this response was already consumed')
|
||||
# # Decode GZip'd content.
|
||||
# if 'gzip' in self.headers.get('content-encoding', ''):
|
||||
# try:
|
||||
# self._content = decode_gzip(self._content)
|
||||
# except zlib.error:
|
||||
# pass
|
||||
|
||||
self._content = self.fo.read()
|
||||
# Read the contents.
|
||||
self._content = self.raw.read() or self.raw.data
|
||||
|
||||
# Decode GZip'd content.
|
||||
@@ -477,22 +470,9 @@ class Response(object):
|
||||
except zlib.error:
|
||||
pass
|
||||
|
||||
# Decode unicode content.
|
||||
if settings.decode_unicode:
|
||||
self._content = get_unicode_from_response(self)
|
||||
# Decode GZip'd content.
|
||||
if 'gzip' in self.headers.get('content-encoding', ''):
|
||||
try:
|
||||
self._content = decode_gzip(self._content)
|
||||
except zlib.error:
|
||||
pass
|
||||
|
||||
# Decode unicode content.
|
||||
if self.config.get('decode_unicode'):
|
||||
self._content = get_unicode_from_response(self)
|
||||
# # Decode unicode content.
|
||||
# if settings.decode_unicode:
|
||||
# self._content = get_unicode_from_response(self)
|
||||
|
||||
self._content_consumed = True
|
||||
return self._content
|
||||
|
||||
Reference in New Issue
Block a user