From d1c89333d05fbfefd2fa71e835164b59f40bc1e2 Mon Sep 17 00:00:00 2001 From: digitalxero Date: Sat, 19 Feb 2011 10:51:54 -0500 Subject: [PATCH] Remove the eventles code, this should live in requests.async or something so the user explicitly requests it Clean up the code to get rid of the unnecessary AuthObject class Cleanup the send method Cleanup the convenience methods by adding a request method that they all use. --- requests/core.py | 280 ++++++++++++++++------------------------------- test_requests.py | 26 ++--- 2 files changed, 103 insertions(+), 203 deletions(-) diff --git a/requests/core.py b/requests/core.py index 9292a9a..e511b84 100644 --- a/requests/core.py +++ b/requests/core.py @@ -13,26 +13,13 @@ from __future__ import absolute_import import urllib import urllib2 - from urllib2 import HTTPError -try: - import eventlet - eventlet.monkey_patch() -except ImportError: - pass - -if not 'eventlet' in locals(): - try: - from gevent import monkey - monkey.patch_all() - except ImportError: - pass - from .packages.poster.encode import multipart_encode from .packages.poster.streaminghttp import register_openers - +__all__ = ['Request', 'Response', 'request', 'get', 'head', 'post', 'put', 'delete', 'add_autoauth', 'AUTOAUTHS', + 'RequestException', 'AuthenticationError', 'URLRequired', 'InvalidMethod', 'HTTPError'] __title__ = 'requests' __version__ = '0.2.4' __build__ = 0x000204 @@ -43,13 +30,11 @@ __copyright__ = 'Copyright 2011 Kenneth Reitz' AUTOAUTHS = [] - - class _Request(urllib2.Request): """Hidden wrapper around the urllib2.Request object. Allows for manual setting of HTTP methods. """ - + def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None): urllib2.Request.__init__(self, url, data, headers, origin_req_host, unverifiable) @@ -66,61 +51,59 @@ class Request(object): """The :class:`Request` object. It carries out all functionality of Requests. Recommended interface is with the Requests functions. """ - + _METHODS = ('GET', 'HEAD', 'PUT', 'POST', 'DELETE') - + def __init__(self, url=None, headers=dict(), files=None, method=None, - params=dict(), data=dict(), auth=None, cookiejar=None): + data=dict(), auth=None, cookiejar=None): self.url = url self.headers = headers self.files = files self.method = method - self.params = params - self.data = data + + # url encode data if it's a dict + if isinstance(data, dict): + self.data = urllib.urlencode(data) + else: + self.data = data + self.response = Response() - + self.auth = auth self.cookiejar = cookiejar self.sent = False - - + def __repr__(self): return '' % (self.method) - - + def __setattr__(self, name, value): if (name == 'method') and (value): if not value in self._METHODS: raise InvalidMethod() - + object.__setattr__(self, name, value) - - + def _checks(self): """Deterministic checks for consistency.""" if not self.url: raise URLRequired - def _get_opener(self): """Creates appropriate opener object for urllib2.""" _handlers = [] if self.auth or self.cookiejar: - if self.auth: - authr = urllib2.HTTPPasswordMgrWithDefaultRealm() - authr.add_password(None, self.url, self.auth.username, self.auth.password) + authr.add_password(None, self.url, self.auth[0], self.auth[1]) auth_handler = urllib2.HTTPBasicAuthHandler(authr) _handlers.append(auth_handler) if self.cookiejar: - cookie_handler = urllib2.HTTPCookieProcessor(cookiejar) _handlers.append(cookie_handler) @@ -133,13 +116,13 @@ class Request(object): def _build_response(self, resp): """Build internal Response object from given response.""" - + self.response.status_code = resp.code self.response.headers = resp.info().dict self.response.content = resp.read() self.response.url = resp.url - + def send(self, anyway=False): """Sends the request. Returns True of successful, false if not. If there was an HTTPError during transmission, @@ -150,106 +133,44 @@ class Request(object): :param anyway: If True, request will be sent, even if it has already been sent. """ - self._checks() - success = False - if self.method in ('GET', 'HEAD', 'DELETE'): - if (not self.sent) or anyway: - - # url encode GET params if it's a dict - if isinstance(self.params, dict): - params = urllib.urlencode(self.params) - else: - params = self.params + req = _Request(("%s?%s" % (self.url, self.data)), method=self.method) + else: + if self.files: + register_openers() + datagen, headers = multipart_encode(self.files) + req = _Request(self.url, data=datagen, headers=headers, method=self.method) + else: + req = _Request(self.url, method=self.method) - req = _Request(("%s?%s" % (self.url, params)), method=self.method) + if self.data: + req.data = self.data - if self.headers: - req.headers = self.headers + if self.headers: + req.headers = self.headers + if not self.sent or anyway: + try: opener = self._get_opener() + resp = opener(req) + except urllib2.HTTPError, why: + self._build_response(why) + self.response.error = why + else: + self._build_response(resp) + self.response.ok = True + self.response.cached = False + else: + self.response.cached = True - try: - resp = opener(req) - self._build_response(resp) - self.response.ok = True - - except urllib2.HTTPError, why: - self._build_response(why) - self.response.error = why - - - elif self.method == 'PUT': - if (not self.sent) or anyway: - - if self.files: - register_openers() - datagen, headers = multipart_encode(self.files) - req = _Request(self.url, data=datagen, headers=headers, method='PUT') - - if self.headers: - req.headers.update(self.headers) - - else: - - req = _Request(self.url, method='PUT') - - if self.headers: - req.headers = self.headers - - req.data = self.data - - try: - opener = self._get_opener() - resp = opener(req) - - self._build_response(resp) - self.response.ok = True - - except urllib2.HTTPError, why: - self._build_response(why) - self.response.error = why - - - elif self.method == 'POST': - if (not self.sent) or anyway: - - if self.files: - register_openers() - datagen, headers = multipart_encode(self.files) - req = _Request(self.url, data=datagen, headers=headers, method='POST') - - if self.headers: - req.headers.update(self.headers) - - else: - req = _Request(self.url, method='POST') - req.headers = self.headers - - # url encode form data if it's a dict - if isinstance(self.data, dict): - req.data = urllib.urlencode(self.data) - else: - req.data = self.data - - try: - opener = self._get_opener() - resp = opener(req) - - self._build_response(resp) - self.response.ok = True - except urllib2.HTTPError, why: - self._build_response(why) - self.response.error = why - self.sent = self.response.ok - + return self.sent - + class Response(object): """The :class:`Request` object. All :class:`Request` objects contain a @@ -264,36 +185,41 @@ class Response(object): self.url = None self.ok = False self.error = None - + self.cached = False + def __repr__(self): return '' % (self.status_code) - + def __nonzero__(self): """Returns true if status_code is 'OK'.""" return not self.error - + def raise_for_status(self): """Raises stored HTTPError if one exists.""" if self.error: raise self.error - -class AuthObject(object): - """The :class:`AuthObject` is a simple HTTP Authentication token. When - given to a Requests function, it enables Basic HTTP Authentication for that - Request. You can also enable Authorization for domain realms with AutoAuth. - See AutoAuth for more details. - - :param username: Username to authenticate with. - :param password: Password for given username. +def request(method, url, **kwargs): + """Sends a `method` 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 of GET/HEAD/DELETE Parameters to send with the :class:`Request`. + :param data: (optional) Bytes/Dictionary of PUT/POST Data to send with the :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. + :param cookies: (optional) 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. """ - - def __init__(self, username, password): - self.username = username - self.password = password + data = kwargs.pop('data', {}) or kwargs.pop('params', {}) + r = Request(method=method, url=url, data=data, headers=kwargs.pop('headers', {}), + cookiejar=kwargs.pop('cookies', None), files=kwargs.pop('files', None), + auth=_detect_auth(url, kwargs.pop('auth', None))) + r.send() + return r.response def get(url, params={}, headers={}, cookies=None, auth=None): """Sends a GET request. Returns :class:`Response` object. @@ -304,12 +230,9 @@ def get(url, params={}, headers={}, cookies=None, auth=None): :param cookies: (optional) CookieJar object to send with the :class:`Request`. :param auth: (optional) AuthObject to enable Basic HTTP Auth. """ - - r = Request(method='GET', url=url, params=params, headers=headers, - cookiejar=cookies, auth=_detect_auth(url, auth)) - r.send() - - return r.response + + return request('GET', url, params=params, headers=headers, cookiejar=cookies, + auth=_detect_auth(url, auth)) def head(url, params={}, headers={}, cookies=None, auth=None): @@ -321,64 +244,53 @@ def head(url, params={}, headers={}, cookies=None, auth=None): :param cookies: (optional) CookieJar object to send with the :class:`Request`. :param auth: (optional) AuthObject to enable Basic HTTP Auth. """ - r = Request(method='HEAD', url=url, params=params, headers=headers, - cookiejar=cookies, auth=_detect_auth(url, auth)) - r.send() - - return r.response + + return request('HEAD', url, params=params, headers=headers, cookiejar=cookies, + auth=_detect_auth(url, auth)) def post(url, data={}, headers={}, files=None, cookies=None, auth=None): """Sends a POST request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary of POST Data to send with the :class:`Request`. + :param data: (optional) Dictionary of POST data to send with the :class:`Request`. :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. :param cookies: (optional) CookieJar object to send with the :class:`Request`. :param auth: (optional) AuthObject to enable Basic HTTP Auth. """ - - r = Request(method='POST', url=url, data=data, headers=headers, - files=files, cookiejar=cookies, auth=_detect_auth(url, auth)) - r.send() - - return r.response - - -def put(url, data='', headers={}, files={}, cookies=None, auth=None): + + return request('POST', url, data=data, headers=headers, files=files, cookiejar=cookies, + auth=_detect_auth(url, auth)) + + +def put(url, data=b'', headers={}, files={}, cookies=None, auth=None): """Sends a PUT request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param data: (optional) Bytes of PUT Data to send with the :class:`Request`. + :param params: (optional) Bytes of PUT Data to send with the :class:`Request`. :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. :param cookies: (optional) CookieJar object to send with the :class:`Request`. :param auth: (optional) AuthObject to enable Basic HTTP Auth. """ - r = Request(method='PUT', url=url, data=data, headers=headers, files=files, - cookiejar=cookies, auth=_detect_auth(url, auth)) - r.send() - - return r.response + return request('PUT', url, data=data, headers=headers, files=files, cookiejar=cookies, + auth=_detect_auth(url, auth)) + - def delete(url, params={}, headers={}, cookies=None, auth=None): """Sends a DELETE request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary of GET Parameters to send with the :class:`Request`. + :param params: (optional) Dictionary of DELETE Parameters to send with the :class:`Request`. :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. :param cookies: (optional) CookieJar object to send with the :class:`Request`. :param auth: (optional) AuthObject to enable Basic HTTP Auth. """ - - r = Request(method='DELETE', url=url, params=params, headers=headers, - cookiejar=cookies, auth=_detect_auth(url, auth)) - r.send() - - return r.response + + return request('DELETE', url, params=params, headers=headers, cookiejar=cookies, + auth=_detect_auth(url, auth)) def add_autoauth(url, authobject): @@ -398,7 +310,7 @@ def add_autoauth(url, authobject): """ global AUTOAUTHS - + AUTOAUTHS.append((url, authobject)) @@ -409,14 +321,14 @@ def _detect_auth(url, auth): return _get_autoauth(url) if not auth else auth - + def _get_autoauth(url): """Returns registered AuthObject for given url if available.""" - + for (autoauth_url, auth) in AUTOAUTHS: - if autoauth_url in url: + if autoauth_url in url: return auth - + return None @@ -426,9 +338,9 @@ class RequestException(Exception): class AuthenticationError(RequestException): """The authentication credentials provided were invalid.""" - + class URLRequired(RequestException): """A valid URL is required to make a request.""" - + class InvalidMethod(RequestException): """An inappropriate method was attempted.""" diff --git a/test_requests.py b/test_requests.py index e365c6e..7ea6798 100644 --- a/test_requests.py +++ b/test_requests.py @@ -8,46 +8,40 @@ import requests class RequestsTestSuite(unittest.TestCase): """Requests test cases.""" - + def setUp(self): pass def tearDown(self): """Teardown.""" pass - + def test_invalid_url(self): self.assertRaises(ValueError, requests.get, 'hiwpefhipowhefopw') - def test_HTTP_200_OK_GET(self): r = requests.get('http://google.com') self.assertEqual(r.status_code, 200) - def test_HTTPS_200_OK_GET(self): r = requests.get('https://google.com') self.assertEqual(r.status_code, 200) - def test_HTTP_200_OK_HEAD(self): r = requests.head('http://google.com') self.assertEqual(r.status_code, 200) - def test_HTTPS_200_OK_HEAD(self): r = requests.head('https://google.com') self.assertEqual(r.status_code, 200) - def test_AUTH_HTTPS_200_OK_GET(self): - auth = requests.AuthObject('requeststest', 'requeststest') + auth = ('requeststest', 'requeststest') url = 'https://convore.com/api/account/verify.json' r = requests.get(url, auth=auth) self.assertEqual(r.status_code, 200) - requests.add_autoauth(url, auth) r = requests.get(url) @@ -56,33 +50,27 @@ class RequestsTestSuite(unittest.TestCase): # reset auto authentication requests.AUTOAUTHS = [] - - def test_POSTBIN_GET_POST_FILES(self): - - bin = requests.post('http://www.postbin.org/') + bin = requests.get('http://www.postbin.org/') self.assertEqual(bin.status_code, 200) post = requests.post(bin.url, data={'some': 'data'}) - self.assertEqual(post.status_code, 201) + self.assertEqual(post.status_code, 200) post2 = requests.post(bin.url, files={'some': open('test_requests.py')}) - self.assertEqual(post2.status_code, 201) - + self.assertEqual(post2.status_code, 200) def test_nonzero_evaluation(self): r = requests.get('http://google.com/some-404-url') self.assertEqual(bool(r), False) - + r = requests.get('http://google.com/') self.assertEqual(bool(r), True) - def test_request_ok_set(self): r = requests.get('http://google.com/some-404-url') self.assertEqual(r.ok, False) - def test_status_raising(self): r = requests.get('http://google.com/some-404-url') self.assertRaises(requests.HTTPError, r.raise_for_status) -- 2.34.1