diff --git a/.gitignore b/.gitignore index 968d26ff..09b54901 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.idea MANIFEST coverage.xml nosetests.xml diff --git a/AUTHORS.rst b/AUTHORS.rst index 43644e52..e1835d24 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -62,4 +62,6 @@ Patches and Suggestions - Ryan Kelly - Rolando Espinoza La fuente - Robert Gieseke -- Idan Gazit \ No newline at end of file +- Idan Gazit +- Ed Summers +- Chris Van Horne \ No newline at end of file diff --git a/HISTORY.rst b/HISTORY.rst index 487cc867..4b595f3f 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,12 @@ History ------- +0.8.4 (2011-12-11) +++++++++++++++++++ + +* Prefetch bugfix. +* Added license to installed version. + 0.8.3 (2011-11-27) ++++++++++++++++++ diff --git a/MANIFEST.in b/MANIFEST.in index 39fbb994..ef350d0c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include README.rst LICENSE HISTORY.rst test_requests.py +include README.rst LICENSE NOTICE HISTORY.rst test_requests.py diff --git a/Makefile b/Makefile index 9500cb76..dbda99fa 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ init: pip install -r reqs.txt test: - nosetests test_requests.py + nosetests --with-color test_requests.py ci: init nosetests test_requests.py --with-xunit --xunit-file=junit-report.xml diff --git a/NOTICE b/NOTICE index 08ba2bc6..a77e5cd5 100644 --- a/NOTICE +++ b/NOTICE @@ -1,12 +1,26 @@ Request includes some vendorized python libraries to ease installation. -Poster License -============== +Urllib3 License +=============== -Copyright (c) 2010 Chris AtLee +This is the MIT license: http://www.opensource.org/licenses/mit-license.php -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Copyright 2008-2011 Andrey Petrov and contributors (see CONTRIBUTORS.txt), +Modifications copyright 2022 Kenneth Reitz. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/_themes/README.rst b/docs/_themes/README.rst index 8648482a..2e875d46 100644 --- a/docs/_themes/README.rst +++ b/docs/_themes/README.rst @@ -2,7 +2,7 @@ krTheme Sphinx Style ==================== This repository contains sphinx styles Kenneth Reitz uses in most of -his projects. It is a drivative of Mitsuhiko's themes for Flask and Flask related +his projects. It is a derivative of Mitsuhiko's themes for Flask and Flask related projects. To use this style in your Sphinx documentation, follow this guide: diff --git a/docs/index.rst b/docs/index.rst index b2851e47..1dc8a0ca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,7 +38,7 @@ Testimonials `Twitter, Inc `_, `Readability `_, and Federal US Institutions -use Requests internally. It has been installed over 45,000 times from PyPi. +use Requests internally. It has been installed over 45,000 times from PyPI. **Armin Ronacher** Requests is the perfect example how beautiful an API can be with the diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst index e1b7d141..099dabd7 100644 --- a/docs/user/advanced.rst +++ b/docs/user/advanced.rst @@ -10,7 +10,7 @@ Session Objects --------------- The Session object allows you to persist certain parameters across -requests. It also perstists cookies across all requests made from the +requests. It also persists cookies across all requests made from the Session instance. A session object has all the methods of the main Requests API. @@ -49,7 +49,7 @@ All values that are contained within a session are directly available to you. Se Body Content Workflow ---------------------- -By default, When you make a request, the body of the response isn't downloaded immediately. The response headers are downloaded when you make a request, but the content isn't downloaded until you access the :class:`Response.content` attribute. +By default, when you make a request, the body of the response isn't downloaded immediately. The response headers are downloaded when you make a request, but the content isn't downloaded until you access the :class:`Response.content` attribute. Let's walk through it:: @@ -80,6 +80,8 @@ Keep-Alive Excellent news — thanks to urllib3, keep-alive is 100% automatic within a session! Any requests that you make within a session will automatically reuse the appropriate connection! +Note that connections are only released back to the pool for reuse once all body data has been read; be sure to either set ``prefetch`` to ``True`` or read the ``content`` property of the ``Response`` object. + If you'd like to disable keep-alive, you can simply set the ``keep_alive`` configuration to ``False``:: s = requests.session() @@ -89,8 +91,8 @@ If you'd like to disable keep-alive, you can simply set the ``keep_alive`` confi Asynchronous Requests ---------------------- -Requests has first-class support for concurrent requests, powered -by gevent. This allows you to send a bunch of HTTP requests at the same +Requests has first-class support for concurrent requests, powered by gevent. +This allows you to send a bunch of HTTP requests at the same time. First, let's import the async module. Heads up — if you don't have `gevent `_ this will fail:: @@ -122,7 +124,7 @@ will also guarantee execution of the ``response`` hook, described below. :: .. admonition:: Throttling - The ``map`` function also takes a ``size`` parameter, that specifies the nubmer of connections to make at a time:: + The ``map`` function also takes a ``size`` parameter, that specifies the number of connections to make at a time:: async.map(rs, size=5) @@ -229,7 +231,7 @@ Let's pretend that we have a web service that will only respond if the def __init__(self, username): # setup any auth-related data here self.username = username - + def __call__(self, r): # modify and return the request r.headers['X-Pizza'] = self.username diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst index 554afd7d..34741174 100644 --- a/docs/user/quickstart.rst +++ b/docs/user/quickstart.rst @@ -300,7 +300,7 @@ establishing OAuth connections. Documentation and examples can be found on the r Redirection and History ----------------------- -Requests will automatically perform location redirection while using impodotent methods. +Requests will automatically perform location redirection while using idempotent methods. GitHub redirects all HTTP requests to HTTPS. Let's see what happens:: @@ -316,9 +316,9 @@ The :class:`Response.history` list contains a list of the :class:`Request` objects that were created in order to complete the request. If you're using GET, HEAD, or OPTIONS, you can disable redirection -handling with the ``disable_redirects`` parameter:: +handling with the ``allow_redirects`` parameter:: - >>> r = requests.get('http://github.com') + >>> r = requests.get('http://github.com', allow_redirects=False) >>> r.status_code 301 >>> r.history @@ -345,7 +345,7 @@ You can tell requests to stop waiting for a response after a given number of sec .. admonition:: Note - ``timeout`` only effects the connection process itself, not the downloading of the respone body. + ``timeout`` only effects the connection process itself, not the downloading of the response body. Errors and Exceptions diff --git a/reqs.txt b/reqs.txt index 46acb760..51fb282b 100644 --- a/reqs.txt +++ b/reqs.txt @@ -4,4 +4,4 @@ gunicorn nose pyflakes omnijson -rudolf \ No newline at end of file +rudolf2 \ No newline at end of file diff --git a/requests/__init__.py b/requests/__init__.py index e09c8345..a1ddac61 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -15,13 +15,14 @@ requests """ __title__ = 'requests' -__version__ = '0.8.3' -__build__ = 0x000803 +__version__ = '0.8.4' +__build__ = 0x000804 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' + from . import utils from .models import Request, Response from .api import request, get, head, post, patch, put, delete, options diff --git a/requests/api.py b/requests/api.py index 0b124e03..82db6cf4 100644 --- a/requests/api.py +++ b/requests/api.py @@ -39,7 +39,7 @@ def request(method, url, :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 'name': file-like-objects (or {'name': ('filename', fileobj)}) for multipart encoding upload. - :param auth: (optional) Auth typle to enable Basic/Digest/Custom HTTP Auth. + :param auth: (optional) Auth tuple to enable Basic/Digest/Custom 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. diff --git a/requests/defaults.py b/requests/defaults.py index 7a5a3fb8..e8db67ab 100644 --- a/requests/defaults.py +++ b/requests/defaults.py @@ -11,7 +11,7 @@ Configurations: :base_headers: Default HTTP headers. :verbose: Stream to write request logging to. :timeout: Seconds until request timeout. -:max_redirects: Maximum njumber of redirects allowed within a request. +:max_redirects: Maximum number of redirects allowed within a request. :decode_unicode: Decode unicode responses automatically? :keep_alive: Reuse HTTP Connections? :max_retries: The number of times a request should be retried in the event of a connection failure. diff --git a/requests/exceptions.py b/requests/exceptions.py index d20a95cd..d0f8f39a 100644 --- a/requests/exceptions.py +++ b/requests/exceptions.py @@ -13,10 +13,10 @@ class RequestException(Exception): request.""" class HTTPError(RequestException): - """An HTTP error occured.""" + """An HTTP error occurred.""" class ConnectionError(RequestException): - """A Connection error occured.""" + """A Connection error occurred.""" class Timeout(RequestException): """The request timed out.""" diff --git a/requests/models.py b/requests/models.py index 9ae95ca5..567d1f66 100644 --- a/requests/models.py +++ b/requests/models.py @@ -151,7 +151,7 @@ class Request(object): if resp: - # Fallback to None if there's no staus_code, for whatever reason. + # Fallback to None if there's no status_code, for whatever reason. response.status_code = getattr(resp, 'status', None) # Make headers case-insensitive. @@ -171,7 +171,7 @@ class Request(object): # Save cookies in Response. response.cookies = cookies - # Save original resopnse for later. + # Save original response for later. response.raw = resp if is_error: @@ -441,11 +441,12 @@ class Request(object): headers=self.headers, redirect=False, assert_same_host=False, - preload_content=prefetch, + preload_content=False, decode_content=False, retries=self.config.get('max_retries', 0), timeout=self.timeout, ) + self.sent = True except MaxRetryError, e: @@ -469,7 +470,8 @@ class Request(object): # If prefetch is True, mark content as consumed. if prefetch: - self.response._content_consumed = True + # Save the response. + self.response.content return self.sent diff --git a/requests/sessions.py b/requests/sessions.py index 247aa183..20d22613 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -123,7 +123,7 @@ class Session(object): :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) Auth typle to enable Basic/Digest/Custom HTTP Auth. + :param auth: (optional) Auth tuple to enable Basic/Digest/Custom 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. diff --git a/requests/utils.py b/requests/utils.py index f31cad88..6d7b8686 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -4,7 +4,7 @@ requests.utils ~~~~~~~~~~~~~~ -This module provides utlity functions that are used within Requests +This module provides utility functions that are used within Requests that are also useful for external consumption. """ @@ -374,7 +374,7 @@ def requote_path(path): """Re-quote the given URL path component. This function passes the given path through an unquote/quote cycle to - ensure that it is fully and consistenty quoted. + ensure that it is fully and consistently quoted. """ parts = path.split("/") parts = (urllib.quote(urllib.unquote(part), safe="") for part in parts) diff --git a/setup.py b/setup.py index 53e770a4..0d81d055 100755 --- a/setup.py +++ b/setup.py @@ -12,12 +12,12 @@ except ImportError: -if sys.argv[-1] == "publish": - os.system("python setup.py sdist upload") +if sys.argv[-1] == 'publish': + os.system('python setup.py sdist upload') sys.exit() -if sys.argv[-1] == "test": - os.system("python test_requests.py") +if sys.argv[-1] == 'test': + os.system('python test_requests.py') sys.exit() required = [] @@ -34,12 +34,14 @@ setup( author='Kenneth Reitz', author_email='me@kennethreitz.com', url='http://python-requests.org', - packages= [ + packages=[ 'requests', 'requests.packages', 'requests.packages.urllib3', 'requests.packages.oreos' ], + package_data={'': ['LICENSE', 'NOTICE']}, + include_package_data=True, install_requires=required, license='ISC', classifiers=( diff --git a/test_requests.py b/test_requests.py index 7e4f146e..a0946472 100755 --- a/test_requests.py +++ b/test_requests.py @@ -81,6 +81,11 @@ class RequestsTestSuite(unittest.TestCase): r = requests.get(httpbin('/get')) self.assertEqual(r.status_code, 200) + def test_response_sent(self): + r = requests.get(httpbin('/get')) + + self.assertTrue(r.request.sent) + def test_HTTP_302_ALLOW_REDIRECT_GET(self): r = requests.get(httpbin('redirect', '1')) self.assertEqual(r.status_code, 200) @@ -577,6 +582,14 @@ class RequestsTestSuite(unittest.TestCase): r = requests.get(hah, allow_redirects=False, config=config) assert r.content == None + def test_cached_response(self): + + r1 = requests.get(httpbin('get'), prefetch=False) + assert r1.content + assert r1.content + + r2 = requests.get(httpbin('get'), prefetch=True) + assert r2.content if __name__ == '__main__': unittest.main()