mirror of
https://github.com/kennethreitz/requests.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'develop'
This commit is contained in:
@@ -7,3 +7,4 @@ pylint.txt
|
||||
docs/_build
|
||||
toy.py
|
||||
.gitignore
|
||||
junit-report.xml
|
||||
@@ -1,6 +1,13 @@
|
||||
History
|
||||
-------
|
||||
|
||||
0.6.5 (2011-10-19)
|
||||
++++++++++++++++++
|
||||
|
||||
* Offline (fast) test suite.
|
||||
* Session dictionary argument merging.
|
||||
|
||||
|
||||
0.6.4 (2011-10-13)
|
||||
++++++++++++++++++
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@ init:
|
||||
pip install -r reqs.txt
|
||||
|
||||
test:
|
||||
nosetests test_requests.py --processes=30
|
||||
nosetests test_requests.py --with-color
|
||||
|
||||
ci: init
|
||||
nosetests --search-test --processes=30 --with-nosexunit test_requests.py
|
||||
nosetests test_requests.py --with-xunit --xunit-file=junit-report.xml
|
||||
|
||||
stats:
|
||||
pyflakes requests | awk -F\: '{printf "%s:%s: [E]%s\n", $1, $2, $3}' > violations.pyflakes.txt
|
||||
|
||||
site:
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
Modules
|
||||
=======
|
||||
|
||||
- `requests-oauth-hook <https://github.com/maraujop/requests-oauth-hook>`_, adds OAuth support to Requests.
|
||||
- `FacePy <https://github.com/jgorset/facepy>`_, a Python wrapper to the Facebook API.
|
||||
- `robotframework-requests <https://github.com/bulkan/robotframework-requests>`_, a Robot Framework API wrapper.
|
||||
- `fullerene <https://github.com/bitprophet/fullerene>`_, a Graphite Dashboard.
|
||||
- `urbanairship-python <https://github.com/benjaminws/urbanairship-python>`_, a fork of the Urban Airship API wrapper.
|
||||
|
||||
|
||||
Articles & Talks
|
||||
================
|
||||
- `Python for the Web <http://gun.io/blog/python-for-the-web/>`_ teaches how to use Python to interact with the web, using Requests.
|
||||
- `Daniel Greenfield's Review of Requests <http://pydanny.blogspot.com/2011/05/python-http-requests-for-humans.html>`_
|
||||
- `My 'Python for Humans' talk <http://python-for-humans.heroku.com>`_ ( `audio <http://codeconf.s3.amazonaws.com/2011/pycodeconf/talks/PyCodeConf2011%20-%20Kenneth%20Reitz.m4a>`_ )
|
||||
- `Issac Kelly's 'Consuming Web APIs' talk <http://issackelly.github.com/Consuming-Web-APIs-with-Python-Talk/slides/slides.html>`_
|
||||
- `Blog post about Requests via Yum <http://arunsag.wordpress.com/2011/08/17/new-package-python-requests-http-for-humans/>`_
|
||||
- `Russian blog post introducing Requests <http://habrahabr.ru/blogs/python/126262/>`_
|
||||
|
||||
|
||||
Integrations
|
||||
============
|
||||
|
||||
ScraperWiki
|
||||
------------
|
||||
|
||||
`ScraperWiki <https://scraperwiki.com/>`_ is an excellent service that allows
|
||||
you to run Python, Ruby, and PHP scraper scripts on the web. Now, Requests
|
||||
v0.6.1 is available to use in your scrapers!
|
||||
|
||||
To give it a try, simply::
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
Managed Packages
|
||||
================
|
||||
|
||||
Requests is available in a number of popular package formats. Of course,
|
||||
the ideal way to install Requests is via The Cheeseshop.
|
||||
|
||||
|
||||
Ubuntu & Debian
|
||||
---------------
|
||||
|
||||
Requests is available installed as a Debian package! Debian Etch Ubuntu, since Oneiric::
|
||||
|
||||
$ apt-get install python-requests
|
||||
|
||||
Unfortunately, the most recent version available is v0.5.0. If you're on the
|
||||
Debian Python Package team, I'd love an update of that :)
|
||||
|
||||
|
||||
Fedora and RedHat
|
||||
-----------------
|
||||
|
||||
You can easily install Requests v0.6.1 with yum on rpm-based systems::
|
||||
|
||||
$ yum install python-requests
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ Requests ecosystem and community.
|
||||
:maxdepth: 2
|
||||
|
||||
community/faq
|
||||
community/out-there.rst
|
||||
community/support
|
||||
community/updates
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
envoy==0.0.2
|
||||
httpbin==0.0.4
|
||||
gunicorn
|
||||
nose
|
||||
pyflakes
|
||||
omnijson
|
||||
rudolf
|
||||
+2
-2
@@ -12,8 +12,8 @@ This module implements the main Requests system.
|
||||
"""
|
||||
|
||||
__title__ = 'requests'
|
||||
__version__ = '0.6.4'
|
||||
__build__ = 0x000604
|
||||
__version__ = '0.6.5'
|
||||
__build__ = 0x000605
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = 'Copyright 2011 Kenneth Reitz'
|
||||
|
||||
+65
-16
@@ -16,21 +16,60 @@ from .utils import add_dict_to_cookiejar
|
||||
|
||||
|
||||
|
||||
def merge_kwargs(local_kwarg, default_kwarg):
|
||||
"""Merges kwarg dictionaries.
|
||||
|
||||
If a local key in the dictionary is set to None, it will be removed.
|
||||
"""
|
||||
|
||||
if default_kwarg is None:
|
||||
return local_kwarg
|
||||
|
||||
if local_kwarg is None:
|
||||
return default_kwarg
|
||||
|
||||
# Bypass if not a dictionary (e.g. timeout)
|
||||
if not hasattr(default_kwarg, 'items'):
|
||||
return local_kwarg
|
||||
|
||||
|
||||
|
||||
# Update new values.
|
||||
kwargs = default_kwarg.copy()
|
||||
kwargs.update(local_kwarg)
|
||||
|
||||
# Remove keys that are set to None.
|
||||
for (k,v) in local_kwarg.items():
|
||||
if v is None:
|
||||
del kwargs[k]
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
class Session(object):
|
||||
"""A Requests session."""
|
||||
|
||||
__attrs__ = ['headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks']
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self,
|
||||
headers=None,
|
||||
cookies=None,
|
||||
auth=None,
|
||||
timeout=None,
|
||||
proxies=None,
|
||||
hooks=None):
|
||||
|
||||
self.headers = headers or {}
|
||||
self.cookies = cookies or {}
|
||||
self.auth = auth
|
||||
self.timeout = timeout
|
||||
self.proxies = proxies or {}
|
||||
self.hooks = hooks or {}
|
||||
|
||||
# Set up a CookieJar to be used by default
|
||||
self.cookies = cookielib.FileCookieJar()
|
||||
|
||||
# Map args from kwargs to instance-local variables
|
||||
map(lambda k, v: (k in self.__attrs__) and setattr(self, k, v),
|
||||
kwargs.iterkeys(), kwargs.itervalues())
|
||||
|
||||
# Map and wrap requests.api methods
|
||||
self._map_api_methods()
|
||||
|
||||
@@ -42,10 +81,8 @@ class Session(object):
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
# print 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
|
||||
@@ -54,23 +91,35 @@ class Session(object):
|
||||
|
||||
def pass_args(func):
|
||||
def wrapper_func(*args, **kwargs):
|
||||
inst_attrs = dict((k, v) for k, v in self.__dict__.iteritems()
|
||||
if k in self.__attrs__)
|
||||
# Combine instance-local values with kwargs values, with
|
||||
# priority to values in kwargs
|
||||
kwargs = dict(inst_attrs.items() + kwargs.items())
|
||||
|
||||
# Argument collector.
|
||||
_kwargs = {}
|
||||
|
||||
# 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(
|
||||
inst_attrs['cookies'], kwargs['cookies']
|
||||
self.cookies, kwargs['cookies']
|
||||
)
|
||||
|
||||
if kwargs.get('headers', None) and inst_attrs.get('headers', None):
|
||||
kwargs['headers'].update(inst_attrs['headers'])
|
||||
for attr in self.__attrs__:
|
||||
# for attr in ['headers',]:
|
||||
s_val = self.__dict__.get(attr)
|
||||
r_val = kwargs.get(attr)
|
||||
|
||||
new_attr = merge_kwargs(r_val, s_val)
|
||||
|
||||
# Skip attributes that were set to None.
|
||||
if new_attr is not None:
|
||||
_kwargs[attr] = new_attr
|
||||
|
||||
# Make sure we didn't miss anything.
|
||||
for (k, v) in kwargs.items():
|
||||
if k not in _kwargs:
|
||||
_kwargs[k] = v
|
||||
|
||||
return func(*args, **_kwargs)
|
||||
|
||||
return func(*args, **kwargs)
|
||||
return wrapper_func
|
||||
|
||||
# Map and decorate each function available in requests.api
|
||||
|
||||
+36
-65
@@ -3,8 +3,12 @@
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import unittest
|
||||
import time
|
||||
import cookielib
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import envoy
|
||||
|
||||
try:
|
||||
import omnijson as json
|
||||
@@ -15,12 +19,10 @@ import requests
|
||||
|
||||
from requests.sessions import Session
|
||||
|
||||
PORT = os.environ.get('HTTPBIN_PORT', '7045')
|
||||
|
||||
HTTPBIN_URL = 'http://httpbin.ep.io/'
|
||||
HTTPSBIN_URL = 'https://httpbin.ep.io/'
|
||||
|
||||
# HTTPBIN_URL = 'http://staging.httpbin.org/'
|
||||
# HTTPSBIN_URL = 'https://httpbin-staging.ep.io/'
|
||||
HTTPBIN_URL = 'http://0.0.0.0:%s/' % (PORT)
|
||||
# HTTPBIN_URL = 'http://127.0.0.1:8000/'
|
||||
|
||||
|
||||
def httpbin(*suffix):
|
||||
@@ -29,15 +31,9 @@ def httpbin(*suffix):
|
||||
return HTTPBIN_URL + '/'.join(suffix)
|
||||
|
||||
|
||||
def httpsbin(*suffix):
|
||||
"""Returns url for HTTPSBIN resource."""
|
||||
|
||||
return HTTPSBIN_URL + '/'.join(suffix)
|
||||
|
||||
|
||||
SERVICES = (httpbin, httpsbin)
|
||||
|
||||
SERVICES = (httpbin, )
|
||||
|
||||
_httpbin = False
|
||||
|
||||
class RequestsTestSuite(unittest.TestCase):
|
||||
"""Requests test cases."""
|
||||
@@ -46,12 +42,21 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
_multiprocess_can_split_ = True
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
global _httpbin
|
||||
|
||||
if not _httpbin:
|
||||
|
||||
self.httpbin = envoy.connect('gunicorn httpbin:app --bind=0.0.0.0:%s' % (PORT))
|
||||
|
||||
_httpbin = True
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
"""Teardown."""
|
||||
pass
|
||||
# self.httpbin.kill()
|
||||
|
||||
|
||||
def test_invalid_url(self):
|
||||
@@ -59,7 +64,7 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
|
||||
|
||||
def test_HTTP_200_OK_GET(self):
|
||||
r = requests.get(httpbin('/'))
|
||||
r = requests.get(httpbin('/get'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_HTTP_302_ALLOW_REDIRECT_GET(self):
|
||||
@@ -70,10 +75,6 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
r = requests.get(httpbin('redirect', '1'), allow_redirects=False)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
def test_HTTPS_200_OK_GET(self):
|
||||
r = requests.get(httpsbin('/'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_HTTP_200_OK_GET_WITH_PARAMS(self):
|
||||
heads = {'User-agent': 'Mozilla/5.0'}
|
||||
@@ -112,12 +113,7 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
|
||||
|
||||
def test_HTTP_200_OK_HEAD(self):
|
||||
r = requests.head(httpbin('/'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_HTTPS_200_OK_HEAD(self):
|
||||
r = requests.head(httpsbin('/'))
|
||||
r = requests.head(httpbin('/get'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
@@ -126,21 +122,11 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_HTTPS_200_OK_PUT(self):
|
||||
r = requests.put(httpsbin('put'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_HTTP_200_OK_PATCH(self):
|
||||
r = requests.patch(httpbin('patch'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_HTTPS_200_OK_PATCH(self):
|
||||
r = requests.patch(httpsbin('patch'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_AUTH_HTTP_200_OK_GET(self):
|
||||
|
||||
for service in SERVICES:
|
||||
@@ -206,7 +192,7 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
r = requests.get(service('status', '500'))
|
||||
self.assertEqual(bool(r), False)
|
||||
|
||||
r = requests.get(service('/'))
|
||||
r = requests.get(service('/get'))
|
||||
self.assertEqual(bool(r), True)
|
||||
|
||||
|
||||
@@ -257,7 +243,7 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
|
||||
for service in SERVICES:
|
||||
|
||||
url = service('/')
|
||||
url = service('/get')
|
||||
|
||||
requests.get(url, params={'foo': u'føø'})
|
||||
requests.get(url, params={u'føø': u'føø'})
|
||||
@@ -275,19 +261,6 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
self.assertEquals(r.status_code, 401)
|
||||
|
||||
|
||||
def test_settings(self):
|
||||
|
||||
def test():
|
||||
r = requests.get(httpbin(''))
|
||||
r.raise_for_status()
|
||||
|
||||
with requests.settings(timeout=0.0000001):
|
||||
self.assertRaises(requests.Timeout, test)
|
||||
|
||||
with requests.settings(timeout=100):
|
||||
requests.get(httpbin(''))
|
||||
|
||||
|
||||
def test_urlencoded_post_data(self):
|
||||
|
||||
for service in SERVICES:
|
||||
@@ -386,9 +359,9 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
self.assertEquals(rbody.get('data'), 'foobar')
|
||||
|
||||
|
||||
def test_idna(self):
|
||||
r = requests.get(u'http://➡.ws/httpbin')
|
||||
assert 'httpbin' in r.url
|
||||
# def test_idna(self):
|
||||
# r = requests.get(u'http://➡.ws/httpbin')
|
||||
# assert 'httpbin' in r.url
|
||||
|
||||
|
||||
def test_urlencoded_get_query_multivalued_param(self):
|
||||
@@ -470,14 +443,7 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
def test_session_HTTP_200_OK_GET(self):
|
||||
|
||||
s = Session()
|
||||
r = s.get(httpbin('/'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
def test_session_HTTPS_200_OK_GET(self):
|
||||
|
||||
s = Session()
|
||||
r = s.get(httpsbin('/'))
|
||||
r = s.get(httpbin('/get'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
@@ -487,13 +453,18 @@ class RequestsTestSuite(unittest.TestCase):
|
||||
|
||||
s = Session()
|
||||
s.headers = heads
|
||||
|
||||
# Make 2 requests from Session object, should send header both times
|
||||
r1 = s.get(httpbin('user-agent'))
|
||||
|
||||
assert heads['User-agent'] in r1.content
|
||||
r2 = s.get(httpbin('user-agent'))
|
||||
|
||||
r2 = s.get(httpbin('user-agent'))
|
||||
assert heads['User-agent'] in r2.content
|
||||
|
||||
new_heads = {'User-agent': 'blah'}
|
||||
r3 = s.get(httpbin('user-agent'), headers=new_heads)
|
||||
assert new_heads['User-agent'] in r3.content
|
||||
|
||||
self.assertEqual(r2.status_code, 200)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user