From ab3200b4cc1fd2bec915a47aafa48a9d1a4774ed Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:41:39 -0400 Subject: [PATCH 1/8] config.py => _config.py --- requests/{config.py => _config.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename requests/{config.py => _config.py} (100%) diff --git a/requests/config.py b/requests/_config.py similarity index 100% rename from requests/config.py rename to requests/_config.py From 4dc48b6521805515b9a3a7a06670d9f5984dd45c Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:25:27 -0400 Subject: [PATCH 2/8] _config => defaults --- requests/_config.py | 68 -------------------------------------------- requests/defaults.py | 48 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 68 deletions(-) delete mode 100644 requests/_config.py create mode 100644 requests/defaults.py diff --git a/requests/_config.py b/requests/_config.py deleted file mode 100644 index 794109c5..00000000 --- a/requests/_config.py +++ /dev/null @@ -1,68 +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'} -settings.accept_gzip = True -settings.proxies = None -settings.verbose = None -settings.timeout = None -settings.max_redirects = 30 -settings.decode_unicode = True - -#: Use socket.setdefaulttimeout() as fallback? -settings.timeout_fallback = True diff --git a/requests/defaults.py b/requests/defaults.py new file mode 100644 index 00000000..72af0600 --- /dev/null +++ b/requests/defaults.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +""" +requests.defaults +~~~~~~~~~~~~~~~~~ + +This module provides the Requests configuration defaults. + +settings parameters: + +- :base_headers: - Sets default User-Agent to `python-requests.org` +- :accept_gzip: - Whether or not to accept gzip-compressed data +- :proxies: - http proxies? +- :verbose: - display verbose information? +- :timeout: - timeout time until request terminates +- :max_redirects: - maximum number of allowed redirects? +- :decode_unicode: - whether or not to accept unicode? + +""" + +from . import __version__ + +defaults = dict() + + +defaults['base_headers'] = { + 'User-Agent': 'python-requests/{0}'.format(__version__), + 'Accept-Encoding': ', '.join([ 'identity', 'deflate', 'compress', 'gzip' ]), +} + + +# defaults['accept_gzip'] = True +defaults['proxies'] = {} +defaults['verbose'] = None +defaults['timeout'] = None +defaults['max_redirects'] = 30 +defaults['decode_unicode'] = True +defaults['timeout_fallback'] = True +# defaults['keep_alive'] = True +# defaults['max_connections'] = 10 + + +# defaults['hooks'] = { +# 'args': list(), +# 'pre_request': list(), +# 'post_request': list(), +# 'response': list() +# } From 5c81fba1eba9187886bf98dbce395cd119f1ccfd Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:26:12 -0400 Subject: [PATCH 3/8] use config object in sessions --- requests/sessions.py | 51 +++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/requests/sessions.py b/requests/sessions.py index 26d0345f..a88a0626 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -11,7 +11,7 @@ requests (cookies, auth, proxies). import cookielib -from . import config +from .defaults import defaults from .models import Request from .hooks import dispatch_hook from .utils import add_dict_to_cookiejar, cookiejar_from_dict, header_expand @@ -51,7 +51,7 @@ def merge_kwargs(local_kwarg, default_kwarg): class Session(object): """A Requests session.""" - __attrs__ = ['headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks', 'params'] + __attrs__ = ['headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks', 'params', 'config'] def __init__(self, @@ -61,7 +61,8 @@ class Session(object): timeout=None, proxies=None, hooks=None, - params=None): + params=None, + config=None): self.headers = headers or {} self.cookies = cookies or {} @@ -70,6 +71,10 @@ class Session(object): self.proxies = proxies or {} self.hooks = hooks or {} self.params = params or {} + self.config = config or {} + + for (k, v) in defaults.items(): + self.config.setdefault(k, v) # Set up a CookieJar to be used by default self.cookies = cookielib.FileCookieJar() @@ -84,8 +89,18 @@ class Session(object): pass def request(self, method, url, - params=None, data=None, headers=None, cookies=None, files=None, auth=None, - timeout=None, allow_redirects=False, proxies=None, hooks=None, return_response=True): + params=None, + data=None, + headers=None, + cookies=None, + files=None, + auth=None, + timeout=None, + allow_redirects=False, + proxies=None, + hooks=None, + return_response=True, + config=None): """Constructs and sends a :class:`Request `. Returns :class:`Response ` object. @@ -102,6 +117,7 @@ class Session(object): :param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed. :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. :param return_response: (optional) If False, an un-sent Request object will returned. + :param config: (optional) A configuration dictionary. """ method = str(method).upper() @@ -120,18 +136,19 @@ class Session(object): headers[k] = header_expand(v) args = dict( - method = method, - url = url, - data = data, - params = params, - headers = headers, - cookies = cookies, - files = files, - auth = auth, - hooks = hooks, - timeout = timeout or config.settings.timeout, - allow_redirects = allow_redirects, - proxies = proxies or config.settings.proxies, + method=method, + url=url, + data=data, + params=params, + headers=headers, + cookies=cookies, + files=files, + auth=auth, + hooks=hooks, + timeout=timeout, + allow_redirects=allow_redirects, + proxies=proxies, + config=config ) for attr in self.__attrs__: From 903f96cc6a948cdb86a2d79c23f93d27a258c4ab Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:28:06 -0400 Subject: [PATCH 4/8] use config throughout models --- requests/models.py | 68 +++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/requests/models.py b/requests/models.py index d58e4ad8..ac235a75 100644 --- a/requests/models.py +++ b/requests/models.py @@ -9,22 +9,22 @@ requests.models import urllib import urllib2 import socket -import codecs import zlib - from urllib2 import HTTPError from urlparse import urlparse, urlunparse, urljoin from datetime import datetime -from .config import settings -from .monkeys import Request as _Request, HTTPBasicAuthHandler, HTTPForcedBasicAuthHandler, HTTPDigestAuthHandler, HTTPRedirectHandler from .structures import CaseInsensitiveDict from .packages.poster.encode import multipart_encode from .packages.poster.streaminghttp import register_openers, get_handlers -from .utils import dict_from_cookiejar, get_unicode_from_response, stream_decode_response_unicode, decode_gzip, stream_decode_gzip +from .utils import (dict_from_cookiejar, get_unicode_from_response, stream_decode_response_unicode, decode_gzip, stream_decode_gzip) from .status_codes import codes from .exceptions import Timeout, URLRequired, TooManyRedirects +from .monkeys import Request as _Request +from .monkeys import ( + HTTPBasicAuthHandler, HTTPForcedBasicAuthHandler, + HTTPDigestAuthHandler, HTTPRedirectHandler) REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved) @@ -37,9 +37,20 @@ class Request(object): """ def __init__(self, - url=None, headers=dict(), files=None, method=None, data=dict(), - params=dict(), auth=None, cookies=None, timeout=None, redirect=False, - allow_redirects=False, proxies=None, hooks=None): + url=None, + headers=dict(), + files=None, + method=None, + data=dict(), + params=dict(), + auth=None, + cookies=None, + timeout=None, + redirect=False, + allow_redirects=False, + proxies=None, + hooks=None, + config=None): #: Float describes the timeout of the request. # (Use socket.setdefaulttimeout() as fallback) @@ -93,6 +104,9 @@ class Request(object): #: CookieJar to attach to :class:`Request `. self.cookies = cookies + #: Dictionary of configurations for this request. + self.config = config + #: True if Request has been sent. self.sent = False @@ -100,16 +114,15 @@ class Request(object): self.hooks = hooks # Header manipulation and defaults. - - if settings.accept_gzip: - settings.base_headers.update({'Accept-Encoding': 'gzip'}) + if self.config.get('accept_gzip'): + self.headers.update({'Accept-Encoding': 'gzip'}) if headers: headers = CaseInsensitiveDict(self.headers) else: headers = CaseInsensitiveDict() - for (k, v) in settings.base_headers.items(): + for (k, v) in self.config.get('base_headers', {}).items(): if k not in headers: headers[k] = v @@ -185,6 +198,7 @@ class Request(object): def build(resp): response = Response() + response.config = self.config response.status_code = getattr(resp, 'code', None) try: @@ -219,7 +233,7 @@ class Request(object): r.raw.close() - if not len(history) < settings.max_redirects: + if not len(history) < self.config.get('max_redirects'): raise TooManyRedirects() history.append(r) @@ -243,9 +257,16 @@ class Request(object): method = self.method request = Request( - url, self.headers, self.files, method, - self.data, self.params, self.auth, self.cookies, - redirect=True + url=url, + headers=self.headers, + files=self.files, + method=method, + # data=self.data, + # params=self.params, + auth=self.auth, + cookies=self.cookies, + redirect=True, + config=self.config ) request.send() r = request.response @@ -313,8 +334,8 @@ class Request(object): self._checks() # Logging - if settings.verbose: - settings.verbose.write('%s %s %s\n' % ( + if self.config.get('verbose'): + self.config.get('verbose').write('%s %s %s\n' % ( datetime.now().isoformat(), self.method, self.url )) @@ -353,14 +374,14 @@ class Request(object): if not 'timeout' in str(err): raise - if settings.timeout_fallback: + if self.config.get('timeout_fallback'): # fall-back and use global socket timeout (This is not thread-safe!) old_timeout = socket.getdefaulttimeout() socket.setdefaulttimeout(self.timeout) resp = opener(req) - if settings.timeout_fallback: + if self.config.get('timeout_fallback'): # restore global timeout socket.setdefaulttimeout(old_timeout) @@ -429,6 +450,9 @@ class Response(object): #: A dictionary of Cookies the server sent back. self.cookies = None + #: Dictionary of configurations for this request. + self.config = None + def __repr__(self): return '' % (self.status_code) @@ -460,7 +484,7 @@ class Response(object): if 'gzip' in self.headers.get('content-encoding', ''): gen = stream_decode_gzip(gen) if decode_unicode is None: - decode_unicode = settings.decode_unicode + decode_unicode = self.config.get('decode_unicode') if decode_unicode: gen = stream_decode_response_unicode(gen, self) return gen @@ -489,7 +513,7 @@ class Response(object): pass # Decode unicode content. - if settings.decode_unicode: + if self.config.get('decode_unicode'): self._content = get_unicode_from_response(self) self._content_consumed = True From f9dfbb73ddbc6ce78cd6e57dd436158fc417d031 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:28:19 -0400 Subject: [PATCH 5/8] requests.request uses config --- requests/api.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/requests/api.py b/requests/api.py index f44f35bf..c0556444 100644 --- a/requests/api.py +++ b/requests/api.py @@ -17,13 +17,24 @@ __all__ = ('request', 'get', 'head', 'post', 'patch', 'put', 'delete') def request(method, url, - params=None, data=None, headers=None, cookies=None, files=None, auth=None, - timeout=None, allow_redirects=False, proxies=None, hooks=None, return_response=True): + params=None, + data=None, + headers=None, + cookies=None, + files=None, + auth=None, + timeout=None, + allow_redirects=False, + proxies=None, + hooks=None, + return_response=True, + config=None): s = session() return s.request( method, url, params, data, headers, cookies, files, auth, - timeout, allow_redirects, proxies, hooks, return_response + timeout, allow_redirects, proxies, hooks, return_response, + config ) From 2f6cf50a6c6e655e8a87c8721fab2049a34d8e8e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:28:25 -0400 Subject: [PATCH 6/8] deprecate settings --- requests/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/requests/__init__.py b/requests/__init__.py index 2b25c9e2..6cce5bfe 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -27,7 +27,6 @@ from .models import HTTPError, Request, Response from .api import request, get, head, post, patch, put, delete from .sessions import session from .status_codes import codes -from .config import settings from .exceptions import ( RequestException, AuthenticationError, Timeout, URLRequired, TooManyRedirects From 6be69e303b636b70a6d10233331eaada2417e2e7 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:29:00 -0400 Subject: [PATCH 7/8] history for config --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index a0666c23..79dad208 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,7 @@ History * Sessions are now the primary interface. * Deprecated InvalidMethodException. * PATCH fix. +* New config system (no more global settings). 0.6.6 (2011-10-19) From 8c34fa84770c34586fd0d83c05eafe0de6a85682 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:31:51 -0400 Subject: [PATCH 8/8] settings => config --- docs/user/advanced.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst index 92dac5f3..5c17898e 100644 --- a/docs/user/advanced.rst +++ b/docs/user/advanced.rst @@ -39,8 +39,8 @@ Sessions can also be used to provide default data to the request methods:: .. admonition:: Global Settings - Certain parameters are best set at the ``request.config`` level - (e.g.. a global proxy, user agent header). + Certain parameters are best set in the ``config`` dictionary + (e.g. user agent header). Asynchronous Requests