From cfd38263d1a8b3c6754c261a93d842fd5090deb8 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 19 Oct 2011 15:54:22 -0400 Subject: [PATCH 01/38] imports cleanup for @alex :sparkles: :cake: :sparkles: --- requests/api.py | 2 +- requests/core.py | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/requests/api.py b/requests/api.py index 1b847b7b..4376c969 100644 --- a/requests/api.py +++ b/requests/api.py @@ -11,7 +11,7 @@ This module impliments the Requests API. """ -import config +from . import config from .models import Request, Response, AuthObject from .status_codes import codes from .hooks import dispatch_hook diff --git a/requests/core.py b/requests/core.py index 79449801..e75db8df 100644 --- a/requests/core.py +++ b/requests/core.py @@ -19,11 +19,13 @@ __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' -from models import HTTPError, Request, Response -from api import * -from exceptions import * -from sessions import session -from status_codes import codes -from config import settings - -import utils +from . import utils +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, + InvalidMethod, TooManyRedirects +) From 6dc664caaf507dccb2e499e4ab02a451ef7a148c Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 19 Oct 2011 16:47:46 -0400 Subject: [PATCH 02/38] move core imports into __init__.py because you can't splat import relatively. dumb. --- requests/__init__.py | 31 +++++++++++++++++++++++++++++-- requests/core.py | 31 ------------------------------- 2 files changed, 29 insertions(+), 33 deletions(-) delete mode 100644 requests/core.py diff --git a/requests/__init__.py b/requests/__init__.py index 15a50506..e75db8df 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -1,4 +1,31 @@ # -*- coding: utf-8 -*- -from core import * -from core import __version__ +""" +requests.core +~~~~~~~~~~~~~ + +This module implements the main Requests system. + +:copyright: (c) 2011 by Kenneth Reitz. +:license: ISC, see LICENSE for more details. + +""" + +__title__ = 'requests' +__version__ = '0.6.6' +__build__ = 0x000606 +__author__ = 'Kenneth Reitz' +__license__ = 'ISC' +__copyright__ = 'Copyright 2011 Kenneth Reitz' + + +from . import utils +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, + InvalidMethod, TooManyRedirects +) diff --git a/requests/core.py b/requests/core.py deleted file mode 100644 index e75db8df..00000000 --- a/requests/core.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.core -~~~~~~~~~~~~~ - -This module implements the main Requests system. - -:copyright: (c) 2011 by Kenneth Reitz. -:license: ISC, see LICENSE for more details. - -""" - -__title__ = 'requests' -__version__ = '0.6.6' -__build__ = 0x000606 -__author__ = 'Kenneth Reitz' -__license__ = 'ISC' -__copyright__ = 'Copyright 2011 Kenneth Reitz' - - -from . import utils -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, - InvalidMethod, TooManyRedirects -) From 0e9d7aad2706d12d9fa27d90dfbdfc58d2adbf1b Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 19 Oct 2011 16:50:20 -0400 Subject: [PATCH 03/38] add back the ascii art --- requests/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/requests/__init__.py b/requests/__init__.py index e75db8df..b443c95e 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- -""" -requests.core -~~~~~~~~~~~~~ +# __ +# /__) _ _ _ _ _/ _ +# / ( (- (/ (/ (- _) / _) +# / -This module implements the main Requests system. +""" +requests +~~~~~~~~ :copyright: (c) 2011 by Kenneth Reitz. :license: ISC, see LICENSE for more details. From ad6a8d53d6ceb22ceb20afb2458b7977e01a9ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20M=C3=B6llerstrand?= Date: Thu, 20 Oct 2011 11:50:27 +0100 Subject: [PATCH 04/38] docs: fix pip-compared-to-easy-install url. --- docs/user/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/install.rst b/docs/user/install.rst index aef598dc..9100ac21 100644 --- a/docs/user/install.rst +++ b/docs/user/install.rst @@ -18,7 +18,7 @@ or, with `easy_install `_:: $ easy_install requests -But, you really `shouldn't do that `_. +But, you really `shouldn't do that `_. From 4f984b0fe66c0d47a9c34dbec1d035c1ac2ed897 Mon Sep 17 00:00:00 2001 From: Zbigniew Siciarz Date: Thu, 20 Oct 2011 17:37:16 +0200 Subject: [PATCH 05/38] New HTTP status codes (draft only). See IETF document at https://tools.ietf.org/html/draft-nottingham-http-new-status-02. --- requests/status_codes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requests/status_codes.py b/requests/status_codes.py index a809de6a..b49c3c13 100644 --- a/requests/status_codes.py +++ b/requests/status_codes.py @@ -56,6 +56,9 @@ _codes = { 424: ('failed_depdendency', 'depdendency'), 425: ('unordered_collection', 'unordered'), 426: ('upgrade_required', 'upgrade'), + 428: ('precondition_required', 'precondition'), + 429: ('too_many_requests', 'too_many'), + 431: ('header_fields_too_large', 'fields_too_large'), 444: ('no_response', 'none'), 449: ('retry_with', 'retry'), 450: ('blocked_by_windows_parental_controls', 'parental_controls'), From 194ff1ad891388794ce2e5af12c8d4e36df3cea0 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 20 Oct 2011 22:09:08 -0400 Subject: [PATCH 06/38] #160 --- requests/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/api.py b/requests/api.py index aba97998..41240f00 100644 --- a/requests/api.py +++ b/requests/api.py @@ -146,7 +146,7 @@ def patch(url, data='', **kwargs): :param **kwargs: Optional arguments that ``request`` takes. """ - return request('patch', url, **kwargs) + return request('patch', url, data='', **kwargs) def delete(url, **kwargs): From 348d2a2d51dd7b175f0c81fa408bd75f950092f9 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 20 Oct 2011 22:43:52 -0400 Subject: [PATCH 07/38] v0.6.7 initial history --- HISTORY.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 2bf6e11d..4ccec8e8 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,12 @@ History ------- +0.6.7 ++++++ + +* PATCH fix. + + 0.6.6 (2011-10-19) ++++++++++++++++++ From d63cd5f547963f428d88941b3b379cf450444ae0 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 20 Oct 2011 23:53:20 -0400 Subject: [PATCH 08/38] periods. --- HISTORY.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4ccec8e8..1c8398c3 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,7 +10,7 @@ History 0.6.6 (2011-10-19) ++++++++++++++++++ -* Session parameter bugfix (params merging) +* Session parameter bugfix (params merging). 0.6.5 (2011-10-18) @@ -24,10 +24,10 @@ History ++++++++++++++++++ * Automatic decoding of unicode, based on HTTP Headers. -* New ``decode_unicode`` setting -* Removal of ``r.read/close`` methods +* New ``decode_unicode`` setting. +* Removal of ``r.read/close`` methods. * New ``r.faw`` interface for advanced response usage.* -* Automatic expansion of parameterized headers +* Automatic expansion of parameterized headers. 0.6.3 (2011-10-13) @@ -39,7 +39,7 @@ History 0.6.2 (2011-10-09) ++++++++++++++++++ -* GET/HEAD obeys allow_redirects=False +* GET/HEAD obeys allow_redirects=False. 0.6.1 (2011-08-20) From ba5eddcf5e7b7fb6efd8f0809f95fda4fe2b6ce0 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 20 Oct 2011 23:53:25 -0400 Subject: [PATCH 09/38] WhitespaceBot --- docs/community/out-there.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/community/out-there.rst b/docs/community/out-there.rst index 2e7b4715..b1584423 100644 --- a/docs/community/out-there.rst +++ b/docs/community/out-there.rst @@ -6,7 +6,7 @@ Modules - `robotframework-requests `_, a Robot Framework API wrapper. - `fullerene `_, a Graphite Dashboard. - `urbanairship-python `_, a fork of the Urban Airship API wrapper. - +- `WhitespaceBot `_, a project that automatically forks repos, strips trailing whitespace, and sends a pull request. Articles & Talks ================ From 3a6d9b09dbb6cf7c279fd5f6ef9a51ebeeb905de Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 12:26:39 -0400 Subject: [PATCH 10/38] test improvements --- test_requests.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test_requests.py b/test_requests.py index a34e2338..188cbc09 100755 --- a/test_requests.py +++ b/test_requests.py @@ -8,6 +8,7 @@ import cookielib import os import unittest +import requests import envoy try: @@ -15,11 +16,10 @@ try: except ImportError: import json -import requests -from requests.sessions import Session -PORT = os.environ.get('HTTPBIN_PORT', '7045') +# TODO: Detect an open port. +PORT = os.environ.get('HTTPBIN_PORT', '7077') HTTPBIN_URL = 'http://0.0.0.0:%s/' % (PORT) # HTTPBIN_URL = 'http://127.0.0.1:8000/' @@ -442,7 +442,7 @@ class RequestsTestSuite(unittest.TestCase): def test_session_HTTP_200_OK_GET(self): - s = Session() + s = requests.session() r = s.get(httpbin('/get')) self.assertEqual(r.status_code, 200) @@ -451,7 +451,7 @@ class RequestsTestSuite(unittest.TestCase): heads = {'User-agent': 'Mozilla/5.0'} - s = Session() + s = requests.session() s.headers = heads # Make 2 requests from Session object, should send header both times @@ -472,7 +472,7 @@ class RequestsTestSuite(unittest.TestCase): params = {'a': 'a_test'} - s = Session() + s = requests.session() s.params = params # Make 2 requests from Session object, should send header both times From dbf70fc40fd0d05133bf93d0d43d1267650ccf78 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:00:26 -0400 Subject: [PATCH 11/38] All methods are valid now --- requests/__init__.py | 2 +- requests/exceptions.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/requests/__init__.py b/requests/__init__.py index b443c95e..630ce6a5 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -30,5 +30,5 @@ from .status_codes import codes from .config import settings from .exceptions import ( RequestException, AuthenticationError, Timeout, URLRequired, - InvalidMethod, TooManyRedirects + TooManyRedirects ) diff --git a/requests/exceptions.py b/requests/exceptions.py index 13305e50..e381e8cf 100644 --- a/requests/exceptions.py +++ b/requests/exceptions.py @@ -12,15 +12,12 @@ class RequestException(Exception): class AuthenticationError(RequestException): """The authentication credentials provided were invalid.""" - + class Timeout(RequestException): """The request timed out.""" class URLRequired(RequestException): """A valid URL is required to make a request.""" -class InvalidMethod(RequestException): - """An inappropriate method was attempted.""" - class TooManyRedirects(RequestException): """Too many redirects.""" From 77909f1d4999dcc988acdae043da406031dd5903 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:07:00 -0400 Subject: [PATCH 12/38] v0.6.7 --- HISTORY.rst | 2 ++ requests/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 1c8398c3..a0666c23 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,6 +4,8 @@ History 0.6.7 +++++ +* Sessions are now the primary interface. +* Deprecated InvalidMethodException. * PATCH fix. diff --git a/requests/__init__.py b/requests/__init__.py index 630ce6a5..2b25c9e2 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -15,8 +15,8 @@ requests """ __title__ = 'requests' -__version__ = '0.6.6' -__build__ = 0x000606 +__version__ = '0.6.7' +__build__ = 0x000607 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' From d552e6c8847fb1a32880f1a2912af9b472f0f40d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:07:14 -0400 Subject: [PATCH 13/38] pep8 all the things --- test_requests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_requests.py b/test_requests.py index 188cbc09..37d2a7d9 100755 --- a/test_requests.py +++ b/test_requests.py @@ -17,7 +17,6 @@ except ImportError: import json - # TODO: Detect an open port. PORT = os.environ.get('HTTPBIN_PORT', '7077') @@ -47,8 +46,9 @@ class RequestsTestSuite(unittest.TestCase): if not _httpbin: - self.httpbin = envoy.connect('gunicorn httpbin:app --bind=0.0.0.0:%s' % (PORT)) + c = envoy.connect('gunicorn httpbin:app --bind=0.0.0.0:%s' % (PORT)) + self.httpbin = c _httpbin = True time.sleep(1) From d72d1162142d1bf8b1b5711c664fbbd674f349d1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:10:18 -0400 Subject: [PATCH 14/38] Move request and get to session --- requests/api.py | 72 +++---------------------- requests/sessions.py | 123 ++++++++++++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 103 deletions(-) diff --git a/requests/api.py b/requests/api.py index 41240f00..b737cfe9 100644 --- a/requests/api.py +++ b/requests/api.py @@ -16,84 +16,24 @@ from .models import Request, Response, AuthObject from .status_codes import codes from .hooks import dispatch_hook from .utils import cookiejar_from_dict, header_expand - +from .sessions import session __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): - """Constructs and sends a :class:`Request `. - Returns :class:`Response ` object. - - :param method: method for the new :class:`Request` object. - :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`. - :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :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. - """ - - method = str(method).upper() - - if cookies is None: - cookies = {} - - cookies = cookiejar_from_dict(cookies) - - # Expand header values - if headers: - for k, v in headers.items() or {}: - headers[k] = header_expand(v) - - args = dict( - method = method, - url = url, - data = data, - params = params, - headers = headers, - cookiejar = cookies, - files = files, - auth = auth, - hooks = hooks, - timeout = timeout or config.settings.timeout, - allow_redirects = allow_redirects, - proxies = proxies or config.settings.proxies, + s = session() + return s.request( + method, url, params, data, headers, cookies, files, auth, + timeout, allow_redirects, proxies, hooks, return_response ) - # Arguments manipulation hook. - args = dispatch_hook('args', hooks, args) - - r = Request(**args) - - # Pre-request hook. - r = dispatch_hook('pre_request', hooks, r) - - # Don't send if asked nicely. - if not return_response: - return r - - # Send the HTTP Request. - r.send() - - # Post-request hook. - r = dispatch_hook('post_request', hooks, r) - - # Response manipulation hook. - r.response = dispatch_hook('response', hooks, r.response) - - return r.response def get(url, **kwargs): - """Sends a GET request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. diff --git a/requests/sessions.py b/requests/sessions.py index 64ef7b2f..0dc5e9d6 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -11,9 +11,10 @@ requests (cookies, auth, proxies). import cookielib -from . import api -from .utils import add_dict_to_cookiejar - +from . import config +from .models import Request +from .hooks import dispatch_hook +from .utils import add_dict_to_cookiejar, cookiejar_from_dict, header_expand def merge_kwargs(local_kwarg, default_kwarg): @@ -25,6 +26,9 @@ def merge_kwargs(local_kwarg, default_kwarg): if default_kwarg is None: return local_kwarg + if isinstance(local_kwarg, basestring): + return local_kwarg + if local_kwarg is None: return default_kwarg @@ -32,8 +36,6 @@ def merge_kwargs(local_kwarg, default_kwarg): if not hasattr(default_kwarg, 'items'): return local_kwarg - - # Update new values. kwargs = default_kwarg.copy() kwargs.update(local_kwarg) @@ -73,7 +75,7 @@ class Session(object): self.cookies = cookielib.FileCookieJar() # Map and wrap requests.api methods - self._map_api_methods() + # self._map_api_methods() def __repr__(self): @@ -85,48 +87,95 @@ class Session(object): def __exit__(self, *args): pass - def _map_api_methods(self): - """Reads each available method from requests.api and decorates - them with a wrapper, which inserts any instance-local attributes - (from __attrs__) that have been set, combining them with **kwargs. + 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): + + """Constructs and sends a :class:`Request `. + Returns :class:`Response ` object. + + :param method: method for the new :class:`Request` object. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`. + :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. + :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. + :param auth: (optional) AuthObject to enable Basic HTTP Auth. + :param timeout: (optional) Float describing the timeout of the request. + :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. """ - def pass_args(func): - def wrapper_func(*args, **kwargs): + method = str(method).upper() - # Argument collector. - _kwargs = {} + if cookies is None: + cookies = {} - # If a session request has a cookie_dict, inject the - # values into the existing CookieJar instead. - if isinstance(kwargs.get('cookies', None), dict): - kwargs['cookies'] = add_dict_to_cookiejar( - self.cookies, kwargs['cookies'] - ) + if isinstance(cookies, dict): + cookies = add_dict_to_cookiejar(self.cookies, cookies) - for attr in self.__attrs__: - # for attr in ['headers',]: - s_val = self.__dict__.get(attr) - r_val = kwargs.get(attr) + cookies = cookiejar_from_dict(cookies) - new_attr = merge_kwargs(r_val, s_val) + # Expand header values + if headers: + for k, v in headers.items() or {}: + headers[k] = header_expand(v) - # Skip attributes that were set to None. - if new_attr is not None: - _kwargs[attr] = new_attr + 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, + ) - # Make sure we didn't miss anything. - for (k, v) in kwargs.items(): - if k not in _kwargs: - _kwargs[k] = v + for attr in self.__attrs__: + session_val = getattr(self, attr, None) + local_val = args.get(attr) - return func(*args, **_kwargs) + args[attr] = merge_kwargs(local_val, session_val) - return wrapper_func + # Arguments manipulation hook. + args = dispatch_hook('args', hooks, args) - # Map and decorate each function available in requests.api - map(lambda fn: setattr(self, fn, pass_args(getattr(api, fn))), - api.__all__) + r = Request(**args) + + # Pre-request hook. + r = dispatch_hook('pre_request', hooks, r) + + # Don't send if asked nicely. + if not return_response: + return r + + # Send the HTTP Request. + r.send() + + # Post-request hook. + r = dispatch_hook('post_request', hooks, r) + + # Response manipulation hook. + r.response = dispatch_hook('response', hooks, r.response) + + return r.response + + def get(self, url, **kwargs): + """Sends a GET request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param **kwargs: Optional arguments that ``request`` takes. + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('GET', url, **kwargs) def session(**kwargs): From f269c6c89a1cf0b6368f58a6c2cc4d095d1f5239 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:10:47 -0400 Subject: [PATCH 15/38] cookiejar => cookies in models --- requests/models.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/requests/models.py b/requests/models.py index 3c952c25..d58e4ad8 100644 --- a/requests/models.py +++ b/requests/models.py @@ -24,7 +24,7 @@ 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 .status_codes import codes -from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects +from .exceptions import Timeout, URLRequired, TooManyRedirects REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved) @@ -38,7 +38,7 @@ class Request(object): def __init__(self, url=None, headers=dict(), files=None, method=None, data=dict(), - params=dict(), auth=None, cookiejar=None, timeout=None, redirect=False, + params=dict(), auth=None, cookies=None, timeout=None, redirect=False, allow_redirects=False, proxies=None, hooks=None): #: Float describes the timeout of the request. @@ -91,7 +91,7 @@ class Request(object): self.auth = auth #: CookieJar to attach to :class:`Request `. - self.cookiejar = cookiejar + self.cookies = cookies #: True if Request has been sent. self.sent = False @@ -132,8 +132,8 @@ class Request(object): _handlers = [] - if self.cookiejar is not None: - _handlers.append(urllib2.HTTPCookieProcessor(self.cookiejar)) + if self.cookies is not None: + _handlers.append(urllib2.HTTPCookieProcessor(self.cookies)) if self.auth: if not isinstance(self.auth.handler, @@ -191,8 +191,8 @@ class Request(object): response.headers = CaseInsensitiveDict(getattr(resp.info(), 'dict', None)) response.raw = resp - if self.cookiejar: - response.cookies = dict_from_cookiejar(self.cookiejar) + if self.cookies: + response.cookies = dict_from_cookiejar(self.cookies) except AttributeError: @@ -244,7 +244,7 @@ class Request(object): request = Request( url, self.headers, self.files, method, - self.data, self.params, self.auth, self.cookiejar, + self.data, self.params, self.auth, self.cookies, redirect=True ) request.send() @@ -364,8 +364,8 @@ class Request(object): # restore global timeout socket.setdefaulttimeout(old_timeout) - if self.cookiejar is not None: - self.cookiejar.extract_cookies(resp, req) + if self.cookies is not None: + self.cookies.extract_cookies(resp, req) except (urllib2.HTTPError, urllib2.URLError), why: if hasattr(why, 'reason'): From 597ace5718eb116819966213e8772458a9141c29 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:13:22 -0400 Subject: [PATCH 16/38] import cleanups --- requests/api.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/requests/api.py b/requests/api.py index b737cfe9..f44f35bf 100644 --- a/requests/api.py +++ b/requests/api.py @@ -11,11 +11,6 @@ This module implements the Requests API. """ -from . import config -from .models import Request, Response, AuthObject -from .status_codes import codes -from .hooks import dispatch_hook -from .utils import cookiejar_from_dict, header_expand from .sessions import session __all__ = ('request', 'get', 'head', 'post', 'patch', 'put', 'delete') @@ -40,7 +35,6 @@ def get(url, **kwargs): :param **kwargs: Optional arguments that ``request`` takes. """ - kwargs.setdefault('allow_redirects', True) return request('GET', url, **kwargs) From 2b3bd78685f9d30bf29e090b58f5aa1a3b799cdf Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:15:28 -0400 Subject: [PATCH 17/38] Add all methods to session --- requests/sessions.py | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/requests/sessions.py b/requests/sessions.py index 0dc5e9d6..1d130a34 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -167,6 +167,7 @@ class Session(object): return r.response + def get(self, url, **kwargs): """Sends a GET request. Returns :class:`Response` object. @@ -178,6 +179,61 @@ class Session(object): return self.request('GET', url, **kwargs) + def head(self, url, **kwargs): + """Sends a HEAD request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param **kwargs: Optional arguments that ``request`` takes. + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('HEAD', url, **kwargs) + + + def post(self, url, data='', **kwargs): + """Sends a POST request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. + :param **kwargs: Optional arguments that ``request`` takes. + """ + + return self.request('post', url, data=data, **kwargs) + + + def put(self, url, data='', **kwargs): + """Sends a PUT request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. + :param **kwargs: Optional arguments that ``request`` takes. + """ + + return self.request('put', url, data=data, **kwargs) + + + def patch(url, data='', **kwargs): + """Sends a PATCH request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. + :param **kwargs: Optional arguments that ``request`` takes. + """ + + return self.request('patch', url, data='', **kwargs) + + + def delete(self, url, **kwargs): + """Sends a DELETE request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param **kwargs: Optional arguments that ``request`` takes. + """ + + return self.request('delete', url, **kwargs) + + + def session(**kwargs): """Returns a :class:`Session` for context-management.""" From 4d97cc75069e532395d748ca9ff9b3aa2a8c9cb8 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:16:10 -0400 Subject: [PATCH 18/38] disable rudolf until it obeys --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8b49b27e..9500cb76 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ init: pip install -r reqs.txt test: - nosetests test_requests.py --with-color + nosetests test_requests.py ci: init nosetests test_requests.py --with-xunit --xunit-file=junit-report.xml From 98dc08236c51483130dfa59e1f74a01b31106a46 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 18:18:39 -0400 Subject: [PATCH 19/38] loose yourself --- requests/sessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/sessions.py b/requests/sessions.py index 1d130a34..d65d2c6b 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -212,7 +212,7 @@ class Session(object): return self.request('put', url, data=data, **kwargs) - def patch(url, data='', **kwargs): + def patch(self, url, data='', **kwargs): """Sends a PATCH request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. From 3d29f6535fb409e52369c8a6dfe8b76b5bb2bdc6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:27:08 -0400 Subject: [PATCH 20/38] kill wrapping of api methods --- requests/sessions.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/requests/sessions.py b/requests/sessions.py index d65d2c6b..26d0345f 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -74,10 +74,6 @@ class Session(object): # Set up a CookieJar to be used by default self.cookies = cookielib.FileCookieJar() - # Map and wrap requests.api methods - # self._map_api_methods() - - def __repr__(self): return '' % (id(self)) From e007a5a13f3234db499a83a10fa891125d77a3ff Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:27:44 -0400 Subject: [PATCH 21/38] docstring --- requests/exceptions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requests/exceptions.py b/requests/exceptions.py index e381e8cf..101d1ce6 100644 --- a/requests/exceptions.py +++ b/requests/exceptions.py @@ -2,7 +2,9 @@ """ requests.exceptions -~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. """ From 61be59d996eace1b958a189c98e0e3a4219aa1b0 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:34:03 -0400 Subject: [PATCH 22/38] show both session styles --- docs/user/advanced.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst index cc6dcb27..92dac5f3 100644 --- a/docs/user/advanced.rst +++ b/docs/user/advanced.rst @@ -17,13 +17,13 @@ A session object has all the methods of the main Requests API. Let's persist some cookies across requests:: - with requests.session() as s: + s = requests.session() - s.get('http://httpbin.org/cookies/set/sessioncookie/123456789') - r = s.get("http://httpbin.org/cookies") + s.get('http://httpbin.org/cookies/set/sessioncookie/123456789') + r = s.get("http://httpbin.org/cookies") - print r.content - # '{"cookies": {"sessioncookie": "123456789"}}' + print r.content + # '{"cookies": {"sessioncookie": "123456789"}}' Sessions can also be used to provide default data to the request methods:: From 958c424c89079239401c1fe236464178f0038760 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:39:23 -0400 Subject: [PATCH 23/38] I don't even want to know. --- test_requests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_requests.py b/test_requests.py index 37d2a7d9..6360e7ed 100755 --- a/test_requests.py +++ b/test_requests.py @@ -68,12 +68,12 @@ class RequestsTestSuite(unittest.TestCase): self.assertEqual(r.status_code, 200) def test_HTTP_302_ALLOW_REDIRECT_GET(self): - r = requests.get(httpbin('redirect', '1')) - self.assertEqual(r.status_code, 200) + r = requests.get(httpbin('redirect', '1')) + self.assertEqual(r.status_code, 200) def test_HTTP_302_GET(self): - r = requests.get(httpbin('redirect', '1'), allow_redirects=False) - self.assertEqual(r.status_code, 302) + r = requests.get(httpbin('redirect', '1'), allow_redirects=False) + self.assertEqual(r.status_code, 302) def test_HTTP_200_OK_GET_WITH_PARAMS(self): From 185450c5e116d3d614fe5ca717477d4251ca025e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:40:45 -0400 Subject: [PATCH 24/38] test entry points --- test_requests.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test_requests.py b/test_requests.py index 6360e7ed..f1211571 100755 --- a/test_requests.py +++ b/test_requests.py @@ -58,11 +58,23 @@ class RequestsTestSuite(unittest.TestCase): """Teardown.""" # self.httpbin.kill() + def test_entry_points(self): + import requests + + requests.session + requests.session().get + requests.session().head + requests.get + requests.head + requests.put + requests.patch + requests.post + + def test_invalid_url(self): self.assertRaises(ValueError, requests.get, 'hiwpefhipowhefopw') - def test_HTTP_200_OK_GET(self): r = requests.get(httpbin('/get')) self.assertEqual(r.status_code, 200) From ab3200b4cc1fd2bec915a47aafa48a9d1a4774ed Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 19:41:39 -0400 Subject: [PATCH 25/38] 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 26/38] _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 27/38] 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 28/38] 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 29/38] 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 30/38] 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 31/38] 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 32/38] 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 From 0ee6c1fa681dec4c9353d6ea719ae021f47e1bf8 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:55:46 -0400 Subject: [PATCH 33/38] kill accept_gzip config --- requests/defaults.py | 12 +----------- requests/models.py | 5 +---- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/requests/defaults.py b/requests/defaults.py index 72af0600..9aad9019 100644 --- a/requests/defaults.py +++ b/requests/defaults.py @@ -28,8 +28,6 @@ defaults['base_headers'] = { 'Accept-Encoding': ', '.join([ 'identity', 'deflate', 'compress', 'gzip' ]), } - -# defaults['accept_gzip'] = True defaults['proxies'] = {} defaults['verbose'] = None defaults['timeout'] = None @@ -37,12 +35,4 @@ 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() -# } +# defaults['max_connections'] = 10 \ No newline at end of file diff --git a/requests/models.py b/requests/models.py index ac235a75..5d78bdff 100644 --- a/requests/models.py +++ b/requests/models.py @@ -1,3 +1,4 @@ + # -*- coding: utf-8 -*- """ @@ -113,10 +114,6 @@ class Request(object): #: Event-handling hooks. self.hooks = hooks - # Header manipulation and defaults. - if self.config.get('accept_gzip'): - self.headers.update({'Accept-Encoding': 'gzip'}) - if headers: headers = CaseInsensitiveDict(self.headers) else: From 97e3c840845bfe7a10eb3ad4d7431fa7cb8a473d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 20:57:39 -0400 Subject: [PATCH 34/38] simplify the URL check --- requests/models.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/requests/models.py b/requests/models.py index 5d78bdff..b2142ea8 100644 --- a/requests/models.py +++ b/requests/models.py @@ -130,13 +130,6 @@ class Request(object): return '' % (self.method) - def _checks(self): - """Deterministic checks for consistency.""" - - if not self.url: - raise URLRequired - - def _get_opener(self): """Creates appropriate opener object for urllib2.""" @@ -328,7 +321,9 @@ class Request(object): already been sent. """ - self._checks() + # Some people... + if not self.url: + raise URLRequired # Logging if self.config.get('verbose'): From 302c4d9c4131dd075382152c7d33cfb6275156a4 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 21:01:45 -0400 Subject: [PATCH 35/38] Don't alter behavior for safe methods anymore. --- requests/models.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/requests/models.py b/requests/models.py index b2142ea8..65c047c5 100644 --- a/requests/models.py +++ b/requests/models.py @@ -332,22 +332,22 @@ class Request(object): )) + # Build the URL url = self._build_url() - if self.method in ('GET', 'HEAD', 'DELETE'): - req = _Request(url, method=self.method) + + + if self.files: + register_openers() + + if self.data: + self.files.update(self.data) + + datagen, headers = multipart_encode(self.files) + req = _Request(url, data=datagen, headers=headers, method=self.method) + else: + req = _Request(url, data=self._enc_data, method=self.method) - if self.files: - register_openers() - - if self.data: - self.files.update(self.data) - - datagen, headers = multipart_encode(self.files) - req = _Request(url, data=datagen, headers=headers, method=self.method) - - else: - req = _Request(url, data=self._enc_data, method=self.method) if self.headers: for k,v in self.headers.iteritems(): From a74568d8d5bc3cc47679261467485f944833cb93 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 21:10:24 -0400 Subject: [PATCH 36/38] simplify request dispatch flow --- requests/models.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/requests/models.py b/requests/models.py index 65c047c5..a6a2c01e 100644 --- a/requests/models.py +++ b/requests/models.py @@ -331,24 +331,27 @@ class Request(object): datetime.now().isoformat(), self.method, self.url )) - # Build the URL url = self._build_url() - + # Attach uploaded files. if self.files: register_openers() + # Add form-data to the multipart. if self.data: self.files.update(self.data) - datagen, headers = multipart_encode(self.files) - req = _Request(url, data=datagen, headers=headers, method=self.method) + data, headers = multipart_encode(self.files) else: - req = _Request(url, data=self._enc_data, method=self.method) + data = self._enc_data + headers = {} + # Build the Urllib2 Request. + req = _Request(url, data=data, headers=headers, method=self.method) + # Add the headers to the request. if self.headers: for k,v in self.headers.iteritems(): req.add_header(k, v) From b66871e87174f3ff7801e6935c9fc761db975855 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 21:30:47 -0400 Subject: [PATCH 37/38] v0.7.0 --- HISTORY.rst | 4 ++-- requests/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 79dad208..0db8550f 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,8 +1,8 @@ History ------- -0.6.7 -+++++ +0.7.0 (2011-10-22) +++++++++++++++++++ * Sessions are now the primary interface. * Deprecated InvalidMethodException. diff --git a/requests/__init__.py b/requests/__init__.py index 6cce5bfe..fdaaf068 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -15,8 +15,8 @@ requests """ __title__ = 'requests' -__version__ = '0.6.7' -__build__ = 0x000607 +__version__ = '0.7.0' +__build__ = 0x000700 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' From 1a4dfad52d4aa419e98d8b3d709704cecaf3f7ba Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 22 Oct 2011 21:33:00 -0400 Subject: [PATCH 38/38] mod string formatting for 2.5 --- requests/defaults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/defaults.py b/requests/defaults.py index 9aad9019..a5699765 100644 --- a/requests/defaults.py +++ b/requests/defaults.py @@ -24,7 +24,7 @@ defaults = dict() defaults['base_headers'] = { - 'User-Agent': 'python-requests/{0}'.format(__version__), + 'User-Agent': 'python-requests/%s' % __version__, 'Accept-Encoding': ', '.join([ 'identity', 'deflate', 'compress', 'gzip' ]), }