Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fec0d1a9a0 | ||
|
|
642c667566 | ||
|
|
b8b87d416e | ||
|
|
6e14d4704d | ||
|
|
f494cd9c72 | ||
|
|
2814664e91 | ||
|
|
1359094cc8 | ||
|
|
7a62b10ff2 | ||
|
|
23d5761bd4 | ||
|
|
cc16073c36 | ||
|
|
ed8ff63048 | ||
|
|
267a852ba6 | ||
|
|
f2b04f94ca | ||
|
|
e350bea167 | ||
|
|
2401f14975 | ||
|
|
be228043a1 | ||
|
|
48ffb627fe | ||
|
|
89192c64f0 | ||
|
|
a67cc5c5a9 | ||
|
|
fa2f1c5f60 | ||
|
|
1d021c5cc1 | ||
|
|
e17111a5dd | ||
|
|
9fdee250de | ||
|
|
c6acfef3d0 | ||
|
|
e4c690e7bc | ||
|
|
ee43ad2497 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,4 +2,5 @@
|
||||
MANIFEST
|
||||
coverage.xml
|
||||
nosetests.xml
|
||||
pylint.txt
|
||||
pylint.txt
|
||||
*.pyc
|
||||
|
||||
5
AUTHORS
5
AUTHORS
@@ -13,4 +13,7 @@ Patches and Suggestions
|
||||
- Various Pocoo Members
|
||||
- Chris Adams
|
||||
- Flavio Percoco Premoli
|
||||
- Dj Gilcrease
|
||||
- Dj Gilcrease
|
||||
- Justin Murphy
|
||||
- Rob Madole
|
||||
- Aram Dulyan
|
||||
|
||||
15
HISTORY.rst
15
HISTORY.rst
@@ -1,6 +1,21 @@
|
||||
History
|
||||
-------
|
||||
|
||||
0.3.2 (2011-04-15)
|
||||
++++++++++++++++++
|
||||
|
||||
* Automatic Decompression of GZip Encoded Content
|
||||
* AutoAuth Support for Tupled HTTP Auth
|
||||
|
||||
|
||||
0.3.1 (2011-04-01)
|
||||
++++++++++++++++++
|
||||
|
||||
* Cookie Changes
|
||||
* Response.read()
|
||||
* Poster fix
|
||||
|
||||
|
||||
0.3.0 (2011-02-25)
|
||||
++++++++++++++++++
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@ copyright = u'2011, Kenneth Reitz'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.2.0'
|
||||
version = '0.3.2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.2.0'
|
||||
release = version
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
105
requests/core.py
105
requests/core.py
@@ -14,6 +14,7 @@ from __future__ import absolute_import
|
||||
|
||||
import urllib
|
||||
import urllib2
|
||||
import zlib
|
||||
|
||||
from urllib2 import HTTPError
|
||||
from urlparse import urlparse
|
||||
@@ -24,15 +25,15 @@ from .packages.poster.streaminghttp import register_openers, get_handlers
|
||||
|
||||
|
||||
__title__ = 'requests'
|
||||
__version__ = '0.3.0'
|
||||
__build__ = 0x000300
|
||||
__version__ = '0.3.2'
|
||||
__build__ = 0x000302
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = 'Copyright 2011 Kenneth Reitz'
|
||||
|
||||
__all__ = [
|
||||
'Request', 'Response', 'request', 'get', 'head', 'post', 'put', 'delete',
|
||||
'auth_manager', 'AuthObject','RequestException', 'AuthenticationError',
|
||||
'Request', 'Response', 'request', 'get', 'head', 'post', 'put', 'delete',
|
||||
'auth_manager', 'AuthObject','RequestException', 'AuthenticationError',
|
||||
'URLRequired', 'InvalidMethod', 'HTTPError'
|
||||
]
|
||||
|
||||
@@ -63,7 +64,7 @@ class Request(object):
|
||||
|
||||
def __init__(self, url=None, headers=dict(), files=None, method=None,
|
||||
data=dict(), auth=None, cookiejar=None):
|
||||
|
||||
|
||||
self.url = url
|
||||
self.headers = headers
|
||||
self.files = files
|
||||
@@ -111,6 +112,9 @@ class Request(object):
|
||||
|
||||
_handlers = []
|
||||
|
||||
if self.cookiejar is not None:
|
||||
_handlers.append(urllib2.HTTPCookieProcessor(self.cookiejar))
|
||||
|
||||
if self.auth:
|
||||
if not isinstance(self.auth.handler, (urllib2.AbstractBasicAuthHandler, urllib2.AbstractDigestAuthHandler)):
|
||||
auth_manager.add_password(self.auth.realm, self.url, self.auth.username, self.auth.password)
|
||||
@@ -119,26 +123,42 @@ class Request(object):
|
||||
|
||||
_handlers.append(self.auth.handler)
|
||||
|
||||
_handlers.extend(get_handlers())
|
||||
opener = urllib2.build_opener(*_handlers)
|
||||
return opener.open
|
||||
else:
|
||||
if not _handlers:
|
||||
return urllib2.urlopen
|
||||
|
||||
_handlers.extend(get_handlers())
|
||||
opener = urllib2.build_opener(*_handlers)
|
||||
|
||||
if self.headers:
|
||||
# Allow default headers in the opener to be overloaded
|
||||
normal_keys = [k.capitalize() for k in self.headers]
|
||||
for key, val in opener.addheaders[:]:
|
||||
if key not in normal_keys:
|
||||
continue
|
||||
# Remove it, we have a value to take its place
|
||||
opener.addheaders.remove((key, val))
|
||||
|
||||
return opener.open
|
||||
|
||||
def _build_response(self, resp):
|
||||
"""Build internal Response object from given response."""
|
||||
|
||||
|
||||
self.response.status_code = getattr(resp, 'code', None)
|
||||
self.response.headers = getattr(resp.info(), 'dict', None)
|
||||
self.response.url = getattr(resp, 'url', None)
|
||||
self.response.content = resp.read()
|
||||
|
||||
if self.response.headers.get('content-encoding', None) == 'gzip':
|
||||
try:
|
||||
self.response.content = zlib.decompress(self.response.content, 16+zlib.MAX_WBITS)
|
||||
except zlib.error:
|
||||
pass
|
||||
|
||||
self.response.url = getattr(resp, 'url', None)
|
||||
|
||||
@staticmethod
|
||||
def _build_url(url, data):
|
||||
"""Build URLs."""
|
||||
|
||||
|
||||
if urlparse(url).query:
|
||||
return '%s&%s' % (url, data)
|
||||
else:
|
||||
@@ -147,7 +167,6 @@ class Request(object):
|
||||
else:
|
||||
return url
|
||||
|
||||
|
||||
def send(self, anyway=False):
|
||||
"""Sends the request. Returns True of successful, false if not.
|
||||
If there was an HTTPError during transmission,
|
||||
@@ -170,20 +189,24 @@ class Request(object):
|
||||
|
||||
if self.data:
|
||||
self.files.update(self.data)
|
||||
|
||||
|
||||
datagen, headers = multipart_encode(self.files)
|
||||
req = _Request(self.url, data=datagen, headers=headers, method=self.method)
|
||||
|
||||
|
||||
else:
|
||||
req = _Request(self.url, data=self._enc_data, method=self.method)
|
||||
|
||||
if self.headers:
|
||||
req.headers = self.headers
|
||||
req.headers.update(self.headers)
|
||||
|
||||
if not self.sent or anyway:
|
||||
try:
|
||||
opener = self._get_opener()
|
||||
resp = opener(req)
|
||||
resp = opener(req)
|
||||
|
||||
if self.cookiejar is not None:
|
||||
self.cookiejar.extract_cookies(resp, req)
|
||||
|
||||
except urllib2.HTTPError, why:
|
||||
self._build_response(why)
|
||||
self.response.error = why
|
||||
@@ -195,13 +218,14 @@ class Request(object):
|
||||
else:
|
||||
self.response.cached = True
|
||||
|
||||
|
||||
self.sent = self.response.ok
|
||||
|
||||
return self.sent
|
||||
|
||||
|
||||
|
||||
def read(self, *args):
|
||||
return self.response.read()
|
||||
|
||||
class Response(object):
|
||||
"""The :class:`Request` object. All :class:`Request` objects contain a
|
||||
:class:`Request.response <response>` attribute, which is an instance of
|
||||
@@ -232,11 +256,13 @@ class Response(object):
|
||||
if self.error:
|
||||
raise self.error
|
||||
|
||||
def read(self, *args):
|
||||
return self.content
|
||||
|
||||
|
||||
class AuthManager(object):
|
||||
"""Authentication Manager."""
|
||||
|
||||
|
||||
def __new__(cls):
|
||||
singleton = cls.__dict__.get('__singleton__')
|
||||
if singleton is not None:
|
||||
@@ -258,8 +284,16 @@ class AuthManager(object):
|
||||
|
||||
def add_auth(self, uri, auth):
|
||||
"""Registers AuthObject to AuthManager."""
|
||||
|
||||
|
||||
uri = self.reduce_uri(uri, False)
|
||||
|
||||
# try to make it an AuthObject
|
||||
if not isinstance(auth, AuthObject):
|
||||
try:
|
||||
auth = AuthObject(*auth)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
self._auth[uri] = auth
|
||||
|
||||
def add_password(self, realm, uri, user, passwd):
|
||||
@@ -267,9 +301,9 @@ class AuthManager(object):
|
||||
# uri could be a single URI or a sequence
|
||||
if isinstance(uri, basestring):
|
||||
uri = [uri]
|
||||
|
||||
|
||||
reduced_uri = tuple([self.reduce_uri(u, False) for u in uri])
|
||||
|
||||
|
||||
if reduced_uri not in self.passwd:
|
||||
self.passwd[reduced_uri] = {}
|
||||
self.passwd[reduced_uri] = (user, passwd)
|
||||
@@ -286,8 +320,14 @@ class AuthManager(object):
|
||||
|
||||
|
||||
def get_auth(self, uri):
|
||||
uri = self.reduce_uri(uri, False)
|
||||
return self._auth.get(uri, None)
|
||||
(in_domain, in_path) = self.reduce_uri(uri, False)
|
||||
|
||||
for domain, path, authority in (
|
||||
(i[0][0], i[0][1], i[1]) for i in self._auth.iteritems()
|
||||
):
|
||||
if in_domain == domain:
|
||||
if path in in_path:
|
||||
return authority
|
||||
|
||||
|
||||
def reduce_uri(self, uri, default_port=True):
|
||||
@@ -311,9 +351,10 @@ class AuthManager(object):
|
||||
}.get(scheme)
|
||||
if dport is not None:
|
||||
authority = "%s:%d" % (host, dport)
|
||||
|
||||
return authority, path
|
||||
|
||||
|
||||
|
||||
def is_suburi(self, base, test):
|
||||
"""Check if test is below base in a URI tree
|
||||
|
||||
@@ -422,8 +463,8 @@ 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.
|
||||
"""
|
||||
|
||||
return request('GET', url, params=params, headers=headers, cookiejar=cookies, auth=auth)
|
||||
|
||||
return request('GET', url, params=params, headers=headers, cookies=cookies, auth=auth)
|
||||
|
||||
|
||||
def head(url, params={}, headers={}, cookies=None, auth=None):
|
||||
@@ -436,7 +477,7 @@ def head(url, params={}, headers={}, cookies=None, auth=None):
|
||||
:param auth: (optional) AuthObject to enable Basic HTTP Auth.
|
||||
"""
|
||||
|
||||
return request('HEAD', url, params=params, headers=headers, cookiejar=cookies, auth=auth)
|
||||
return request('HEAD', url, params=params, headers=headers, cookies=cookies, auth=auth)
|
||||
|
||||
|
||||
def post(url, data={}, headers={}, files=None, cookies=None, auth=None):
|
||||
@@ -450,7 +491,7 @@ def post(url, data={}, headers={}, files=None, cookies=None, auth=None):
|
||||
:param auth: (optional) AuthObject to enable Basic HTTP Auth.
|
||||
"""
|
||||
|
||||
return request('POST', url, data=data, headers=headers, files=files, cookiejar=cookies, auth=auth)
|
||||
return request('POST', url, data=data, headers=headers, files=files, cookies=cookies, auth=auth)
|
||||
|
||||
|
||||
def put(url, data='', headers={}, files={}, cookies=None, auth=None):
|
||||
@@ -464,7 +505,7 @@ def put(url, data='', headers={}, files={}, cookies=None, auth=None):
|
||||
:param auth: (optional) AuthObject to enable Basic HTTP Auth.
|
||||
"""
|
||||
|
||||
return request('PUT', url, data=data, headers=headers, files=files, cookiejar=cookies, auth=auth)
|
||||
return request('PUT', url, data=data, headers=headers, files=files, cookies=cookies, auth=auth)
|
||||
|
||||
|
||||
def delete(url, params={}, headers={}, cookies=None, auth=None):
|
||||
@@ -477,7 +518,7 @@ def delete(url, params={}, headers={}, cookies=None, auth=None):
|
||||
:param auth: (optional) AuthObject to enable Basic HTTP Auth.
|
||||
"""
|
||||
|
||||
return request('DELETE', url, params=params, headers=headers, cookiejar=cookies, auth=auth)
|
||||
return request('DELETE', url, params=params, headers=headers, cookies=cookies, auth=auth)
|
||||
|
||||
|
||||
|
||||
|
||||
7
setup.py
7
setup.py
@@ -8,7 +8,7 @@ import requests
|
||||
from distutils.core import setup
|
||||
|
||||
|
||||
|
||||
|
||||
if sys.argv[-1] == "publish":
|
||||
os.system("python setup.py sdist upload")
|
||||
sys.exit()
|
||||
@@ -16,10 +16,11 @@ if sys.argv[-1] == "publish":
|
||||
if sys.argv[-1] == "test":
|
||||
os.system("python test_requests.py")
|
||||
sys.exit()
|
||||
|
||||
|
||||
required = []
|
||||
|
||||
# if python > 2.6, require simplejson
|
||||
if sys.version_info[:2] < (2,6):
|
||||
required.append('simplejson')
|
||||
|
||||
setup(
|
||||
name='requests',
|
||||
|
||||
63
test_requests.py
Normal file → Executable file
63
test_requests.py
Normal file → Executable file
@@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
import cookielib
|
||||
|
||||
import requests
|
||||
|
||||
@@ -28,20 +29,25 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_HTTP_200_OK_GET_WITH_PARAMS(self):
|
||||
|
||||
heads = {'User-agent': 'Mozilla/5.0'}
|
||||
|
||||
|
||||
r = requests.get('http://www.google.com/search', params={'q': 'test'}, headers=heads)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_HTTP_200_OK_GET_WITH_MIXED_PARAMS(self):
|
||||
|
||||
heads = {'User-agent': 'Mozilla/5.0'}
|
||||
|
||||
r = requests.get('http://google.com/search?test=true', params={'q': 'test'}, headers=heads)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_user_agent_transfers(self):
|
||||
"""Issue XX"""
|
||||
heads = {'User-agent':
|
||||
'Mozilla/5.0 (github.com/kennethreitz/requests)'}
|
||||
|
||||
r = requests.get('http://whatsmyua.com', headers=heads);
|
||||
self.assertTrue(heads['User-agent'] in r.content)
|
||||
|
||||
def test_HTTP_200_OK_HEAD(self):
|
||||
r = requests.head('http://google.com')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
@@ -64,11 +70,9 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
requests.auth_manager.empty()
|
||||
|
||||
def test_POSTBIN_GET_POST_FILES(self):
|
||||
|
||||
bin = requests.post('http://www.postbin.org/')
|
||||
print bin.url
|
||||
self.assertEqual(bin.status_code, 200)
|
||||
|
||||
|
||||
post = requests.post(bin.url, data={'some': 'data'})
|
||||
self.assertEqual(post.status_code, 201)
|
||||
|
||||
@@ -76,35 +80,64 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
self.assertEqual(post2.status_code, 201)
|
||||
|
||||
def test_POSTBIN_GET_POST_FILES_WITH_PARAMS(self):
|
||||
|
||||
bin = requests.post('http://www.postbin.org/')
|
||||
|
||||
|
||||
self.assertEqual(bin.status_code, 200)
|
||||
|
||||
post2 = requests.post(bin.url, files={'some': open('test_requests.py')}, data={'some': 'data'})
|
||||
self.assertEqual(post2.status_code, 201)
|
||||
|
||||
|
||||
def test_POSTBIN_GET_POST_FILES_WITH_HEADERS(self):
|
||||
bin = requests.post('http://www.postbin.org/')
|
||||
self.assertEqual(bin.status_code, 200)
|
||||
|
||||
post2 = requests.post(bin.url, files={'some': open('test_requests.py')},
|
||||
headers={'User-Agent': 'requests-tests'})
|
||||
|
||||
self.assertEqual(post2.status_code, 201)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
r = requests.get('http://google.com/')
|
||||
self.assertFalse(r.error)
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
def test_cookie_jar(self):
|
||||
"""
|
||||
.. todo:: This really doesn't test to make sure the cookie is working
|
||||
"""
|
||||
jar = cookielib.CookieJar()
|
||||
self.assertFalse(jar)
|
||||
|
||||
requests.get('http://google.com', cookies=jar)
|
||||
self.assertTrue(jar)
|
||||
|
||||
def test_decompress_gzip(self):
|
||||
|
||||
r = requests.get('http://api.stackoverflow.com/1.1/users/495995/top-answer-tags')
|
||||
r.content.decode('ascii')
|
||||
|
||||
def test_autoauth(self):
|
||||
|
||||
conv_auth = ('requeststest', 'requeststest')
|
||||
requests.auth_manager.add_auth('convore.com', conv_auth)
|
||||
|
||||
r = requests.get('https://convore.com/api/account/verify.json')
|
||||
self.assertEquals(r.status_code, 200)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user