Compare commits

..

1660 Commits

Author SHA1 Message Date
Kenneth Reitz
373a34a144 date fix 2012-05-02 19:17:14 -04:00
Kenneth Reitz
9324c2a9b4 oauthlib 2012-05-02 19:15:43 -04:00
Kenneth Reitz
fb2931801e v0.12.0 2012-05-02 19:13:19 -04:00
Kenneth Reitz
8ac6b266c9 pre-send hook
#516
2012-05-02 19:09:18 -04:00
Kenneth Reitz
efe5d13ed6 Merge pull request #516 from EnTeQuAk/move_pre_request
Move pre_request to a more usable place, followup to #382
2012-05-02 15:58:08 -07:00
Kenneth Reitz
a9963e3841 upper case automatically 2012-05-02 18:57:06 -04:00
Kenneth Reitz
f1d104e004 making history 2012-05-02 18:56:51 -04:00
Kenneth Reitz
996f99b267 Merge remote-tracking branch 'origin/develop' into develop 2012-05-02 18:47:53 -04:00
Kenneth Reitz
62d2ea8034 default chunk size for .content much bigger 2012-05-02 18:47:50 -04:00
Kenneth Reitz
ed15c70cd0 Merge pull request #573 from idangazit/develop
Lazily encode data, params, files
2012-05-02 14:19:56 -07:00
Idan Gazit
cf6b20429a Merge remote-tracking branch 'upstream/develop' into develop 2012-05-03 00:08:00 +03:00
Idan Gazit
324336e7f6 Lazily encode data, params, files
Previously, data, params, and files were encoded and stored in
Request.__init__, and subsequently put into service during
Request.send. The problem with this approach is that hooks and auth
callables need to be aware of the eager encoding, and if they touch the
originals, make sure to update the encoded versions.

A better approach is to only encode late in the sending process. This
way, hooks and auth callables can safely make changes without fear of
the old, encoded variant overriding it.
2012-05-03 00:04:13 +03:00
Idan Gazit
d240b1fe15 PEP8 Cleanup 2012-05-02 23:16:38 +03:00
Kenneth Reitz
53d60cac4f Revert "Update Makefile and travis configuration to run all (non-external) tests"
This reverts commit a453a78c7c.
2012-05-02 02:38:20 -04:00
Kenneth Reitz
6271046a27 Revert "Cache the value of the Response.text property"
This reverts commit d232948188.
2012-05-02 02:38:11 -04:00
Kenneth Reitz
8a81a437d2 Revert "Use utf-8 as the default encoding"
This reverts commit 35d5ac6e8f.
2012-05-02 02:37:51 -04:00
Shivaram Lingamneni
a453a78c7c Update Makefile and travis configuration to run all (non-external) tests 2012-05-01 23:21:05 -07:00
Shivaram Lingamneni
bdd7f8f8a2 Change setup.py to reflect required/optional dependencies 2012-05-01 23:21:05 -07:00
Shivaram Lingamneni
d232948188 Cache the value of the Response.text property 2012-05-01 22:28:50 -07:00
Shivaram Lingamneni
35d5ac6e8f Use utf-8 as the default encoding
(fixes crashes on failure to import chardet)
2012-05-01 21:46:53 -07:00
Shivaram Lingamneni
fdd08215ea update documentation to correspond to new cookie API 2012-05-01 21:46:53 -07:00
Shivaram Lingamneni
ff7cfa732f restore docs/_build directory to .gitignore 2012-05-01 19:18:55 -07:00
Kenneth Reitz
45be14ed6f Merge pull request #565 from slingamn/cookiejar
Support CookieJar, references #281
2012-05-01 17:22:37 -07:00
Shivaram Lingamneni
11a3eaec26 add Python 3 compatibility 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
7832f2ae7e add laurentb's test case for cookie handling on redirects 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
6eb349f5d2 remove unused import in test 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
ff169d32fe fix and test for a bug dhagrow reported 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
404ecaf95b clarified documentation from e-mail discussion 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
1de14e6a93 fix usage of compat.urlparse
(this code path appears to have been exercised only by secure cookies)
2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
492bda1343 add a test for redirection 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
4d6871d917 Further changes to move cookies to CookieJar 2012-05-01 17:00:19 -07:00
miguel
c4ab96b638 mostly complete cookie support based on cookiejar 2012-05-01 17:00:19 -07:00
miguel
fed6cfbf4d mostly complete cookie support based on cookiejar 2012-05-01 17:00:19 -07:00
miguel
2a27b123fd catch TooManyRedirects in safe_mode 2012-05-01 17:00:19 -07:00
Shivaram Lingamneni
7c5151e8e7 changes to .gitignore 2012-05-01 17:00:19 -07:00
Kenneth Reitz
a189c238cc LOLJK 2012-05-01 07:22:59 -04:00
Kenneth Reitz
d427bb8603 OAUTH ALL THE THINGS 2012-05-01 07:19:04 -04:00
Kenneth Reitz
7eed89a0df v0.11.3 2012-05-01 07:17:35 -04:00
Kenneth Reitz
5d9699bbdc oauthlib only for 2 2012-05-01 07:07:18 -04:00
Kenneth Reitz
e6cce7a5bd syntax errors 2012-05-01 07:06:55 -04:00
Kenneth Reitz
d79e1bbaad or str 2012-05-01 07:02:13 -04:00
Kenneth Reitz
bf1744eea2 hax 2012-05-01 06:57:25 -04:00
Kenneth Reitz
9427e1efe8 missed an import 2012-05-01 06:55:19 -04:00
Kenneth Reitz
661af1dc1a only import oauthlib in python2 2012-05-01 06:54:09 -04:00
Kenneth Reitz
a5bc99d53e no -e 2012-05-01 06:50:38 -04:00
Kenneth Reitz
14fae695bf uh, sure 2012-05-01 06:47:58 -04:00
Kenneth Reitz
be04142723 Revert "Call auth callable before encoding body data"
This reverts commit 9217a2523d.
2012-05-01 06:42:58 -04:00
Kenneth Reitz
748c65f7a7 git+git://github.com/idangazit/oauthlib.git 2012-05-01 06:27:55 -04:00
Idan Gazit
2fc9f6bbc9 Trim down OAuth1 callable logic
Moved much of the validation out of requests and into oauthlib
2012-05-01 06:20:53 -04:00
Idan Gazit
65bf3ab201 Backing out stupidly incorrect str vs unicode check
It's simply wrong. Since compat.py sets str = unicode for py2, the
original logic is sound.
2012-05-01 06:20:53 -04:00
Idan Gazit
906fcd7328 Fix order of return values from OAuth Client.sign() 2012-05-01 06:20:52 -04:00
Idan Gazit
7b819852b9 Fix Content-Type validation in OAuth1 callable 2012-05-01 06:20:52 -04:00
Idan Gazit
9217a2523d Call auth callable before encoding body data 2012-05-01 06:20:52 -04:00
Idan Gazit
0aedef07c3 Improve _encode_params to handle lists of two-element tuples 2012-05-01 06:20:52 -04:00
Idan Gazit
3e60a9eb9c Proper test for str vs unicode when preparing data
In python 2.x, requests sets str = unicode in requests/compat.py. This causes
isinstance(foo, str) to return True even if foo is a unicode string.
2012-05-01 06:20:52 -04:00
Idan Gazit
798dc4ae1d Initial implementation of OAuth1 request signing with OAuthLib 2012-05-01 06:20:52 -04:00
Idan Gazit
632d9893b0 Improve docstring description of auth parameter 2012-05-01 06:20:52 -04:00
Idan Gazit
809d9863bf Add .egg-info/ dir to gitignore 2012-05-01 06:20:52 -04:00
Kenneth Reitz
742cbeaee1 httpbin weirdness 2012-05-01 05:51:59 -04:00
Kenneth Reitz
2159c80270 v0.11.2 2012-04-22 22:29:26 -04:00
Kenneth Reitz
8e9446d3fb revert 2012-04-22 22:29:00 -04:00
Kenneth Reitz
a7da521a62 merge conflict 2012-04-22 22:26:53 -04:00
Kenneth Reitz
2621fe2bff Revert "Add failing tests for invalid %encodings"
This reverts commit e28c1c9bfa.
2012-04-22 22:26:07 -04:00
Kenneth Reitz
3843a40f7c Revert "Reenable test_session_with_escaped_url test"
This reverts commit 3550ac7473.
2012-04-22 22:25:57 -04:00
Kenneth Reitz
f647352d01 v0.11.2 2012-04-22 22:08:39 -04:00
Kenneth Reitz
1631f0f5ae Merge pull request #552 from slingamn/bundle_2
attempt to use the OS's certificate bundle
2012-04-22 18:53:31 -07:00
Shivaram Lingamneni
b4eb8663af prefer certifi's bundle to the OS bundle 2012-04-22 18:43:59 -07:00
Shivaram Lingamneni
e1528ce3be add the FreeBSD certificate bundle path 2012-04-19 14:27:26 -07:00
Shivaram Lingamneni
1360e77cb2 Add a smoke test for https functionality 2012-04-16 17:50:40 -07:00
Shivaram Lingamneni
9921099546 Try to use the OS's CA certificate bundle for SSL verification 2012-04-16 15:28:31 -07:00
Kenneth Reitz
2f6b5feb1a Merge pull request #550 from reclosedev/develop
Fix issue #549. Add 'prefetch' to Session.__attrs__ and Requests.__init__
2012-04-14 03:19:10 -07:00
Roman Haritonov
d569a2d6bc fix #549 Add 'prefetch' to Session.__attrs__ and Requests.__init__ 2012-04-13 19:25:10 +04:00
Kenneth Reitz
e3ba495ed9 Merge branch 'develop' of https://github.com/catwell/requests into develop 2012-04-13 08:34:18 +02:00
Kenneth Reitz
d4a77cf2af Merge pull request #548 from umbrae/httperror_fix
A get with an invalid port should wrap urllib3's LocationParseError exception with our own.
2012-04-12 12:44:44 -07:00
Chris Dary
3a2eaa67a2 A get with an invalid port should wrap urllib3's LocationParseError exception with our own. 2012-04-12 12:35:34 -04:00
Pierre Chapuis
f3ad56f103 Encode Multipart Post data at Request creation
This fixes #298 (File upload not working with
HTTP digest authentication)
2012-04-12 17:49:48 +02:00
Pierre Chapuis
c3e6c41fc1 Fix infinite loop on wrong Digest Authentication 2012-04-12 16:33:15 +02:00
Kenneth Reitz
8a055c5d42 Merge pull request #535 from Jonty/develop
Fix decoding of invalid %encodings in URLs
2012-04-11 08:02:46 -07:00
Jonty Wareing
06e4971fe7 Rewrite unquote_unreserved based on urllib.unquote
This is almost entirely taken from the unquote implementation in urllib,
slightly modified for the case in hand. It now deals with invalid %encodings
rather than exploding, and the code is somewhat simpler.
2012-04-11 14:56:19 +00:00
Jonty Wareing
e28c1c9bfa Add failing tests for invalid %encodings 2012-04-11 14:55:43 +00:00
Jonty Wareing
3550ac7473 Reenable test_session_with_escaped_url test 2012-04-11 14:55:43 +00:00
Idan Gazit
51800bf36f Trigger setup.py develop when installing requirements 2012-04-11 14:05:33 +03:00
Idan Gazit
c89a3e207e Clarify digest hash method names 2012-04-11 14:02:59 +03:00
Kenneth Reitz
365c64fe3b #539 2012-04-10 23:00:25 -03:00
Kenneth Reitz
6b652f766d Merge pull request #545 from sharat87/patch-1
Add docs on sending lists for multivalued query params.
2012-04-10 08:43:46 -07:00
Shrikant Sharat Kandula
5a8a8f2bd3 Add docs on sending lists for multivalued query params. 2012-04-10 14:42:38 +05:30
Kenneth Reitz
821cbb3e08 moar 2012-04-09 04:22:10 -04:00
Kenneth Reitz
f8798aee28 Merge pull request #542 from newmaniese/develop
Attempting to address issue #377 by making content on the response model a little smarter
2012-04-08 20:13:38 -07:00
Michael Newman
11cd2b8253 Fixing a silly typo in my test 2012-04-08 18:46:26 -04:00
Michael Newman
1677c688cb Shamelessly adding myself to the authors list 2012-04-08 18:42:08 -04:00
Michael Newman
b92feb3f0a If there is no content in a response don't throw an error the second time that content is attempted to be read. This addresses issue #377 <https://github.com/kennethreitz/requests/issues/377> 2012-04-08 18:39:44 -04:00
Kenneth Reitz
7d4d91f013 Merge pull request #540 from jhalcrow/patch-1
Correct path to test_requests.py for setup.py test
2012-04-06 10:01:19 -07:00
Jonathan Halcrow
3279906737 Correct path to test_requests.py for setup.py test 2012-04-06 12:50:16 -03:00
Kenneth Reitz
c7b1bc8197 Merge pull request #534 from ThiefMaster/patch-1
Remove bad tab indent
2012-04-04 01:05:00 -07:00
Adrian
da288ad57a Remove bad tab indent 2012-04-04 11:03:49 +03:00
Andrey Petrov
03ae9bee74 Fixed typoe (s/repsonses/responses/) 2012-04-02 16:59:08 -07:00
Kenneth Reitz
a364395612 Merge pull request #530 from Osmose/sidebar_donate
Fix #506: Change "Support Requests" to "Donate".
2012-04-02 00:44:00 -07:00
Kenneth Reitz
37f3a29d49 Michael Kelly 2012-04-02 03:43:11 -04:00
Michael Kelly
48396f97a9 Fix #506: Change "Support Requests" to "Donate". 2012-04-02 00:40:20 -07:00
Kenneth Reitz
ccd19c53c8 Merge remote-tracking branch 'origin/develop' into develop 2012-03-31 17:39:31 -04:00
Kenneth Reitz
2bae0d295b new urllib3 version
#498
2012-03-31 17:39:26 -04:00
Kenneth Reitz
8755969629 Merge pull request #529 from piotr-dobrogost/develop
Removed unnecessary leading slashes in httpbin's endpoints
2012-03-31 13:21:17 -07:00
Piotr Dobrogost
e12d053ab8 Removed unnecessary leading slashes in httpbin's endpoints 2012-03-31 22:16:55 +02:00
Kenneth Reitz
13b07cb5d8 Merge pull request #528 from floppym/dist-tests
Include tests in tarballs.
2012-03-31 11:36:21 -07:00
Mike Gilbert
d3adc9d334 Include tests in tarballs. 2012-03-31 14:22:49 -04:00
Kenneth Reitz
751e2ea2d4 roadmap 2012-03-31 03:21:31 -04:00
Kenneth Reitz
dab3df7619 fake change for commit hook test 2012-03-31 03:11:43 -04:00
Kenneth Reitz
171b370b0e app engine #498 2012-03-31 03:08:12 -04:00
Kenneth Reitz
bcbc1be1c8 blah 2012-03-31 03:06:28 -04:00
Kenneth Reitz
04c329d703 license=open("LICENSE").read( 2012-03-31 02:53:14 -04:00
Kenneth Reitz
9a62aa6380 .. :changelog: 2012-03-31 02:51:38 -04:00
Kenneth Reitz
11e5c8eab7 HTTP/1.1 2012-03-31 00:08:38 -04:00
Kenneth Reitz
775b6f6f00 v0.11.1 2012-03-30 23:42:56 -04:00
Kenneth Reitz
dacc1d8aaf default to true for redirects now, since safe 2012-03-30 23:42:04 -04:00
Kenneth Reitz
18591920f3 upload data on redirects too 2012-03-30 23:31:19 -04:00
Kenneth Reitz
193eb42891 v0.11.1 2012-03-30 23:30:56 -04:00
Kenneth Reitz
b20d171c1c POST redirect => GET
#269
2012-03-30 23:28:07 -04:00
Kenneth Reitz
590211e13e Merge remote-tracking branch 'origin/develop' into develop 2012-03-30 23:15:47 -04:00
Kenneth Reitz
fff5269d1a Fix app engine error for #498 2012-03-30 23:15:43 -04:00
Kenneth Reitz
e831947be4 strict mode for #269 2012-03-30 23:15:31 -04:00
Kenneth Reitz
c205ce658f Merge pull request #519 from pulpe/doc-fix
little correction of curl in docs
2012-03-30 19:58:38 -07:00
pulpe
13060f89c7 little correction of curl in docs 2012-03-28 10:45:21 +02:00
Christopher Grebs
f25901874a Move pre_request to a more usable place, followup to #382
Having the hook called so late makes it impossible to overwrite the HTTP request
calling behavior and set self.sent to True in case of possible cache matches
for example.

This way we can interfere before we waste any CPU time to calculate
a request.
2012-03-27 15:38:56 +02:00
Kenneth Reitz
3cc6acaca4 Merge remote-tracking branch 'origin/develop' into develop 2012-03-25 15:26:58 -04:00
Kenneth Reitz
21ccf8f8c0 urllib3 v1.3 2012-03-25 15:26:55 -04:00
Kenneth Reitz
b973d08b0e Merge pull request #512 from silent1mezzo/master
Adds MissingSchema and InvalidSchema Exceptions
2012-03-25 12:00:57 -07:00
Adam McKerlie
d24ee0e1dc Created MissingSchema and InvalidSchema which inherits from RequestException and ValueError 2012-03-25 11:03:36 -04:00
Kenneth Reitz
afb1bd103a paypal 2012-03-25 03:56:00 -04:00
Kenneth Reitz
4c1852f928 Merge branch 'develop' of github.com:kennethreitz/requests into develop 2012-03-22 15:00:51 -04:00
Kenneth Reitz
6e26f5754b #508 2012-03-22 15:00:47 -04:00
Daniel Miller
82d1b340dc Suggesting changing "async.map(rs)" to "responses = async.map(rs)" just to show that it returns a list rather than mutating the original? Maybe this is apparent for most, but I was a bit confused =/ http://goo.gl/gE4up 2012-03-22 11:57:19 -07:00
Kenneth Reitz
eab2ab9faa Steve Pulec 2012-03-18 22:19:48 -04:00
Kenneth Reitz
12427e3434 Merge branch 'patch-1' of https://github.com/spulec/requests into develop 2012-03-18 22:18:49 -04:00
Kenneth Reitz
76bf523a1f Merge #491 2012-03-18 22:15:05 -04:00
Kenneth Reitz
613816dd9d Merge pull request #488 from newmaniese/develop
Excluding select from the monkey patching that gevent does to allow sele...
2012-03-18 19:08:51 -07:00
Kenneth Reitz
f8ec2544ce Merge pull request #494 from JDrosdeck/doc
Add quickstart doc and example for passing parameters in a GET request
2012-03-18 19:07:31 -07:00
Steve Pulec
3c2f52d681 Fixes issues #496 by having Response.ok catch all Requests exceptions. 2012-03-18 23:06:42 -03:00
Kenneth Reitz
3baf3ab069 Merge pull request #497 from iandanforth/develop
Develop
2012-03-18 19:04:56 -07:00
Kenneth Reitz
5c575b30c2 Merge remote-tracking branch 'origin/develop' into develop 2012-03-18 22:02:46 -04:00
Kenneth Reitz
e65f52aae4 remove debian packaging warning
it's up to date now
2012-03-18 22:02:43 -04:00
Ian Danforth
44277441d6 Sphinx throws an error if you don't escape ** in **kwargs 2012-03-18 18:11:15 -07:00
Ian Danforth
7b68c124d5 Sphinx throws an error if you don't escape ** in **kwargs 2012-03-18 18:09:58 -07:00
Jonathan Drosdeck
f2172922c5 Add quickstart doc and example for passing parameters in a GET request 2012-03-18 15:37:46 -04:00
Michael Newman
079a825ac3 Merge https://github.com/kennethreitz/requests into develop 2012-03-16 15:32:50 -04:00
Kenneth Reitz
9cf9d76eb5 Merge pull request #477 from maxcountryman/develop
potentially fixes #338
2012-03-15 18:15:27 -07:00
Kenneth Reitz
dc7029ec98 Merge pull request #483 from maxcountryman/cleanup
removing unused import
2012-03-15 18:14:35 -07:00
Kenneth Reitz
f0019c06d7 Merge pull request #489 from maxcountryman/patch-1
fixing link to AUTHORS in README
2012-03-15 18:13:26 -07:00
Max Countryman
a094ad8f31 fixing link to AUTHORS in README 2012-03-15 22:05:08 -03:00
Michael Newman
d6827a37d0 Excluding select from the monkey patching that gevent does to allow select.poll and requests.async in the same project
Fix for issue #487, including a regression test that checks the
existence of select.poll before and after loading requests.async.
2012-03-15 14:41:45 -04:00
Kenneth Reitz
5b7a79b0ff Merge pull request #486 from Pinkerton/patch-1
Fix issue #484
2012-03-14 20:08:17 -07:00
Pinkerton
ee861f4287 Fix issue #484 2012-03-14 19:54:06 -07:00
Kenneth Reitz
0c0bab3ad0 v0.11.0 2012-03-14 20:31:43 -04:00
Kenneth Reitz
1c73ec22e9 Nick Chadwick 2012-03-14 20:30:03 -04:00
Kenneth Reitz
4677ba5cd9 only verify private cert when verity is true 2012-03-14 20:29:30 -04:00
Kenneth Reitz
093709be4d Merge branch 'develop' of https://github.com/chadnickbok/requests into develop 2012-03-14 20:27:07 -04:00
Kenneth Reitz
f6ed16bbbe Merge remote-tracking branch 'origin/develop' into develop 2012-03-14 20:27:02 -04:00
chadnickbok@gmail.com
fc618aa78a Updated Requests api to accept a 'cert' argument.
This argument can be either a string, containing the path to a
pem-formatted key and certificate chain, or a tuple of (cert, key).

When supplied a tuple, the values are paths to an SSL certificate
chain file and key, respectively.
2012-03-14 17:15:29 -07:00
chadnickbok@gmail.com
82e69de44f Exposed key_file and cert_file in requests, to support https client certificates. 2012-03-14 15:57:30 -07:00
Max Countryman
8f8062723a removing unused import 2012-03-13 20:10:32 -04:00
Idan Gazit
cc4381b91e Merge branch 'develop' of github.com:kennethreitz/requests into develop 2012-03-13 17:05:24 -07:00
Idan Gazit
eae641485b Remove unused import 2012-03-13 17:04:26 -07:00
Kenneth Reitz
29309201b6 remove cruft 2012-03-13 16:44:45 -07:00
Kenneth Reitz
0dd6c40205 dict sequence 2012-03-13 16:42:16 -07:00
Kenneth Reitz
84d9a1b577 dict_to_sequence 2012-03-13 16:39:51 -07:00
Idan Gazit
17170a2ca7 Merge branch 'develop', remote-tracking branch 'upstream/develop' into develop 2012-03-13 12:59:33 -07:00
Kenneth Reitz
8d34538f4c further lies. 2012-03-12 20:54:02 -07:00
Kenneth Reitz
8d1a85a8d0 Merge branch 'josh' into develop 2012-03-12 20:51:59 -07:00
Kenneth Reitz
06f048e507 lies. 2012-03-12 20:46:23 -07:00
Max Countryman
83a9f2c740 explicating the cause of LookupError with a better comment 2012-03-11 22:22:29 -04:00
Max Countryman
bc5cc0dc92 potentially fixes #338
This attempts to fix an issue where encoding of a string might fail when the
encoding is set to some unknown format. Here we attempt to catch the
LookupException and subsequently blindly encode the string one final time.
That is we call str() over response.content without specifying an encoding.
This may still fail in certain cases but does properly handle the case of #338
by returning the expected string.
2012-03-09 17:30:35 -05:00
Kenneth Reitz
6562137731 cookie history 2012-03-09 08:59:12 -08:00
Kenneth Reitz
d078b69aef catch cookie errors that are prone to failure 2012-03-09 08:56:41 -08:00
Kenneth Reitz
0a1e527aec Merge of maxcountryman 2012-03-09 08:51:03 -08:00
Kenneth Reitz
9f55f503b1 merge conflict and fixes for python3 2012-03-09 08:43:12 -08:00
Kenneth Reitz
253cba373b _detected_encoding 2012-03-09 08:35:51 -08:00
Kenneth Reitz
9451ae2e98 iter_lines py3 compatibility
#470
2012-03-09 08:26:12 -08:00
Kenneth Reitz
d203349740 Merge remote-tracking branch 'origin/develop' into develop 2012-03-09 08:07:17 -08:00
Kenneth Reitz
4aad69594d chunk_size iter_lines 2012-03-09 08:07:10 -08:00
Kenneth Reitz
c7f165ae6f Merge branch 'iter_lines-fix' of https://github.com/fawek/requests into develop 2012-03-09 08:03:20 -08:00
Kenneth Reitz
98cbde1324 Chris Dary 2012-03-09 07:59:08 -08:00
Kenneth Reitz
77e5443f71 self.config.get('trust_env')
just for @mitsuhiko
2012-03-09 07:58:00 -08:00
Kenneth Reitz
e15ae8f9a7 v0.10.8 2012-03-09 07:55:54 -08:00
Kenneth Reitz
0eb2509449 Merge pull request #475 from umbrae/generate-chunked-valueerror-fix
Generate chunked ValueError fix
2012-03-08 14:57:58 -08:00
Chris Dary
bd0e002804 Move chunked head redirect test to ext 2012-03-08 14:44:07 -08:00
Chris Dary
0e65dff008 Remove unnecessary bit from previous branch.
This reverts commit e2645826be.
2012-03-08 13:22:38 -08:00
Chris Dary
fba77fc65f Potential fix for #436 2012-03-08 13:10:18 -08:00
Chris Dary
1cf5ec872c Merge remote-tracking branch 'upstream/develop' into develop 2012-03-08 08:19:33 -08:00
Johannes Gorset
21c2146be4 Facilitate proxy configuration by environment variables 2012-03-08 13:34:23 +01:00
Kenneth Reitz
2f91d8e773 bunk 2012-03-07 16:54:53 -08:00
Kenneth Reitz
946f7ec579 percent encoded 2012-03-07 16:50:02 -08:00
Kenneth Reitz
658d609e9f default encode_uri to True 2012-03-07 16:46:15 -08:00
Kenneth Reitz
abca7f0ad0 Merge remote-tracking branch 'origin/develop' into develop 2012-03-07 16:30:30 -08:00
Kenneth Reitz
cf5ddecc4c encode_uri 2012-03-07 16:28:04 -08:00
Kenneth Reitz
c1a44259d6 disablable encode_urls 2012-03-07 16:25:46 -08:00
Kenneth Reitz
54b2cb0b27 move config around a bit 2012-03-07 16:25:27 -08:00
Kenneth Reitz
09b6aef835 encode urls setting 2012-03-07 16:13:34 -08:00
Jakub Wieczorek
228c5e68ae Considerably simplify and fix the iter_lines() function
1. Do not use rstrip() as this would also throw away meaningful whitespaces
2. Avoid assuming what striplines() considers a line break terminator,
   the list of those is quite long in Unicode.
3. Add tests for the above edge cases.
2012-03-05 18:39:55 +01:00
Kenneth Reitz
6bb0529bed Merge pull request #466 from maxcountryman/develop
fixing a capitalization error in the send() method doc string
2012-03-01 14:21:45 -08:00
Max Countryman
1532effb68 fixing a capitalization error in the send() method doc string 2012-03-01 17:20:01 -05:00
Kenneth Reitz
65eaebb177 Merge remote-tracking branch 'origin/develop' into develop 2012-02-28 15:21:21 -05:00
Kenneth Reitz
ab0714ce9c develop 2012-02-28 15:21:12 -05:00
Kenneth Reitz
a3a7c504ad Merge pull request #464 from brendanmaguire/session_prefetch
Removed prefetch from args.
2012-02-28 12:19:25 -08:00
Brendan Maguire
ca45da39fa Removed prefetch from args. 2012-02-28 20:16:01 +00:00
Kenneth Reitz
313ff95ee4 Merge pull request #463 from brendanmaguire/session_prefetch
Prefetch for sessions
2012-02-28 12:08:48 -08:00
Brendan Maguire
97815c9930 Prefetch for sessions 2012-02-28 20:02:21 +00:00
Chris Dary
e2645826be Decode URL to utf-8 before joining.
To avoid UnicodeDecodeError's like on http://blip.fm/~1abvfu
2012-02-28 12:08:37 -05:00
Kenneth Reitz
7cc898f9ed master build test 2012-02-26 11:30:44 -05:00
Kenneth Reitz
ec979dc60a nose not found :( 2012-02-26 10:26:45 -05:00
Kenneth Reitz
32a6d07036 simpleci 2012-02-26 10:25:26 -05:00
Kenneth Reitz
d6c2d8f1dc simpleci 2012-02-26 10:24:48 -05:00
Kenneth Reitz
4a5c94f410 rudolf the red-nosed reindeer 2012-02-26 10:22:47 -05:00
Kenneth Reitz
0eb5b633aa v0.10.6 2012-02-25 23:17:45 -05:00
Kenneth Reitz
56c36ac27d history 2012-02-25 23:16:08 -05:00
Kenneth Reitz
508bd26741 Merge remote-tracking branch 'origin/develop' into develop 2012-02-25 23:15:54 -05:00
Kenneth Reitz
835053c55e #452 2012-02-25 23:15:33 -05:00
Kenneth Reitz
f0e0a62bbe Merge branch 'develop' of https://github.com/honzajavorek/requests into develop 2012-02-25 23:14:49 -05:00
Kenneth Reitz
bdcbabb758 Merge pull request #450 from Lukasa/issue_440
Issue #440: Accept '=' in cookie keys.
2012-02-25 20:14:11 -08:00
Kenneth Reitz
7cc2d468c7 urllib3 v1.2.2 2012-02-25 23:11:20 -05:00
Kenneth Reitz
83f4c01564 urllib3 release 2012-02-25 23:11:06 -05:00
Kenneth Reitz
cfeb485434 v0.10.5 2012-02-25 23:05:39 -05:00
Kenneth Reitz
d3b7f98814 hurray for passing tests 2012-02-25 22:44:46 -05:00
Kenneth Reitz
f5b0043c08 #457 2012-02-25 22:40:18 -05:00
Kenneth Reitz
6ce27f7d55 Merge branch 'develop' of https://github.com/asciimoo/requests into develop 2012-02-25 22:39:29 -05:00
asciimoo
531dc35126 [enh] async.imap added -- generator object handling 2012-02-26 04:04:33 +01:00
Kenneth Reitz
d974b46dbe simplify httpbin stuff 2012-02-25 21:57:30 -05:00
Kenneth Reitz
ea1d5f3648 Fix content-length: 0
#454
2012-02-24 18:42:33 -05:00
Kenneth Reitz
83b4081e85 Builds?? 2012-02-24 00:45:17 -05:00
Kenneth Reitz
e18e79d820 python3 fix 2012-02-24 00:44:01 -05:00
Kenneth Reitz
7234c7240a Merge branch 'master' into develop 2012-02-23 23:51:24 -05:00
Kenneth Reitz
7fa6276eb7 i can't believe i'm doing this 2012-02-23 22:43:16 -05:00
Kenneth Reitz
bbdf81dc1c teh spelling 2012-02-23 22:34:17 -05:00
Kenneth Reitz
4b0d53dcb7 no color 2012-02-23 22:27:29 -05:00
Kenneth Reitz
746d2cad5d mirrors 2012-02-23 22:22:43 -05:00
Kenneth Reitz
14f57f6585 Merge remote-tracking branch 'origin/develop' into develop 2012-02-23 22:21:16 -05:00
Kenneth Reitz
e63dff0a3a travis ci 2012-02-23 22:14:31 -05:00
Honza Javorek
09c0365255 str is redefined in compat module, but was not imported 2012-02-23 23:51:59 +01:00
Honza Javorek
1661bf6543 get_unicode_from_response returned str instead of unicode 2012-02-23 17:28:56 +01:00
Cory Benfield
2ef0b1b51d Accept '=' in cookie keys. 2012-02-21 22:51:38 +00:00
Kenneth Reitz
3c58600187 Merge pull request #449 from benweatherman/develop
Don't bonk if .netrc isn't readable
2012-02-21 13:55:50 -08:00
Ben
572c15d049 Don't bonk if .netrc isn't readable.
It's possible in some shared hosting environments that the .netrc file isn't readable by the user for the calling process. In that circumstance, just forgo the netrc authentication.
2012-02-21 15:53:33 -06:00
Kenneth Reitz
99a6074816 Merge pull request #447 from gwrtheyrn/patch-1
Added StringIO/Image example to quickstart documentation.
2012-02-21 00:27:16 -08:00
Danilo Bargen
8b750ee182 Added StringIO/Image example to quickstart documentation. 2012-02-21 09:24:52 +01:00
Kenneth Reitz
c9b4920230 v0.10.4 2012-02-20 16:21:25 -05:00
Kenneth Reitz
793d314c8d Merge branch 'netrc' into develop 2012-02-20 16:20:44 -05:00
Kenneth Reitz
8c873712fe .netrc 2012-02-20 16:20:07 -05:00
Kenneth Reitz
faae6b87b1 v0.10.4 2012-02-20 16:12:08 -05:00
Kenneth Reitz
fd7610dd7a python 3 unicode grr 2012-02-20 16:07:36 -05:00
Kenneth Reitz
b0e1865073 netrc fix 2012-02-20 15:43:45 -05:00
Kenneth Reitz
de0658f7e8 stick .netrc auth in pipeline 2012-02-20 15:43:38 -05:00
Kenneth Reitz
79bb9ee141 netrc parsing 2012-02-20 15:35:19 -05:00
Kenneth Reitz
2f33679cb3 spacing 2012-02-20 15:35:02 -05:00
Kenneth Reitz
6f5735274b history for HEAD 3xx 2012-02-20 14:02:13 -05:00
Kenneth Reitz
709828204a HEADs don't follow redirects by default. 2012-02-20 13:56:11 -05:00
Kenneth Reitz
b355b678a9 danger_mode redirect test 2012-02-20 13:51:46 -05:00
Kenneth Reitz
124c172c72 100k times 2012-02-20 13:49:29 -05:00
Kenneth Reitz
709c8bdcbf v0.10.3 2012-02-20 13:49:06 -05:00
Kenneth Reitz
2c55d269ce allow 3XX in danger_mode 2012-02-20 13:46:54 -05:00
Kenneth Reitz
e0d1b09ffe don't raise for redirects if they're not allowed 2012-02-20 13:40:55 -05:00
Kenneth Reitz
ceb42dd5de no more SOPA 2012-02-20 12:39:25 -05:00
Kenneth Reitz
80fe5dc147 none headers test
#433
2012-02-20 12:31:52 -05:00
Kenneth Reitz
d806ffc1cd test cleanups 2012-02-20 12:30:22 -05:00
Kenneth Reitz
4f75f1f41d Values can be none #433 2012-02-20 12:30:12 -05:00
Kenneth Reitz
fe10eeb5be SCHEMAS 2012-02-20 12:25:53 -05:00
Kenneth Reitz
cf37f63ccb #435 2012-02-20 12:22:11 -05:00
Kenneth Reitz
e7efce91fb models cleanup 2012-02-20 12:21:01 -05:00
Kenneth Reitz
5f834715d0 Merge branch 'issue_380' of https://github.com/Lukasa/requests into develop 2012-02-20 12:11:31 -05:00
Kenneth Reitz
dd89df314d v0.10.3 2012-02-20 12:09:46 -05:00
Kenneth Reitz
fdbb53db19 __file__ 2012-02-20 12:06:59 -05:00
Shrikant Sharat
590ce29743 Implemented #439. Added supporting test. 2012-02-19 15:11:19 +05:30
Kenneth Reitz
7548bc7ccc Update HISTORY.rst 2012-02-16 18:10:44 -05:00
Cory Benfield
544ebf402f Correct unfortunate typo. 2012-02-16 20:42:05 +00:00
Cory Benfield
640538adcb Fail if unsupported schemas are used.
requests only supports http and https. This change enforces that.
2012-02-16 20:20:20 +00:00
Cory Benfield
1ded0ad3d5 Remove a wayward change. 2012-02-16 19:32:20 +00:00
Cory Benfield
d339b0f64f Added failing test for issue #380. 2012-02-16 18:21:32 +00:00
Kenneth Reitz
8e2696b385 history 2012-02-15 03:14:48 -05:00
Kenneth Reitz
b5212ddc3d remove bunk utils for decoding 2012-02-15 03:09:40 -05:00
Kenneth Reitz
dacaae520a bytes data fix for python3 2012-02-15 03:09:26 -05:00
Kenneth Reitz
e663c77e70 fix bytes 2012-02-15 02:54:00 -05:00
Kenneth Reitz
ec109c9ac8 path fixes 2012-02-15 02:53:50 -05:00
Kenneth Reitz
0b9a2a1581 move tests over 2012-02-15 02:52:32 -05:00
Kenneth Reitz
2759060559 it's a start 2012-02-15 02:45:21 -05:00
Kenneth Reitz
00b13673e3 simplify 2012-02-15 02:28:58 -05:00
Kenneth Reitz
91ac5ba110 don't rely on urllib3's decode 2012-02-15 02:07:55 -05:00
Kenneth Reitz
0d8c08cd22 binary data upload bug test 2012-02-15 02:03:29 -05:00
Kenneth Reitz
ab4c03adc3 cleanups 2012-02-15 02:03:13 -05:00
Kenneth Reitz
75b0c4be1b latin1, remove unicode_literals
Fixes #407
2012-02-15 02:01:36 -05:00
Kenneth Reitz
4a8e6415c7 sp 2012-02-15 01:47:08 -05:00
Kenneth Reitz
58bf158840 RuntimeError 2012-02-15 01:46:06 -05:00
Kenneth Reitz
c0f066626e whitespace 2012-02-15 01:42:57 -05:00
Kenneth Reitz
69c7a8638e make all the tests 2012-02-15 01:42:52 -05:00
Kenneth Reitz
1b6f1b091c Merge branch '400-header_expand-unicode' of https://github.com/acdha/requests into develop 2012-02-15 01:25:29 -05:00
Kenneth Reitz
d39cdc45d1 decode response url again 2012-02-15 01:21:38 -05:00
Kenneth Reitz
7f761f3adf history for 0.10.2 2012-02-15 01:18:41 -05:00
Kenneth Reitz
5e76943f02 Merge branch 'develop' of https://github.com/Lukasa/requests into develop 2012-02-15 01:08:10 -05:00
Kenneth Reitz
b887ea3b60 Merge branch 'mgiuca-uri-cleanup-nonpath' into develop 2012-02-15 01:00:52 -05:00
Matt Giuca
690426ac86 Added Matt Giuca to AUTHORS. 2012-02-15 12:06:34 +11:00
Matt Giuca
b8298b0710 Rename utils.requote_path to requote_uri.
It is now applied to a whole URI, not just the path.
2012-02-15 12:03:08 +11:00
Matt Giuca
3bd5406c06 Now requotes the entire URL, not just the path (Issue #429). 2012-02-15 12:00:47 +11:00
Matt Giuca
3ae0ff3685 Added test cases for URI cleaning in the query part (Issue #429). 2012-02-15 12:00:27 +11:00
Cory Benfield
80e29bfcab Change the RFC we reference. 2012-02-14 14:11:25 +00:00
Cory Benfield
d7107c2cdc Make clearer the source of forbidden characters 2012-02-14 12:58:35 +00:00
Cory Benfield
658da765ec Keep non RFC cookie key characters separate.
Moved the characters that we accept in keys but that the RFC forbids
into a separate string to keep track of them.
2012-02-14 10:25:40 +00:00
Kenneth Reitz
9e2f5dd0ed Merge branch 'py3-uri-encoding' of https://github.com/mgiuca/requests into develop 2012-02-14 04:30:10 -05:00
Matt Giuca
1ffce4f7dc Simplify requote_path.
It no longer needs to split on '/' since '/' will not be encoded.
2012-02-14 12:57:49 +11:00
Matt Giuca
fcac1c3746 Fixed URI encoding of reserved characters (Issue #369).
Previously, util.requote_path would unquote and requote all characters,
causing reserved characters to become encoded (changing the semantics of the
URI). Now, it has special code for unquoting just the unreserved characters,
then quotes only illegal characters.
This ensures that illegal characters are fixed, and URIs are normalised, but
reserved characters do not erroneously become quoted.
Test case test_session_with_escaped_url now passes.
2012-02-14 12:51:03 +11:00
Matt Giuca
c0763bb8d5 Changed test case test_path_is_not_double_encoded.
Uses the space character instead of ~ as a test (since ~ is unreserved, it
shouldn't really be encoded at all).
2012-02-14 12:49:31 +11:00
Matt Giuca
75bd9d0e94 Added test case testing URI normalisation.
Tests that percent-encoded unreserved characters get de-encoded.
2012-02-14 12:20:48 +11:00
Matt Giuca
08bc1198d3 Added test case for Issue #369.
Tests that legal reserved and unreserved characters in the path are not
percent-encoded. Currently fails.
2012-02-14 12:15:32 +11:00
Matt Giuca
cf54f60367 Fixed URI re-encoding on Python 3 (Issue #369).
Request.full_url now performs requoting of the path (like it does in Python 2).
Request.path_url no longer quotes the already-quoted path (double quoting).
Fixed utils.requote_path so it works properly in Python 3.
2012-02-14 11:50:02 +11:00
Matt Giuca
329efcae6e Added test case for quoted and illegal characters in the URL.
This is a test case for issue #369.
It passes in Python 2, but fails in Python 3 (though the test suite doesn't
actually work in Python 3, it can be shown to fail with some modification).
2012-02-14 11:47:14 +11:00
Kenneth Reitz
5a2a78f7df Merge pull request #425 from Lukasa/develop
Issue #335: Accept unusual keys in cookies.
2012-02-13 16:14:39 -08:00
Cory Benfield
f72c13ffda Accept unusual keys in cookies.
The Oreos module throws CookieErrors when it catches keys that have
characters that shouldn't be in them, like colons and braces. Other
services are happy to send out such keys, however. This commit makes
requests non-standards compliant, just like everyone else is.
2012-02-14 00:10:26 +00:00
Chris Adams
0a17badb21 header_expand: handle Unicode strings (closes #400) 2012-02-13 11:10:05 -05:00
Kenneth Reitz
12f9aa3669 Merge pull request #410 from eriolv/develop
Fix SyntaxError on Python3 because "except Error, e" is not supported anymore
2012-02-12 02:16:48 -08:00
Kenneth Reitz
afa2e86a4d Merge pull request #413 from bancek/patch-1
Typo fix in oreos/structures.py
2012-02-06 09:08:03 -08:00
Luka Zakrajšek
b7842ab34b Typo fix in oreos/structures.py 2012-02-06 13:42:34 +01:00
Greg Taylor
f8b3141204 Use basestring instead of str to determine when to return headers as-is. This makes sure that unicode instances aren't enumerated. 2012-02-05 13:57:35 -05:00
Daniele Tricoli
c40d6d0509 Since requests 0.10.1 dropped Python5 support, to catch an exception and
store the exception object in a variable the "as" keyword can be used so
Python3 will not raise a SyntaxError
2012-02-05 04:18:22 +01:00
Kenneth Reitz
a74481a1d4 Update docs/community/faq.rst 2012-02-03 13:24:00 -05:00
Kenneth Reitz
b898415d0d :trollface:
because i can.
2012-02-02 17:23:47 -05:00
Kenneth Reitz
b47effe5d8 test #2 2012-02-01 13:35:34 -05:00
Kenneth Reitz
4f10605389 quick test 2012-02-01 13:33:59 -05:00
Kenneth Reitz
120e62900b Native Instruments! 2012-01-31 02:15:55 -05:00
Kenneth Reitz
986704dc62 v0.10.2 2012-01-30 09:41:09 -05:00
Kenneth Reitz
2f13956357 Merge branch 'unicode_missing_self' of https://github.com/Telofy/requests into develop 2012-01-30 09:35:53 -05:00
Kenneth Reitz
8d700dd1e5 Merge branch 'pr-urlfix-1' of https://github.com/brendoncrawford/requests into develop 2012-01-30 09:33:31 -05:00
Kenneth Reitz
5be412db13 Brendon Crawford 2012-01-30 09:33:14 -05:00
Telofy
a61a861cfb The self was missing again, and I think the two blocks were redundant. 2012-01-30 12:23:43 +01:00
Brendon Crawford
c363ca476f Added ability to check if missing trailing slash in path.
Previously this URL would not work:

    http://example.com?foo=bar

But this URL would work:

    http://example.com/?foo=bar

Even though a slash is required for a valid URL, it is a common use case
for the slash to be left out, so it would be a good idea to account for this.
2012-01-29 23:24:54 -08:00
Kenneth Reitz
319b1ed551 Merge branch '239-socket-leak' of https://github.com/acdha/requests into develop 2012-01-29 19:06:41 -05:00
Chris Adams
67f50a0fe5 Less redundant freeing of resources on redirects
With 495646bb6a the double flush is no longer
needed.
2012-01-29 18:45:14 -05:00
Chris Adams
b98cc8b4e9 Revert "Initial stop-the-bleeding fix"
This reverts commit 730c0e2e2b.
2012-01-29 18:43:13 -05:00
Chris Adams
495646bb6a async: force prefetch=True on send
… otherwise we can run out of sockets before any of the responses are ever
processed
2012-01-29 18:42:48 -05:00
Kenneth Reitz
4516bd45b2 Release redirected connections.
#239
2012-01-29 18:00:33 -05:00
Chris Adams
730c0e2e2b Initial stop-the-bleeding fix
This is redundant but it avoids crashing otherwise working code. The code-smell
from duplication suggests that this interface should be refactored slightly.
2012-01-29 17:31:59 -05:00
Chris Adams
3020d0e56a Consistent self.cookies usage
This avoids two variables pointing to the same thing and avoids
a duplicate dict update() call
2012-01-29 16:52:08 -05:00
Chris Adams
49bed18a83 Minor PEP-8 cleanup 2012-01-29 16:51:28 -05:00
Kenneth Reitz
e6959412aa only do oreos for 2 2012-01-28 23:10:03 -05:00
Kenneth Reitz
04c0bcc9b4 wow. 2012-01-27 11:18:56 -06:00
Kenneth Reitz
ec4edae977 lazy tests 2012-01-27 11:16:47 -06:00
David Kemp (Work)
f478c34671 add failing test for unicode headers (python 2.x only) 2012-01-26 18:45:38 +00:00
Kenneth Reitz
a0ef4f2358 Merge pull request #389 from johtso/patch-1
Fix httpbin urls with missing .org in docs
2012-01-25 22:40:30 -08:00
Johannes
ca57e93ebf Fix httpbin urls with missing .org 2012-01-26 02:13:04 +00:00
Kenneth Reitz
5ca5b7ec65 Merge remote-tracking branch 'origin/develop' into develop 2012-01-25 11:26:08 -05:00
Kenneth Reitz
2b202aabd7 David Kemp 2012-01-25 11:26:04 -05:00
Kenneth Reitz
cb64d31171 Merge pull request #387 from davidarkemp/develop
fix problem with path being double escaped
2012-01-25 08:25:26 -08:00
David Kemp (Work)
80eafe3b63 fix problem with path being double escaped 2012-01-25 16:21:07 +00:00
Kenneth Reitz
16aa444261 Merge branch 'develop' of https://github.com/mastahyeti/requests into develop 2012-01-25 09:04:41 -05:00
Kenneth Reitz
0bbdbac17f moar tests 2012-01-25 09:03:20 -05:00
Piotr Dobrogost
c430b60e38 Standard tests from RequestsTestSuite run using async api 2012-01-24 21:56:59 +01:00
Ben
02f6555536 added myself to authors.rst 2012-01-24 09:59:41 -06:00
Mastahyeti
4293e3fdb2 moved call to pre_request hook, allowing for more meaningful use. 2012-01-23 20:56:05 -06:00
Kenneth Reitz
50298bbf97 80k 2012-01-23 02:52:38 -05:00
Kenneth Reitz
ac82fa47a0 @takluyver 2012-01-23 02:49:10 -05:00
Kenneth Reitz
976bfbf687 text 2012-01-23 02:43:38 -05:00
Kenneth Reitz
1bc377b188 r.text 2012-01-23 02:42:34 -05:00
Kenneth Reitz
a89530aef5 explain binary response data 2012-01-23 02:42:05 -05:00
Kenneth Reitz
c32b1cd6d6 better feature list 2012-01-23 02:34:42 -05:00
Kenneth Reitz
90f5c8bd85 r.text 2012-01-23 02:32:09 -05:00
Kenneth Reitz
878bb61d24 readme update 2012-01-23 02:31:16 -05:00
Kenneth Reitz
8493d8329e PYTHON 3 2012-01-23 02:28:01 -05:00
Kenneth Reitz
57aeafa115 pythons 2012-01-23 02:21:35 -05:00
Kenneth Reitz
a29e862adf new pythons! 2012-01-23 02:21:30 -05:00
Kenneth Reitz
5ed62e1137 don't let that happen... 2012-01-23 02:19:56 -05:00
Kenneth Reitz
f99a2534c9 v0.10.1 2012-01-23 02:18:26 -05:00
Kenneth Reitz
a939423006 dammit, i changed again 2012-01-23 02:03:16 -05:00
Kenneth Reitz
4493acc5ee fix 26 2012-01-23 02:01:53 -05:00
Kenneth Reitz
c4eb9301bb assert isinstance 2012-01-23 01:59:13 -05:00
Kenneth Reitz
57ba337e79 assert isinstance 2012-01-23 01:58:32 -05:00
Kenneth Reitz
3d542693bc no more unittest2 2012-01-23 01:56:58 -05:00
Kenneth Reitz
5f2607ffca yikes 2012-01-23 01:54:00 -05:00
Kenneth Reitz
ab916a8a8d hmm 2012-01-23 01:52:33 -05:00
Kenneth Reitz
1fb4bd82f7 cchch changes 2012-01-23 01:48:40 -05:00
Kenneth Reitz
d892e93589 requirements.txt 2012-01-23 01:47:39 -05:00
Kenneth Reitz
38c2532c5f new certifi 2012-01-23 01:46:41 -05:00
Kenneth Reitz
18b5ee7d5b fixes 2012-01-23 01:44:07 -05:00
Kenneth Reitz
9fd2d07c1d reqs fixes 2012-01-23 01:44:01 -05:00
Kenneth Reitz
e7bcc3b332 oh snap 2012-01-23 01:32:09 -05:00
Kenneth Reitz
b001fcf968 SimpleCookie 2012-01-23 01:02:16 -05:00
Kenneth Reitz
125619c783 urllib3 update 2012-01-23 01:01:42 -05:00
Kenneth Reitz
fe6882623c more stuff and things 2012-01-23 00:52:38 -05:00
Kenneth Reitz
11c4315da3 good 2012-01-23 00:43:01 -05:00
Kenneth Reitz
672e66ba5f compat 2012-01-23 00:34:31 -05:00
Kenneth Reitz
bcfddb3d65 cleanups and stuffs 2012-01-23 00:29:50 -05:00
Kenneth Reitz
9cae98c167 blah 2012-01-23 00:25:48 -05:00
Kenneth Reitz
b0e2e4f284 blah 2012-01-23 00:15:25 -05:00
Kenneth Reitz
36842db26f stuff and things 2012-01-22 20:12:49 -05:00
Kenneth Reitz
e84a7c7e6f whatever 2012-01-22 20:12:43 -05:00
Kenneth Reitz
2109afc144 further 2012-01-22 19:42:13 -05:00
Kenneth Reitz
786dfdd7e5 python3 version of urllib3 2012-01-22 15:06:58 -05:00
Kenneth Reitz
62d05f842d dates 2012-01-21 23:19:49 -05:00
Kenneth Reitz
fc3b03a5f5 @gulopine 2012-01-21 23:18:06 -05:00
Kenneth Reitz
f4f2bd9fab Response.url. 2012-01-21 23:10:37 -05:00
Kenneth Reitz
b0555b68e7 history! 2012-01-21 23:06:34 -05:00
Kenneth Reitz
497695864b Beautiful history. 2012-01-21 23:03:07 -05:00
Kenneth Reitz
128b49a1fb whitespace 2012-01-21 23:00:28 -05:00
Kenneth Reitz
0dbda6665d cleanup 2012-01-21 22:59:57 -05:00
Kenneth Reitz
464279f48d typo
Signed-off-by: Kenneth Reitz <me@kennethreitz.com>
2012-01-21 22:58:38 -05:00
Kenneth Reitz
b14a244ab4 simpler 2012-01-21 22:57:24 -05:00
Kenneth Reitz
2c7e920298 don't double decode 2012-01-21 22:56:53 -05:00
Kenneth Reitz
b725bfd3fb Use chardet for detection when no encoding is provided. 2012-01-21 22:55:41 -05:00
Kenneth Reitz
47e96b8040 chardet 2012-01-21 22:35:19 -05:00
Kenneth Reitz
9a1348707c chardet 2012-01-21 22:35:11 -05:00
Kenneth Reitz
ada98899f8 build number 2012-01-21 20:00:12 -05:00
Kenneth Reitz
16a7a26452 v0.10.0 2012-01-21 19:58:51 -05:00
Kenneth Reitz
2c04f9d199 Merge remote-tracking branch 'origin/develop' into develop 2012-01-21 17:48:55 -05:00
Kenneth Reitz
70e98e47cf No encoding? r.text is None. 2012-01-21 17:48:51 -05:00
Kenneth Reitz
b525dc29f7 Merge pull request #370 from piotr-dobrogost/develop
tiny map() refactoring
2012-01-21 05:13:15 -08:00
Kenneth Reitz
a3fb5ac326 history 2012-01-21 07:47:46 -05:00
Kenneth Reitz
8e6f98f44e Merge branch 'redsea' into develop 2012-01-21 07:17:30 -05:00
Kenneth Reitz
9ba93b885c history 2012-01-21 07:17:23 -05:00
Kenneth Reitz
5f44d79729 move digest to new register_hook
#372
2012-01-21 07:14:26 -05:00
Kenneth Reitz
a3b26c7e5b Provide new register_hook system.
#372
2012-01-21 07:13:58 -05:00
Kenneth Reitz
e9be7c1a58 make list of HOOKS available 2012-01-21 07:07:18 -05:00
Kenneth Reitz
6c359b2457 Merge branch 'develop' of https://github.com/jgorset/requests into redsea 2012-01-21 06:36:06 -05:00
Johannes Gorset
7647e52943 Facilitate for multiple hooks 2012-01-21 12:14:55 +01:00
Johannes Gorset
a0ae2e6c7b Default the encoding of "text" media subtypes to "ISO-8859-1"
Ref. RFC2616 (HyperText Transfer Protocol), section 3.7.1 (Canonicalization and Text Defaults).
2012-01-21 11:01:45 +01:00
Kenneth Reitz
efd2b57b92 cleanup docs for request defaults 2012-01-21 01:44:57 -05:00
Kenneth Reitz
47aba0cc20 remove is_error 2012-01-21 01:31:23 -05:00
Kenneth Reitz
f5a2b75924 only try to decode if self.encoding is set 2012-01-21 01:28:26 -05:00
Kenneth Reitz
49a38ac89a New bytes/unicode separation.
Response.content for bytes.
New Response.text for unicode.
2012-01-21 01:24:21 -05:00
Kenneth Reitz
6d071f4331 kill decode_unicode config 2012-01-21 01:23:35 -05:00
Piotr Dobrogost
3873121c01 tiny map() refactoring 2012-01-20 21:42:25 +01:00
Kenneth Reitz
5bff8e362f Update docs/dev/todo.rst 2012-01-19 18:43:43 -05:00
Kenneth Reitz
62733146be Merge pull request #366 from jgorset/how-to-help
Elaborate on how to help
2012-01-19 15:42:55 -08:00
Kenneth Reitz
99f6581770 Merge pull request #368 from jgorset/unicode-response-url
Decode response URL to a unicode string.
2012-01-19 15:42:27 -08:00
Johannes Gorset
b37fbf30a3 Decode response URL to a unicode string.
Fixes #182
2012-01-20 00:34:44 +01:00
Johannes Gorset
e65d0ac9e3 Elaborate on how to help 2012-01-20 00:09:30 +01:00
Kenneth Reitz
61a0e85672 Merge pull request #364 from gthank/8efb6cc870bd23de0d8d87708217d818236a733f
Allow sessions and async requests to mix.
2012-01-19 11:12:23 -08:00
Kenneth Reitz
c18e6459a8 v0.9.3 2012-01-18 21:56:33 -05:00
Kenneth Reitz
6db255d17d Merge branch 'develop' of github.com:kennethreitz/requests into develop 2012-01-18 21:49:25 -05:00
Kenneth Reitz
49d79546e8 v0.9.2 2012-01-18 21:25:03 -05:00
Kenneth Reitz
f3ba022f46 Merge branch 'streaming' of https://github.com/RonnyPfannschmidt/requests into develop 2012-01-18 21:05:56 -05:00
Kenneth Reitz
17f2002839 Merge pull request #363 from gazpachoking/develop
Stop always verifying certs for same host that has verified once.
2012-01-18 17:19:43 -08:00
Chase Sterling
a6ee9757a7 Add myself to AUTHORS 2012-01-18 19:51:10 -05:00
Chase Sterling
d9cb18ad2a Make sure verify=False is respected for session even when there has already been a verified request to the same host.
Update tests to expose the (fixed) problem.
2012-01-18 19:49:22 -05:00
Kenneth Reitz
557480cfe8 SOPA 2012-01-18 11:14:32 -05:00
Kenneth Reitz
5dae0bb9bf Merge pull request #360 from mastahyeti/develop
Make requests.async.send asynchronous
2012-01-17 13:32:04 -08:00
Ben
e38046e6c6 The async.send method wasn't really doing anything useful. It was just calling the r.send() method of the Request object 'r'. It took an optional kwarg pools, and assigned it to r._pools which isn't used by anything. This situation was eaither broken or not fully implemented yet. I modified async.map to call r.send rather than send(r) and then modified async.send to actually make use of the pool that it is passed. 2012-01-17 15:21:09 -06:00
Ben
97be9ee4cd The async.send method wasn't really doing anything useful. It was just calling the r.send() method of the Request object 'r'. It took an optional kwarg pools, and assigned it to r._pools which isn't used by anything. This situation was eaither broken or not fully implemented yet. I modified async.map to call r.send rather than send(r) and then modified async.send to actually make use of the pool that it is passed. 2012-01-17 15:20:52 -06:00
Ben
c658b363e3 The async.send method wasn't really doing anything useful. It was just calling the r.send() method of the Request object 'r'. It took an optional kwarg pools, and assigned it to r._pools which isn't used by anything. This situation was eaither broken or not fully implemented yet. I modified async.map to call r.send rather than send(r) and then modified async.send to actually make use of the pool that it is passed. 2012-01-17 15:17:38 -06:00
Ronny Pfannschmidt
7f9cef0114 close the chunked fd at the end and honor content chunksizes for a potential first chunk 2012-01-17 18:14:47 +01:00
Hank Gay
8efb6cc870 Allow mixing sessions and async. 2012-01-17 11:44:59 -05:00
Ronny Pfannschmidt
1c8a141711 remove debug print 2012-01-17 17:39:37 +01:00
Ronny Pfannschmidt
4d38790b5b even more evil, fixes my misstakes with chunked reading 2012-01-17 17:38:52 +01:00
Ronny Pfannschmidt
5cfbb0aaf5 insanity for chunked iteration 2012-01-17 13:16:09 +01:00
Ronny Pfannschmidt
29271a4100 make Response.iter_lines yield the pending buffer if its actually a complete line 2012-01-17 12:47:22 +01:00
Kenneth Reitz
df0dc2b67a +1 2012-01-15 16:39:46 -05:00
Kenneth Reitz
ff286f351c Update AUTHORS.rst 2012-01-13 17:38:28 -05:00
Kenneth Reitz
430125b396 Merge pull request #355 from fkumro/develop
Added prefetch documentation for api
2012-01-13 14:38:09 -08:00
Frank Kumro
0536e5b708 Added prefetch documentation for api 2012-01-12 22:16:31 -05:00
Kenneth Reitz
e6990162e5 Tom Moertel 2012-01-12 12:53:45 -08:00
Kenneth Reitz
d9b304b906 Merge pull request #352 from tmoertel/develop
Fix bug in HTTP-digest auth w/ URI having query string
2012-01-12 12:52:02 -08:00
Tom Moertel
79f5d532c6 Fix bug in HTTP-digest auth w/ URI having query string 2012-01-10 18:18:54 -05:00
Kenneth Reitz
6af6a08b7a Merge pull request #344 from sharat87/patch-1
Do not pass over the `session` argument to `Session.request` method
2012-01-10 11:11:01 -08:00
Kenneth Reitz
96d5044722 Merge pull request #348 from LucianU/develop
Fixed code in 'Event Hooks' section
2012-01-10 11:10:02 -08:00
Kenneth Reitz
4258201900 Update AUTHORS.rst 2012-01-10 11:09:09 -08:00
Kenneth Reitz
11e5126454 Merge pull request #347 from LucianU/patch-1
Printing the entire traceback, instead of just a warning, when an except...
2012-01-10 11:08:53 -08:00
Kenneth Reitz
9e953f3320 Merge pull request #350 from piotr-dobrogost/develop
fixes issue #349
2012-01-10 11:07:45 -08:00
Piotr Dobrogost
bbbeedb0a2 fixes issue #349 2012-01-10 16:47:21 +01:00
Lucian Ursu
de17f4e5a4 Fixed code in 'Event Hooks' section 2012-01-10 12:17:57 +02:00
Lucian Ursu
86eba21b8a Printing the entire traceback, instead of just a warning, when an exception is encountered 2012-01-10 12:10:58 +02:00
Shrikant Sharat Kandula
53d679edba The request method of Session class does not take a session argument. But api.request does. So, it has to be popped before you can send the whole kwargs dict to Session.request method. 2012-01-09 11:16:54 +05:30
Kenneth Reitz
89c90add2c Update docs/index.rst 2012-01-07 18:32:56 -05:00
Kenneth Reitz
a869be1e5a Merge pull request #343 from shazow/urllib3-attribution
urllib3 attribution in docs
2012-01-07 15:28:17 -08:00
Andrey Petrov
68619b8088 Merge branch 'develop' of https://github.com/kennethreitz/requests into urllib3-attribution 2012-01-07 15:19:02 -08:00
Andrey Petrov
534cdd7587 Rewriting history for correctness. 2012-01-07 15:17:14 -08:00
Andrey Petrov
e185aec920 Adding a humble mention of urllib3 to the Requests intros. 2012-01-07 15:17:06 -08:00
Kenneth Reitz
14e8eea0ee Merge remote-tracking branch 'origin/develop' into develop 2012-01-07 17:18:53 -05:00
Kenneth Reitz
2b849545ea urllib3 update 2012-01-07 17:18:49 -05:00
Kenneth Reitz
15396fb2f9 Update docs/user/advanced.rst 2012-01-07 13:44:09 -05:00
Kenneth Reitz
1acef81ed3 Merge pull request #342 from bjedwards/patch-1
Fix syntax error in last commit.
2012-01-06 12:53:56 -08:00
Ben Edwards
a25141f9f4 Fix syntax error in last commit. 2012-01-06 13:52:49 -07:00
Kenneth Reitz
d339ffe9d9 @ojii 2012-01-06 11:36:04 -05:00
Kenneth Reitz
c5ba5888b5 Merge pull request #341 from ojii/patch-1
Give a more useful error message when the URL supplied does not contain ...
2012-01-06 08:20:49 -08:00
Jonas Obrist
3415e6de0b Give a more useful error message when the URL supplied does not contain a schema. 2012-01-06 16:20:33 +01:00
Kenneth Reitz
638532dd9a v0.9.1 2012-01-06 01:10:53 -05:00
Kenneth Reitz
c6fc7d99b5 Merge branch 'develop' of https://github.com/gazpachoking/requests into develop 2012-01-06 01:08:06 -05:00
Kenneth Reitz
281e0598bc Merge pull request #333 from bryanhelmig/develop
Add eager mode for raising errors immediately.
2012-01-05 22:04:11 -08:00
Bryan Helmig
aa39fb0c80 mention of error modes in quickstart 2012-01-05 14:11:19 -06:00
Bryan Helmig
459a91c54f highway to the danger_mode 2012-01-05 12:50:44 -06:00
Bryan Helmig
115b51e68c add eager mode for raising errors immediately 2012-01-04 22:08:01 -06:00
Kenneth Reitz
4441697e49 Update README.rst 2012-01-03 10:21:13 -05:00
Chase Sterling
5174ab4325 Make sure newlines at chunk borders do not get dropped using iter_lines. 2012-01-03 00:38:59 -05:00
Chase Sterling
95911f059a Refactor r.iter_lines to retrieve more than one byte at a time.
Fixes universal line ending handling, but takes away ability to specyfy
custom line endings.
2012-01-02 16:19:35 -05:00
Kenneth Reitz
e3288d5e33 Update docs/user/install.rst 2012-01-02 02:50:09 -05:00
Kenneth Reitz
49140d6880 2012 2012-01-01 00:44:20 -05:00
Chase Sterling
9c6ffc5303 Refactor stream_decode_gzip and _deflate into one function, stream_decompress.
stream_decompress will now iterate over the raw data if there is a problem with decompression
Remove gzip decoding from Response.content, as urllib3 was doing it anyway.
2011-12-30 22:18:08 -05:00
Chase Sterling
f80984f377 Implement automatic deflating when using response.iter_content. refs #327
Refactor response.iter_lines to use responset.iter_content.
2011-12-30 18:55:56 -05:00
Kenneth Reitz
9c0a0fbd01 ch ch changes 2011-12-28 04:49:51 -05:00
Kenneth Reitz
57dbab2932 v0.9.0 history 2011-12-28 04:48:57 -05:00
Kenneth Reitz
7fdb541e2d make it true 2011-12-28 04:48:27 -05:00
Kenneth Reitz
082f4d8948 packaging 2011-12-28 04:38:38 -05:00
Kenneth Reitz
8aa015ffc9 v0.8.9 2011-12-28 04:26:23 -05:00
Kenneth Reitz
cfb1a478ac ssl hostname 2011-12-28 04:25:43 -05:00
Kenneth Reitz
28db6c3f53 engrish 2011-12-28 03:58:08 -05:00
Kenneth Reitz
5f768b191d certifi v0.0.4 2011-12-28 03:51:41 -05:00
Kenneth Reitz
d9a9a981bc certifi v0.0.2 2011-12-28 03:30:33 -05:00
Kenneth Reitz
9fcfec18da ssl docs 2011-12-28 03:18:40 -05:00
Kenneth Reitz
a83268b01b v0.8.8 release 2011-12-28 03:01:36 -05:00
Kenneth Reitz
a1afbfbaa3 external tests 2011-12-28 03:01:00 -05:00
Kenneth Reitz
4114b04521 v0.8.8! 2011-12-28 03:00:53 -05:00
Kenneth Reitz
f7e67c01ea only use session verify when not modified 2011-12-28 02:57:36 -05:00
Kenneth Reitz
544a5fea59 more info 2011-12-28 02:51:49 -05:00
Kenneth Reitz
0a8bb2e1b3 verification support in sessions 2011-12-28 02:51:42 -05:00
Kenneth Reitz
5184f0c5a9 SSL support! 2011-12-28 02:43:13 -05:00
Kenneth Reitz
9a1a4136ac new SSLError 2011-12-28 02:43:03 -05:00
Kenneth Reitz
ca26c1a253 api cleanup 2011-12-28 02:42:57 -05:00
Kenneth Reitz
a91ac242f3 simplify api.request 2011-12-28 01:51:26 -05:00
Kenneth Reitz
31d495fb02 certifi 2011-12-28 01:28:49 -05:00
Kenneth Reitz
bdda99c0c1 urllib3 update 2011-12-27 23:14:54 -05:00
Kenneth Reitz
9ed93044e0 Merge branch 'develop' 2011-12-24 03:16:54 -05:00
Kenneth Reitz
0bfc029b5e v0.8.7 2011-12-24 03:16:40 -05:00
Kenneth Reitz
4eb2759400 force safe mode for async 2011-12-24 03:06:13 -05:00
Kenneth Reitz
0001f5b651 Merge remote-tracking branch 'origin/develop' into develop 2011-12-23 17:24:34 -05:00
Ori Livneh
e1615e0f1e Make safe_mode handle exceptions more consistently 2011-12-23 16:14:46 -05:00
Kenneth Reitz
3483bae24f Update docs/index.rst 2011-12-22 23:09:27 -05:00
Ori Livneh
716d29c49c fix iteration on null responses in safe_mode 2011-12-22 21:10:43 -05:00
Ori Livneh
a7223f86a9 Undo stupid change to while loop 2011-12-22 17:51:22 -05:00
Ori Livneh
2c0ff95d4d Revert "Revert "Make safe_mode play nice with timeout (fixes #312)""
This reverts commit 91766548d1.
2011-12-22 17:50:43 -05:00
Ori Livneh
91766548d1 Revert "Make safe_mode play nice with timeout (fixes #312)"
This reverts commit 805c4db55413c96c5d6e0f95560119c000f660c9.
2011-12-22 17:42:57 -05:00
Ori Livneh
12f3c65e5a Make safe_mode play nice with timeout (fixes #312) 2011-12-22 16:52:29 -05:00
Kenneth Reitz
f5e421e880 1 instead of True
#313
2011-12-22 11:55:55 -05:00
Kenneth Reitz
9d88ac7b50 Merge branch 'develop' of https://github.com/atdt/requests into develop
Conflicts:
	AUTHORS.rst
2011-12-22 11:55:13 -05:00
Kenneth Reitz
75dc012f41 AUTHORS += 'Ori Livneh'
#313
2011-12-22 11:54:07 -05:00
Ori Livneh
f214b91d77 fix bug that causes iter_lines to truncate content
Currently, if the response does not terminate with a newline, iter_lines
truncates the trailing remainder.
2011-12-20 02:01:37 -05:00
Kenneth Reitz
f80fbad4ff Update AUTHORS.rst 2011-12-19 12:25:59 -05:00
Kenneth Reitz
2e38f54b39 Merge pull request #311 from jemerick/patch-1
Add Twitter Streaming API example to Advanced Usage docs
2011-12-19 08:51:15 -08:00
Jason Emerick
2c153c1556 Add Twitter Streaming API example to Advanced Usage docs 2011-12-19 11:45:32 -05:00
Kenneth Reitz
70fbd27d5c Merge commit 'v0.8.6' 2011-12-18 19:19:14 -05:00
Kenneth Reitz
c910b958f0 quotes 2011-12-18 19:18:16 -05:00
Kenneth Reitz
6ce4ece8aa v0.8.6 2011-12-18 19:18:09 -05:00
Kenneth Reitz
5be6c21b14 added @chrisguitarguy to authors.
#309
2011-12-18 19:17:51 -05:00
Kenneth Reitz
8207ed074e keep auth DRY 2011-12-18 19:14:50 -05:00
Kenneth Reitz
f8cf713f41 Merge branch 'proxy_auth' of https://github.com/chrisguitarguy/requests into develop 2011-12-18 19:11:39 -05:00
Kenneth Reitz
8f58c095c5 urllib3 update 2011-12-18 14:10:38 -05:00
Kenneth Reitz
5937282618 pyc importer 2011-12-18 14:07:21 -05:00
Kenneth Reitz
a3b8ef15db urllib3 import 2011-12-18 14:07:12 -05:00
Christopher Davis
4e2ecd6987 Fixed some tab/spaces mixed issues 2011-12-17 13:48:40 -06:00
Christopher Davis
814e0520ad Add Proxy Authorization support 2011-12-17 13:40:04 -06:00
Kenneth Reitz
19a2a6c6d1 Merge branch 'develop' 2011-12-14 10:43:41 -05:00
Kenneth Reitz
0e711f2f9d v0.8.5 2011-12-14 10:43:08 -05:00
Kenneth Reitz
5e60279a19 whitespace 2011-12-14 10:37:46 -05:00
Kenneth Reitz
6fb2674446 iter_lines! 2011-12-14 10:37:40 -05:00
Kenneth Reitz
5a3aae73ba test iter_lines 2011-12-14 10:34:31 -05:00
Kenneth Reitz
47510486ec httpbin reports multiple values now 2011-12-14 10:33:47 -05:00
Kenneth Reitz
c3bba1543b new reqs location 2011-12-14 10:33:29 -05:00
Kenneth Reitz
cef1811415 httpbin v0.0.6 2011-12-14 10:33:22 -05:00
Kenneth Reitz
21acc6b732 newline 2011-12-13 18:23:04 -05:00
Kenneth Reitz
ba71e2a3cb shuffle reqs 2011-12-13 14:37:25 -05:00
Kenneth Reitz
baf3dcb6c7 less 2011-12-12 18:30:45 -05:00
Kenneth Reitz
8b92b6513c trying less toc 2011-12-12 18:29:41 -05:00
Kenneth Reitz
03ddf26596 more assertive 2011-12-11 11:57:50 -05:00
Kenneth Reitz
8c1fd5db95 Merge branch 'develop' 2011-12-11 11:41:42 -05:00
Kenneth Reitz
10eed6344c v0.8.4 2011-12-11 11:39:57 -05:00
Kenneth Reitz
06eee390dd updated notice 2011-12-11 11:39:11 -05:00
Kenneth Reitz
fad9abfd77 Merge remote-tracking branch 'origin/develop' into develop 2011-12-11 11:26:16 -05:00
Kenneth Reitz
a5f79712bb Fix for #303 2011-12-11 11:26:13 -05:00
Kenneth Reitz
c71ac7917a Test for #303 2011-12-11 11:22:33 -05:00
Kenneth Reitz
4e59f9ec93 Merge pull request #305 from oasisbob/develop
Fix spelling errors, typos.
2011-12-11 08:04:26 -08:00
Nick Hatch
a6412b02ba Fix spelling errors, typos. 2011-12-11 01:58:55 -06:00
Kenneth Reitz
961f78ab5f Merge remote-tracking branch 'origin/develop' into develop 2011-12-09 13:23:26 -08:00
Kenneth Reitz
463ca76cc4 colors! 2011-12-09 13:23:16 -08:00
Kenneth Reitz
f58ab8bc03 Update AUTHORS.rst 2011-12-09 08:43:02 -08:00
Kenneth Reitz
3a06c35da3 Merge pull request #301 from cwvh/patch-1
Fixed typo in documentation.
2011-12-09 08:42:18 -08:00
Chris Van Horne
37070ac30e Fixed spelling error in documentation. 2011-12-09 00:48:22 -07:00
Kenneth Reitz
e56d05d230 Update AUTHORS.rst 2011-12-06 18:41:20 -08:00
Kenneth Reitz
f1fa8f0064 Merge pull request #300 from edsu/develop
disable_redirects should be allow_redirects in docs
2011-12-06 18:38:31 -08:00
Ed Summers
56d6d703f9 disable_redirects parameter does not seem to exist anymore, updated docs to point folks at allow_redirects 2011-12-06 21:36:32 -05:00
Kenneth Reitz
7fbbdeb324 Merge remote-tracking branch 'origin/develop' into develop 2011-11-30 12:45:17 -05:00
Kenneth Reitz
f7e4832472 sp 2011-11-30 12:45:13 -05:00
Kenneth Reitz
4ed16d99c2 Merge pull request #294 from failberg/develop
Documentation fix: clarification of keep-alive behavior.
2011-11-29 00:06:54 -08:00
Bryan Berg
02f422d132 Clarification of keep-alive behavior.
The existing behavior was a little opaque for me--I was making a PUT request which returned a HTTP 204 with a 0-byte body. I was never reading the body and was wondering why my connections were not being reused.
2011-11-28 22:55:02 -08:00
Kenneth Reitz
a76f4925b5 didn't mean to save that 2011-11-27 15:07:05 -05:00
Kenneth Reitz
c2e942f230 no .idea ignore 2011-11-27 11:31:48 -05:00
Kenneth Reitz
c7b99f7819 Set Response.sent to True
Fixes #291
2011-11-27 11:29:52 -05:00
Kenneth Reitz
6bb4c4ebe6 Added test for Request.sent.
#291
2011-11-27 11:24:59 -05:00
Kenneth Reitz
d1dfa02070 Merge branch 'develop' 2011-11-27 10:45:19 -05:00
Kenneth Reitz
ee36baf4f3 test tuple'd auth 2011-11-27 10:41:06 -05:00
Kenneth Reitz
e85b857a35 no link to self 2011-11-27 10:37:14 -05:00
Kenneth Reitz
e7ed1224d2 flattr 2011-11-27 10:32:36 -05:00
Kenneth Reitz
9f29a31f66 v0.8.3 2011-11-27 10:08:19 -05:00
Kenneth Reitz
356bf42373 v0.8.3 2011-11-27 10:06:39 -05:00
Kenneth Reitz
ba00c4411c add github buttons to sidebars 2011-11-27 10:00:47 -05:00
Kenneth Reitz
c74b66a53e v0.8.3 2011-11-27 10:00:40 -05:00
Kenneth Reitz
a7a619ba5c Merge branch 'auth_callables' of https://github.com/idangazit/requests into develop
Conflicts:
	requests/models.py
2011-11-26 10:14:14 -05:00
Kenneth Reitz
65c06579b4 Update AUTHORS.rst 2011-11-26 10:10:57 -05:00
Kenneth Reitz
a5ff4be7b0 Merge pull request #283 from rgieseke/develop
Display full URL when logging.
2011-11-26 07:10:08 -08:00
Kenneth Reitz
52ac24120c Merge pull request #287 from sharat87/patch-2
Allow generators or any iterators for async.map
2011-11-26 07:09:37 -08:00
Kenneth Reitz
a77b91671c Merge pull request #288 from sharat87/session-arg
Add use_session argument to request method.
2011-11-25 20:04:24 -08:00
Shrikant Sharat
a350ceffb9 Rename use_session to session. 2011-11-25 11:41:40 +05:30
Shrikant Sharat
5c72601599 Add use_session argument to request method.
This allows usage of an existing session to make a request with the
request and the get, post etc. function.
2011-11-25 08:32:07 +05:30
Shrikant Sharat Kandula
99b6e35940 Allow generators or any iterators for async.map 2011-11-25 07:45:12 +05:30
Robert Gieseke
8ae4b440e3 Display full URL when logging. 2011-11-20 10:14:51 +01:00
Idan Gazit
1933d3c707 Added support for HTTP Basic Auth credentials in 2-tuple 2011-11-19 23:59:27 +02:00
Kenneth Reitz
9d8d1d14f1 package 2011-11-19 16:28:22 -05:00
Kenneth Reitz
42b33ae1a1 Merge branch 'develop' 2011-11-19 16:19:40 -05:00
Kenneth Reitz
ab23536b1b quickstart for encoding 2011-11-19 16:15:48 -05:00
Kenneth Reitz
b51640b051 history :) 2011-11-19 16:13:12 -05:00
Kenneth Reitz
6421ec1784 iter_content uses new encoding system 2011-11-19 16:12:38 -05:00
Kenneth Reitz
296d8cc097 new (elegant) request decoding model.
Closes #282
2011-11-19 16:09:20 -05:00
Kenneth Reitz
bbf1021156 import cleanup 2011-11-19 15:45:45 -05:00
Kenneth Reitz
8ffe17cb09 use monkey patched cookies 2011-11-19 15:43:46 -05:00
Kenneth Reitz
e17155151b backup 2011-11-19 15:42:36 -05:00
Kenneth Reitz
1da54de5dc 2.5 fix 2011-11-19 15:19:56 -05:00
Kenneth Reitz
8693fc746f v0.8.2 2011-11-19 15:18:48 -05:00
Kenneth Reitz
5309ad005f cookies are oreos 2011-11-19 15:15:51 -05:00
Kenneth Reitz
43854067d4 oreos! 2011-11-19 15:15:30 -05:00
Kenneth Reitz
5a7fbbb00d kill all the monkeys 2011-11-19 13:04:10 -05:00
Kenneth Reitz
04ee583822 Update docs/index.rst 2011-11-19 11:56:37 -05:00
Kenneth Reitz
2a7223585e Merge pull request #280 from darkrho/58e018af136190a2c757b13bf9371cecc2d51273
Updated docs with an example of explicit filename in file uploads section
2011-11-18 21:26:08 -08:00
Rolando Espinoza La fuente
58e018af13 updated docs for last change in files argument to support explicit filename. 2011-11-18 18:45:10 -04:00
Rolando Espinoza La fuente
c165255e98 use session's hooks as defaults for every requests. 2011-11-18 18:19:27 -04:00
Kenneth Reitz
cf60062df1 Merge remote-tracking branch 'origin/develop' into develop 2011-11-18 15:34:37 -05:00
Kenneth Reitz
82a5f1dd9b Merge pull request #271 from darkrho/develop
Filenames improvement and cookie fix
2011-11-18 12:34:07 -08:00
Kenneth Reitz
c70b7bb012 Rolando Espinoza La fuente 2011-11-18 15:34:02 -05:00
Kenneth Reitz
16aa01420b Merge branch 'develop' of https://github.com/darkrho/requests into develop 2011-11-18 15:33:20 -05:00
Kenneth Reitz
e98e61da12 Merge pull request #274 from elpres/patch-1
Corrected period to comma.
2011-11-18 12:06:39 -08:00
Kenneth Reitz
cfefcab8e0 Ryan Kelly 2011-11-18 14:48:28 -05:00
Kenneth Reitz
eb5d191a57 Merge branch 'develop' of https://github.com/rfk/requests into develop 2011-11-18 14:44:21 -05:00
Kenneth Reitz
3ea9c53826 best testimonial ever 2011-11-18 13:47:20 -05:00
Ryan Kelly
3900243297 Dont use requote_path when dealing with redirects.
This was breaking redirect locations with a query string, by quoting the
question-mark.  Since the path will be passed through requote_path on
the next request anyway, doing it here seems unnecessary.
2011-11-18 09:03:28 +11:00
Idan Gazit
7fdb09b766 Converted auth to use callable objects instead of tuples.
My attempt to address #275 on kennethreitz/requests.
2011-11-17 13:44:13 +02:00
elpres
81efe1fa88 Corrected period to comma. 2011-11-17 11:31:55 +01:00
Ryan Kelly
f7fdfe8b9a Correct handling of URLs with quoted slashes. 2011-11-17 11:00:02 +11:00
Kenneth Reitz
76dacaf231 homepage update 2011-11-16 18:16:09 -05:00
Rolando Espinoza La fuente
89241c525e use ";" instead "\r\n" as separator for cookies as is better supported
in odd web servers.
2011-11-16 00:04:48 -04:00
Rolando Espinoza La fuente
bf499a80de added support for explicit filenames in files parameter.
files = {
    "files[]": ("myfile", open("foo")),
}
2011-11-16 00:03:19 -04:00
Kenneth Reitz
6b129ec0c9 urllib3 fix 2011-11-15 10:01:37 -05:00
Kenneth Reitz
1165bec773 Merge branch 'develop' 2011-11-15 10:00:05 -05:00
Kenneth Reitz
b79dea97fd v0.8.1 2011-11-15 09:56:21 -05:00
Kenneth Reitz
4504953212 Only send URL path to servers
Closes #256
2011-11-15 09:52:42 -05:00
Kenneth Reitz
2ccc68c4b4 Merge pull request #268 from benmao/develop
fixed: 301 request does not use proxy.
2011-11-15 05:58:10 -08:00
ben
7c66e6f267 fixed: 301 request does not use proxy. 2011-11-15 15:53:38 +08:00
Kenneth Reitz
bec201c5ca Merge pull request #267 from benmao/develop
fixed proxy
2011-11-14 19:04:02 -08:00
ben
35b0c5e16e fixed proxy 2011-11-15 10:59:39 +08:00
Kenneth Reitz
fc0565fa5d Merge pull request #260 from joequery/doc_changes
Doc changes
2011-11-14 13:43:01 -08:00
Kenneth Reitz
289e813ab6 Merge pull request #262 from petermanser/patch-1
Fixing status codes. Somehow these were wrong.
2011-11-14 13:42:24 -08:00
Kenneth Reitz
8a1b0e1852 Merge pull request #264 from pennersr/patch-1
Pass along timeout when following redirects (closes #263)
2011-11-14 13:42:18 -08:00
Raymond Penners
f0edd4a3e0 Pass along timeout when following redirects (closes #263) 2011-11-14 10:04:07 +01:00
Peter Manser
a64a62088a Fixing status codes. Somehow these were wrong. 2011-11-14 09:44:43 +01:00
Joseph McCullough
588b6bbf8a Added OAuth reference to quickstart file 2011-11-14 01:09:12 -06:00
Joseph McCullough
d3cbf37352 Removed closed issues from todo doc 2011-11-14 00:49:11 -06:00
Kenneth Reitz
6b377cc919 grocer's apostrophe 2011-11-13 01:24:29 -05:00
Kenneth Reitz
e91fe9b2b8 stray note 2011-11-13 01:21:58 -05:00
Kenneth Reitz
45c9ecc82a missing param in quick start 2011-11-13 01:21:30 -05:00
Kenneth Reitz
3d49eb40f8 sp 2011-11-13 01:17:27 -05:00
Kenneth Reitz
9f6246a7b8 s 2011-11-13 00:59:22 -05:00
Kenneth Reitz
8f20058d0d Merge branch 'master' of github.com:kennethreitz/requests 2011-11-13 00:51:50 -05:00
Kenneth Reitz
6e9cb09fff Merge branch 'develop' 2011-11-13 00:51:40 -05:00
Kenneth Reitz
9aa62d5622 13th 2011-11-13 00:48:54 -05:00
Kenneth Reitz
bcc48a9607 whatespace 2011-11-13 00:43:14 -05:00
Kenneth Reitz
3458e6a905 upstream urllib3 2011-11-13 00:38:08 -05:00
Kenneth Reitz
0086f97b65 Guess filename.
Closes #192
2011-11-13 00:36:22 -05:00
Kenneth Reitz
06b9d154cc Merge pull request #255 from shazow/patch-1
Adding me into a Urllib3 subsection (as was in urllib3-backup).
2011-11-12 19:52:05 -08:00
Andrey Petrov
e8668fb512 Adding me into a Urllib3 subsection (as was in urllib3-backup). 2011-11-12 18:16:20 -08:00
Kenneth Reitz
b40128219f Merge branch 'develop' 2011-11-12 18:35:39 -05:00
Kenneth Reitz
14a798882c fixes 2011-11-12 18:34:40 -05:00
Kenneth Reitz
37bbdbe8c3 urllib3 in setup.py 2011-11-12 18:34:33 -05:00
Kenneth Reitz
4ab76943ef document timeouts 2011-11-12 18:34:27 -05:00
Kenneth Reitz
30377ca912 redirection docs 2011-11-12 18:23:26 -05:00
Kenneth Reitz
0a24de2ef9 big docs update on workflow of request lifecycle 2011-11-12 18:23:19 -05:00
Kenneth Reitz
3462d9c87b trust built-in if its available 2011-11-12 16:49:08 -05:00
Kenneth Reitz
2584c48e8d python2.5 cookie support 2011-11-12 16:47:40 -05:00
Kenneth Reitz
0a4b7356ac rip 2.7.x collections out 2011-11-12 16:47:14 -05:00
Kenneth Reitz
ec926a4958 test fix 2011-11-12 16:46:53 -05:00
Kenneth Reitz
e84d84b5b8 use new collections MutableMutex 2011-11-12 16:39:18 -05:00
Kenneth Reitz
cfc1a76381 no auto async 2011-11-12 13:14:51 -08:00
Kenneth Reitz
6730818ddc explicit 2011-11-12 13:14:42 -08:00
Kenneth Reitz
7ee2b79127 import async if it's available 2011-11-12 13:08:17 -08:00
Kenneth Reitz
58c77bac27 quicker start 2011-11-12 13:03:29 -08:00
Kenneth Reitz
40c54800a6 file uploads 2011-11-12 13:01:42 -08:00
Kenneth Reitz
3fccf63f49 stylee 2011-11-12 12:58:46 -08:00
Kenneth Reitz
6a23625c11 give Request session reference for parameter+redirects 2011-11-12 12:57:32 -08:00
Kenneth Reitz
474e17b0af remove bunk __all__s 2011-11-12 12:53:23 -08:00
Kenneth Reitz
f1e8700e9a consistiency 2011-11-12 12:51:30 -08:00
Kenneth Reitz
c05c64d21b better defaults 2011-11-12 12:48:45 -08:00
Kenneth Reitz
c0d8e8e846 models cleanup 2011-11-12 12:48:28 -08:00
Kenneth Reitz
58e3dd9de8 fix urllib3 bug 2011-11-12 12:47:21 -08:00
Kenneth Reitz
02408973c6 keep-alive as config option only
better defaults
2011-11-12 12:47:11 -08:00
Kenneth Reitz
df2c80e28e fix form data tests 2011-11-12 12:45:35 -08:00
Kenneth Reitz
60558fdcc4 big quick start updates 2011-11-12 12:39:31 -08:00
Kenneth Reitz
52b9f01e6e kill small css file 2011-11-12 11:30:24 -08:00
Kenneth Reitz
b7bb1c7b61 Merge remote-tracking branch 'origin/develop' into develop 2011-11-12 10:01:42 -08:00
Kenneth Reitz
7c206c74ba Timeouts for urllib3 2011-11-12 10:01:05 -08:00
Kenneth Reitz
50279dd83c Remove timeout configuration 2011-11-12 10:00:30 -08:00
Kenneth Reitz
cdd0613aec Update AUTHORS 2011-11-12 07:45:34 -08:00
Kenneth Reitz
69e7e94c4c updated urllib3 2011-11-12 07:35:55 -08:00
Kenneth Reitz
f5f2ddfa74 throttling 2011-11-12 07:35:41 -08:00
Kenneth Reitz
ff0f9613f2 Merge https://github.com/juanriaza/requests into develop 2011-11-12 07:29:03 -08:00
Kenneth Reitz
30ed6643d7 Merge remote-tracking branch 'origin/develop' into develop 2011-11-12 07:28:26 -08:00
Kenneth Reitz
d9798f4a3c Merge pull request #249 from dasevilla/patch-1
The 'requests-oauth-hook' project was renamed to requests-oauth
2011-11-12 07:19:11 -08:00
Kenneth Reitz
82f2ad6f99 Merge pull request #252 from joequery/fix_doc_typo
Fix various documentation typos
2011-11-11 21:17:21 -08:00
Joseph McCullough
6833b326f8 Fixed gevent reference 2011-11-11 23:15:19 -06:00
Joseph McCullough
afc6561fdb Fixed session API ref typo 2011-11-11 22:17:22 -06:00
Kenneth Reitz
81817852ad Merge pull request #250 from dasevilla/patch-2
Verbose logging example does not work
2011-11-11 14:56:17 -08:00
Devin Sevilla
2d8440ea98 Verbose logging example does not work 2011-11-10 15:34:18 -08:00
Devin Sevilla
a348fd7ae3 The 'requests-oauth-hook' project was renamed to requests-oauth 2011-11-10 15:14:38 -08:00
Kenneth Reitz
1588ad7c46 remove poster 2011-11-09 22:44:58 -08:00
Kenneth Reitz
ae9cdf1a47 options history 2011-11-09 22:18:35 -08:00
Kenneth Reitz
220f687e6f Merge branch 'develop' of https://github.com/jbrendel/requests into develop
Conflicts:
	AUTHORS
	requests/__init__.py
2011-11-09 22:15:54 -08:00
Kenneth Reitz
f4296ba758 Joseph McCullough 2011-11-09 22:01:24 -08:00
Kenneth Reitz
3d6937af7d Merge branch 'develop' of https://github.com/joequery/requests into develop 2011-11-09 21:59:19 -08:00
Kenneth Reitz
fad1c665a6 remove the jar references 2011-11-09 21:36:34 -08:00
Kenneth Reitz
b17ec8e1df yep! 2011-11-09 19:09:11 -08:00
Kenneth Reitz
d1b6db05a4 prefetch handling for _content_consumed 2011-11-09 17:56:29 -08:00
Kenneth Reitz
2999c71e46 more proper prefetch 2011-11-09 17:54:13 -08:00
Kenneth Reitz
0b424e1637 note about prefetch method 2011-11-09 17:52:20 -08:00
Kenneth Reitz
87239802c1 proxy pooling! 2011-11-09 17:50:36 -08:00
Kenneth Reitz
0c4342a3a6 prefetching on all methods 2011-11-09 17:47:19 -08:00
Kenneth Reitz
bd45bc716a add prefetch to main request distpatch 2011-11-09 17:46:19 -08:00
Kenneth Reitz
dfbfb2303f ref 2011-11-09 17:34:59 -08:00
Kenneth Reitz
4002efb56a history 2011-11-09 17:34:21 -08:00
Kenneth Reitz
f7257eada6 Session at root 2011-11-09 17:30:20 -08:00
Kenneth Reitz
02ea563a06 massive css improvements 2011-11-09 17:30:03 -08:00
Kenneth Reitz
341ac9fe8a 800px yo! 2011-11-09 17:26:32 -08:00
Kenneth Reitz
5bc919a24f cross-references in documentation 2011-11-09 17:26:23 -08:00
Kenneth Reitz
a0c3570640 better stepping for elastic design 2011-11-09 17:26:13 -08:00
Kenneth Reitz
ce42b338f4 Configurations 2011-11-09 17:16:03 -08:00
Kenneth Reitz
17088763e7 better advanced quick start 2011-11-09 17:15:54 -08:00
Kenneth Reitz
53bf544050 better api docs 2011-11-09 17:15:44 -08:00
Kenneth Reitz
e725f30625 document defaults 2011-11-09 16:52:27 -08:00
Kenneth Reitz
4e8b680865 explain sessions and keep alive 2011-11-09 16:52:20 -08:00
Kenneth Reitz
92a8db6da0 httplib + urllib3 2011-11-09 16:52:10 -08:00
Kenneth Reitz
2131ba4dda check! 2011-11-09 16:26:36 -08:00
Kenneth Reitz
7a1a40e445 ultra cookie compatibility 2011-11-09 16:26:15 -08:00
Kenneth Reitz
52a95cb93a header and cookie fixes for redirects 2011-11-09 16:24:48 -08:00
Kenneth Reitz
0c4b973dcf keep_alive is now disable-able! 2011-11-09 15:54:24 -08:00
Kenneth Reitz
7192b8022e import ConnectionError 2011-11-09 15:47:09 -08:00
Kenneth Reitz
147c24154e better defaults for "models" 2011-11-09 15:46:45 -08:00
Kenneth Reitz
99f0ef4766 add safe_mode for @bitprophet :) 2011-11-09 15:46:01 -08:00
Kenneth Reitz
35ed9b5f38 dict(o or []) 2011-11-09 15:44:55 -08:00
Kenneth Reitz
0f2dcff725 add query data yourself, foo' 2011-11-09 15:44:14 -08:00
Kenneth Reitz
5b73f2ea61 infos 2011-11-09 15:43:54 -08:00
Kenneth Reitz
1d2abea94b new ConnectionError for bad APIs :) 2011-11-09 15:30:47 -08:00
Kenneth Reitz
6a51f6b2f8 add 'max_retries' configuration 2011-11-09 15:30:33 -08:00
Kenneth Reitz
c48f0d990f Merge branch 'develop' into feature/rewrite
Conflicts:
	requests/__init__.py
	test_requests.py
2011-11-09 15:13:38 -08:00
Kenneth Reitz
f9141f51ec Make sure that session-level cookies work. 2011-11-09 15:04:13 -08:00
Kenneth Reitz
e649003974 test the cookies! 2011-11-09 15:02:53 -08:00
Kenneth Reitz
358478eb88 Cookie persistence! 2011-11-09 14:57:38 -08:00
Kenneth Reitz
498b446f14 Models cleanup 2011-11-09 14:57:00 -08:00
Kenneth Reitz
f5bbb9714d Note about terrible DNS providers for testing 2011-11-09 10:24:41 -05:00
Joseph McCullough
1031ec4942 Reverted GET example back to Github. 2011-11-08 12:10:06 -06:00
Joseph McCullough
827b2340a2 Forgot to delete line mentioning Github in GET section 2011-11-08 02:23:32 -06:00
Joseph McCullough
8de59f03a0 Added POST to quick start. Modified GET in doc to use httpbin 2011-11-08 01:37:39 -06:00
jbrendel
73ba48be2e Added support for OPTIONS method. 2011-11-08 12:31:18 +13:00
Kenneth Reitz
72943d0247 Merge branch 'develop' 2011-11-07 14:21:31 -05:00
Kenneth Reitz
8c90c610cd v0.7.6
Fixes #237
2011-11-07 14:20:32 -05:00
Kenneth Reitz
1a85e110b8 Merge branch 'develop' of github.com:kennethreitz/requests into develop 2011-11-07 14:18:20 -05:00
Kenneth Reitz
12fa108ede add query data to digest path 2011-11-07 14:18:05 -05:00
Kenneth Reitz
9c3ca6e740 The Washington Post 2011-11-07 10:42:10 -05:00
Kenneth Reitz
12ada03548 Merge pull request #244 from neogenix/patch-1
Updated your 2001, to 2011... unless you went back in time ;)
2011-11-06 19:58:34 -08:00
Patrick
daa4fbf4e2 Updated your 2001, to 2011... unless you went back in time ;) 2011-11-06 21:57:47 -06:00
Juan Riaza
6fefffd03e #GH-241 2011-11-06 22:02:14 +01:00
Kenneth Reitz
7ce305fa89 french post 2011-11-06 13:25:34 -05:00
Kenneth Reitz
04cdd0f2e7 daikon 2011-11-06 13:24:23 -05:00
Kenneth Reitz
33ee732082 steal @shazow's contribute paragraph 2011-11-04 23:57:43 -04:00
Kenneth Reitz
d0b96f8e3b Merge branch 'develop' 2011-11-04 23:33:12 -04:00
Kenneth Reitz
cf36d8c753 changes! 2011-11-04 23:32:15 -04:00
Kenneth Reitz
bd562a7ab3 Merge branch 'develop' of https://github.com/davidfischer/requests into develop 2011-11-04 23:28:21 -04:00
Kenneth Reitz
72c8163aee davidfischer 2011-11-04 23:27:50 -04:00
Kenneth Reitz
2bae57e0a6 v0.7.5 2011-11-04 23:26:31 -04:00
Kenneth Reitz
f7968b6797 r.content is None of there's an invalid response.
Fixes #236
2011-11-04 23:24:38 -04:00
Kenneth Reitz
4cae63a297 take out weinre 2011-11-04 23:00:38 -04:00
Kenneth Reitz
628325ae90 Official™ mobile-friendly 2011-11-04 22:58:43 -04:00
Kenneth Reitz
b3e2410f44 mobile auto width 2011-11-04 22:15:54 -04:00
Kenneth Reitz
a02189a8e9 hide rtd on mobile docs 2011-11-04 22:14:12 -04:00
Kenneth Reitz
d343fda7f0 Merge remote-tracking branch 'origin/develop' into develop 2011-11-04 21:59:16 -04:00
Kenneth Reitz
f9bcf7c611 revert 2011-11-04 21:59:12 -04:00
Kenneth Reitz
23b0535a0d Update AUTHORS 2011-11-04 11:51:38 -03:00
Kenneth Reitz
32c7cbf1ad Merge pull request #238 from brutasse/docs-typo
Fixed a broken link in the docs
2011-11-04 07:51:07 -07:00
Bruno Renié
8fe6f8c618 Fixed a broken link in the docs 2011-11-04 15:49:29 +01:00
Kenneth Reitz
80c55f5767 python-rexster 2011-11-03 19:03:11 -03:00
David Fischer
3efd5dbab4 A cleaner and more complete fix for auth/redirects 2011-11-03 08:05:55 -07:00
David Fischer
eaf1264879 Fixes an issue with auth and redirects 2011-11-02 23:29:31 -07:00
Kenneth Reitz
f5592ceb48 Merge remote-tracking branch 'origin/develop' into develop 2011-11-02 20:39:15 -04:00
Kenneth Reitz
e32840f631 fix request docs 2011-11-02 20:39:06 -04:00
Kenneth Reitz
4596c02339 Merge pull request #234 from anatomyofashane/develop
ch ch chcnages
2011-10-31 18:53:07 -07:00
Shane McDonald
4fcf14e124 ch ch chcnages
via @kennethreitz
2011-10-31 21:50:57 -04:00
Kenneth Reitz
797301a63b Merge pull request #233 from anatomyofashane/develop
Update docs/_themes/kr/static/flasky.css_t
2011-10-31 18:26:52 -07:00
anatomyofashane
3615cbc9df Update docs/_themes/kr/static/flasky.css_t 2011-10-31 22:24:59 -03:00
Kenneth Reitz
b8c55da48d stuff and things and stuff 2011-10-27 01:08:51 -04:00
Kenneth Reitz
5b54b3e53f Merge branch 'develop' into feature/rewrite
Conflicts:
	requests/__init__.py
2011-10-27 00:57:03 -04:00
Kenneth Reitz
e43b438729 test fix 2011-10-26 18:42:58 -04:00
Kenneth Reitz
3326030862 Merge branch 'develop' 2011-10-26 18:38:50 -04:00
Kenneth Reitz
8836c4b12a history 2011-10-26 18:38:32 -04:00
Kenneth Reitz
3a4f6ba8b3 v0.7.4 2011-10-26 18:36:14 -04:00
Kenneth Reitz
6ac1e02691 hooks fix #227 2011-10-26 18:35:01 -04:00
Kenneth Reitz
6140fac6aa Default Accept header, a la curl 2011-10-25 16:10:49 -04:00
Kenneth Reitz
a957bcfd7b Merge branch 'develop' into feature/rewrite 2011-10-24 20:55:45 -04:00
Kenneth Reitz
73ed950e70 simplify 2011-10-24 20:55:35 -04:00
Kenneth Reitz
6ef5094be6 Merge remote-tracking branch 'origin/develop' into develop 2011-10-24 20:55:01 -04:00
Kenneth Reitz
077758f713 Merge pull request #224 from stoey/84e89429
Syntax error for Python 2.5
2011-10-24 17:54:05 -07:00
Kenneth Reitz
8b9f689ecc Merge branch 'develop' into feature/rewrite
Conflicts:
	requests/__init__.py
	requests/models.py
2011-10-24 10:09:36 -04:00
Kenneth Reitz
428fc9c0bd PASS ALL TEH TESTS 2011-10-24 01:46:05 -04:00
Kenneth Reitz
d04f31b302 HTTPError 2011-10-23 18:33:27 -04:00
Kenneth Reitz
4673d3dfa7 v0.8.0 2011-10-23 18:28:32 -04:00
Kenneth Reitz
a548b6249d HTTPError 2011-10-23 18:27:54 -04:00
Kenneth Reitz
a9822b0bb6 fix content uploads 2011-10-23 18:24:14 -04:00
Kenneth Reitz
3d3f05884f use new system 2011-10-23 18:15:21 -04:00
Kenneth Reitz
50c39fd95a poolmanager in sessions 2011-10-23 18:15:13 -04:00
Kenneth Reitz
28a9534383 add pool configurations to defaults 2011-10-23 18:15:02 -04:00
Kenneth Reitz
c108c5300f No mo' HttpError 2011-10-23 17:18:46 -04:00
Kenneth Reitz
c60618ae01 Merge branch 'develop' 2011-10-23 16:57:28 -04:00
Kenneth Reitz
0008b035e2 v0.7.3 2011-10-23 16:56:47 -04:00
Kenneth Reitz
be69529dca oops, debugging prints 2011-10-23 16:53:21 -04:00
Kenneth Reitz
dac050bf40 New status_code-based errors 2011-10-23 16:36:53 -04:00
Kenneth Reitz
e7a7615e0d Merge branch 'feature/urllib3-backup' into feature/rewrite 2011-10-23 16:31:41 -04:00
Kenneth Reitz
7c271a466f Import urllib3 2011-10-23 16:18:52 -04:00
Kenneth Reitz
95336a0542 Merge branch 'develop' into feature/rewrite 2011-10-23 16:15:06 -04:00
Kenneth Reitz
e257151ffc Merge branch 'master' into develop 2011-10-23 16:10:24 -04:00
Kenneth Reitz
84a2b35b71 Readme update. 2011-10-23 16:03:06 -04:00
Kenneth Reitz
e15834da8e v0.7.2 2011-10-23 15:40:26 -04:00
Kenneth Reitz
f1bb25b1ec bugfix 2011-10-23 15:39:33 -04:00
Kenneth Reitz
6b9cb059f6 Merge branch 'develop' 2011-10-23 15:21:42 -04:00
Kenneth Reitz
02cf3dce37 v0.7.1 2011-10-23 15:18:27 -04:00
Kenneth Reitz
4fb72a2e68 Merge branch 'feature/detach' into develop 2011-10-23 15:18:09 -04:00
Kenneth Reitz
58b1c69b6a Explain custom auth handlers 2011-10-23 15:13:34 -04:00
Kenneth Reitz
8f8dbec0d5 docs for basic/digest auth 2011-10-23 14:59:46 -04:00
Kenneth Reitz
e46251b727 ch ch changes 2011-10-23 14:52:20 -04:00
Kenneth Reitz
82cbae479c history for this 2011-10-23 14:51:22 -04:00
Kenneth Reitz
b88fbb5e0c KILL THE AUTH HANDLERS 2011-10-23 14:49:59 -04:00
Kenneth Reitz
68b4830948 Add argument injection hook back 2011-10-23 14:47:15 -04:00
Kenneth Reitz
9966017a49 Add new utilities from werkzeug 2011-10-23 14:46:58 -04:00
Kenneth Reitz
53c7b77735 Digest Authentication test. 2011-10-23 14:46:44 -04:00
Kenneth Reitz
491a3c075d Move hooks into internal event loop 2011-10-23 14:46:35 -04:00
Kenneth Reitz
4916b1c2ce pep8 2011-10-23 14:44:26 -04:00
Kenneth Reitz
60b37e54b5 Digest authentication support!
Ripped from urllib2
2011-10-23 14:44:20 -04:00
Kenneth Reitz
b7c788cc56 prettier async patching 2011-10-23 14:44:00 -04:00
Kenneth Reitz
12db1576e9 auth tuple fix 2011-10-23 12:26:46 -04:00
Kenneth Reitz
af6aa3e572 Move hooks out of top-level loop 2011-10-23 12:26:41 -04:00
Kenneth Reitz
20e0ee4968 Remove AuthObject entirely. 2011-10-23 11:35:01 -04:00
Kenneth Reitz
4892a305d9 more advanced authentication mechanism 2011-10-23 11:33:03 -04:00
Kenneth Reitz
495c3d5006 Use new authentication style in models
🤘
2011-10-23 11:15:42 -04:00
Kenneth Reitz
06a5aed8e2 assert sessions are using new auth 2011-10-23 11:15:11 -04:00
Kenneth Reitz
0dae52220b fix base64 encoding for httpbasic 2011-10-23 11:14:59 -04:00
Kenneth Reitz
d23c4b94c1 httpbasic authentication cleanup 2011-10-23 11:00:36 -04:00
Kenneth Reitz
94c587d642 Comment out authentication handlers 2011-10-23 11:00:21 -04:00
Kenneth Reitz
340f7a0733 initial auth module w/ httpbasic auth 2011-10-23 10:56:04 -04:00
Kenneth Reitz
b8d4a5ea61 v0.7.1 plans 2011-10-23 10:04:46 -04:00
Kenneth Reitz
5b5b3def00 Merge branch 'develop' 2011-10-22 22:14:15 -04:00
Kenneth Reitz
1a4dfad52d mod string formatting for 2.5 2011-10-22 21:33:00 -04:00
Kenneth Reitz
b66871e871 v0.7.0 2011-10-22 21:30:47 -04:00
Kenneth Reitz
a74568d8d5 simplify request dispatch flow 2011-10-22 21:10:24 -04:00
Kenneth Reitz
302c4d9c41 Don't alter behavior for safe methods anymore. 2011-10-22 21:01:45 -04:00
Kenneth Reitz
97e3c84084 simplify the URL check 2011-10-22 20:57:39 -04:00
Kenneth Reitz
0ee6c1fa68 kill accept_gzip config 2011-10-22 20:55:46 -04:00
Kenneth Reitz
f0fe8b971b Merge branch 'feature/config' into develop 2011-10-22 20:32:11 -04:00
Kenneth Reitz
8c34fa8477 settings => config 2011-10-22 20:31:51 -04:00
Kenneth Reitz
6be69e303b history for config 2011-10-22 20:29:00 -04:00
Kenneth Reitz
2f6cf50a6c deprecate settings 2011-10-22 20:28:25 -04:00
Kenneth Reitz
f9dfbb73dd requests.request uses config 2011-10-22 20:28:19 -04:00
Kenneth Reitz
903f96cc6a use config throughout models 2011-10-22 20:28:06 -04:00
Kenneth Reitz
5c81fba1eb use config object in sessions 2011-10-22 20:26:12 -04:00
Kenneth Reitz
4dc48b6521 _config => defaults 2011-10-22 20:25:27 -04:00
Kenneth Reitz
ab3200b4cc config.py => _config.py 2011-10-22 19:41:39 -04:00
Kenneth Reitz
185450c5e1 test entry points 2011-10-22 19:40:45 -04:00
Kenneth Reitz
958c424c89 I don't even want to know. 2011-10-22 19:39:23 -04:00
Kenneth Reitz
61be59d996 show both session styles 2011-10-22 19:34:03 -04:00
Kenneth Reitz
e007a5a13f docstring 2011-10-22 19:27:44 -04:00
Kenneth Reitz
3d29f6535f kill wrapping of api methods 2011-10-22 19:27:08 -04:00
Kenneth Reitz
98dc08236c loose yourself 2011-10-22 18:18:39 -04:00
Kenneth Reitz
4ab0bfefd3 Merge branch 'master' into develop 2011-10-22 18:17:04 -04:00
Kenneth Reitz
e418631ce8 Merge branch 'feature/primary-sessions' into develop 2011-10-22 18:16:43 -04:00
Kenneth Reitz
4d97cc7506 disable rudolf until it obeys 2011-10-22 18:16:10 -04:00
Kenneth Reitz
2b3bd78685 Add all methods to session 2011-10-22 18:15:28 -04:00
Kenneth Reitz
597ace5718 import cleanups 2011-10-22 18:13:22 -04:00
Kenneth Reitz
f269c6c89a cookiejar => cookies in models 2011-10-22 18:10:47 -04:00
Kenneth Reitz
d72d116214 Move request and get to session 2011-10-22 18:10:32 -04:00
Kenneth Reitz
d552e6c884 pep8 all the things 2011-10-22 18:07:14 -04:00
Kenneth Reitz
77909f1d49 v0.6.7 2011-10-22 18:07:00 -04:00
Kenneth Reitz
dbf70fc40f All methods are valid now 2011-10-22 18:02:34 -04:00
Kenneth Reitz
3a6d9b09db test improvements 2011-10-22 12:27:10 -04:00
Kenneth Reitz
b19d8785a4 Update AUTHORS 2011-10-21 11:25:02 -03:00
Kenneth Reitz
41e60b8a00 Merge pull request #217 from thedaniel/async-doc
Clarify documentation around async.map and Request.send
2011-10-21 07:24:11 -07:00
Daniel Hengeveld
eddf5254fb Clarify documentation around async.map and Request.send 2011-10-20 23:55:03 -07:00
Kenneth Reitz
ba5eddcf5e WhitespaceBot 2011-10-20 23:53:25 -04:00
Kenneth Reitz
d63cd5f547 periods. 2011-10-20 23:53:20 -04:00
Kenneth Reitz
348d2a2d51 v0.6.7 initial history 2011-10-20 22:43:52 -04:00
Kenneth Reitz
194ff1ad89 #160 2011-10-20 22:09:08 -04:00
Kenneth Reitz
3b6904c5ef Merge branch 'master' into develop 2011-10-20 11:42:09 -04:00
Kenneth Reitz
8d0e03ce41 Merge remote-tracking branch 'origin/develop' into develop 2011-10-20 11:42:00 -04:00
Kenneth Reitz
baa3f78430 Merge pull request #214 from zsiciarz/new_http_codes
New http codes
2011-10-20 08:41:43 -07:00
Zbigniew Siciarz
4f984b0fe6 New HTTP status codes (draft only).
See IETF document at
https://tools.ietf.org/html/draft-nottingham-http-new-status-02.
2011-10-20 17:37:16 +02:00
Kenneth Reitz
c5ed4c9953 Update AUTHORS 2011-10-20 09:46:32 -03:00
Kenneth Reitz
681956e0c4 Merge pull request #213 from fredrikmollerstrand/develop
Fix pip-compared-to-easy-install url
2011-10-20 05:46:16 -07:00
Fredrik Möllerstrand
ad6a8d53d6 docs: fix pip-compared-to-easy-install url. 2011-10-20 11:50:27 +01:00
Kenneth Reitz
0e9d7aad27 add back the ascii art 2011-10-19 16:50:20 -04:00
Kenneth Reitz
6dc664caaf move core imports into __init__.py
because you can't splat import relatively. dumb.
2011-10-19 16:47:46 -04:00
Kenneth Reitz
98c5ded4f3 Merge branch 'master' into develop 2011-10-19 16:36:22 -04:00
Kenneth Reitz
5568f77ad5 Merge branch 'master' into develop 2011-10-19 16:36:12 -04:00
Kenneth Reitz
cfd38263d1 imports cleanup for @alex 🍰 2011-10-19 15:54:22 -04:00
Kenneth Reitz
c052029399 Update AUTHORS 2011-10-19 12:04:34 -03:00
Kenneth Reitz
b7243684de Merge pull request #211 from tvaught/master
Minor doc spelling tweaks
2011-10-19 08:04:04 -07:00
travis
055f7c1eb6 Some Doc and doctoring fixes by the Speling Poleece. 2011-10-19 10:00:13 -05:00
Kenneth Reitz
e27241df73 Update docs/index.rst 2011-10-19 11:41:33 -03:00
Kenneth Reitz
23efd56b12 Merge branch 'develop' 2011-10-19 03:40:39 -04:00
Kenneth Reitz
d938f32089 v0.6.6 2011-10-19 03:39:36 -04:00
Kenneth Reitz
7dc75ce3ce test session persistent params 2011-10-19 03:37:52 -04:00
Kenneth Reitz
8c74860fd1 add params to session merge attributes 2011-10-19 03:32:53 -04:00
Kenneth Reitz
492133ba64 white in spaaaaaccceeee 2011-10-19 01:36:38 -04:00
Kenneth Reitz
82e8fdbb29 Merge branch 'develop' 2011-10-19 01:31:32 -04:00
Kenneth Reitz
b37b977d20 v0.6.5 2011-10-19 01:30:45 -04:00
Kenneth Reitz
ec94f5030c testing session method attribute merging 2011-10-19 01:10:06 -04:00
Kenneth Reitz
65a765fe88 new local merging of keyword arguments for sessions 2011-10-19 01:09:55 -04:00
Kenneth Reitz
9645e882b2 "Python on the Web" blog post 2011-10-18 17:26:21 -04:00
Kenneth Reitz
ef1e27ea9f apt-get install python-requests 2011-10-17 20:59:27 -04:00
Kenneth Reitz
6bd8e9e73f sp 2011-10-17 20:58:52 -04:00
Kenneth Reitz
de4035fb96 ignore junit xml 2011-10-17 20:57:04 -04:00
Kenneth Reitz
38bd234936 pycodeconf audio 2011-10-17 20:56:54 -04:00
Kenneth Reitz
7481980c1a descriptions for "out there" 2011-10-17 20:52:55 -04:00
Kenneth Reitz
a4234e97be Add "out there" section to docs 2011-10-17 20:41:40 -04:00
Kenneth Reitz
9b42c954c6 Offline test suite 2011-10-15 13:01:56 -04:00
Kenneth Reitz
d0b9357f1b all teh colors 2011-10-15 12:54:50 -04:00
Kenneth Reitz
a688f026dc settings are being deprecated 2011-10-15 12:37:08 -04:00
Kenneth Reitz
60917e0b9f timeout adjustment 2011-10-15 12:35:47 -04:00
Kenneth Reitz
f0bcdd075e gunicorn 2011-10-15 12:33:14 -04:00
Kenneth Reitz
7a0f3638b5 Test suite cleanup 2011-10-15 12:32:42 -04:00
Kenneth Reitz
12997080a8 use gunicorn to serve tests 2011-10-15 12:30:49 -04:00
Kenneth Reitz
6e840f46e1 make test 2011-10-15 12:16:24 -04:00
Kenneth Reitz
12d6697815 v0.0.4 2011-10-15 12:05:40 -04:00
Kenneth Reitz
d85c5356dc remove idna tests, for now 2011-10-15 12:05:35 -04:00
Kenneth Reitz
ff6dbc556b Merge branch 'feature/httpbin' into develop 2011-10-15 11:56:20 -04:00
Kenneth Reitz
35bfa9e91d HTTP Integration 2011-10-15 11:55:57 -04:00
Kenneth Reitz
d98de70f4a envoy. 2011-10-15 11:05:29 -04:00
Kenneth Reitz
e1dfb7c883 httpbin 2011-10-15 09:55:00 -04:00
Kenneth Reitz
15755be3c7 nosexunit is a steaming pile of trash 2011-10-15 09:52:45 -04:00
Dan Head
84e89429f0 Syntax fix for Python 2.5 2011-10-14 22:24:42 +00:00
Kenneth Reitz
daf9b60550 gah, gevent won't work with pypy 2011-10-13 22:39:13 -04:00
Kenneth Reitz
1382d655ed omnijson for python2.5 2011-10-13 22:37:23 -04:00
Kenneth Reitz
f0cfba708b take out pyflakes.. for now. 2011-10-13 22:34:01 -04:00
Kenneth Reitz
435bd1242a reqs.txt for ci and dev 2011-10-13 22:30:19 -04:00
Kenneth Reitz
4f6fc98509 Merge branch 'release/0.6.4' 2011-10-13 22:23:04 -04:00
Kenneth Reitz
9011852db0 Bunk submodule. 2011-10-13 22:22:38 -04:00
Kenneth Reitz
29548bfab6 Remove hacking file. 2011-10-13 22:20:43 -04:00
Kenneth Reitz
efc267ce59 Remove deprecated tox configuration. 2011-10-13 22:20:23 -04:00
Kenneth Reitz
244172bdd4 v0.6.4 2011-10-13 22:17:54 -04:00
Kenneth Reitz
f1f56c3081 Remove debian sources. 2011-10-13 22:17:24 -04:00
Kenneth Reitz
bfa010383e Merge pull request #202 from kennethreitz/feature/content-stream
Content Streaming
2011-10-13 19:16:26 -07:00
Kenneth Reitz
daf7aeb8c3 Async API 2011-10-13 22:15:55 -04:00
Kenneth Reitz
573ab095e4 fo => raw 2011-10-13 22:11:50 -04:00
Kenneth Reitz
030d877ed5 v0.6.4 2011-10-13 22:11:42 -04:00
Kenneth Reitz
33dec52b8e merge cleanups 2011-10-13 22:05:57 -04:00
Kenneth Reitz
aa31b6b4dd Merge fixes 2011-10-13 22:02:50 -04:00
Kenneth Reitz
46f0146adf Merge branch 'feature-content-streaming' of https://github.com/mitsuhiko/requests into feature/content-stream
Conflicts:
	AUTHORS
	HISTORY.rst
	docs/api.rst
	docs/community/faq.rst
	docs/user/intro.rst
	requests/api.py
	requests/models.py
2011-10-13 21:54:42 -04:00
Kenneth Reitz
b14fa0764b gevent installation documentation 2011-10-13 21:50:04 -04:00
Kenneth Reitz
15511584d1 Merge branch 'release/0.6.3' 2011-10-13 21:33:55 -04:00
Kenneth Reitz
80cd1ee663 v0.6.3 history 2011-10-13 21:23:42 -04:00
Kenneth Reitz
3161783e49 history fix 2011-10-13 21:19:47 -04:00
Kenneth Reitz
e9b4defe8d Merge pull request #201 from kennethreitz/feature/async
Beautiful Async Module
2011-10-13 18:15:18 -07:00
Kenneth Reitz
a4b87c6fc1 v0.6.3 history 2011-10-13 21:14:31 -04:00
Kenneth Reitz
cc350d54b7 v0.6.3 2011-10-13 21:13:46 -04:00
Kenneth Reitz
3afd07451c prefetch=False for async.map 2011-10-13 21:10:34 -04:00
Kenneth Reitz
27ee6e0f45 Async requests docs 2011-10-13 21:10:25 -04:00
Kenneth Reitz
849934ccd6 Merge branch 'develop' into feature/async 2011-10-13 20:50:22 -04:00
Kenneth Reitz
597f0ae5fd Catch raw socket errors 2011-10-13 20:47:58 -04:00
Kenneth Reitz
2115046bbc Merge branch 'develop' into feature/async 2011-10-13 20:33:55 -04:00
Kenneth Reitz
565745f7b7 Make it so. 2011-10-13 20:33:39 -04:00
Kenneth Reitz
76b8afee94 Make tests go to 11! 2011-10-13 20:33:34 -04:00
Kenneth Reitz
892fcd6cc0 store hooks in Request. 2011-10-13 20:19:59 -04:00
Kenneth Reitz
5537902796 Remove keep_alive cruft from urllib3 (for now) 2011-10-13 20:17:22 -04:00
Kenneth Reitz
9518d053a4 _return_request => return_response 2011-10-13 20:11:25 -04:00
Kenneth Reitz
93c44157ba initial import of urllib3 branch async 2011-10-13 20:11:05 -04:00
Kenneth Reitz
d47522e6fb v0.6.3 plans 2011-10-13 19:54:59 -04:00
Kenneth Reitz
3e233e4856 v0.6.2 in changelog 2011-10-13 19:53:34 -04:00
Kenneth Reitz
b908559ac8 urllib2 => httplib 2011-10-13 19:41:40 -04:00
Kenneth Reitz
4a7fdef3ea Migrate new docs over. 2011-10-13 14:54:36 -04:00
Kenneth Reitz
a0e9b21c9d blargh 2011-10-13 14:34:56 -04:00
Kenneth Reitz
0cfd801f09 Merge pull request #196 from pyos/patch-2
Fix errors introduced by merging an outdated pull request.
2011-10-12 06:34:44 -07:00
Douglas Morrison
c4f013a6f9 Achieve full API compatibility. 2011-10-12 13:21:09 +00:00
Douglas Morrison
20c930e48e Fix errors introduced by merging an outdated pull request.
Don't do that anymore, OK?
2011-10-12 13:00:34 +00:00
Kenneth Reitz
abe33f0ef4 AUTHORS += 'Luca De Vitis' 2011-10-11 08:40:32 -04:00
Kenneth Reitz
3cfc83b23b merge cleanups 2011-10-11 08:39:43 -04:00
Kenneth Reitz
e4c85b318f Merge branch 'develop' of https://github.com/monkeython/requests into develop
Conflicts:
	requests/api.py
	requests/config.py
	requests/models.py
2011-10-11 08:36:35 -04:00
Kenneth Reitz
f524fe4934 python version support update 2011-10-11 08:05:11 -04:00
Kenneth Reitz
fedbafc79b v0.7.0 dev 2011-10-10 21:08:30 -04:00
Kenneth Reitz
4dc48aea63 remove logger for urllib3 2011-10-10 21:08:17 -04:00
Kenneth Reitz
c8f2b3a722 undo ref trickery 2011-10-10 21:05:54 -04:00
Kenneth Reitz
e7b31af784 urllib3 fix 2011-10-10 20:59:10 -04:00
Kenneth Reitz
8fbd6d85e0 Merge remote-tracking branch 'origin/develop' into develop 2011-10-10 20:07:14 -04:00
Kenneth Reitz
8d4afcb5b8 urllib3 upgrade 2011-10-10 20:07:10 -04:00
Kenneth Reitz
a166dd0ad7 Edited AUTHORS via GitHub 2011-10-10 15:58:34 -03:00
Kenneth Reitz
5871291956 Merge pull request #191 from nakajima/patch-1
just fixed a typo
2011-10-10 11:57:57 -07:00
Pat Nakajima
24ffc3610a just fixed a typo 2011-10-10 15:56:58 -03:00
Kenneth Reitz
85507dd042 shorten testimonials a bit 2011-10-10 14:36:32 -04:00
Kenneth Reitz
4ada2e5664 Added Armin's awesome testimonial \o/ 2011-10-10 14:33:35 -04:00
Kenneth Reitz
0cf9ede580 fix builds 2011-10-10 09:58:47 -04:00
Kenneth Reitz
975a183796 --core-target 2011-10-10 09:39:44 -04:00
Kenneth Reitz
7671e3878c blah 2011-10-10 09:20:24 -04:00
Kenneth Reitz
372e4d94c5 pyflakes 2011-10-10 08:56:23 -04:00
Kenneth Reitz
e9f94e698d lost in merge 2011-10-10 01:27:05 -04:00
Kenneth Reitz
9697290111 added nose to reqs 2011-10-09 16:04:00 -04:00
Kenneth Reitz
03babafc7b Weakrefs for Reuqest/Response.
Closes #186
2011-10-09 08:34:13 -04:00
Kenneth Reitz
78b5d9ed45 Fix accidental-merge docstrings 2011-10-09 08:26:42 -04:00
Kenneth Reitz
ba93593711 Merge branch 'master' into develop
Conflicts:
	AUTHORS
	HISTORY.rst
	requests/api.py
	requests/core.py
	requests/models.py
	test_requests.py
2011-10-09 07:16:49 -04:00
Kenneth Reitz
a8695ecd32 v0.6.2 2011-10-09 07:11:48 -04:00
Kenneth Reitz
98c719f714 Merge branch 'redirect-no-follow' of https://github.com/millerdev/requests 2011-10-09 07:05:14 -04:00
Kenneth Reitz
b970d468d1 whoops 2011-10-06 11:58:03 -04:00
Daniel Miller
dda533cf67 Added myself to AUTHORS file 2011-10-05 15:09:57 -04:00
Daniel Miller
aa04cc9b42 Make get and head requests respect allow_redirects=False. 2011-10-05 14:36:12 -04:00
Kenneth Reitz
608d057066 nice and fast nose tests 2011-10-04 11:33:19 -04:00
Kenneth Reitz
04bcb74970 Add a trailing slash for twitter.com 2011-10-04 11:33:11 -04:00
Kenneth Reitz
6e90aa7d65 Merge branch 'refactor-urls' of https://github.com/jerem/requests into develop 2011-10-03 10:11:03 -04:00
Jérémy Bethmont
2361a6fc79 Renamed get_clean_url -> cleanup_url. 2011-10-03 11:16:43 +02:00
Jérémy Bethmont
7077272baa Merge remote-tracking branch 'upstream/develop' into refactor-urls
Conflicts:
	requests/models.py
2011-10-03 11:14:59 +02:00
Kenneth Reitz
0b475dd654 Test improvements
#180
2011-10-01 20:51:41 -04:00
Kenneth Reitz
1997dee3d9 🍰 2011-10-01 06:17:02 -04:00
Kenneth Reitz
e1c0646f95 urllib3 bugfix 2011-10-01 06:04:41 -04:00
Kenneth Reitz
c9f5614417 urllib3 update 2011-10-01 06:04:22 -04:00
Kenneth Reitz
7875a12617 async documentation 2011-10-01 04:52:28 -04:00
Kenneth Reitz
5afe11ba1c async module cleanups 2011-10-01 04:40:53 -04:00
Kenneth Reitz
47b98bc90f Typos
/cc @umbrae
2011-10-01 04:36:50 -04:00
Kenneth Reitz
b58433fb74 ascii arts 2011-10-01 04:35:34 -04:00
Kenneth Reitz
e228cf1cc4 Merge branch 'develop' of github.com:kennethreitz/requests into develop 2011-10-01 03:10:41 -04:00
Kenneth Reitz
3092483433 requests.async. Oh, yes :) 2011-09-30 07:08:59 -04:00
Kenneth Reitz
30d937f299 urllib3 2011-09-30 07:08:38 -04:00
Kenneth Reitz
e8c2fc1585 ch ch ch changes 2011-09-30 07:08:33 -04:00
Kenneth Reitz
2e391fa44c pass hooks around, disable auto send request. 2011-09-30 07:08:04 -04:00
Kenneth Reitz
2f5008107c keepalive => keep_alive 2011-09-30 07:07:39 -04:00
Kenneth Reitz
4cd54d2f87 keepalive => keep_alive 2011-09-30 07:07:09 -04:00
Kenneth Reitz
87e8a12a9f Edited requests/api.py via GitHub 2011-09-29 10:28:00 -03:00
Jérémy Bethmont
ffde764a91 Removed unused imports. 2011-09-26 11:00:25 +02:00
Jérémy Bethmont
62d29d5106 Fixed #174 and refactored urls quoting/concatenation in one function in utils.py. 2011-09-26 10:57:45 +02:00
Kenneth Reitz
5c132c98ca requests cookies behaving 2011-09-26 01:57:31 -04:00
Kenneth Reitz
14bd9ebb45 yay cookies 2011-09-26 01:33:18 -04:00
Kenneth Reitz
2f9e287f7d explicitly 2011-09-26 00:55:36 -04:00
Kenneth Reitz
8ac2fe6eb1 send file name 2011-09-26 00:53:43 -04:00
Kenneth Reitz
1c5ce723d8 multipart file uplaods 2011-09-26 00:38:57 -04:00
Kenneth Reitz
a7d280cb3d cleanup 2011-09-26 00:04:38 -04:00
Kenneth Reitz
111336459e perfection. 2011-09-26 00:01:53 -04:00
Kenneth Reitz
cff3b7f9bd urllib3 update 2011-09-25 22:59:20 -04:00
Kenneth Reitz
cfc19b4dde urllib3, don't decode content 2011-09-25 21:57:21 -04:00
Kenneth Reitz
f52c0032a3 urllib3 update 2011-09-25 21:46:07 -04:00
Kenneth Reitz
dfe0e9382d explaining 2011-09-25 21:44:24 -04:00
Kenneth Reitz
a699ddd14a connection pooling works :D 2011-09-25 21:41:03 -04:00
Kenneth Reitz
ae4e85f11c POOL PARTY!!!!!!!!!!!!!!! 2011-09-25 21:23:04 -04:00
Kenneth Reitz
e2af50b7c9 remove bunk get 2011-09-25 21:09:40 -04:00
Kenneth Reitz
1758070cdc clarity yo 2011-09-25 21:06:41 -04:00
Kenneth Reitz
7881aaa759 clarity™ 2011-09-25 21:05:27 -04:00
Kenneth Reitz
ed160f2d2a rework session argument
Closes #141
2011-09-25 21:02:50 -04:00
Kenneth Reitz
802bcc9ba3 configuration rework 2011-09-25 20:57:29 -04:00
Kenneth Reitz
351a711ce9 cleanup 2011-09-25 20:36:39 -04:00
Kenneth Reitz
0cf0bde158 session work
merge kwargs and such
2011-09-25 20:36:30 -04:00
Kenneth Reitz
dc7b4e7d32 Don't add params to redirect / new configuration 2011-09-25 20:14:32 -04:00
Kenneth Reitz
9488af5a42 cleanups 2011-09-25 19:41:48 -04:00
Kenneth Reitz
bd2b0c45ba simplify 2011-09-25 19:39:21 -04:00
Kenneth Reitz
8565053c93 works for block and non-block connections 2011-09-25 19:01:40 -04:00
Kenneth Reitz
5287b8cd9f fix 2011-09-25 18:57:17 -04:00
Kenneth Reitz
0b22bc9b42 cookie jar => cookies 2011-09-25 18:02:22 -04:00
Kenneth Reitz
182f92ab26 hrmm 2011-09-25 18:00:37 -04:00
Kenneth Reitz
55cea74b56 urllib3 update 2011-09-25 17:42:27 -04:00
Kenneth Reitz
33df9d1bf2 monkeys are deprecated 2011-09-25 17:42:19 -04:00
Kenneth Reitz
37ed9116b7 remove async (for now) 2011-09-25 17:42:13 -04:00
Kenneth Reitz
3af8af5730 remove debían 2011-09-25 17:42:02 -04:00
Kenneth Reitz
0db4dab03e urllib3 updates 2011-09-25 16:05:14 -04:00
Kenneth Reitz
df66fa7975 merge bugs 2011-09-25 16:02:22 -04:00
Kenneth Reitz
d2894b3c58 Merge branch 'develop' into urllib3
Conflicts:
	requests/api.py
	requests/exceptions.py
	requests/models.py
2011-09-25 16:00:44 -04:00
Kenneth Reitz
cd01aa4666 Work for Pie in docs 2011-09-23 03:23:19 -04:00
Kenneth Reitz
74ce263d69 Merge branch 'fixencodings' of https://github.com/jerem/requests into develop 2011-09-22 09:25:06 -04:00
Michael Van Veen
ac9f9b653c Merge branch 'pep8' of github.com:mvanveen/requests into pep8 2011-09-22 03:52:34 -07:00
Michael Van Veen
c48cf2bba8 rearranged imports in core.py 2011-09-22 03:52:05 -07:00
Michael Van Veen
dcebab4c35 PEP8fied all the things
I ran the pep8 checker (version 0.6.1) on the code base and tried to
clean up as many pep8 errors as I could.  Everything except line-width
errors are gone (I was worried about messing up the documentor since I
haven't fiddled with it).
2011-09-22 03:45:41 -07:00
Michael Van Veen
5345a89dc5 added toa AUTHORS file 2011-09-22 03:42:56 -07:00
Jérémy Bethmont
95b0549c75 Ignore unknown encoding. 2011-09-22 11:13:51 +02:00
Kenneth Reitz
04bcab8057 fails 2011-09-18 03:20:11 -04:00
Kenneth Reitz
332f55e552 serious commenting 2011-09-18 01:59:28 -04:00
Kenneth Reitz
7f3f641fb8 super comments! 2011-09-18 01:48:23 -04:00
Kenneth Reitz
18270e1059 cleanups 2011-09-18 01:43:04 -04:00
Kenneth Reitz
645933a5da Gotta catch 'em all! 2011-09-18 01:32:54 -04:00
Kenneth Reitz
2a2e7bd190 pass around connections like pokémon cards 2011-09-18 01:32:37 -04:00
Kenneth Reitz
2d38f51834 kill AuthenticationError 2011-09-18 01:32:00 -04:00
Kenneth Reitz
a3cc97128b Response.fo => Reponse.raw
raise_for_status() fixes
2011-09-17 22:46:17 -04:00
Kenneth Reitz
71d3490bcd optional blocking in urllib3 (for now) 2011-09-17 22:40:30 -04:00
Kenneth Reitz
aa5e477236 basic get request works 2011-09-17 22:02:06 -04:00
Kenneth Reitz
3127a34298 remove invalidmethod 2011-09-17 20:41:10 -04:00
Kenneth Reitz
0cb7376db0 urllib3 in authors 2011-09-17 20:34:30 -04:00
Kenneth Reitz
e69a3a41f6 import urllib3! 2011-09-17 20:32:21 -04:00
Kenneth Reitz
608c61dcd9 remove poster! \o/ 2011-09-17 20:32:13 -04:00
Kenneth Reitz
3dd2a0443d remove notice file 2011-09-17 20:31:56 -04:00
Kenneth Reitz
84434fddee import urllib3 2011-09-17 20:30:08 -04:00
Kenneth Reitz
784b671559 mock reqs for tests 2011-09-17 16:28:51 -04:00
Kenneth Reitz
edfa15558b Merge branch 'feature/improve-test-structure' of https://github.com/mrtazz/requests into develop 2011-09-17 16:24:51 -04:00
Daniel Schauenberg
1481e9ae6a add test with kwargs for api.delete 2011-09-17 17:54:18 +02:00
Daniel Schauenberg
1d1927bb2b add test with kwargs for api.patch 2011-09-17 17:53:49 +02:00
Daniel Schauenberg
42c45df84d add test with kwargs for api.put 2011-09-17 17:53:27 +02:00
Daniel Schauenberg
29f7a5bcfa add test with kwargs for api.post 2011-09-17 17:53:01 +02:00
Daniel Schauenberg
5c5c13a28f add test with kwargs for api.head 2011-09-17 17:52:07 +02:00
Daniel Schauenberg
cb2e87210c add test with kwargs for api.get 2011-09-17 17:50:19 +02:00
Daniel Schauenberg
14081bed46 add unit test for api.request 2011-09-17 17:25:27 +02:00
Kenneth Reitz
2826ca4362 Merge branch 'feature/improve-test-structure' of https://github.com/mrtazz/requests into develop 2011-09-15 22:30:25 -04:00
Daniel Schauenberg
f996313aab move original tests to tests/integration 2011-09-16 00:33:03 +02:00
Daniel Schauenberg
7127bcda97 add basic unit tests for requests.api 2011-09-16 00:32:18 +02:00
Kenneth Reitz
3443ede52a ref to bug in history 2011-09-15 10:09:36 -04:00
Kenneth Reitz
4b93bb4082 history! 2011-09-15 10:08:25 -04:00
Jérémy Bethmont
2a9ae4b367 Fixed #161 (quoting issue). 2011-09-15 11:57:10 +02:00
Kenneth Reitz
a8e77688f0 Merge pull request #150 2011-09-14 08:39:52 -04:00
Kenneth Reitz
34e3c7b68f fix for #160 2011-09-14 08:34:36 -04:00
Kenneth Reitz
c8914bd4d4 X 2011-09-10 20:18:49 -04:00
Kenneth Reitz
1b2533f92d better 2011-09-10 19:54:16 -04:00
Kenneth Reitz
37d269c104 more concise 2011-09-10 19:45:34 -04:00
Kenneth Reitz
d697c37d3e readabilty 2011-09-10 19:43:52 -04:00
Kenneth Reitz
4df5aadb01 ambiguous 2011-09-10 19:40:33 -04:00
Kenneth Reitz
058ef27178 clarify docs version 2011-09-10 19:11:03 -04:00
Kenneth Reitz
ccb9eb28e1 slimming down the repo 2011-09-10 19:03:16 -04:00
Kenneth Reitz
d5a0384630 trailing 2011-09-07 18:41:07 -04:00
Kenneth Reitz
fa47067802 hrm 2011-09-07 18:19:54 -04:00
Kenneth Reitz
45fabf4b96 cleaner setup.py 2011-09-07 18:10:58 -04:00
Kenneth Reitz
46e01db785 Makefile! 2011-09-07 18:10:09 -04:00
Kenneth Reitz
8da0abfa1a that shouldn't be there... 2011-09-07 17:52:46 -04:00
Kenneth Reitz
dd5a39731a Merge branch 'feature/curl' into develop
Conflicts:
	AUTHORS
	HISTORY.rst
2011-09-05 16:27:38 -04:00
Kenneth Reitz
b6aa868c28 Merge branch 'curl_feature' of https://github.com/mawaldne/requests into feature/curl 2011-09-05 16:25:17 -04:00
Kenneth Reitz
724ff7e4fa yep 2011-09-05 16:25:09 -04:00
Kenneth Reitz
1a64a29c84 Merge branch 'fix_redirect' of https://github.com/jerem/requests into develop 2011-09-05 16:22:39 -04:00
Mike Waldner
2aa32c16dc Updated unit tests
#139
2011-09-03 20:54:55 -04:00
Armin Ronacher
0d6773c68c Fail silently if encoding header is missing 2011-09-03 18:04:51 +02:00
Armin Ronacher
41876fd8c6 Implemented content streaming for responses. 2011-09-03 17:59:30 +02:00
verm666
6f84ce72f2 Fixed logic for auto redirect in GET and HEAD methods. 2011-09-02 15:44:18 -04:00
Jérémy Bethmont
824d54f131 Only the path should be encoded (not the query, otherwise it makes a wrong redirection). 2011-09-02 15:06:58 +02:00
Luca De Vitis
07dd324e2f Reverted hooks from sub-package to module. 2011-09-01 18:22:12 +02:00
Kenneth Reitz
6d25fff3f9 Added Josselin Jacquard to AUTHORS 2011-08-30 23:58:31 -04:00
Kenneth Reitz
9bfe04586d Merge branch 'develop' of https://github.com/kigeia/requests into develop 2011-08-30 23:57:24 -04:00
Josselin Jacquard
1ecb593c7b Fix a bug when content-type is empty 2011-08-30 12:04:48 +02:00
Mike Waldner
e46351cfbd Unit Tests for curl_from_request
#139
2011-08-28 23:31:43 -04:00
Mike Waldner
58d63d55bc Sphinx Documentation
#139
2011-08-28 21:19:51 -04:00
Kenneth Reitz
fed17cb58a history 2011-08-28 03:23:54 -04:00
Kenneth Reitz
35fc3b4dbb cleanup 2011-08-28 03:22:46 -04:00
Kenneth Reitz
dba7a5a7e2 shortcut strings 2011-08-28 03:22:20 -04:00
Kenneth Reitz
2fa180e9ea automatic header expansion 2011-08-28 03:22:03 -04:00
Kenneth Reitz
3b9fc987b8 cleanup 2011-08-28 03:09:26 -04:00
Kenneth Reitz
e272ec13c3 tuples too 2011-08-28 03:07:45 -04:00
Kenneth Reitz
b97b4439c0 header expanding 2011-08-28 02:40:19 -04:00
Mike Waldner
3f98034c2a Trailing whitespace
#139
2011-08-25 23:57:56 -04:00
Mike Waldner
3d448f843e Adding cookies
#139
2011-08-25 23:55:24 -04:00
Luca De Vitis
d8c923c385 Added json_content and etree_content, more docs and comments. 2011-08-25 16:28:47 +02:00
Luca De Vitis
3bf6c63d52 Applied new hooks api 2011-08-25 16:26:10 +02:00
Luca De Vitis
335bf7018d default hooks copy fixed 2011-08-25 16:24:55 +02:00
Luca De Vitis
d8fb6d2a5a No more sets in default hooks, code cleanup, more docs and comments. 2011-08-25 16:19:19 +02:00
Luca De Vitis
c243d09398 Added gracefull_hooks, default_hooks and 'Accept-Encoding' base_header 2011-08-25 16:17:38 +02:00
Mike Waldner
7fa4fdacc9 Adding in file support
#139
2011-08-24 22:01:06 -04:00
Mike Waldner
71195bb219 Adding myself to Authors. Small cleanup
#139
2011-08-24 01:50:06 -04:00
Mike Waldner
ec0b708b18 Removing trailing whitespace
#139
2011-08-24 01:40:44 -04:00
Mike Waldner
cfee830877 Renaming vars. String formatting
#139
2011-08-24 01:39:43 -04:00
Mike Waldner
3dd2235ac5 Adding basic authentication. Also string formatting
#139
2011-08-24 01:30:38 -04:00
Mike Waldner
cc2c54093e Adding basic authentication. Also string formatting 2011-08-24 01:21:44 -04:00
Kenneth Reitz
2dfcc0bb7b string formatting
#139
2011-08-24 00:04:18 -04:00
Kenneth Reitz
256c86f8f7 moving curl into utils
#139
2011-08-23 23:54:33 -04:00
Kenneth Reitz
a276ebd240 Merge branch 'curl_feature' of https://github.com/mawaldne/requests into feature/curl 2011-08-23 23:50:56 -04:00
Kenneth Reitz
1d0a5b2665 whitespace 2011-08-23 23:09:51 -04:00
Kenneth Reitz
636e61d68b utils.unicode_from_html 2011-08-23 23:09:09 -04:00
Mike Waldner
0bf60c8876 Adding check when _enc_data in None 2011-08-23 23:08:26 -04:00
Kenneth Reitz
a94541d38c Only decode unicode from http headers
HTTP client, not HTML
#115
2011-08-23 23:03:18 -04:00
Kenneth Reitz
ce3b85a62e unsuccessful 2011-08-23 23:01:35 -04:00
Kenneth Reitz
281aa5ebc4 updated AUTHORS 2011-08-23 23:01:23 -04:00
Mike Waldner
84d9ff0c5c More Small Cleanup 2011-08-23 22:34:05 -04:00
Mike Waldner
68a2954c67 Merge remote-tracking branch 'upstream/develop' into develop 2011-08-23 22:22:51 -04:00
Mike Waldner
c56acf0e32 Small Cleanup 2011-08-23 22:17:36 -04:00
Mike Waldner
2a17e5237c Ive never seen anyone use the --'s unix command options 2011-08-23 22:03:42 -04:00
Luca De Vitis
56406b3442 hooks now comply hook interface 2011-08-23 23:43:40 +02:00
Luca De Vitis
660e090315 Forgot to add the hooks sub-package 2011-08-23 23:39:07 +02:00
Luca De Vitis
d12eac8669 * hooks is a package now.
* Added hooks.setup_hooks to setup multiple and default hooks
* Added hooks.response hooks to unicode encoding, and uncompress response.
* Modified hooks.dispatch_hooks api: don't need a key any more.
2011-08-23 23:30:50 +02:00
Luca De Vitis
2dc556e082 Added multiple hooks support. 2011-08-23 15:06:22 +02:00
jbergstroem
75027f9557 Typos, nits and some 80w fixes 2011-08-23 11:37:51 +02:00
jbergstroem
e8dbecb4db Add test_requests.py to manifest 2011-08-23 11:29:36 +02:00
Kenneth Reitz
317c5b693a _content 2011-08-21 07:12:54 -04:00
Den Shabalin
a86af4477e AUTHORS -= Den Shabalin (I've already been mentioned in the list @ line 41.) 2011-08-21 14:09:03 +03:00
Den Shabalin
59924b9223 Merge branch 'develop' of git://github.com/kennethreitz/requests into develop 2011-08-21 14:06:31 +03:00
Kenneth Reitz
c8110222a5 no need to set content
avoids 2.5 workaround
2011-08-21 07:01:29 -04:00
Kenneth Reitz
1143d4237f AUTHORS += 'Den Shabalin' 2011-08-21 06:59:13 -04:00
Kenneth Reitz
8d5108b142 faq 2011-08-21 06:58:34 -04:00
Den Shabalin
03e18bb7ca Merge branch 'master' of git://github.com/kennethreitz/requests into develop 2011-08-21 12:13:56 +03:00
Den Shabalin
6a96652396 Refactor response.content into a property. This makes content attribute discoverable through dir(response) and also guards from errors like forgetting to raise AttributeError in __getattr__. Also you don't have to create fake self.content to fool Sphinx any more. 2011-08-21 11:57:03 +03:00
Kenneth Reitz
d4bdd84364 new FAQs 2011-08-20 23:00:17 -04:00
Kenneth Reitz
b45b329861 history 2011-08-20 22:55:30 -04:00
Kenneth Reitz
28ee9788a0 Request 2011-08-20 22:51:29 -04:00
Kenneth Reitz
596aceb185 big docs update 2011-08-20 22:47:03 -04:00
Kenneth Reitz
1f3e53b32e yay 2011-08-20 20:05:38 -04:00
Kenneth Reitz
13db806861 docstringin' it up 2011-08-20 20:04:11 -04:00
Kenneth Reitz
d0fdf0eb38 no longer required 2011-08-20 19:59:41 -04:00
Kenneth Reitz
c5d787d6fd cleanups 2011-08-20 19:59:21 -04:00
Kenneth Reitz
873d128c5a docstrings for utils module 2011-08-20 19:58:00 -04:00
Kenneth Reitz
7f35ec7665 r.fo bugfix 2011-08-20 19:52:18 -04:00
Kenneth Reitz
86cc274cf0 remote read/close methods from response 2011-08-20 19:49:23 -04:00
Kenneth Reitz
c19b2c5172 settings.decode_unicode 2011-08-20 19:47:43 -04:00
Kenneth Reitz
4906686186 utils.decode_gzip 2011-08-20 19:46:50 -04:00
Kenneth Reitz
f038ec3b6e may have multiple encoding values 2011-08-20 19:44:24 -04:00
Kenneth Reitz
a609f726e6 settings.allow_unicode 2011-08-20 19:43:36 -04:00
Kenneth Reitz
7bd47777a9 no separate test suite 2011-08-20 19:40:33 -04:00
Kenneth Reitz
21cd47d223 Merge branch 'feature/unicode' into feature/fo
Conflicts:
	AUTHORS
2011-08-20 19:30:46 -04:00
Kenneth Reitz
882ea76aa9 cleanups, response.fo 2011-08-20 19:26:56 -04:00
Kenneth Reitz
850e1c7d40 Merge branch 'develop' of https://github.com/janrito/requests into develop 2011-08-20 19:23:53 -04:00
Kenneth Reitz
01411e37d6 AUTHORS += Alejandro Giacometti 2011-08-20 19:22:48 -04:00
Kenneth Reitz
4922daf498 added Rick Mak to AUTHORS 2011-08-20 19:22:18 -04:00
Kenneth Reitz
8fbb1e6d97 move encoding methods into utils for external consumption 2011-08-20 19:17:41 -04:00
Kenneth Reitz
7fc8c7ccfd move encoding detection out of request object. 2011-08-20 19:17:25 -04:00
Kenneth Reitz
7eb272b299 Merge https://github.com/rickmak/requests into feature/unicode
Conflicts:
	requests/models.py
2011-08-20 18:42:18 -04:00
Kenneth Reitz
8bfa909ff2 merge remnant (oops) 2011-08-20 18:34:33 -04:00
Kenneth Reitz
3b085ed20f Merge branch 'develop' 2011-08-20 18:26:04 -04:00
Kenneth Reitz
8b640979ee v0.6.1 2011-08-20 18:25:32 -04:00
Kenneth Reitz
c58ddff3a4 history update 2011-08-20 18:24:58 -04:00
Alejandro Giacometti
5f16a8a6b1 Added readline method to response object. 2011-08-20 23:05:39 +02:00
Kenneth Reitz
53a53668d9 no more roadmap 2011-08-19 20:59:16 -04:00
Kenneth Reitz
e7d8982583 Merge branch 'feature/jerem' into develop 2011-08-19 20:12:53 -04:00
Kenneth Reitz
abc5e27931 config max_redirects 2011-08-19 20:12:41 -04:00
Kenneth Reitz
c75eaec852 integrate codes into models.py 2011-08-19 20:12:33 -04:00
Kenneth Reitz
d9a349c1a1 303 status code 2011-08-19 20:12:16 -04:00
Kenneth Reitz
9d143ed653 Merge branch 'develop' of https://github.com/jerem/requests into feature/jerem 2011-08-19 19:58:24 -04:00
Kenneth Reitz
ce4927e5d3 added Den Shabalin to AUTHORS 2011-08-19 19:39:53 -04:00
Den Shabalin
17c551539b Merge branch 'master' of github.com:densh/requests into issue-128 2011-08-19 19:20:54 +03:00
Den Shabalin
2f55393593 Fixes an issue #128: `Response not working with lxml''. This error happend due to lxml's attempt to do .geturl() call on the response object. __getattr__ didn't raise AttributeError so response.geturl'' returned None and response.geturl()'' resulted into `TypeError: 'NoneType' object is not callable'' seen in the issue. 2011-08-19 19:18:26 +03:00
Rick Mak
d26f3333e4 Fix tried_encodings scope 2011-08-18 14:42:35 +08:00
Rick Mak
820e2c73e6 Import re 2011-08-18 14:22:54 +08:00
Kenneth Reitz
efbbb84315 Added Mikko Ohtamaa to AUTHORS
#124
2011-08-17 20:17:22 -04:00
Kenneth Reitz
96e7a60b8d Allow any method, if so inclined
#124
2011-08-17 20:15:28 -04:00
Jérémy Bethmont
c22b71fc5b Handle redirection without scheme. 2011-08-17 16:04:53 +02:00
Kenneth Reitz
007963afde authors 2011-08-17 09:45:31 -04:00
Kenneth Reitz
0708736c45 Merge branch 'patch-1' of https://github.com/sharat87/requests into develop 2011-08-17 09:45:23 -04:00
Kenneth Reitz
61d50d531c Authors += Armin 2011-08-17 09:41:24 -04:00
Jérémy Bethmont
a17110b32a Merge remote-tracking branch 'upstream/develop' into develop 2011-08-17 15:32:11 +02:00
Jérémy Bethmont
571d808d25 Fixed bad merge. 2011-08-17 15:31:24 +02:00
Shrikant Sharat Kandula
5e6ecdad9f Typo in documentation
The kwarg is named `headers`, not `header`. Also, its a dict, not a set.
-
Armin Ronacher
91e75f7215 As proposed by @davidbgk this is only consistent with \o/ :) 2011-08-17 13:40:29 +03:00
Kenneth Reitz
81d599786a Merge branch 'develop' 2011-08-17 04:33:34 -04:00
Kenneth Reitz
9471b0ab88 let's do this 2011-08-17 04:32:46 -04:00
Jeremy Selier
470af42bf2 Fixing myself :) 2011-08-17 11:28:47 +03:00
Kenneth Reitz
0b34812afc readme cleanup 2011-08-17 04:23:16 -04:00
Kenneth Reitz
47a36de74e supported interpreters 2011-08-17 04:17:21 -04:00
Kenneth Reitz
0c21aa5530 doc cleanups 2011-08-17 04:16:19 -04:00
Jérémy Bethmont
fe109b27be Merge remote-tracking branch 'upstream/develop' into develop
Conflicts:
	requests/models.py
2011-08-17 10:07:43 +02:00
Kenneth Reitz
3f873dc222 hooks in api layer only 2011-08-17 04:05:20 -04:00
Kenneth Reitz
e0ae2b4155 fixes 2011-08-17 04:03:54 -04:00
Kenneth Reitz
5f603ae787 typo 2011-08-17 04:01:11 -04:00
Kenneth Reitz
d4502aff87 consiserererr 2011-08-17 04:00:12 -04:00
Kenneth Reitz
3992ed6ad1 cookies docs 2011-08-17 03:58:55 -04:00
Kenneth Reitz
b72eb53a73 changing history 2011-08-17 03:25:31 -04:00
Kenneth Reitz
4d0c6cefd0 yawns 2011-08-17 03:21:31 -04:00
Kenneth Reitz
3f8f1dc00c cleaner defaults 2011-08-17 03:19:51 -04:00
Kenneth Reitz
008c77c911 hijack arguments 2011-08-17 03:19:46 -04:00
Kenneth Reitz
77b37687b6 advanced docs 2011-08-17 03:07:24 -04:00
Kenneth Reitz
b7307298d2 merge headers, don't overwrite 2011-08-17 02:49:29 -04:00
Kenneth Reitz
abcf81e2a8 docs update 2011-08-17 02:49:13 -04:00
Kenneth Reitz
e477fce211 add_dict_to_cookiejar
Signed-off-by: Kenneth Reitz <me@kennethreitz.com>
2011-08-17 02:25:56 -04:00
Kenneth Reitz
467766cfe8 cookie session persistence 2011-08-17 02:25:41 -04:00
Kenneth Reitz
66391e5c9d ACTIVVVAATTTEEEEEEE 2011-08-17 02:01:19 -04:00
Kenneth Reitz
f7024a6000 super cookiejar_from_dict powwerrrs 2011-08-17 02:01:13 -04:00
Kenneth Reitz
ec33ce9d29 sp. 2011-08-17 01:32:12 -04:00
Kenneth Reitz
d0aa0175e6 v0.6.0 2011-08-17 01:32:04 -04:00
Kenneth Reitz
d9e5717377 cookiejar_from_dict
#12
2011-08-17 01:29:58 -04:00
Kenneth Reitz
7e255177dc get cookies from response
#116
2011-08-17 01:23:49 -04:00
Kenneth Reitz
b0a0b509da session at root package level 2011-08-17 01:00:00 -04:00
Rick Mak
8c737069a5 Return the r.content as unicode. 2011-08-17 12:49:19 +08:00
Kenneth Reitz
51038497f6 better 2011-08-17 00:40:49 -04:00
Kenneth Reitz
855c273707 whitespace 2011-08-17 00:40:37 -04:00
Kenneth Reitz
281ab5a8f9 move hooks into api layer only 2011-08-17 00:40:28 -04:00
Kenneth Reitz
7836536459 post_request hook 2011-08-17 00:33:28 -04:00
Kenneth Reitz
2a0eff9c71 docstrings 2011-08-17 00:33:21 -04:00
Kenneth Reitz
3e8a14e133 pre_request hook 2011-08-17 00:28:03 -04:00
Kenneth Reitz
8ef0e88220 attach hooks to Request 2011-08-17 00:27:41 -04:00
Kenneth Reitz
e102c1b4ca RTD doesn't work w/ this 2011-08-17 00:17:58 -04:00
Kenneth Reitz
5ba43d0fe5 hook plans 2011-08-17 00:16:57 -04:00
Kenneth Reitz
783e540d6d sigh 2011-08-17 00:09:47 -04:00
Kenneth Reitz
24da41005c hmmm 2011-08-17 00:09:38 -04:00
Kenneth Reitz
17d3e1d498 whitespace 2011-08-17 00:08:39 -04:00
Kenneth Reitz
8d2ab68a97 space 2011-08-17 00:08:06 -04:00
Kenneth Reitz
7322aa5b64 newlines 2011-08-17 00:02:18 -04:00
Kenneth Reitz
6b11cf21f3 todo 2011-08-17 00:00:47 -04:00
Kenneth Reitz
9322d13f61 cleanups 2011-08-16 23:58:55 -04:00
Kenneth Reitz
86a06c5c18 auth_manager internal 2011-08-16 23:58:07 -04:00
Kenneth Reitz
d0cb56932c new hooks system
#118
2011-08-16 23:57:44 -04:00
Kenneth Reitz
fc04d8a368 cleanups 2011-08-16 22:55:18 -04:00
Kenneth Reitz
519b9cee96 relative imports 2011-08-16 22:55:10 -04:00
Kenneth Reitz
efba606e57 doctoring for Session 2011-08-16 22:20:26 -04:00
Kenneth Reitz
5bb18810d4 memory location repr for requests-client 2011-08-16 22:19:49 -04:00
Kenneth Reitz
853383a8d3 docstring fix 2011-08-16 22:16:22 -04:00
Kenneth Reitz
f319006813 session => sessions 2011-08-16 22:15:03 -04:00
Kenneth Reitz
2fa021582b Merge branch 'feature/session' of https://github.com/tomhsx/requests into feature/session
Conflicts:
	AUTHORS
2011-08-16 02:34:44 -04:00
Tom Hogans
0ed641a26e Added docs regarding requests.session to docs/user/advanced.rst 2011-08-16 02:00:11 -04:00
Mike Waldner
aad27218d5 Using build_url and also including headers 2011-08-16 01:39:02 -04:00
Tom Hogans
c2fd568695 Added tests for requests.session 2011-08-16 01:38:39 -04:00
Kenneth Reitz
8f72c48548 added alex to authors 2011-08-15 22:17:55 -04:00
alopatin
08a821381a Fixed misc spelling mistakes. 2011-08-15 22:53:22 -03:00
Kenneth Reitz
4625445d2a Merge branch 'develop' of https://github.com/moliware/requests into develop 2011-08-15 21:50:00 -04:00
Tom Hogans
ca428504d4 Added request.session functionality 2011-08-15 16:01:26 -04:00
JensDiemer
88f79b74ce use settings.timeout_fallback bool for socket.setdefaulttimeout() fallback 2011-08-15 17:03:37 +02:00
JensDiemer
647cdd3847 Use socket.setdefaulttimeout(timeout) only if timeout argument doesn't exist (Python <2.6) - https://github.com/kennethreitz/requests/issues/112 2011-08-15 16:51:33 +02:00
moliware
c510d21e4e headers.update is not the same that add headers one by one with add_header 2011-08-15 11:58:57 +02:00
Mike Waldner
430e87d0fd First commit of curl command from request 2011-08-15 00:12:14 -04:00
Kenneth Reitz
49e5df1ff9 whoops 2011-08-14 22:32:35 -04:00
Kenneth Reitz
2357b13824 Response Headers quickstart 2011-08-14 22:30:30 -04:00
Kenneth Reitz
f137db6803 raise_for_status quick start 2011-08-14 22:20:03 -04:00
Kenneth Reitz
2cf0dad573 models.. 2011-08-14 22:12:50 -04:00
Kenneth Reitz
414b9dde84 not tablib.. 2011-08-14 22:08:01 -04:00
Kenneth Reitz
d50742f059 massive documentation update 2011-08-14 22:07:15 -04:00
Kenneth Reitz
3bc9a181a1 basic FAQ 2011-08-14 21:16:04 -04:00
Kenneth Reitz
975720a30c I'll have to manually add that to sphinx 2011-08-14 15:50:18 -04:00
Kenneth Reitz
1361506ae6 status blocks 2011-08-14 15:44:03 -04:00
Kenneth Reitz
23ff27ea4b Documentation fixes 2011-08-14 11:43:25 -04:00
Kenneth Reitz
933cbd735b emphasize r.content 2011-08-14 11:06:41 -04:00
Kenneth Reitz
ce1945c780 status codes fix 2011-08-14 10:43:02 -04:00
Kenneth Reitz
f52a413b6a Merge branch 'patch-1' of https://github.com/SimonSapin/requests into develop 2011-08-14 10:41:15 -04:00
Kenneth Reitz
ced96912f3 Merge remote-tracking branch 'origin/develop' into develop 2011-08-14 10:40:32 -04:00
Kenneth Reitz
f6e97c322b Merge branch 'develop' of https://github.com/jbochi/requests into develop 2011-08-14 10:39:47 -04:00
Kenneth Reitz
c9d61aefe4 Merge branch 'docs-typos' of https://github.com/markstory/requests into develop 2011-08-14 10:39:35 -04:00
Kenneth Reitz
85c79658ef Merge pull request #108 from zed/patch-1
fix typo
2011-08-14 07:21:52 -07:00
zed
c4c86fd6e8 fix typo 2011-08-14 17:46:43 +04:00
Mark Story
95dcdd8a05 Fixing a small typo. 2011-08-14 09:13:50 -04:00
Juarez Bochi
43669183ce Edited PATCH Requests in README 2011-08-14 07:30:43 -03:00
Simon Sapin
56e58fdcaf Fix a link in the documentation. 2011-08-14 09:50:25 +03:00
Kenneth Reitz
47378164ef \o/ 2011-08-13 14:55:41 -04:00
Kenneth Reitz
9469b4bb69 status_codes lookup dict 2011-08-13 14:50:59 -04:00
Kenneth Reitz
6cead64345 supporting codes class 2011-08-13 14:50:48 -04:00
Kenneth Reitz
773630b010 requests.codes 2011-08-13 14:50:38 -04:00
Kenneth Reitz
907e529471 changing history muahaha 2011-08-13 13:17:41 -04:00
Kenneth Reitz
2d70647f72 attach request object to responses 2011-08-13 13:17:17 -04:00
Kenneth Reitz
10cc4673f9 remove Response.cached 2011-08-13 13:14:10 -04:00
Kenneth Reitz
629d730da6 all main functions are **kwargs now. People shouldn't be relying on the order. 2011-08-13 13:11:16 -04:00
Kenneth Reitz
d4eabaaacc better 2011-08-13 13:04:14 -04:00
Kenneth Reitz
5693314a37 response error handling rework 2011-08-13 13:01:44 -04:00
Kenneth Reitz
2e4724ccea history 2011-08-13 12:34:13 -04:00
Kenneth Reitz
e7084940e1 added Jeremy Selie to AUTHORS 2011-08-13 09:40:24 -04:00
Kenneth Reitz
b141da36a4 test relative redirects 2011-08-13 09:37:14 -04:00
Kenneth Reitz
bb16fe8115 http/https tests 2011-08-13 09:37:07 -04:00
Kenneth Reitz
a987729712 whitespace! 2011-08-13 09:14:49 -04:00
Kenneth Reitz
f7cc7b1778 Merge branch 'patch-1' of https://github.com/jeremys/requests into develop 2011-08-13 08:39:16 -04:00
Jérémy Bethmont
e1909375f5 Merge branch 'memoryleak' into develop
Conflicts:
	requests/models.py
2011-08-09 17:31:26 +02:00
Jérémy Bethmont
cf94c96a68 Always close connection during redirections. 2011-08-09 17:30:19 +02:00
Jérémy Bethmont
e7e395549f Handle too many redirects. 2011-08-09 17:28:58 +02:00
Jérémy Bethmont
e776242de1 Merge branch 'urlencode' into develop 2011-08-09 15:42:18 +02:00
Jérémy Bethmont
7b79cea738 Use urljoin instead of manual concatenation. 2011-08-09 15:41:59 +02:00
Jérémy Bethmont
32a861b2ed Fixed memory leak (see http://bugs.python.org/issue1208304) 2011-08-09 15:34:44 +02:00
Jérémy Bethmont
2ce26d4a1c Merge remote-tracking branch 'upstream/develop' into develop 2011-08-09 15:16:23 +02:00
Jérémy Bethmont
aa0f78b740 Better support of utf-8 paths. 2011-08-09 15:14:08 +02:00
Zbigniew Siciarz
e4adef5226 Added proxies to requests.settings 2011-08-09 10:03:09 +02:00
Jérémy Bethmont
7dc581fad9 Merge branch 'develop' into urlencode 2011-08-08 18:14:08 +02:00
Jérémy Bethmont
0b6dc091f5 Added support for URLs with path not encoded. 2011-08-08 18:11:33 +02:00
Kenneth Reitz
e1714e678e Added Peter Manser to AUTHORS 2011-08-04 22:08:32 -03:00
Kenneth Reitz
d10b08ff88 Merge pull request #99 from petermanser/develop
Fixing minor bug in code example - missing apostrophe
2011-08-04 18:07:49 -07:00
Peter Manser
18c42e88f5 Fixing minor bug in code example - missing apostrophe 2011-08-04 21:47:15 +02:00
Kenneth Reitz
f238dffc18 Merge https://github.com/bclermont/requests into develop 2011-08-02 23:23:41 -04:00
Jeremy Selier
5a7ec361f4 Join with the latest URL not the first one. 2011-08-02 18:51:21 +03:00
Jeremy Selier
291d4742d6 Fixes correct "relative" redirections. Example: http://digg.com/d1qIwX, which redirects to "/news/story/A_Manifesto_How_to_Save_Media", which requests transforms to: http://digg.com//news/story/A_Manifesto_How_to_Save_Media" which results in an endless redirect loop. 2011-08-02 18:05:03 +03:00
Kenneth Reitz
95ba6fcab2 Merge branch 'release/0.5.1' 2011-07-23 22:59:15 -04:00
Kenneth Reitz
1cdd1d04ce v0.5.1 2011-07-23 22:58:32 -04:00
Kenneth Reitz
3293c0e8f4 Python 2.5 bugfix 2011-07-23 22:49:01 -04:00
Kenneth Reitz
074150ff2c test fix 2011-07-23 22:42:51 -04:00
Kenneth Reitz
c3c90bb09c default headers and content encoding settings
Closes #78
2011-07-23 22:35:46 -04:00
Kenneth Reitz
87560d65ca redirect history length test 2011-07-23 22:16:21 -04:00
Kenneth Reitz
7e4f7fa600 added Rubén Abad to AUTHORS 2011-07-23 22:12:41 -04:00
Kenneth Reitz
7f9c6233bb history bugfix in history 2011-07-23 22:12:34 -04:00
Kenneth Reitz
9b6a190652 Merge branch 'develop' of https://github.com/rabad/requests into develop 2011-07-23 22:11:59 -04:00
Kenneth Reitz
1e1fb1e7a8 Redirect history fix (Closes #91) 2011-07-23 22:11:54 -04:00
Kenneth Reitz
080db5ee5d CaseInsensitiveDict notes 2011-07-23 21:49:08 -04:00
Kenneth Reitz
2edda29448 fixing bad url shortner link 2011-07-23 21:48:28 -04:00
Kenneth Reitz
6ba3523a26 Merge branch 'develop' of https://github.com/tgulacsi/requests into develop 2011-07-23 21:45:45 -04:00
Kenneth Reitz
87e7a04209 v0.5.1 history update 2011-07-23 21:42:12 -04:00
Kenneth Reitz
260e32a7c3 default user agent! 2011-07-23 21:39:14 -04:00
Kenneth Reitz
5fff2c757b forced_basic default handler. 2011-07-23 21:37:17 -04:00
Kenneth Reitz
30d699b64f Forced Basic Auth for 404'd resources 2011-07-23 21:36:24 -04:00
Kenneth Reitz
7d91d3fb5c use patched HTTPBasicAuthHandler 2011-07-23 20:10:37 -04:00
Gulácsi Tamás
747f882b0e structures: CaseInsensitiveDict.__delitem__ missing "value" fix 2011-07-23 22:25:07 +02:00
Gulácsi Tamás
369e7cb38f add myself to AUTHORS 2011-07-23 22:19:28 +02:00
Gulácsi Tamás
04c456b877 structures: little bit more general, lower-key-caching version of CaseInsensitiveDict 2011-07-23 22:16:12 +02:00
Gulácsi Tamás
f408829d51 test_request: simplejson is just as good as omnijson for test 2011-07-23 22:15:28 +02:00
Rubén Abad
73b414ab45 We can represent multivalued params with arrays 2011-07-13 11:08:54 +02:00
Kenneth Reitz
f18c40fd36 👍 2011-07-09 10:41:44 -04:00
Jérémy Bethmont
891e52d723 Added the possibility to access headers without fetching the whole body (fixes #86). 2011-06-29 11:10:39 +02:00
Xu Pan
d2ff0f40eb add doseq to urlencode in model._encode_params to enable list as dict value 2011-06-26 13:32:19 +08:00
Kenneth Reitz
787110c853 international domain name support! 2011-06-24 20:32:28 -04:00
Kenneth Reitz
20319044a3 Added Jérémy Bethmont to AUTHORS. 2011-06-24 18:47:41 -04:00
Kenneth Reitz
6f08c81698 note about indns 2011-06-24 18:24:44 -04:00
Jérémy Bethmont
868cd3d1cb Implemented idna (fixes #76). 2011-06-24 12:21:25 +02:00
Kenneth Reitz
39edf7a7fa raise_for_status +URLError 2011-06-23 06:22:46 -04:00
Kenneth Reitz
4cf4362610 typos 2011-06-23 06:06:56 -04:00
Kenneth Reitz
0b719f037c ! 2011-06-23 05:34:44 -04:00
Kenneth Reitz
9603589b06 oops 2011-06-23 05:32:05 -04:00
Kenneth Reitz
5f38c1209e TURTLES 2011-06-23 05:18:13 -04:00
Kenneth Reitz
749edb3554 new sidebar logo 2011-06-23 05:16:13 -04:00
Kenneth Reitz
882b465968 tox fix 2011-06-23 05:15:09 -04:00
Kenneth Reitz
784fe8bbdb working requests logo 2011-06-23 03:30:32 -04:00
Kenneth Reitz
6253cf4c18 TODO Docs 2011-06-23 03:30:22 -04:00
Kenneth Reitz
8521075868 playing nice. 2011-06-21 22:55:35 -04:00
Kenneth Reitz
2d98ca7477 Merge branch 'release/0.5.0' 2011-06-21 22:44:02 -04:00
Kenneth Reitz
e2d6a92150 Timeouts are normal errors now.
--
FIX ALL TEH TESTS!
2011-06-21 22:43:15 -04:00
Kenneth Reitz
162b751f6d Timeouts are normal errors now.
--
BREAK ALL TEH TESTS!
2011-06-21 22:40:27 -04:00
Kenneth Reitz
20aed5488b Release the v0.5.0! 2011-06-21 22:26:06 -04:00
Kenneth Reitz
2374d0fd7a so many paramatersssss 2011-06-21 22:22:46 -04:00
Kenneth Reitz
483d00736c readme update 2011-06-21 22:22:02 -04:00
Kenneth Reitz
15de7d9dba add PATCH to docs 2011-06-21 22:21:54 -04:00
Kenneth Reitz
34a583b821 PATCH in Docs 2011-06-21 22:06:31 -04:00
Kenneth Reitz
2da86daa3a update history 2011-06-21 22:03:56 -04:00
Kenneth Reitz
b4eac4c993 redirect fix 2011-06-21 22:00:04 -04:00
Kenneth Reitz
b4a4f38cce verbose output stream support 2011-06-21 21:59:57 -04:00
Kenneth Reitz
8c81cf64de proper PATCH testing 2011-06-21 18:24:28 -04:00
Kenneth Reitz
00f066a467 PATCH support 2011-06-21 18:03:06 -04:00
Kenneth Reitz
bdf9f90c8a omnijson for tests 2011-06-21 17:59:24 -04:00
Kenneth Reitz
428678b2e4 Added Alberto Paro to AUTHORS 2011-06-21 17:35:29 -04:00
Alberto Paro
bcd30f05ab Added setuptools management to setup.py to allow to install in develop mode 2011-06-21 22:48:31 +02:00
Kenneth Reitz
bd49da067f updated history 2011-06-21 00:07:41 -04:00
moliware
3e7c682e66 Support for proxies 2011-06-19 22:36:50 +02:00
Kenneth Reitz
bbd1e40bd5 no pypy default 2011-06-17 14:09:33 -04:00
Kenneth Reitz
a25f5ff1dd that works 2011-06-17 13:51:29 -04:00
Richard Boulton
80d860d2d4 Allow POST and PUT requests to take both querystring params and request body
data.
2011-06-16 15:48:43 +01:00
Richard Boulton
f31ade335d Change documentation comments for "params" and "data" parameters to refer to
the request body or the query string, as appropriate.  "GET parameters", "POST
data", etc aren't the ideal terminology to use - they come from common usage
with web browsers, rather than the HTTP specification, so are off-putting in
other contexts.
2011-06-16 15:40:14 +01:00
Richard Boulton
023ab755e5 Move the code to encode the request data into a static helper method - I think this makes the code clearer, but it also prepares the way for reusing the encoding code 2011-06-16 13:35:33 +01:00
Richard Boulton
4320f81bf4 Actually use the HTTPSBIN variable for test https requests 2011-06-16 13:06:22 +01:00
Kenneth Reitz
47f1f28385 + Richard Boulton to AUTHOURS 2011-06-16 06:27:13 -04:00
Richard Boulton
3d1444b829 Update documentation of the "data" parameter for requests.post() to indicate that it allows bytes. Update documentation of requests.put() to refer to the "data" parameter rather than the (hidden, but functional) "params" parameter, and note that that also allows both bytes and dictionaries. 2011-06-16 03:18:47 -07:00
Zbigniew Siciarz
4d3a9defd2 Porting cookie test to httpbin.org. 2011-06-16 09:08:32 +02:00
Zbigniew Siciarz
1f1211747b Merge remote-tracking branch 'upstream/develop' into develop 2011-06-16 08:56:38 +02:00
Kenneth Reitz
45e30048f0 port request tests to httpbin.org 2011-06-16 00:11:47 -04:00
Kenneth Reitz
245c6edec3 todo 2011-06-15 22:56:14 -04:00
Kenneth Reitz
cb0a96fbf3 Redirect chain flag default off. 2011-06-15 22:43:26 -04:00
Zbigniew Siciarz
fade9e36b6 Merge branch 'develop' of git://github.com/kennethreitz/requests into develop 2011-06-13 12:41:40 +02:00
Zbigniew Siciarz
24e2a05605 Merge branch 'master' of git://github.com/kennethreitz/requests into develop 2011-06-13 12:41:33 +02:00
Kenneth Reitz
1749260c97 update tests 2011-06-12 22:02:35 -04:00
Kenneth Reitz
3b86c3c0e3 httpbin 2011-06-12 22:00:17 -04:00
Kenneth Reitz
8f3da7b72c added Daniele Tricoli 'Eriol' to authors 2011-06-12 13:14:56 -04:00
Kenneth Reitz
d6cde6a5df add Zbigniew Siciarz to authors 2011-06-09 18:09:39 -04:00
Zbigniew Siciarz
54fd24b757 Testing that cookies actually work. 2011-06-09 12:30:43 +02:00
Kenneth Reitz
2153b21152 less hostility 2011-06-08 19:22:19 -04:00
Kenneth Reitz
74013d751c rackspace cloud's net connection is insane 2011-06-08 19:18:11 -04:00
Kenneth Reitz
1fa1cdd2a3 WHITESPACE 2011-06-08 19:11:08 -04:00
Kenneth Reitz
cd0d0a2b17 whitespace 2011-06-05 21:22:35 -04:00
Kenneth Reitz
e63569041a Update AUTHORS
Refs #46
2011-05-27 08:02:57 -04:00
Kenneth Reitz
54449483b6 Merge branch 'patch-1' of https://github.com/JNRowe/requests into develop 2011-05-27 08:00:22 -04:00
Kenneth Reitz
52bedf4c0b default post data to empty byte string
Refs #45
2011-05-27 07:59:28 -04:00
James Rowe
5962c0ea86 Subclass dict for CaseInsensitiveDict. 2011-05-27 00:17:44 -07:00
Johannes
9b2d7382bf Conform api.* arguments to api.request arguments.
Fixes #40.
Fixes #41.
2011-05-27 08:36:03 +02:00
Bruno Clermont
d91af4cadf add debian packaging 2011-05-26 15:37:31 -04:00
Kenneth Reitz
7e3d265b0f gauge.es 2011-05-24 18:38:45 -04:00
Kenneth Reitz
f990a7b453 Merge branch 'develop' of github.com:kennethreitz/requests into develop 2011-05-24 17:18:28 -04:00
Kenneth Reitz
ef02d02b1f testimonial cleanup 2011-05-24 17:18:19 -04:00
Kenneth Reitz
04c169ecfe Merge pull request #39 from mrtazz/patch-1
e.g. should be i.e. I guess
2011-05-23 08:42:52 -07:00
Daniel Schauenberg
5593f12347 e.g. should be i.e. I guess 2011-05-23 08:39:15 -07:00
Kenneth Reitz
3189d8690e refactor^2 2011-05-22 18:01:21 -04:00
Kenneth Reitz
b51e042e73 Merge pull request #38 from jgorset/requests
---

Ive refactored `api.request`. I think. The new version is more robust in that it no longer accepts arbitrary arguments and raises an exception if one attempts to call it with both `params` and `data` (that should probably be supported, though, but thats a topic for another issue).

Conflicts:
	requests/api.py
2011-05-22 17:54:10 -04:00
Johannes
82f1320ed5 Refactor api.request 2011-05-22 23:49:29 +02:00
Kenneth Reitz
add6feab02 Merge branch 'release/0.4.1' 2011-05-22 14:16:48 -04:00
Kenneth Reitz
670c4aecdd version bump (v0.4.1) 2011-05-22 14:13:49 -04:00
Kenneth Reitz
215d3984cc setup cleanup 2011-05-22 13:58:37 -04:00
Kenneth Reitz
0b36d925f6 remove debug print 2011-05-22 13:56:57 -04:00
Kenneth Reitz
bc290f62d7 defaults 2011-05-22 13:55:13 -04:00
Kenneth Reitz
c0faa9e79c new settings location 2011-05-22 13:31:17 -04:00
Kenneth Reitz
f887906ec3 cleanup — comments 2011-05-22 13:31:09 -04:00
Kenneth Reitz
982fd9d803 new config module 2011-05-22 13:30:55 -04:00
Kenneth Reitz
d64bf501d0 no import packages 2011-05-22 13:30:22 -04:00
Kenneth Reitz
49f1ec1efb settings -> config
reimpliment settings as singleton
2011-05-22 13:27:17 -04:00
Kenneth Reitz
0741448798 pypy binary moved 2011-05-22 12:14:50 -04:00
Kenneth Reitz
8a4d5c4683 useragent 2011-05-22 12:10:56 -04:00
Kenneth Reitz
3cdb777c23 restore allow_redirect behavior 2011-05-22 11:35:01 -04:00
Kenneth Reitz
ddc5452978 Merge pull request #37 from jgorset/requests
---

![Meme](http://i.imgur.com/kXzcW.jpg)
2011-05-22 11:25:31 -04:00
Johannes
8aa6fabd4d Support relative redirects. Fixes #36 2011-05-22 11:41:15 +02:00
Kenneth Reitz
398f5b501f not tablib.. 2011-05-21 16:24:28 -04:00
Kenneth Reitz
8d9bcefa9d Merge pull request #35 from jgorset/requests
---

Ive completed the migration of the requests settings to the new `settings` module, but my attempt to facilitate for manipulating settings outside of the context manager (eg. `requests.settings.timeout = 5`) has been thwarted by the namespace collision of the context manager and the module.

Im probably just being stupid. Youll figure it out.

Conflicts:
	requests/api.py
2011-05-21 13:04:32 -04:00
Kenneth Reitz
0b29964bf8 updated history 2011-05-21 13:00:21 -04:00
Kenneth Reitz
06e662be86 python2.5 with 2011-05-21 12:47:29 -04:00
Kenneth Reitz
e153b94190 Improved redirection behavior for 301/303 2011-05-21 12:44:58 -04:00
Johannes
7d0374df2f Slight refactor 2011-05-20 22:50:50 +02:00
Johannes
2f60748c73 Stop importing inspect 2011-05-20 20:45:51 +02:00
Johannes
bbd58b922b Migrate settings to new module 2011-05-20 20:32:39 +02:00
Kenneth Reitz
21e51b504e no toys 2011-05-20 12:55:36 -04:00
Kenneth Reitz
ba79a2eb97 new settings module 2011-05-20 12:54:42 -04:00
Johannes
ef81c16611 Fix typos 2011-05-20 18:34:43 +02:00
Johannes
da26f1f377 Adjust tests 2011-05-20 18:31:23 +02:00
Johannes
c8cc2d0421 Relocate exceptions 2011-05-20 18:20:17 +02:00
Johannes
a00dc1abf3 Raise Timeout on request timeouts 2011-05-20 18:17:46 +02:00
Johannes
59c747b793 Fix typos 2011-05-19 23:32:27 +02:00
Johannes Gorset
baddc5b6ad Refactor Request#__init__ 2011-05-19 10:16:54 +02:00
Johannes Gorset
637d0330c2 Add test for non-urlencoded post data 2011-05-19 10:14:15 +02:00
Johannes Gorset
21e2d0c34a Add tests for settings 2011-05-19 10:13:42 +02:00
Johannes Gorset
ec5f227381 Refactor settings 2011-05-19 10:13:37 +02:00
Kenneth Reitz
8ffb2462f9 home page url change 2011-05-18 10:11:07 -04:00
Kenneth Reitz
12187155b4 urllib2 2011-05-16 01:38:48 -04:00
Kenneth Reitz
d7f49f3aa5 no quickstart till done 2011-05-16 01:33:33 -04:00
Kenneth Reitz
461497f5be "a kennethreitz project" 2011-05-16 01:31:54 -04:00
Kenneth Reitz
7929bb91be api update 2011-05-16 01:18:09 -04:00
Kenneth Reitz
6e13e7343d Big API update 2011-05-16 01:13:05 -04:00
Kenneth Reitz
f9f3b46ef6 not tablib 2011-05-16 00:10:30 -04:00
Kenneth Reitz
cc851818c2 doc fixes (pretty) 2011-05-15 23:24:25 -04:00
Kenneth Reitz
ba45b9d890 Major docs cleanup 2011-05-15 23:19:19 -04:00
Kenneth Reitz
9fd70c209b GA and CR 2011-05-15 23:00:15 -04:00
Kenneth Reitz
b7970c2a46 config update 2011-05-15 22:58:17 -04:00
Kenneth Reitz
a7d072a7c0 features philosophy 2011-05-15 21:29:49 -04:00
Kenneth Reitz
054891ab5e can/cant 2011-05-15 21:22:40 -04:00
Kenneth Reitz
d18ea48b95 docs update 2011-05-15 21:14:51 -04:00
Kenneth Reitz
d39cde206b installation 2011-05-15 21:01:48 -04:00
Kenneth Reitz
58d5e0318e api.py -> api.rst 2011-05-15 21:01:44 -04:00
Kenneth Reitz
3e23e48239 docs intro 2011-05-15 20:46:36 -04:00
Kenneth Reitz
f1f5788066 docs refactor 2011-05-15 20:46:28 -04:00
Kenneth Reitz
928facfcd9 better links 2011-05-15 20:34:40 -04:00
Kenneth Reitz
70857f3097 example udpate 2011-05-15 20:25:01 -04:00
Kenneth Reitz
da726fc030 webkit scrollbars 2011-05-15 20:24:55 -04:00
Kenneth Reitz
874a874ea6 better index 2011-05-15 17:52:09 -04:00
Kenneth Reitz
0f76e17258 index cleanup 2011-05-15 17:49:59 -04:00
Kenneth Reitz
6b36911260 testimonials 2011-05-15 17:28:16 -04:00
Kenneth Reitz
1ebf3afb24 orgs 2011-05-15 13:23:05 -04:00
Kenneth Reitz
84544b1d01 link fix 2011-05-15 13:14:22 -04:00
Kenneth Reitz
319b570f82 much better index 2011-05-15 13:13:41 -04:00
Kenneth Reitz
f7481adf45 better verbage 2011-05-15 13:05:22 -04:00
Kenneth Reitz
9b165629f9 better title 2011-05-15 13:01:58 -04:00
Kenneth Reitz
79b43b2b6e better 2011-05-15 12:49:19 -04:00
Kenneth Reitz
80b71a03ce initial doc index 2011-05-15 12:43:34 -04:00
Kenneth Reitz
2546bafdde name fix 2011-05-15 11:35:06 -04:00
Kenneth Reitz
d27e4bff1e ignore builds 2011-05-15 00:41:26 -04:00
Kenneth Reitz
27dd96cf3d config update 2011-05-15 00:41:00 -04:00
Kenneth Reitz
3e45e4ba51 added krthemes 2011-05-15 00:38:59 -04:00
Kenneth Reitz
0ee249247a updated history for v0.4.0 2011-05-15 00:00:44 -04:00
Kenneth Reitz
0f520a8c69 Merge branch 'release/0.4.0' into develop 2011-05-14 23:58:07 -04:00
Kenneth Reitz
aa33194606 Merge branch 'release/0.4.0' 2011-05-14 23:58:00 -04:00
Kenneth Reitz
51360e1ede version bump 2011-05-14 23:57:53 -04:00
Kenneth Reitz
af0febe8ad history update 2011-05-14 23:57:19 -04:00
Kenneth Reitz
155863bf71 readme update 2011-05-14 23:55:15 -04:00
Kenneth Reitz
3cec61481c ignore http errors in redirect loops 2011-05-14 23:22:26 -04:00
Kenneth Reitz
5708fe9565 python 2.5 fix 2011-05-14 23:21:58 -04:00
Kenneth Reitz
c40deefb8a cleanup mess 2011-05-14 23:03:31 -04:00
Kenneth Reitz
cd8ce63a3b Custom RedirectHandler and .history support.
Closes #23
2011-05-14 23:01:13 -04:00
Kenneth Reitz
35beda21b8 pass things into the dict 2011-05-14 22:02:14 -04:00
Kenneth Reitz
85b8b2bd44 CaseInsensitiveDict for Headers 2011-05-14 22:02:07 -04:00
Kenneth Reitz
29aa7736ca Headers: Default to None 2011-05-14 21:52:33 -04:00
Kenneth Reitz
e8ff405fce remote async __all__ 2011-05-14 21:50:41 -04:00
Kenneth Reitz
5172d24e66 New CaseInsensitiveDict 2011-05-14 21:50:25 -04:00
Kenneth Reitz
dfe7d877eb date header on history 2011-05-14 14:46:47 -04:00
Kenneth Reitz
0c00a17372 Merge branch 'release/0.3.4' 2011-05-14 14:31:24 -04:00
Kenneth Reitz
fa1db95814 Version bump: v0.3.4 2011-05-14 14:30:36 -04:00
Kenneth Reitz
d77c0ec138 history update 2011-05-14 14:29:41 -04:00
Kenneth Reitz
8ba12ff4f3 cleaner patch names 2011-05-14 14:24:12 -04:00
Kenneth Reitz
14ef462263 package refactor 2011-05-14 14:21:42 -04:00
Kenneth Reitz
1421ffa32a HTTP Basic recursion. Fixes #31 2011-05-14 14:02:36 -04:00
Kenneth Reitz
62931b60f8 history for v0.3.4 2011-05-14 13:11:08 -04:00
Kenneth Reitz
b1e28c7fd8 Added Megan Emurayama to authors 2011-05-14 13:04:49 -04:00
Kenneth Reitz
9b0bb871d2 Merge pull request #29 from meganemura/requests
---

raised Attribute Error when post str data something like json because of not having items attribute.
move encoding data to utf-8 inside hasattr(data, items)
2011-05-12 13:36:45 -04:00
megane murayama
1971bdbe67 fix for post non-dict data 2011-05-12 12:50:09 -04:00
Kenneth Reitz
912f48eece slight refactor 2011-05-12 10:12:04 -04:00
Kenneth Reitz
86fb0cb235 Merge https://github.com/jgorset/requests into develop 2011-05-12 10:09:00 -04:00
Johannes Gorset
23ee58d6ec Encode both keys and values for incoming unicode data as UTF-8, coincidentally fixing a bug that caused UTF-8 encoded byte strings to be encoded twice and causing an UnicodeDecodeError. 2011-05-12 10:27:41 +02:00
Kenneth Reitz
9e0dcae0aa Merge branch 'release/0.3.3' into develop 2011-05-12 04:02:18 -04:00
Kenneth Reitz
7215452da5 Merge branch 'release/0.3.3' 2011-05-12 04:02:16 -04:00
Kenneth Reitz
01b22a7e12 version bump 2011-05-12 04:02:06 -04:00
Kenneth Reitz
d28804cc48 update history 2011-05-12 03:57:17 -04:00
Kenneth Reitz
a046a04aa2 Merge branch 'feature/timeout' into develop 2011-05-12 03:56:13 -04:00
Kenneth Reitz
59dd3ed459 unicode urls 2011-05-12 03:20:27 -04:00
Kenneth Reitz
b6f6048cff Encode incoming data.
Closes #27.
2011-05-12 03:14:09 -04:00
Kenneth Reitz
8a4a05aac0 test for unicode url issues 2011-05-12 03:12:30 -04:00
Kenneth Reitz
64d6c3074f sphinx extension fix 2011-05-12 00:29:31 -04:00
Kenneth Reitz
45ca6d8a78 Merge pull request #26 from jgorset/requests
---

Ive implemented a `settings` context manager as described in [pull request #25](https://github.com/kennethreitz/requests/pull/25#issuecomment-1039541).

    >>> import requests
    >>> with requests.settings(timeout=0.5):
    ...     requests.get(http://example.org) # Times out after 0.5 seconds
    ...     requests.get(http://example.org, timeout=10) # Times out after 10 seconds

Settings may also be manipulated separately:

    >>> import requests
    >>> requests.timeout = 0.5
    >>> requests.get(http://example.org) # Times out after 0.5 seconds
2011-04-21 17:24:43 -04:00
Johannes
77f4b8a75e Implement settings context manager 2011-04-21 18:38:33 +02:00
Kenneth Reitz
122c4f0514 updated history w/ latest changes 2011-04-21 10:37:22 -04:00
Kenneth Reitz
83494152fe Merge branch 'timeout' of https://github.com/jgorset/requests into develop 2011-04-21 10:28:26 -04:00
Kenneth Reitz
f6f636f74c Merge pull request #24 from jgorset/requests
---

I made some insignificant corrections to the README.
2011-04-21 10:16:54 -04:00
Johannes
39e9424f01 Update AUTHORS 2011-04-21 14:55:50 +02:00
Johannes
d93731213a Implement optional timeout for request functions 2011-04-21 14:54:30 +02:00
Johannes
f31dc8a9ef Substitute 'request' for 'requests' 2011-04-21 14:17:02 +02:00
Johannes
4687951a04 Substitute <request object> for the actual return value of the request functions 2011-04-21 14:01:43 +02:00
Kenneth Reitz
576cba81d9 Merge branch 'master' into develop 2011-04-15 18:00:37 -04:00
Kenneth Reitz
d3a46c822f preliminary multidicts 2011-04-15 18:00:10 -04:00
Kenneth Reitz
ea86602765 Merge branch 'release/0.3.2' into develop 2011-04-15 17:29:38 -04:00
Kenneth Reitz
fec0d1a9a0 history changes 2011-04-15 17:29:26 -04:00
Kenneth Reitz
642c667566 Merge branch 'release/0.3.2' 2011-04-15 17:27:17 -04:00
Kenneth Reitz
b8b87d416e install simplejson if python < 2.6 2011-04-15 17:27:02 -04:00
Kenneth Reitz
6e14d4704d version bump 2011-04-15 17:26:51 -04:00
Kenneth Reitz
f494cd9c72 add autoauth tuple http basic test 2011-04-15 17:24:03 -04:00
Kenneth Reitz
2814664e91 Fixes #20. 2011-04-15 17:21:38 -04:00
Kenneth Reitz
1359094cc8 test for gzip decompress 2011-04-14 19:46:35 -04:00
Kenneth Reitz
7a62b10ff2 Automatically decompress gzipped responses if content-type is set. fixes #19 2011-04-14 19:44:29 -04:00
Kenneth Reitz
23d5761bd4 accept any extra args to r.read() 2011-04-02 18:22:05 -04:00
Kenneth Reitz
cc16073c36 Merge branch 'develop' 2011-04-01 14:55:24 -04:00
Kenneth Reitz
ed8ff63048 Version bump to 0.3.1 2011-04-01 14:53:53 -04:00
Kenneth Reitz
267a852ba6 Update history 2011-04-01 14:52:33 -04:00
Kenneth Reitz
f2b04f94ca Response.read() [file like object] 2011-03-31 04:47:02 -04:00
Kenneth Reitz
e350bea167 added Request.read 2011-03-31 04:46:19 -04:00
robmadole
2401f14975 Fixing User-agent header problem introduced with Python 2.7.1 2011-03-30 00:07:24 -05:00
Kenneth Reitz
be228043a1 whitespace fix 2011-03-21 20:45:37 -04:00
Kenneth Reitz
48ffb627fe added Aram Dulyan to authors 2011-03-09 13:22:47 -05:00
Aram Dulyan
89192c64f0 An empty cookiejar evaluates to False, so it needs to be compared to None for the cookie functionality to work. 2011-03-09 22:31:13 +11:00
Kenneth Reitz
a67cc5c5a9 someone stole the cookie jar 2011-03-06 19:19:22 -05:00
Kenneth Reitz
fa2f1c5f60 Merge branch 'develop' of https://github.com/robmadole/requests into develop 2011-03-06 19:08:32 -05:00
Kenneth Reitz
1d021c5cc1 Added Rob Madole to AUTHORS 2011-03-06 19:07:29 -05:00
Kenneth Reitz
e17111a5dd testing requests with poster and adding headers 2011-03-06 18:50:28 -05:00
Kenneth Reitz
9fdee250de Better POSTER header compatibility (Fixes #13) 2011-03-06 18:48:44 -05:00
Kenneth Reitz
c6acfef3d0 Added Justin Murphy to AUTHORS 2011-03-06 18:48:14 -05:00
robmadole
e4c690e7bc Initial support for cookies 2011-03-01 09:21:00 -06:00
robmadole
ee43ad2497 Ignore those compiled files 2011-03-01 09:15:14 -06:00
Kenneth Reitz
044252ea7b Merge branch 'release/0.3.0' 2011-02-25 09:00:23 -05:00
Kenneth Reitz
f8032e08ae tests cleanups 2011-02-25 08:58:24 -05:00
Kenneth Reitz
f0d2ac3dd5 Readme update 2011-02-25 08:58:17 -05:00
Kenneth Reitz
270898e521 Readme Updates 2011-02-25 08:48:09 -05:00
Kenneth Reitz
897dd3aaa8 whitespace 2011-02-25 08:11:17 -05:00
Kenneth Reitz
dd01f8661e hacking whitespace fixes 2011-02-25 08:11:10 -05:00
Kenneth Reitz
99c3970fd3 history 2011-02-25 08:04:03 -05:00
Kenneth Reitz
839c8cf150 postbin tests were broken 2011-02-25 08:00:23 -05:00
Kenneth Reitz
b252cd8403 allow files to be upload along with form data 2011-02-25 08:00:11 -05:00
Kenneth Reitz
b3b2b19212 hmmm 2011-02-25 07:39:19 -05:00
Kenneth Reitz
a74e954788 test improvements 2011-02-25 07:21:11 -05:00
Kenneth Reitz
32f75585ad url builder, cleanups 2011-02-25 07:20:59 -05:00
Kenneth Reitz
9a8b25d5fa makin' history 2011-02-25 07:20:37 -05:00
Kenneth Reitz
14ba99f975 prettier imports 2011-02-25 05:03:12 -05:00
Kenneth Reitz
ccb7fdd8c2 Version bump 2011-02-25 04:48:10 -05:00
Kenneth Reitz
9a1d90d184 Proper async module docs 2011-02-25 04:43:18 -05:00
Kenneth Reitz
22798ca32b Prepping for v0.3.0 release. 2011-02-25 04:40:33 -05:00
Kenneth Reitz
3fe4753d5d Cleanups 2011-02-24 02:06:48 -05:00
Kenneth Reitz
d91157c567 Merge branch 'develop' into merge/xero 2011-02-24 01:53:55 -05:00
Kenneth Reitz
e7b8e9371a merge changes 2011-02-24 01:51:53 -05:00
Kenneth Reitz
1f60e1004c Merge https://github.com/Digitalxero/requests into merge/xero 2011-02-24 01:45:44 -05:00
Kenneth Reitz
9e45d201f3 Added Dj Gilcrease to AUTHORS. 2011-02-24 01:38:58 -05:00
Kenneth Reitz
47ecb3662d !+= 2011-02-24 01:30:00 -05:00
Kenneth Reitz
7369e47f18 Added Flavio to AUTHORS 2011-02-24 01:29:51 -05:00
Flavio Percoco Premoli
6f5b64bca6 small workaround for issue #7 2011-02-23 08:49:08 +01:00
Kenneth Reitz
e788ca7ee6 Safer error response handling. 2011-02-21 14:36:41 -05:00
Kenneth Reitz
68dea921e7 Added HACKING file. 2011-02-21 02:25:01 -05:00
digitalxero
f96157d259 Fix a syntax error on py2.5 and pypy 2011-02-19 15:33:24 -05:00
digitalxero
718f45698d Reset copyright on the async module 2011-02-19 15:21:47 -05:00
digitalxero
15761fc126 Made it so people can add their own auth handlers and not just the 4 provided by Python 2011-02-19 15:07:58 -05:00
digitalxero
edfdef2396 Add in a proper AuthManager instead of the list version that was being used.
Added support for all Auth types that python supports
2011-02-19 15:04:56 -05:00
digitalxero
a9e18e9106 Update the README 2011-02-19 11:18:29 -05:00
digitalxero
3b82b06adc Added an async module to make it explicit to the user that they are using async calls. 2011-02-19 11:13:10 -05:00
digitalxero
d1c89333d0 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.
2011-02-19 10:51:54 -05:00
Kenneth Reitz
e26570d0d8 Merge branch 'hotfix/date' into develop 2011-02-19 01:30:22 -05:00
Kenneth Reitz
8b3c4da2c7 Merge branch 'hotfix/date' 2011-02-19 01:30:10 -05:00
Kenneth Reitz
5c4aa1f4b7 history date fix 2011-02-19 01:30:03 -05:00
Kenneth Reitz
d2cdefa7df Merge branch 'release/0.2.4' 2011-02-19 01:03:39 -05:00
Kenneth Reitz
720d0b2c38 Version needs to be available externally. 2011-02-19 01:02:13 -05:00
Kenneth Reitz
d2584ff853 Production Ready! Added Python 2.5 to Support list. 2011-02-19 01:02:01 -05:00
Kenneth Reitz
433452f9f1 Simpler setup.py versioning. 2011-02-19 01:01:51 -05:00
Kenneth Reitz
a34e0bea8b Version Bump (v0.2.4) 2011-02-19 01:00:03 -05:00
Kenneth Reitz
f66b35454f v0.2.4 Release information 2011-02-19 00:59:56 -05:00
Kenneth Reitz
b5c2806e8c Roadmap update 2011-02-19 00:43:27 -05:00
Kenneth Reitz
5072399f7a Import fix for python2.5 2011-02-19 00:41:28 -05:00
Kenneth Reitz
736cb70e9a Merge branch 'develop' of github.com:kennethreitz/requests into develop 2011-02-19 00:38:09 -05:00
Kenneth Reitz
8eafb8d3df Added autoauth tests 2011-02-19 00:37:33 -05:00
Kenneth Reitz
e8234a0137 import fix 2011-02-18 16:13:49 -05:00
Kenneth Reitz
fbe0393eb3 cstring io fix for py3 2011-02-18 16:08:26 -05:00
Kenneth Reitz
b82e72eb04 cStringIO fix. 2011-02-18 16:00:34 -05:00
Kenneth Reitz
a7c87edebe screw 2.4 2011-02-18 15:57:50 -05:00
Kenneth Reitz
7e20f32b02 pypy configuration 2011-02-18 04:41:42 -05:00
Kenneth Reitz
4419e7183f no more test suite 2011-02-18 04:41:34 -05:00
Kenneth Reitz
6bde955170 Python 2.5 Fixes. 2011-02-18 04:39:53 -05:00
Kenneth Reitz
952970f403 Merge branch 'release/0.9.4' 2011-02-18 03:35:18 -05:00
Kenneth Reitz
d3911da653 tox update (usable now?) 2011-02-18 03:32:10 -05:00
Kenneth Reitz
7b6ed48a86 tox setup for 2.4-2.7 2011-02-17 19:38:40 -05:00
Kenneth Reitz
7229dbe033 Making everyone else happy. 2011-02-17 16:22:03 -05:00
Kenneth Reitz
015d6b78d5 cleaning up line lengths 2011-02-17 16:20:53 -05:00
Kenneth Reitz
f4c4bf3d0b Much nicer helper functions and constructors 2011-02-17 16:17:46 -05:00
Kenneth Reitz
efedbd9775 added test_suite.sh for CI 2011-02-17 13:14:03 -05:00
Kenneth Reitz
f4e03a5d32 gitignore update for jenkins 2011-02-17 13:13:52 -05:00
Kenneth Reitz
34ca692c9c from __future__ import absolute_imports 2011-02-16 12:47:58 -05:00
Kenneth Reitz
a5517960ea history indent fix for rest/pypi 2011-02-15 10:02:39 -05:00
Kenneth Reitz
fa42c12e5b I need autodoc. 2011-02-15 09:58:02 -05:00
Kenneth Reitz
8ac29b40e9 new documentation on Request changes. 2011-02-15 09:51:46 -05:00
Kenneth Reitz
adb53c2b4f Merge branch 'release/0.2.3' into develop 2011-02-15 09:46:58 -05:00
Kenneth Reitz
53e785f656 Merge branch 'release/0.2.3' 2011-02-15 09:46:55 -05:00
Kenneth Reitz
d5256802d4 v0.2.3 2011-02-15 09:46:46 -05:00
Kenneth Reitz
933cf49daa v0.2.3 2011-02-15 09:45:54 -05:00
Kenneth Reitz
83a9bcf1a1 Updating AUTHORS 2011-02-15 09:44:52 -05:00
Kenneth Reitz
4ad73c3655 leave room for _ 2011-02-15 09:42:05 -05:00
Kenneth Reitz
7ad08c5eda New tests for new HTTP STATUS Handling 2011-02-15 09:37:21 -05:00
Kenneth Reitz
4f1301f6ad Now Requests has it's own HTTPError 2011-02-15 09:36:34 -05:00
Kenneth Reitz
6d8a531e87 HTTPError changes are going down in history 2011-02-15 09:26:44 -05:00
Kenneth Reitz
748633d616 raise_for_status is better 2011-02-15 09:26:07 -05:00
Kenneth Reitz
ce122cc811 None, not False 2011-02-15 09:22:11 -05:00
Kenneth Reitz
c900b4379b Added new HTTPError handing mechanisms. 2011-02-15 09:18:43 -05:00
Kenneth Reitz
d6fa43fba7 Merge branch 'release/0.2.2' into develop 2011-02-14 12:59:22 -05:00
87 changed files with 12792 additions and 1360 deletions

1
.env Normal file
View File

@@ -0,0 +1 @@
workon r

12
.gitignore vendored
View File

@@ -1,2 +1,10 @@
.idea
MANIFEST
MANIFEST
coverage.xml
nosetests.xml
pylint.txt
toy.py
junit-report.xml
requests.egg-info/
docs/_build
*.pyc
*.swp

10
.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
language: python
python:
- 2.6
- 2.7
- 3.2
env: HTTPBIN_URL=http://httpbin.org/
script: make simpleci
install:
- pip install nose
- pip install . --use-mirrors

1
.workon Normal file
View File

@@ -0,0 +1 @@
/Users/kreitz/.virtualenvs/r26/

13
AUTHORS
View File

@@ -1,13 +0,0 @@
Requests is written and maintained by Kenneth Reitz and
various contributors:
Development Lead
````````````````
- Kenneth Reitz <me@kennethreitz.com>
Patches and Suggestions
```````````````````````
- Various Pocoo Members

99
AUTHORS.rst Normal file
View File

@@ -0,0 +1,99 @@
Requests is written and maintained by Kenneth Reitz and
various contributors:
Development Lead
````````````````
- Kenneth Reitz <me@kennethreitz.com>
Urllib3
```````
- Andrey Petrov <andrey.petrov@shazow.net>
Patches and Suggestions
```````````````````````
- Various Pocoo Members
- Chris Adams
- Flavio Percoco Premoli
- Dj Gilcrease
- Justin Murphy
- Rob Madole
- Aram Dulyan
- Johannes Gorset
- 村山めがね (Megane Murayama)
- James Rowe
- Daniel Schauenberg
- Zbigniew Siciarz
- Daniele Tricoli 'Eriol'
- Richard Boulton
- Miguel Olivares <miguel@moliware.com>
- Alberto Paro
- Jérémy Bethmont
- 潘旭 (Xu Pan)
- Tamás Gulácsi
- Rubén Abad
- Peter Manser
- Jeremy Selier
- Jens Diemer
- Alex <@alopatin>
- Tom Hogans <tomhsx@gmail.com>
- Armin Ronacher
- Shrikant Sharat Kandula
- Mikko Ohtamaa
- Den Shabalin
- Daniel Miller <danielm@vs-networks.com>
- Alejandro Giacometti
- Rick Mak
- Johan Bergström
- Josselin Jacquard
- Travis N. Vaught
- Fredrik Möllerstrand
- Daniel Hengeveld
- Dan Head
- Bruno Renié
- David Fischer
- Joseph McCullough
- Juergen Brendel
- Juan Riaza
- Ryan Kelly
- Rolando Espinoza La fuente
- Robert Gieseke
- Idan Gazit
- Ed Summers
- Chris Van Horne
- Christopher Davis
- Ori Livneh
- Jason Emerick
- Bryan Helmig
- Jonas Obrist
- Lucian Ursu
- Tom Moertel
- Frank Kumro Jr
- Chase Sterling
- Marty Alchin
- takluyver
- Ben Toews (mastahyeti)
- David Kemp
- Brendon Crawford
- Denis (Telofy)
- Cory Benfield (Lukasa)
- Matt Giuca
- Adam Tauber
- Honza Javorek
- Brendan Maguire <maguire.brendan@gmail.com>
- Chris Dary
- Danver Braganza <danverbraganza@gmail.com>
- Max Countryman
- Nick Chadwick
- Jonathan Drosdeck
- Jiri Machalek
- Steve Pulec
- Michael Kelly
- Michael Newman <newmaniese@gmail.com>
- Jonty Wareing <jonty@jonty.co.uk>
- Shivaram Lingamneni
- Miguel Turner

View File

@@ -1,6 +1,432 @@
.. :changelog:
History
-------
0.12.0 (2012-05-02)
+++++++++++++++++++
- EXPERIMENTAL OAUTH SUPPORT!
- Proper CookieJar-backed cookies interface with awesome dict-like interface.
- Speed fix for non-iterated content chunks.
- Move ``pre_request`` to a more usable place.
- New ``pre_send`` hook.
- Lazily encode data, params, files
- Load system Certificate Bundle if ``certify`` isn't available.
- Cleanups, fixes.
0.11.2 (2012-04-22)
+++++++++++++++++++
- Attempt to use the OS's certificate bundle if ``certifi`` isn't available.
- Infinite digest auth redirect fix
- Multi-part file upload improvements
- Fix decoding of invalid %encodings in URLs
- If there is no content in a response don't throw an error the second time that content is attempted to be read.
- Upload data on redirects.
0.11.1 (2012-03-30)
+++++++++++++++++++
* POST redirects now break RFC to do what browsers do: Follow up with a GET.
* New ``strict_mode`` configuration to disable new redirect behavior.
0.11.0 (2012-03-14)
+++++++++++++++++++
* Private SSL Certificate support
* Remove select.poll from Gevent monkeypatching
* Remove redundant generator for chunked transfer encoding
* Fix: Response.ok raises Timeout Exception in safe_mode
0.10.8 (2012-03-09)
+++++++++++++++++++
* Generate chunked ValueError fix
* Proxy configuration by environment variables
* Simplification of iter_lines.
* New `trust_env` configuration for disabling system/environment hints.
* Suppress cookie errors.
0.10.7 (2012-03-07)
+++++++++++++++++++
* `encode_uri` = False
0.10.6 (2012-02-25)
+++++++++++++++++++
* Allow '=' in cookies.
0.10.5 (2012-02-25)
+++++++++++++++++++
* Response body with 0 content-length fix.
* New async.imap.
* Don't fail on netrc.
0.10.4 (2012-02-20)
+++++++++++++++++++
* Honor netrc.
0.10.3 (2012-02-20)
+++++++++++++++++++
* HEAD requests don't follow redirects anymore.
* raise_for_status() doesn't raise for 3xx anymore.
* Make Session objects picklable.
* ValueError for invalid schema URLs.
0.10.2 (2012-01-15)
+++++++++++++++++++
* Vastly improved URL quoting.
* Additional allowed cookie key values.
* Attempted fix for "Too many open files" Error
* Replace unicode errors on first pass, no need for second pass.
* Append '/' to bare-domain urls before query insertion.
* Exceptions now inherit from RuntimeError.
* Binary uploads + auth fix.
* Bugfixes.
0.10.1 (2012-01-23)
+++++++++++++++++++
* PYTHON 3 SUPPORT!
* Dropped 2.5 Support. (*Backwards Incompatible*)
0.10.0 (2012-01-21)
+++++++++++++++++++
* ``Response.content`` is now bytes-only. (*Backwards Incompatible*)
* New ``Response.text`` is unicode-only.
* If no ``Response.encoding`` is specified and ``chardet`` is available, ``Respoonse.text`` will guess an encoding.
* Default to ISO-8859-1 (Western) encoding for "text" subtypes.
* Removal of `decode_unicode`. (*Backwards Incompatible*)
* New multiple-hooks system.
* New ``Response.register_hook`` for registering hooks within the pipeline.
* ``Response.url`` is now Unicode.
0.9.3 (2012-01-18)
++++++++++++++++++
* SSL verify=False bugfix (apparent on windows machines).
0.9.2 (2012-01-18)
++++++++++++++++++
* Asynchronous async.send method.
* Support for proper chunk streams with boundaries.
* session argument for Session classes.
* Print entire hook tracebacks, not just exception instance.
* Fix response.iter_lines from pending next line.
* Fix but in HTTP-digest auth w/ URI having query strings.
* Fix in Event Hooks section.
* Urllib3 update.
0.9.1 (2012-01-06)
++++++++++++++++++
* danger_mode for automatic Response.raise_for_status()
* Response.iter_lines refactor
0.9.0 (2011-12-28)
++++++++++++++++++
* verify ssl is default.
0.8.9 (2011-12-28)
++++++++++++++++++
* Packaging fix.
0.8.8 (2011-12-28)
++++++++++++++++++
* SSL CERT VERIFICATION!
* Release of Cerifi: Mozilla's cert list.
* New 'verify' argument for SSL requests.
* Urllib3 update.
0.8.7 (2011-12-24)
++++++++++++++++++
* iter_lines last-line truncation fix
* Force safe_mode for async requests
* Handle safe_mode exceptions more consistently
* Fix iteration on null responses in safe_mode
0.8.6 (2011-12-18)
++++++++++++++++++
* Socket timeout fixes.
* Proxy Authorization support.
0.8.5 (2011-12-14)
++++++++++++++++++
* Response.iter_lines!
0.8.4 (2011-12-11)
++++++++++++++++++
* Prefetch bugfix.
* Added license to installed version.
0.8.3 (2011-11-27)
++++++++++++++++++
* Converted auth system to use simpler callable objects.
* New session parameter to API methods.
* Display full URL while logging.
0.8.2 (2011-11-19)
++++++++++++++++++
* New Unicode decoding system, based on over-ridable `Response.encoding`.
* Proper URL slash-quote handling.
* Cookies with ``[``, ``]``, and ``_`` allowed.
0.8.1 (2011-11-15)
++++++++++++++++++
* URL Request path fix
* Proxy fix.
* Timeouts fix.
0.8.0 (2011-11-13)
++++++++++++++++++
* Keep-alive support!
* Complete removal of Urllib2
* Complete removal of Poster
* Complete removal of CookieJars
* New ConnectionError raising
* Safe_mode for error catching
* prefetch parameter for request methods
* OPTION method
* Async pool size throttling
* File uploads send real names
* Vendored in urllib3
0.7.6 (2011-11-07)
++++++++++++++++++
* Digest authentication bugfix (attach query data to path)
0.7.5 (2011-11-04)
++++++++++++++++++
* Response.content = None if there was an invalid repsonse.
* Redirection auth handling.
0.7.4 (2011-10-26)
++++++++++++++++++
* Session Hooks fix.
0.7.3 (2011-10-23)
++++++++++++++++++
* Digest Auth fix.
0.7.2 (2011-10-23)
++++++++++++++++++
* PATCH Fix.
0.7.1 (2011-10-23)
++++++++++++++++++
* Move away from urllib2 authentication handling.
* Fully Remove AuthManager, AuthObject, &c.
* New tuple-based auth system with handler callbacks.
0.7.0 (2011-10-22)
++++++++++++++++++
* Sessions are now the primary interface.
* Deprecated InvalidMethodException.
* PATCH fix.
* New config system (no more global settings).
0.6.6 (2011-10-19)
++++++++++++++++++
* Session parameter bugfix (params merging).
0.6.5 (2011-10-18)
++++++++++++++++++
* Offline (fast) test suite.
* Session dictionary argument merging.
0.6.4 (2011-10-13)
++++++++++++++++++
* Automatic decoding of unicode, based on HTTP Headers.
* New ``decode_unicode`` setting.
* Removal of ``r.read/close`` methods.
* New ``r.faw`` interface for advanced response usage.*
* Automatic expansion of parameterized headers.
0.6.3 (2011-10-13)
++++++++++++++++++
* Beautiful ``requests.async`` module, for making async requests w/ gevent.
0.6.2 (2011-10-09)
++++++++++++++++++
* GET/HEAD obeys allow_redirects=False.
0.6.1 (2011-08-20)
++++++++++++++++++
* Enhanced status codes experience ``\o/``
* Set a maximum number of redirects (``settings.max_redirects``)
* Full Unicode URL support
* Support for protocol-less redirects.
* Allow for arbitrary request types.
* Bugfixes
0.6.0 (2011-08-17)
++++++++++++++++++
* New callback hook system
* New persistient sessions object and context manager
* Transparent Dict-cookie handling
* Status code reference object
* Removed Response.cached
* Added Response.request
* All args are kwargs
* Relative redirect support
* HTTPError handling improvements
* Improved https testing
* Bugfixes
0.5.1 (2011-07-23)
++++++++++++++++++
* International Domain Name Support!
* Access headers without fetching entire body (``read()``)
* Use lists as dicts for parameters
* Add Forced Basic Authentication
* Forced Basic is default authentication type
* ``python-requests.org`` default User-Agent header
* CaseInsensitiveDict lower-case caching
* Response.history bugfix
0.5.0 (2011-06-21)
++++++++++++++++++
* PATCH Support
* Support for Proxies
* HTTPBin Test Suite
* Redirect Fixes
* settings.verbose stream writing
* Querystrings for all methods
* URLErrors (Connection Refused, Timeout, Invalid URLs) are treated as explicity raised
``r.requests.get('hwe://blah'); r.raise_for_status()``
0.4.1 (2011-05-22)
++++++++++++++++++
* Improved Redirection Handling
* New 'allow_redirects' param for following non-GET/HEAD Redirects
* Settings module refactoring
0.4.0 (2011-05-15)
++++++++++++++++++
* Response.history: list of redirected responses
* Case-Insensitive Header Dictionaries!
* Unicode URLs
0.3.4 (2011-05-14)
++++++++++++++++++
* Urllib2 HTTPAuthentication Recursion fix (Basic/Digest)
* Internal Refactor
* Bytes data upload Bugfix
0.3.3 (2011-05-12)
++++++++++++++++++
* Request timeouts
* Unicode url-encoded data
* Settings context manager and module
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)
++++++++++++++++++
* Automatic Authentication API Change
* Smarter Query URL Parameterization
* Allow file uploads and POST data together
* New Authentication Manager System
- Simpler Basic HTTP System
- Supports all build-in urllib2 Auths
- Allows for custom Auth Handlers
0.2.4 (2011-02-19)
++++++++++++++++++
* Python 2.5 Support
* PyPy-c v1.4 Support
* Auto-Authentication tests
* Improved Request object constructor
0.2.3 (2011-02-15)
++++++++++++++++++
* New HTTPHandling Methods
- Reponse.__nonzero__ (false if bad HTTP Status)
- Response.ok (True if expected HTTP Status)
- Response.error (Logged HTTPError if bad HTTP Status)
- Reponse.raise_for_status() (Raises stored HTTPError)
0.2.2 (2011-02-14)
++++++++++++++++++

View File

@@ -1,4 +1,4 @@
Copyright (c) 2011 Kenneth Reitz.
Copyright (c) 2012 Kenneth Reitz.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

View File

@@ -1 +1 @@
include README.rst LICENSE HISTORY.rst
include README.rst LICENSE NOTICE HISTORY.rst tests/*.py

41
Makefile Normal file
View File

@@ -0,0 +1,41 @@
SHELL := /bin/bash
init:
python setup.py develop
pip install -r requirements.txt
test:
nosetests ./tests/*
lazy:
nosetests --with-color tests/test_requests.py
simple:
nosetests tests/test_requests.py
server:
gunicorn httpbin:app --bind=0.0.0.0:7077 &
ci: init
nosetests tests/test_requests.py --with-xunit --xunit-file=junit-report.xml
simpleci:
nosetests tests/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:
cd docs; make dirhtml
pyc:
find . -name "*.pyc" -exec rm '{}' ';'
deps:
rm -fr requests/packages/urllib3
git clone https://github.com/shazow/urllib3.git
cd urllib3 && git checkout master && cd ..
mv urllib3/urllib3 requests/packages/
rm -fr urllib3
docs: site

25
NOTICE
View File

@@ -1,12 +1,25 @@
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 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 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.

View File

@@ -1,109 +1,52 @@
Requests: The Simple (e.g. usable) HTTP Module
==============================================
Requests: HTTP for Humans
=========================
Most existing Python modules for dealing HTTP requests are insane. I have to look up *everything* that I want to do. Most of my worst Python experiences are a result of the various built-in HTTP libraries (yes, even worse than Logging).
But this one's different. This one's going to be awesome. And simple.
.. image:: https://secure.travis-ci.org/kennethreitz/requests.png?branch=develop
Requests is an ISC Licensed HTTP library, written in Python, for human
beings.
Most existing Python modules for sending HTTP requests are extremely
verbose and cumbersome. Python's builtin urllib2 module provides most of
the HTTP capabilities you should need, but the api is thoroughly broken.
It requires an enormous amount of work (even method overrides) to
perform the simplest of tasks.
Things shouldn't be this way. Not in Python.
::
>>> r = requests.get('https://api.github.com', auth=('user', 'pass'))
>>> r.status_code
204
>>> r.headers['content-type']
'application/json'
>>> r.text
...
See `the same code, without Requests <https://gist.github.com/973705>`_.
Requests allow you to send HTTP/1.1 requests. You can add headers, form data,
multipart files, and parameters with simple Python dictionaries, and access the
response data in the same way. It's powered by httplib and `urllib3
<https://github.com/shazow/urllib3>`_, but it does all the hard work and crazy
hacks for you.
Really simple.
Features
--------
- Extremely simple GET, HEAD, POST, PUT, DELETE Requests
+ Simple HTTP Header Request Attachment
+ Simple Data/Params Request Attachment
+ Simple Multipart File Uploads
+ CookieJar Support
- Simple Basic HTTP Authentication
+ Simple URL + HTTP Auth Registry
Usage
-----
It couldn't be simpler. ::
>>> import requests
>>> r = requests.get('http://google.com')
HTTPS? Basic Authentication? ::
>>> r = requests.get('https://convore.com/api/account/verify.json')
>>> r.status_code
401
Uh oh, we're not authorized! Let's add authentication. ::
>>> conv_auth = requests.AuthObject('requeststest', 'requeststest')
>>> r = requests.get('https://convore.com/api/account/verify.json', auth=conv_auth)
>>> r.status_code
200
>>> r.headers['content-type']
'application/json'
>>> r.content
'{"username": "requeststest", "url": "/users/requeststest/", "id": "9408", "img": "censored-long-url"}'
API
---
**Requests:**
All request functions return a Response object (see below).
If a {filename: fileobject} dictionary is passed in (files=...), a multipart_encode upload will be performed.
If CookieJar object is is passed in (cookies=...), the cookies will be sent with the request.
GET Requests
>>> request.get(url, params={}, headers={}, cookies=None, auth=None)
<request object>
HEAD Requests
>>> request.head(url, params={}, headers={}, cookies=None, auth=None)
<request object>
PUT Requests
>>> request.put(url, data='', headers={}, files={}, cookies=None, auth=None)
<request object>
POST Requests
>>> request.post(url, data={}, headers={}, files={}, cookies=None, auth=None)
<request object>
DELETE Requests
>>> request.delete(url, params={}, headers={}, cookies=None, auth=None)
<request object>
**Responses:**
Request.status_code:
(Integer) Received HTTP Status Code Response
Request.headers:
(Dictionary) Received HTTP Response Headers
Request.content:
(Bytes) Received Content
Request.url
(String) URL of response. Useful for detecting redirects.
**HTTP Authentication Registry:**
You can register AuthObjects to automatically enable HTTP Authentication on requests that contain a registered base URL string.
>>> requests.add_autoauth(url, authobject)
- International Domains and URLs
- Keep-Alive & Connection Pooling
- Sessions with Cookie Persistence
- Browser-style SSL Verification
- Basic/Digest Authentication
- Elegant Key/Value Cookies
- Automatic Decompression
- Unicode Response Bodies
- Multipart File Uploads
- Connection Timeouts
Installation
@@ -112,27 +55,22 @@ Installation
To install requests, simply: ::
$ pip install requests
Or, if you absolutely must: ::
$ easy_install requests
But, you really shouldn't do that.
Contribute
----------
If you'd like to contribute, simply fork `the repository`_, commit your changes to the **develop** branch (or branch off of it), and send a pull request. Make sure you add yourself to AUTHORS_.
Roadmap
-------
- Sphinx Documentation
- Exhaustive Unittests
#. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. There is a Contributor Friendly tag for issues that should be ideal for people who are not very familiar with the codebase yet.
#. Fork `the repository`_ on Github to start making your changes to the **develop** branch (or branch off of it).
#. Write a test which shows that the bug was fixed or that the feature works as expected.
#. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_.
.. _`the repository`: http://github.com/kennethreitz/requests
.. _AUTHORS: http://github.com/kennethreitz/requests/blob/master/AUTHORS
.. _AUTHORS: https://github.com/kennethreitz/requests/blob/develop/AUTHORS.rst

BIN
docs/_static/requests-sidebar.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

43
docs/_templates/sidebarintro.html vendored Normal file
View File

@@ -0,0 +1,43 @@
<p class="logo">
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" alt="Logo"/>
</a>
</p>
<p>
<iframe src="http://markdotto.github.com/github-buttons/github-btn.html?user=kennethreitz&repo=requests&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
</p>
<p>
Requests is an elegant and simple HTTP library for Python, built for
human beings. You are currently looking at the documentation of the
development release.
</p>
<h3>Donate</h3>
<p>
If you love Requests, consider making a small donation <a href="https://flattr.com/thing/442264/Requests">on Flattr</a>:
</p>
<p>
<a class="FlattrButton" style="display:none;" rev="flattr;button:compact;" href="http://docs.python-requests.org/"></a>
<noscript><a href="http://flattr.com/thing/442264/Requests" target="_blank">
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a></noscript>
</p>
<h3>Feedback</h3>
<p>
Feedback is greatly appreciated. If you have any questions, comments,
random praise, or anonymous threats, <a href="mailto:me@kennethreitz.com">
shoot me an email</a>.
</p>
<h3>Useful Links</h3>
<ul>
<li><a href="http://pypi.python.org/pypi/requests">Requests @ PyPI</a></li>
<li><a href="http://github.com/kennethreitz/requests">Requests @ GitHub</a></li>
<li><a href="https://flattr.com/thing/442264/Requests">Requests @ Flattr</a></li>
<li><a href="http://github.com/kennethreitz/requests/issues">Issue Tracker</a></li>
</ul>

25
docs/_templates/sidebarlogo.html vendored Normal file
View File

@@ -0,0 +1,25 @@
<p class="logo">
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" alt="Logo"/>
</a>
</p>
<p>
<iframe src="http://markdotto.github.com/github-buttons/github-btn.html?user=kennethreitz&repo=requests&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
</p>
<p>
Requests is an elegant and simple HTTP library for Python, built for
human beings. You are currently looking at the documentation of the
development release.
</p>
<h3>Support Requests</h3>
<p>
If you love Requests, consider making a small donation <a href="https://flattr.com/thing/442264/Requests">on Flattr</a>:
</p>
<p>
<a class="FlattrButton" style="display:none;" rev="flattr;button:compact;" href="http://docs.python-requests.org/"></a>
<noscript><a href="http://flattr.com/thing/442264/Requests" target="_blank">
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a></noscript>
</p>

3
docs/_themes/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.pyc
*.pyo
.DS_Store

45
docs/_themes/LICENSE vendored Normal file
View File

@@ -0,0 +1,45 @@
Modifications:
Copyright (c) 2011 Kenneth Reitz.
Original Project:
Copyright (c) 2010 by Armin Ronacher.
Some rights reserved.
Redistribution and use in source and binary forms of the theme, with or
without modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
We kindly ask you to only use these themes in an unmodified manner just
for Flask and Flask-related products, not for unrelated projects. If you
like the visual style and want to use it for your own projects, please
consider making some larger changes to the themes (such as changing
font faces, sizes, colors or margins).
THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

25
docs/_themes/README.rst vendored Normal file
View File

@@ -0,0 +1,25 @@
krTheme Sphinx Style
====================
This repository contains sphinx styles Kenneth Reitz uses in most of
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:
1. put this folder as _themes into your docs folder. Alternatively
you can also use git submodules to check out the contents there.
2. add this to your conf.py: ::
sys.path.append(os.path.abspath('_themes'))
html_theme_path = ['_themes']
html_theme = 'flask'
The following themes exist:
**kr**
the standard flask documentation theme for large projects
**kr_small**
small one-page theme. Intended to be used by very small addon libraries.

86
docs/_themes/flask_theme_support.py vendored Normal file
View File

@@ -0,0 +1,86 @@
# flasky extensions. flasky pygments style based on tango style
from pygments.style import Style
from pygments.token import Keyword, Name, Comment, String, Error, \
Number, Operator, Generic, Whitespace, Punctuation, Other, Literal
class FlaskyStyle(Style):
background_color = "#f8f8f8"
default_style = ""
styles = {
# No corresponding class for the following:
#Text: "", # class: ''
Whitespace: "underline #f8f8f8", # class: 'w'
Error: "#a40000 border:#ef2929", # class: 'err'
Other: "#000000", # class 'x'
Comment: "italic #8f5902", # class: 'c'
Comment.Preproc: "noitalic", # class: 'cp'
Keyword: "bold #004461", # class: 'k'
Keyword.Constant: "bold #004461", # class: 'kc'
Keyword.Declaration: "bold #004461", # class: 'kd'
Keyword.Namespace: "bold #004461", # class: 'kn'
Keyword.Pseudo: "bold #004461", # class: 'kp'
Keyword.Reserved: "bold #004461", # class: 'kr'
Keyword.Type: "bold #004461", # class: 'kt'
Operator: "#582800", # class: 'o'
Operator.Word: "bold #004461", # class: 'ow' - like keywords
Punctuation: "bold #000000", # class: 'p'
# because special names such as Name.Class, Name.Function, etc.
# are not recognized as such later in the parsing, we choose them
# to look the same as ordinary variables.
Name: "#000000", # class: 'n'
Name.Attribute: "#c4a000", # class: 'na' - to be revised
Name.Builtin: "#004461", # class: 'nb'
Name.Builtin.Pseudo: "#3465a4", # class: 'bp'
Name.Class: "#000000", # class: 'nc' - to be revised
Name.Constant: "#000000", # class: 'no' - to be revised
Name.Decorator: "#888", # class: 'nd' - to be revised
Name.Entity: "#ce5c00", # class: 'ni'
Name.Exception: "bold #cc0000", # class: 'ne'
Name.Function: "#000000", # class: 'nf'
Name.Property: "#000000", # class: 'py'
Name.Label: "#f57900", # class: 'nl'
Name.Namespace: "#000000", # class: 'nn' - to be revised
Name.Other: "#000000", # class: 'nx'
Name.Tag: "bold #004461", # class: 'nt' - like a keyword
Name.Variable: "#000000", # class: 'nv' - to be revised
Name.Variable.Class: "#000000", # class: 'vc' - to be revised
Name.Variable.Global: "#000000", # class: 'vg' - to be revised
Name.Variable.Instance: "#000000", # class: 'vi' - to be revised
Number: "#990000", # class: 'm'
Literal: "#000000", # class: 'l'
Literal.Date: "#000000", # class: 'ld'
String: "#4e9a06", # class: 's'
String.Backtick: "#4e9a06", # class: 'sb'
String.Char: "#4e9a06", # class: 'sc'
String.Doc: "italic #8f5902", # class: 'sd' - like a comment
String.Double: "#4e9a06", # class: 's2'
String.Escape: "#4e9a06", # class: 'se'
String.Heredoc: "#4e9a06", # class: 'sh'
String.Interpol: "#4e9a06", # class: 'si'
String.Other: "#4e9a06", # class: 'sx'
String.Regex: "#4e9a06", # class: 'sr'
String.Single: "#4e9a06", # class: 's1'
String.Symbol: "#4e9a06", # class: 'ss'
Generic: "#000000", # class: 'g'
Generic.Deleted: "#a40000", # class: 'gd'
Generic.Emph: "italic #000000", # class: 'ge'
Generic.Error: "#ef2929", # class: 'gr'
Generic.Heading: "bold #000080", # class: 'gh'
Generic.Inserted: "#00A000", # class: 'gi'
Generic.Output: "#888", # class: 'go'
Generic.Prompt: "#745334", # class: 'gp'
Generic.Strong: "bold #000000", # class: 'gs'
Generic.Subheading: "bold #800080", # class: 'gu'
Generic.Traceback: "bold #a40000", # class: 'gt'
}

65
docs/_themes/kr/layout.html vendored Normal file
View File

@@ -0,0 +1,65 @@
{%- extends "basic/layout.html" %}
{%- block extrahead %}
{{ super() }}
{% if theme_touch_icon %}
<link rel="apple-touch-icon" href="{{ pathto('_static/' ~ theme_touch_icon, 1) }}" />
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9">
{% endblock %}
{%- block relbar2 %}{% endblock %}
{%- block footer %}
<div class="footer">
&copy; Copyright {{ copyright }}.
</div>
<a href="https://github.com/kennethreitz/requests" class="github">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" class="github"/>
</a>
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<script type="text/javascript">
new HelloBar(36402,48802);
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-8742933-11']);
_gaq.push(['_setDomainName', 'none']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<script type="text/javascript">
(function() {
var t = document.createElement('script');
t.type = 'text/javascript';
t.async = true;
t.id = 'gauges-tracker';
t.setAttribute('data-site-id',
'4ddc27f6613f5d186d000007');
t.src = '//secure.gaug.es/track.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(t, s);
})();
</script>
{%- endblock %}

19
docs/_themes/kr/relations.html vendored Normal file
View File

@@ -0,0 +1,19 @@
<h3>Related Topics</h3>
<ul>
<li><a href="{{ pathto(master_doc) }}">Documentation overview</a><ul>
{%- for parent in parents %}
<li><a href="{{ parent.link|e }}">{{ parent.title }}</a><ul>
{%- endfor %}
{%- if prev %}
<li>Previous: <a href="{{ prev.link|e }}" title="{{ _('previous chapter')
}}">{{ prev.title }}</a></li>
{%- endif %}
{%- if next %}
<li>Next: <a href="{{ next.link|e }}" title="{{ _('next chapter')
}}">{{ next.title }}</a></li>
{%- endif %}
{%- for parent in parents %}
</ul></li>
{%- endfor %}
</ul></li>
</ul>

570
docs/_themes/kr/static/flasky.css_t vendored Normal file
View File

@@ -0,0 +1,570 @@
/*
* flasky.css_t
* ~~~~~~~~~~~~
*
* :copyright: Copyright 2010 by Armin Ronacher. Modifications by Kenneth Reitz.
* :license: Flask Design License, see LICENSE for details.
*/
{% set page_width = '940px' %}
{% set sidebar_width = '220px' %}
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro';
font-size: 17px;
background-color: white;
color: #000;
margin: 0;
padding: 0;
}
div.document {
width: {{ page_width }};
margin: 30px auto 0 auto;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 {{ sidebar_width }};
}
div.sphinxsidebar {
width: {{ sidebar_width }};
}
hr {
border: 1px solid #B1B4B6;
}
div.body {
background-color: #ffffff;
color: #3E4349;
padding: 0 30px 0 30px;
}
img.floatingflask {
padding: 0 0 10px 10px;
float: right;
}
div.footer {
width: {{ page_width }};
margin: 20px auto 30px auto;
font-size: 14px;
color: #888;
text-align: right;
}
div.footer a {
color: #888;
}
div.related {
display: none;
}
div.sphinxsidebar a {
color: #444;
text-decoration: none;
border-bottom: 1px dotted #999;
}
div.sphinxsidebar a:hover {
border-bottom: 1px solid #999;
}
div.sphinxsidebar {
font-size: 14px;
line-height: 1.5;
}
div.sphinxsidebarwrapper {
padding: 18px 10px;
}
div.sphinxsidebarwrapper p.logo {
padding: 0;
margin: -10px 0 0 -20px;
text-align: center;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: 'Garamond', 'Georgia', serif;
color: #444;
font-size: 24px;
font-weight: normal;
margin: 0 0 5px 0;
padding: 0;
}
div.sphinxsidebar h4 {
font-size: 20px;
}
div.sphinxsidebar h3 a {
color: #444;
}
div.sphinxsidebar p.logo a,
div.sphinxsidebar h3 a,
div.sphinxsidebar p.logo a:hover,
div.sphinxsidebar h3 a:hover {
border: none;
}
div.sphinxsidebar p {
color: #555;
margin: 10px 0;
}
div.sphinxsidebar ul {
margin: 10px 0;
padding: 0;
color: #000;
}
div.sphinxsidebar input {
border: 1px solid #ccc;
font-family: 'Georgia', serif;
font-size: 1em;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #004B6B;
text-decoration: underline;
}
a:hover {
color: #6D4100;
text-decoration: underline;
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Garamond', 'Georgia', serif;
font-weight: normal;
margin: 30px 0px 10px 0px;
padding: 0;
}
div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }
div.body h2 { font-size: 180%; }
div.body h3 { font-size: 150%; }
div.body h4 { font-size: 130%; }
div.body h5 { font-size: 100%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #ddd;
padding: 0 4px;
text-decoration: none;
}
a.headerlink:hover {
color: #444;
background: #eaeaea;
}
div.body p, div.body dd, div.body li {
line-height: 1.4em;
}
div.admonition {
background: #fafafa;
margin: 20px -30px;
padding: 10px 30px;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
div.admonition tt.xref, div.admonition a tt {
border-bottom: 1px solid #fafafa;
}
dd div.admonition {
margin-left: -60px;
padding-left: 60px;
}
div.admonition p.admonition-title {
font-family: 'Garamond', 'Georgia', serif;
font-weight: normal;
font-size: 24px;
margin: 0 0 10px 0;
padding: 0;
line-height: 1;
}
div.admonition p.last {
margin-bottom: 0;
}
div.highlight {
background-color: white;
}
dt:target, .highlight {
background: #FAF3E8;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre, tt {
font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.9em;
}
img.screenshot {
}
tt.descname, tt.descclassname {
font-size: 0.95em;
}
tt.descname {
padding-right: 0.08em;
}
img.screenshot {
-moz-box-shadow: 2px 2px 4px #eee;
-webkit-box-shadow: 2px 2px 4px #eee;
box-shadow: 2px 2px 4px #eee;
}
table.docutils {
border: 1px solid #888;
-moz-box-shadow: 2px 2px 4px #eee;
-webkit-box-shadow: 2px 2px 4px #eee;
box-shadow: 2px 2px 4px #eee;
}
table.docutils td, table.docutils th {
border: 1px solid #888;
padding: 0.25em 0.7em;
}
table.field-list, table.footnote {
border: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
table.footnote {
margin: 15px 0;
width: 100%;
border: 1px solid #eee;
background: #fdfdfd;
font-size: 0.9em;
}
table.footnote + table.footnote {
margin-top: -15px;
border-top: none;
}
table.field-list th {
padding: 0 0.8em 0 0;
}
table.field-list td {
padding: 0;
}
table.footnote td.label {
width: 0px;
padding: 0.3em 0 0.3em 0.5em;
}
table.footnote td {
padding: 0.3em 0.5em;
}
dl {
margin: 0;
padding: 0;
}
dl dd {
margin-left: 30px;
}
blockquote {
margin: 0 0 0 30px;
padding: 0;
}
ul, ol {
margin: 10px 0 10px 30px;
padding: 0;
}
pre {
background: #eee;
padding: 7px 30px;
margin: 15px -30px;
line-height: 1.3em;
}
dl pre, blockquote pre, li pre {
margin-left: -60px;
padding-left: 60px;
}
dl dl pre {
margin-left: -90px;
padding-left: 90px;
}
tt {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
}
tt.xref, a tt {
background-color: #FBFBFB;
border-bottom: 1px solid white;
}
a.reference {
text-decoration: none;
border-bottom: 1px dotted #004B6B;
}
a.reference:hover {
border-bottom: 1px solid #6D4100;
}
a.footnote-reference {
text-decoration: none;
font-size: 0.7em;
vertical-align: top;
border-bottom: 1px dotted #004B6B;
}
a.footnote-reference:hover {
border-bottom: 1px solid #6D4100;
}
a:hover tt {
background: #EEE;
}
@media screen and (max-width: 870px) {
div.sphinxsidebar {
display: none;
}
div.document {
width: 100%;
}
div.documentwrapper {
margin-left: 0;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
}
div.bodywrapper {
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
}
ul {
margin-left: 0;
}
.document {
width: auto;
}
.footer {
width: auto;
}
.bodywrapper {
margin: 0;
}
.footer {
width: auto;
}
.github {
display: none;
}
}
@media screen and (max-width: 875px) {
body {
margin: 0;
padding: 20px 30px;
}
div.documentwrapper {
float: none;
background: white;
}
div.sphinxsidebar {
display: block;
float: none;
width: 102.5%;
margin: 50px -30px -20px -30px;
padding: 10px 20px;
background: #333;
color: white;
}
div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,
div.sphinxsidebar h3 a {
color: white;
}
div.sphinxsidebar a {
color: #aaa;
}
div.sphinxsidebar p.logo {
display: none;
}
div.document {
width: 100%;
margin: 0;
}
div.related {
display: block;
margin: 0;
padding: 10px 0 20px 0;
}
div.related ul,
div.related ul li {
margin: 0;
padding: 0;
}
div.footer {
display: none;
}
div.bodywrapper {
margin: 0;
}
div.body {
min-height: 0;
padding: 0;
}
.rtd_doc_footer {
display: none;
}
.document {
width: auto;
}
.footer {
width: auto;
}
.footer {
width: auto;
}
.github {
display: none;
}
}
/* scrollbars */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-button:start:decrement,
::-webkit-scrollbar-button:end:increment {
display: block;
height: 10px;
}
::-webkit-scrollbar-button:vertical:increment {
background-color: #fff;
}
::-webkit-scrollbar-track-piece {
background-color: #eee;
-webkit-border-radius: 3px;
}
::-webkit-scrollbar-thumb:vertical {
height: 50px;
background-color: #ccc;
-webkit-border-radius: 3px;
}
::-webkit-scrollbar-thumb:horizontal {
width: 50px;
background-color: #ccc;
-webkit-border-radius: 3px;
}
/* misc. */
.revsys-inline {
display: none!important;
}

7
docs/_themes/kr/theme.conf vendored Normal file
View File

@@ -0,0 +1,7 @@
[theme]
inherit = basic
stylesheet = flasky.css
pygments_style = flask_theme_support.FlaskyStyle
[options]
touch_icon =

22
docs/_themes/kr_small/layout.html vendored Normal file
View File

@@ -0,0 +1,22 @@
{% extends "basic/layout.html" %}
{% block header %}
{{ super() }}
{% if pagename == 'index' %}
<div class=indexwrapper>
{% endif %}
{% endblock %}
{% block footer %}
{% if pagename == 'index' %}
</div>
{% endif %}
{% endblock %}
{# do not display relbars #}
{% block relbar1 %}{% endblock %}
{% block relbar2 %}
{% if theme_github_fork %}
<a href="http://github.com/{{ theme_github_fork }}"><img style="position: fixed; top: 0; right: 0; border: 0;"
src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
{% endif %}
{% endblock %}
{% block sidebar1 %}{% endblock %}
{% block sidebar2 %}{% endblock %}

View File

@@ -0,0 +1,287 @@
/*
* flasky.css_t
* ~~~~~~~~~~~~
*
* Sphinx stylesheet -- flasky theme based on nature theme.
*
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: 'Georgia', serif;
font-size: 17px;
color: #000;
background: white;
margin: 0;
padding: 0;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 40px auto 0 auto;
width: 700px;
}
hr {
border: 1px solid #B1B4B6;
}
div.body {
background-color: #ffffff;
color: #3E4349;
padding: 0 30px 30px 30px;
}
img.floatingflask {
padding: 0 0 10px 10px;
float: right;
}
div.footer {
text-align: right;
color: #888;
padding: 10px;
font-size: 14px;
width: 650px;
margin: 0 auto 40px auto;
}
div.footer a {
color: #888;
text-decoration: underline;
}
div.related {
line-height: 32px;
color: #888;
}
div.related ul {
padding: 0 0 0 10px;
}
div.related a {
color: #444;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #004B6B;
text-decoration: underline;
}
a:hover {
color: #6D4100;
text-decoration: underline;
}
div.body {
padding-bottom: 40px; /* saved for footer */
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Garamond', 'Georgia', serif;
font-weight: normal;
margin: 30px 0px 10px 0px;
padding: 0;
}
{% if theme_index_logo %}
div.indexwrapper h1 {
text-indent: -999999px;
background: url({{ theme_index_logo }}) no-repeat center center;
height: {{ theme_index_logo_height }};
}
{% endif %}
div.body h2 { font-size: 180%; }
div.body h3 { font-size: 150%; }
div.body h4 { font-size: 130%; }
div.body h5 { font-size: 100%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: white;
padding: 0 4px;
text-decoration: none;
}
a.headerlink:hover {
color: #444;
background: #eaeaea;
}
div.body p, div.body dd, div.body li {
line-height: 1.4em;
}
div.admonition {
background: #fafafa;
margin: 20px -30px;
padding: 10px 30px;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
div.admonition p.admonition-title {
font-family: 'Garamond', 'Georgia', serif;
font-weight: normal;
font-size: 24px;
margin: 0 0 10px 0;
padding: 0;
line-height: 1;
}
div.admonition p.last {
margin-bottom: 0;
}
div.highlight{
background-color: white;
}
dt:target, .highlight {
background: #FAF3E8;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre, tt {
font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.85em;
}
img.screenshot {
}
tt.descname, tt.descclassname {
font-size: 0.95em;
}
tt.descname {
padding-right: 0.08em;
}
img.screenshot {
-moz-box-shadow: 2px 2px 4px #eee;
-webkit-box-shadow: 2px 2px 4px #eee;
box-shadow: 2px 2px 4px #eee;
}
table.docutils {
border: 1px solid #888;
-moz-box-shadow: 2px 2px 4px #eee;
-webkit-box-shadow: 2px 2px 4px #eee;
box-shadow: 2px 2px 4px #eee;
}
table.docutils td, table.docutils th {
border: 1px solid #888;
padding: 0.25em 0.7em;
}
table.field-list, table.footnote {
border: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
table.footnote {
margin: 15px 0;
width: 100%;
border: 1px solid #eee;
}
table.field-list th {
padding: 0 0.8em 0 0;
}
table.field-list td {
padding: 0;
}
table.footnote td {
padding: 0.5em;
}
dl {
margin: 0;
padding: 0;
}
dl dd {
margin-left: 30px;
}
pre {
padding: 0;
margin: 15px -30px;
padding: 8px;
line-height: 1.3em;
padding: 7px 30px;
background: #eee;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
}
dl pre {
margin-left: -60px;
padding-left: 60px;
}
tt {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
}
tt.xref, a tt {
background-color: #FBFBFB;
}
a:hover tt {
background: #EEE;
}

10
docs/_themes/kr_small/theme.conf vendored Normal file
View File

@@ -0,0 +1,10 @@
[theme]
inherit = basic
stylesheet = flasky.css
nosidebar = true
pygments_style = flask_theme_support.FlaskyStyle
[options]
index_logo = ''
index_logo_height = 120px
github_fork = ''

144
docs/api.rst Normal file
View File

@@ -0,0 +1,144 @@
.. _api:
API
===
.. module:: requests
This part of the documentation covers all the interfaces of Requests. For
parts where Requests depends on external libraries, we document the most
important right here and provide links to the canonical documentation.
Main Interface
--------------
All of Request's functionality can be accessed by these 7 methods.
They all return an instance of the :class:`Response <Response>` object.
.. autofunction:: request
---------------------
.. autoclass:: Response
:inherited-members:
---------------------
.. autofunction:: head
.. autofunction:: get
.. autofunction:: post
.. autofunction:: put
.. autofunction:: patch
.. autofunction:: delete
-----------------
.. autofunction:: session
Exceptions
~~~~~~~~~~
.. module:: requests
.. autoexception:: RequestException
.. autoexception:: ConnectionError
.. autoexception:: HTTPError
.. autoexception:: URLRequired
.. autoexception:: TooManyRedirects
.. _configurations:
Configurations
--------------
.. automodule:: requests.defaults
.. _async:
Async
-----
.. module:: requests.async
.. autofunction:: map
.. autofunction:: request
.. autofunction:: head
.. autofunction:: get
.. autofunction:: post
.. autofunction:: put
.. autofunction:: patch
.. autofunction:: delete
Utilities
---------
These functions are used internally, but may be useful outside of
Requests.
.. module:: requests.utils
Status Code Lookup
~~~~~~~~~~~~~~~~~~
.. autofunction:: requests.codes
::
>>> requests.codes['temporary_redirect']
307
>>> requests.codes.teapot
418
>>> requests.codes['\o/']
200
Cookies
~~~~~~~
.. autofunction:: dict_from_cookiejar
.. autofunction:: cookiejar_from_dict
.. autofunction:: add_dict_to_cookiejar
Encodings
~~~~~~~~~
.. autofunction:: get_encodings_from_content
.. autofunction:: get_encoding_from_headers
.. autofunction:: get_unicode_from_response
.. autofunction:: decode_gzip
Internals
---------
These items are an internal component to Requests, and should never be
seen by the end user (developer). This part of the API documentation
exists for those who are extending the functionality of Requests.
Classes
~~~~~~~
.. autoclass:: requests.Response
:inherited-members:
.. autoclass:: requests.Request
:inherited-members:
.. _sessionapi:
.. autoclass:: requests.Session
:inherited-members:

83
docs/community/faq.rst Normal file
View File

@@ -0,0 +1,83 @@
.. _faq:
Frequently Asked Questions
==========================
This part of the documentation answers common questions about Requests.
Encoded Data?
-------------
Requests automatically decompresses gzip-encoded responses, and does
its best to decode response content to unicode when possible.
You can get direct access to the raw response (and even the socket),
if needed as well.
Custom User-Agents?
-------------------
Requests allows you to easily override User-Agent strings, along with
any other HTTP Header.
Why not Httplib2?
-----------------
Chris Adams gave an excellent summary on
`Hacker News <http://news.ycombinator.com/item?id=2884406>`_:
httplib2 is part of why you should use requests: it's far more respectable
as a client but not as well documented and it still takes way too much code
for basic operations. I appreciate what httplib2 is trying to do, that
there's a ton of hard low-level annoyances in building a modern HTTP
client, but really, just use requests instead. Kenneth Reitz is very
motivated and he gets the degree to which simple things should be simple
whereas httplib2 feels more like an academic exercise than something
people should use to build production systems[1].
Disclosure: I'm listed in the requests AUTHORS file but can claim credit
for, oh, about 0.0001% of the awesomeness.
1. http://code.google.com/p/httplib2/issues/detail?id=96 is a good example:
an annoying bug which affect many people, there was a fix available for
months, which worked great when I applied it in a fork and pounded a couple
TB of data through it, but it took over a year to make it into trunk and
even longer to make it onto PyPI where any other project which required "
httplib2" would get the working version.
Python 3 Support?
-----------------
Yes! Here's a list of Python platforms that are officially
supported:
* cPython 2.6
* cPython 2.7
* cPython 3.1
* cPython 3.2
* PyPy-c 1.4
* PyPy-c 1.5
* PyPy-c 1.6
* PyPy-c 1.7
Keep-alive Support?
-------------------
Yep!
Proxy Support?
--------------
You bet!
SSL Verification?
-----------------
Absolutely.

View File

@@ -0,0 +1,63 @@
Modules
=======
- `requests-oauth <https://github.com/maraujop/requests-oauth>`_, 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.
- `WhitespaceBot <https://github.com/Gunio/WhitespaceBot/>`_, a project that automatically forks repos, strips trailing whitespace, and sends a pull request.
- `python-rexster <https://github.com/CulturePlex/python-rexster>`_, Rexter client that provides a simple interface for graph databases.
- `daikon <https://github.com/neogenix/daikon>`_, a CLI for ElasticSearch.
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/>`_
- `French blog post introducing Requests <http://www.nicosphere.net/requests-urllib2-de-python-simplifie-2432/>`_
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
Fedora and RedHat
-----------------
You can easily install Requests v0.6.1 with yum on rpm-based systems::
$ yum install python-requests

View File

@@ -0,0 +1,37 @@
.. _support:
Support
=======
If you have a questions or issues about Requests, there are several options:
Send a Tweet
------------
If your question is less than 140 characters, feel free to send a tweet to
`@kennethreitz <http://twitter.com/kennethreitz>`_.
File an Issue
-------------
If you notice some unexpected behavior in Requests, or want to see support
for a new feature,
`file an issue on GitHub <https://github.com/kennethreitz/requests/issues>`_.
E-mail
------
I'm more than happy to answer any personal or in-depth questions about
Requests. Feel free to email
`requests@kennethreitz.com <mailto:requests@kennethreitz.com>`_.
IRC
---
The official Freenode channel for Requests is
`#python-requests <irc://irc.freenode.net/python-requests>`_
I'm also available as **kennethreitz** on Freenode.

View File

@@ -0,0 +1,30 @@
.. _updates:
Updates
=======
If you'd like to stay up to date on the community and development of Requests,
there are several options:
GitHub
------
The best way to track the development of Requests is through
`the GitHub repo <https://github.com/kennethreitz/requests>`_.
Twitter
-------
I often tweet about new features and releases of Requests.
Follow `@kennethreitz <https://twitter.com/kennethreitz>`_ for updates.
Mailing List
------------
There's a low-volume mailing list for Requests. To subscribe to the
mailing list, send an email to
`requests@librelist.org <mailto:requests@librelist.org>`_.

View File

@@ -16,7 +16,9 @@ import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('..'))
import requests
from requests import __version__
# -- General configuration -----------------------------------------------------
@@ -25,7 +27,7 @@ import sys, os
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.jsmath', 'sphinx.ext.viewcode']
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -41,16 +43,16 @@ master_doc = 'index'
# General information about the project.
project = u'Requests'
copyright = u'2011, Kenneth Reitz'
copyright = u'2012. A <a href="http://kennethreitz.com/pages/open-projects.html">Kenneth Reitz</a> Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.2.0'
version = __version__
# 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.
@@ -81,7 +83,7 @@ exclude_patterns = ['_build']
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = 'flask_theme_support.FlaskyStyle'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
@@ -112,6 +114,7 @@ html_theme = 'default'
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
@@ -131,7 +134,12 @@ html_static_path = ['_static']
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Custom sidebar templates, maps document names to template names.
html_sidebars = {
'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'],
'**': ['sidebarlogo.html', 'localtoc.html', 'relations.html',
'sourcelink.html', 'searchbox.html']
}
# Additional templates that should be rendered to pages, maps page names to
# template names.
@@ -147,10 +155,10 @@ html_static_path = ['_static']
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
html_show_sphinx = False
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
@@ -230,3 +238,7 @@ texinfo_documents = [
# Documents to append as an appendix to all manuals.
texinfo_appendices = []
sys.path.append(os.path.abspath('_themes'))
html_theme_path = ['_themes']
html_theme = 'kr'

5
docs/dev/authors.rst Normal file
View File

@@ -0,0 +1,5 @@
Authors
=======
.. include:: ../../AUTHORS.rst

0
docs/dev/internals.rst Normal file
View File

26
docs/dev/todo.rst Normal file
View File

@@ -0,0 +1,26 @@
How to Help
===========
Requests is under active development, and contributions are more than welcome!
#. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
There is a Contributor Friendly tag for issues that should be ideal for people who are not very
familiar with the codebase yet.
#. Fork `the repository`_ on Github to start making your changes to the **develop**
branch (or branch off of it).
#. Write a test which shows that the bug was fixed or that the feature works as expected.
#. Send a pull request and bug the maintainer until it gets merged and published. :)
Make sure to add yourself to AUTHORS_.
Development dependencies
------------------------
You'll need to install ``gunicorn`` and ``httpbin`` in order to run requests' test suite::
$ pip install -r requirements.txt
What Needs to be Done
---------------------
- Documentation needs a roadmap.

View File

@@ -3,18 +3,131 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Requests's documentation!
====================================
Requests: HTTP for Humans
=========================
Contents:
Release v\ |version|. (:ref:`Installation <install>`)
Requests is an :ref:`ISC Licensed <isc>` HTTP library, written in Python, for human beings.
Python's standard **urllib2** module provides most of
the HTTP capabilities you need, but the API is thoroughly **broken**.
It was built for a different time — and a different web. It requires an *enormous* amount of work (even method overrides) to perform the simplest of tasks.
Things shouldnt be this way. Not in Python.
::
>>> r = requests.get('https://api.github.com', auth=('user', 'pass'))
>>> r.status_code
204
>>> r.headers['content-type']
'application/json'
>>> r.text
...
See `the same code, without Requests <https://gist.github.com/973705>`_.
Requests takes all of the work out of Python HTTP/1.1 — making your integration with web services seamless. There's no need to manually add query strings to your URLs, or to form-encode your POST data. Keep-alive and HTTP connection pooling are 100% automatic, powered by `urllib3 <https://github.com/shazow/urllib3>`_, which is embedded within Requests.
Testimonials
------------
`Heroku <http://heroku.com>`_, `PayPal <https://www.paypal.com/>`_,
`Transifex <https://www.transifex.net/>`_,
`Native Instruments <http://www.native-instruments.com/>`_, `The Washington Post <http://www.washingtonpost.com/>`_,
`Twitter, Inc <http://twitter.com>`_,
`Readability <http://readability.com>`_, and
Federal US Institutions
use Requests internally. It has been installed over 100,000 times from PyPI.
**Armin Ronacher**
Requests is the perfect example how beautiful an API can be with the
right level of abstraction.
**Matt DeBoard**
I'm going to get @kennethreitz's Python requests module tattooed
on my body, somehow. The whole thing.
**Daniel Greenfeld**
Nuked a 1200 LOC spaghetti code library with 10 lines of code thanks to
@kennethreitz's request library. Today has been AWESOME.
**Kenny Meyers**
Python HTTP: When in doubt, or when not in doubt, use Requests. Beautiful,
simple, Pythonic.
Feature Support
---------------
Requests is ready for today's web.
- International Domains and URLs
- Keep-Alive & Connection Pooling
- Sessions with Cookie Persistence
- Browser-style SSL Verification
- Basic/Digest Authentication
- Elegant Key/Value Cookies
- Automatic Decompression
- Unicode Response Bodies
- Multipart File Uploads
- Connection Timeouts
- ``.netrc`` support
User Guide
----------
This part of the documentation, which is mostly prose, begins with some
background information about Requests, then focuses on step-by-step
instructions for getting the most out of Requests.
.. toctree::
:maxdepth: 2
Indices and tables
==================
user/intro
user/install
user/quickstart
user/advanced
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Community Guide
-----------------
This part of the documentation, which is mostly prose, details the
Requests ecosystem and community.
.. toctree::
:maxdepth: 1
community/faq
community/out-there.rst
community/support
community/updates
API Documentation
-----------------
If you are looking for information on a specific function, class or method,
this part of the documentation is for you.
.. toctree::
:maxdepth: 2
api
Developer Guide
---------------
If you want to contribute to the project, this part of the documentation is for
you.
.. toctree::
:maxdepth: 1
dev/internals
dev/todo
dev/authors

321
docs/user/advanced.rst Normal file
View File

@@ -0,0 +1,321 @@
.. _advanced:
Advanced Usage
==============
This document covers some of Requests more advanced features.
Session Objects
---------------
The Session object allows you to persist certain parameters across
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.
Let's persist some cookies across requests::
s = requests.session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")
print r.text
# '{"cookies": {"sessioncookie": "123456789"}}'
Sessions can also be used to provide default data to the request methods::
headers = {'x-test': 'true'}
auth = ('user', 'pass')
with requests.session(auth=auth, headers=headers) as c:
# both 'x-test' and 'x-test2' are sent
c.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
Any dictionaries that you pass to a request method will be merged with the session-level values that are set. The method-level parameters override session parameters.
.. admonition:: Remove a Value From a Dict Parameter
Sometimes you'll want to omit session-level keys from a dict parameter. To do this, you simply set that key's value to ``None`` in the method-level parameter. It will automatically be omitted.
All values that are contained within a session are directly available to you. See the :ref:`Session API Docs <sessionapi>` to learn more.
SSL Cert Verification
---------------------
Requests can verify SSL certificates for HTTPS requests, just like a web browser. To check a host's SSL certificate, you can use the ``verify`` argument::
>>> requests.get('https://kennethreitz.com', verify=True)
requests.exceptions.SSLError: hostname 'kennethreitz.com' doesn't match either of '*.herokuapp.com', 'herokuapp.com'
I don't have SSL setup on this domain, so it fails. Excellent. Github does though::
>>> requests.get('https://github.com', verify=True)
<Response [200]>
You can also pass ``verify`` the path to a CA_BUNDLE file for private certs. You can also set the ``REQUESTS_CA_BUNDLE`` environment variable.
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.
Let's walk through it::
tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
r = requests.get(tarball_url)
The request has been made, but the connection is still open. The response body has not been downloaded yet. ::
r.content
The content has been downloaded and cached.
You can override this default behavior with the ``prefetch`` parameter::
r = requests.get(tarball_url, prefetch=True)
# Blocks until all of request body has been downloaded.
Configuring Requests
--------------------
Sometimes you may want to configure a request to customize its behavior. To do
this, you can pass in a ``config`` dictionary to a request or session. See the :ref:`Configuration API Docs <configurations>` to learn more.
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()
s.config['keep_alive'] = False
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 time.
First, let's import the async module. Heads up — if you don't have
`gevent <http://pypi.python.org/pypi/gevent>`_ this will fail::
from requests import async
The ``async`` module has the exact same api as ``requests``, except it
doesn't send the request immediately. Instead, it returns the ``Request``
object.
We can build a list of ``Request`` objects easily::
urls = [
'http://python-requests.org',
'http://httpbin.org',
'http://python-guide.org',
'http://kennethreitz.com'
]
rs = [async.get(u) for u in urls]
Now we have a list of ``Request`` objects, ready to be sent. We could send them
one at a time with ``Request.send()``, but that would take a while. Instead,
we'll send them all at the same time with ``async.map()``. Using ``async.map()``
will also guarantee execution of the ``response`` hook, described below. ::
>>> responses = async.map(rs)
>>> responses
[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]
.. admonition:: Throttling
The ``map`` function also takes a ``size`` parameter, that specifies the number of connections to make at a time::
async.map(rs, size=5)
Event Hooks
-----------
Requests has a hook system that you can use to manipulate portions of
the request process, or signal event handling.
Available hooks:
``args``:
A dictionary of the arguments being sent to Request().
``pre_request``:
The Request object, directly before being sent.
``post_request``:
The Request object, directly after being sent.
``response``:
The response generated from a Request.
You can assign a hook function on a per-request basis by passing a
``{hook_name: callback_function}`` dictionary to the ``hooks`` request
parameter::
hooks=dict(args=print_url)
That ``callback_function`` will receive a chunk of data as its first
argument.
::
def print_url(args):
print args['url']
If an error occurs while executing your callback, a warning is given.
If the callback function returns a value, it is assumed that it is to
replace the data that was passed in. If the function doesn't return
anything, nothing else is effected.
Let's print some request method arguments at runtime::
>>> requests.get('http://httpbin.org', hooks=dict(args=print_url))
http://httpbin.org
<Response [200]>
Let's hijack some arguments this time with a new callback::
def hack_headers(args):
if args.get('headers') is None:
args['headers'] = dict()
args['headers'].update({'X-Testing': 'True'})
return args
hooks = dict(args=hack_headers)
headers = dict(yo=dawg)
And give it a try::
>>> requests.get('http://httpbin.org/headers', hooks=hooks, headers=headers)
{
"headers": {
"Content-Length": "",
"Accept-Encoding": "gzip",
"Yo": "dawg",
"X-Forwarded-For": "::ffff:24.127.96.129",
"Connection": "close",
"User-Agent": "python-requests.org",
"Host": "httpbin.org",
"X-Testing": "True",
"X-Forwarded-Protocol": "",
"Content-Type": ""
}
}
Custom Authentication
---------------------
Requests allows you to use specify your own authentication mechanism.
Any callable which is passed as the ``auth`` argument to a request method will
have the opportunity to modify the request before it is dispatched.
Authentication implementations are subclasses of ``requests.auth.AuthBase``,
and are easy to define. Requests provides two common authentication scheme
implementations in ``requests.auth``: ``HTTPBasicAuth`` and ``HTTPDigestAuth``.
Let's pretend that we have a web service that will only respond if the
``X-Pizza`` header is set to a password value. Unlikely, but just go with it.
::
from requests.auth import AuthBase
class PizzaAuth(AuthBase):
"""Attaches HTTP Pizza Authentication to the given Request object."""
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
return r
Then, we can make a request using our Pizza Auth::
>>> requests.get('http://pizzabin.org/admin', auth=PizzaAuth('kenneth'))
<Response [200]>
Streaming Requests
------------------
With ``requests.Response.iter_lines()`` you can easily iterate over streaming
APIs such as the `Twitter Streaming API <https://dev.twitter.com/docs/streaming-api>`_.
To use the Twitter Streaming API to track the keyword "requests":
::
import requests
import json
r = requests.post('https://stream.twitter.com/1/statuses/filter.json',
data={'track': 'requests'}, auth=('username', 'password'))
for line in r.iter_lines():
if line: # filter out keep-alive new lines
print json.loads(line)
Verbose Logging
---------------
If you want to get a good look at what HTTP requests are being sent
by your application, you can turn on verbose logging.
To do so, just configure Requests with a stream to write to::
>>> my_config = {'verbose': sys.stderr}
>>> requests.get('http://httpbin.org/headers', config=my_config)
2011-08-17T03:04:23.380175 GET http://httpbin.org/headers
<Response [200]>
Proxies
-------
If you need to use a proxy, you can configure individual requests with the
``proxies`` argument to any request method:
::
import requests
proxies = {
"http": "10.10.1.10:3128"
"https": "10.10.1.10:1080"
}
requests.get("http://example.org", proxies=proxies)
You can also configure proxies by environment variables ``HTTP_PROXY`` and ``HTTPS_PROXY``.
::
$ export HTTP_PROXY="10.10.1.10:3128"
$ export HTTPS_PROXY="10.10.1.10:1080"
$ python
>>> import requests
>>> requests.get("http://example.org")

78
docs/user/install.rst Normal file
View File

@@ -0,0 +1,78 @@
.. _install:
Installation
============
This part of the documentation covers the installation of Requests.
The first step to using any software package is getting it properly installed.
Distribute & Pip
----------------
Installing requests is simple with `pip <http://www.pip-installer.org/>`_::
$ pip install requests
or, with `easy_install <http://pypi.python.org/pypi/setuptools>`_::
$ easy_install requests
But, you really `shouldn't do that <http://www.pip-installer.org/en/latest/other-tools.html#pip-compared-to-easy-install>`_.
Cheeseshop Mirror
-----------------
If the Cheeseshop is down, you can also install Requests from Kenneth Reitz's
personal `Cheeseshop mirror <http://pip.kennethreitz.com/>`_::
$ pip install -i http://pip.kennethreitz.com/simple requests
Get the Code
------------
Requests is actively developed on GitHub, where the code is
`always available <https://github.com/kennethreitz/requests>`_.
You can either clone the public repository::
git clone git://github.com/kennethreitz/requests.git
Download the `tarball <https://github.com/kennethreitz/requests/tarball/master>`_::
$ curl -OL https://github.com/kennethreitz/requests/tarball/master
Or, download the `zipball <https://github.com/kennethreitz/requests/zipball/master>`_::
$ curl -OL https://github.com/kennethreitz/requests/zipball/master
Once you have a copy of the source, you can embed it in your Python package,
or install it into your site-packages easily::
$ python setup.py install
.. _gevent:
Installing Gevent
-----------------
If you are using the ``requests.async`` module for making concurrent
requests, you need to install gevent.
To install gevent, you'll need ``libevent``.
OSX::
$ brew install libevent
Ubuntu::
$ apt-get install libevent-dev
Once you have ``libevent``, you can install ``gevent`` with ``pip``::
$ pip install gevent

49
docs/user/intro.rst Normal file
View File

@@ -0,0 +1,49 @@
.. _introduction:
Introduction
============
Philosophy
----------
Requests was developed with a few :pep:`20` idioms in mind.
#. Beautiful is better than ugly.
#. Explicit is better than implicit.
#. Simple is better than complex.
#. Complex is better than complicated.
#. Readability counts.
All contributions to Requests should keep these important rules in mind.
ISC License
-----------
A large number of open source projects you find today are `GPL Licensed`_.
While the GPL has its time and place, it should most certainly not be your
go-to license for your next open source project.
A project that is released as GPL cannot be used in any commercial product
without the product itself also being offered as open source.
The MIT, BSD, ISC, and Apache2 licenses are great alternatives to the GPL
that allow your open-source software to be used freely in proprietary,
closed-source software.
Requests is released under terms of `The ISC License`_.
.. _`GPL Licensed`: http://www.opensource.org/licenses/gpl-license.php
.. _`The ISC License`: http://www.opensource.org/licenses/isc-license
Requests License
----------------
Copyright (c) 2011, Kenneth Reitz
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

432
docs/user/quickstart.rst Normal file
View File

@@ -0,0 +1,432 @@
.. _quickstart:
Quickstart
==========
.. module:: requests.models
Eager to get started? This page gives a good introduction in how to get started
with Requests. This assumes you already have Requests installed. If you do not,
head over to the :ref:`Installation <install>` section.
First, make sure that:
* Requests is :ref:`installed <install>`
* Requests is :ref:`up-to-date <updates>`
Lets gets started with some simple use cases and examples.
Make a GET Request
------------------
Making a standard request with Requests is very simple.
Let's get GitHub's public timeline ::
r = requests.get('https://github.com/timeline.json')
Now, we have a :class:`Response` object called ``r``. We can get all the
information we need from this.
Typically, you want to send some sort of data in the urls query string.
To do this, simply pass a dictionary to the `params` argument. Your
dictionary of data will automatically be encoded when the request is made::
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get("http://httpbin.org/get", params=payload)
>>> print r.text
{
"origin": "179.13.100.4",
"args": {
"key2": "value2",
"key1": "value1"
},
"url": "http://httpbin.org/get",
"headers": {
"Connections": "keep-alive",
"Content-Length": "",
"Accept-Encoding": "identity, deflate, compress, gzip",
"Accept": "*/*",
"User-Agent": "python-requests/0.11.0",
"Host": httpbin.org",
"Content-Type": ""
},
}
Response Content
----------------
We can read the content of the server's response::
>>> r.text
'[{"repository":{"open_issues":0,"url":"https://github.com/...
Requests will automatically decode content from the server. Most unicode
charsets are seamlessly decoded.
When you make a request, ``r.encoding`` is set, based on the HTTP headers.
Requests will use that encoding when you access ``r.text``. If ``r.encoding``
is ``None``, Requests will make an extremely educated guess of the encoding
of the response body. You can manually set ``r.encoding`` to any encoding
you'd like, and that charset will be used.
Binary Response Content
-----------------------
You can also access the response body as bytes, for non-text requests::
>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...
The ``gzip`` and ``deflate`` transfer-encodings are automatically decoded for you.
For example to create an image from binary data returned by a request, you can
use the following code:
>>> from PIL import Image
>>> from StringIO import StringIO
>>> i = Image.open(StringIO(r.content))
Raw Response Content
--------------------
In the rare case that you'd like to get the absolute raw socket response from the server,
you can access ``r.raw``::
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
Make a POST Request
-------------------
POST requests are equally simple::
r = requests.post("http://httpbin.org/post")
Typically, you want to send some form-encoded data — much like an HTML form.
To do this, simply pass a dictionary to the `data` argument. Your
dictionary of data will automatically be form-encoded when the request is made::
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> print r.text
{
"origin": "179.13.100.4",
"files": {},
"form": {
"key2": "value2",
"key1": "value1"
},
"url": "http://httpbin.org/post",
"args": {},
"headers": {
"Content-Length": "23",
"Accept-Encoding": "identity, deflate, compress, gzip",
"Accept": "*/*",
"User-Agent": "python-requests/0.8.0",
"Host": "127.0.0.1:7077",
"Content-Type": "application/x-www-form-urlencoded"
},
"data": ""
}
There are many times that you want to send data that is not form-encoded. If you pass in a ``string`` instead of a ``dict``, that data will be posted directly.
For example, the GitHub API v3 accepts JSON-Encoded POST/PATCH data::
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload))
Custom Headers
--------------
If you'd like to add HTTP headers to a request, simply pass in a ``dict`` to the
``headers`` parameter.
For example, we didn't specify our content-type in the previous example::
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
r = requests.post(url, data=json.dumps(payload), headers=headers)
POST a Multipart-Encoded File
-----------------------------
Requests makes it simple to upload Multipart-encoded files::
>>> url = 'http://httpbin.org/post'
>>> files = {'report.xls': open('report.xls', 'rb')}
>>> r = requests.post(url, files=files)
>>> r.text
{
"origin": "179.13.100.4",
"files": {
"report.xls": "<censored...binary...data>"
},
"form": {},
"url": "http://httpbin.org/post",
"args": {},
"headers": {
"Content-Length": "3196",
"Accept-Encoding": "identity, deflate, compress, gzip",
"Accept": "*/*",
"User-Agent": "python-requests/0.8.0",
"Host": "httpbin.org:80",
"Content-Type": "multipart/form-data; boundary=127.0.0.1.502.21746.1321131593.786.1"
},
"data": ""
}
Setting filename explicitly::
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'))}
>>> r = requests.post(url, files=files)
>>> r.text
{
"origin": "179.13.100.4",
"files": {
"file": "<censored...binary...data>"
},
"form": {},
"url": "http://httpbin.org/post",
"args": {},
"headers": {
"Content-Length": "3196",
"Accept-Encoding": "identity, deflate, compress, gzip",
"Accept": "*/*",
"User-Agent": "python-requests/0.8.0",
"Host": "httpbin.org:80",
"Content-Type": "multipart/form-data; boundary=127.0.0.1.502.21746.1321131593.786.1"
},
"data": ""
}
Response Status Codes
---------------------
We can check the response status code::
>>> r.status_code
200
Requests also comes with a built-in status code lookup object for easy
reference::
>>> r.status_code == requests.codes.ok
True
If we made a bad request (non-200 response), we can raise it with
:class:`Response.raise_for_status()`::
>>> _r = requests.get('http://httpbin.org/status/404')
>>> _r.status_code
404
>>> _r.raise_for_status()
Traceback (most recent call last):
File "requests/models.py", line 394, in raise_for_status
raise self.error
urllib2.HTTPError: HTTP Error 404: NOT FOUND
But, since our ``status_code`` was ``200``, when we call it::
>>> r.raise_for_status()
None
All is well.
Response Headers
----------------
We can view the server's response headers with a simple Python dictionary
interface::
>>> r.headers
{
'status': '200 OK',
'content-encoding': 'gzip',
'transfer-encoding': 'chunked',
'connection': 'close',
'server': 'nginx/1.0.4',
'x-runtime': '148ms',
'etag': '"e1ca502697e5c9317743dc078f67693f"',
'content-type': 'application/json; charset=utf-8'
}
The dictionary is special, though: it's made just for HTTP headers. According to
`RFC 2616 <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html>`_, HTTP
Headers are case-insensitive.
So, we can access the headers using any capitalization we want::
>>> r.headers['Content-Type']
'application/json; charset=utf-8'
>>> r.headers.get('content-type')
'application/json; charset=utf-8'
If a header doesn't exist in the Response, its value defaults to ``None``::
>>> r.headers['X-Random']
None
Cookies
-------
If a response contains some Cookies, you can get quick access to them::
>>> url = 'http://httpbin.org/cookies/set/requests-is/awesome'
>>> r = requests.get(url)
>>> r.cookies['requests-is']
'awesome'
To send your own cookies to the server, you can use the ``cookies``
parameter::
>>> url = 'http://httpbin.org/cookies'
>>> cookies = dict(cookies_are='working')
>>> r = requests.get(url, cookies=cookies)
>>> r.text
'{"cookies": {"cookies_are": "working"}}'
Basic Authentication
--------------------
Most web services require authentication. There many different types of
authentication, but the most common is HTTP Basic Auth.
Making requests with Basic Auth is extremely simple::
>>> from requests.auth import HTTPBasicAuth
>>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
<Response [200]>
Due to the prevalence of HTTP Basic Auth, requests provides a shorthand for
this authentication method::
>>> requests.get('https://api.github.com/user', auth=('user', 'pass'))
<Response [200]>
Providing the credentials as a tuple in this fashion is functionally equivalent
to the ``HTTPBasicAuth`` example above.
Digest Authentication
---------------------
Another popular form of web service protection is Digest Authentication::
>>> from requests.auth import HTTPDigestAuth
>>> url = 'http://httpbin.org/digest-auth/auth/user/pass'
>>> requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
<Response [200]>
OAuth Authentication
--------------------
Miguel Araujo's `requests-oauth <http://pypi.python.org/pypi/requests-oauth>`_ project provides a simple interface for
establishing OAuth connections. Documentation and examples can be found on the requests-oauth `git repository <https://github.com/maraujop/requests-oauth>`_.
Redirection and History
-----------------------
Requests will automatically perform location redirection while using idempotent methods.
GitHub redirects all HTTP requests to HTTPS. Let's see what happens::
>>> r = requests.get('http://github.com')
>>> r.url
'https://github.com/'
>>> r.status_code
200
>>> r.history
[<Response [301]>]
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 ``allow_redirects`` parameter::
>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r.status_code
301
>>> r.history
[]
If you're using POST, PUT, PATCH, *&c*, you can also explicitly enable redirection as well::
>>> r = requests.post('http://github.com', allow_redirects=True)
>>> r.url
'https://github.com/'
>>> r.history
[<Response [301]>]
Timeouts
--------
You can tell requests to stop waiting for a response after a given number of seconds with the ``timeout`` parameter::
>>> requests.get('http://github.com', timeout=0.001)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: Request timed out.
.. admonition:: Note
``timeout`` only effects the connection process itself, not the downloading of the response body.
Errors and Exceptions
---------------------
In the event of a network problem (e.g. DNS failure, refused connection, etc),
Requests will raise a :class:`ConnectionError` exception.
In the event of the rare invalid HTTP response, Requests will raise
an :class:`HTTPError` exception.
If a request times out, a :class:`Timeout` exception is raised.
If a request exceeds the configured number of maximum redirections, a :class:`TooManyRedirects` exception is raised.
All exceptions that Requests explicitly raises inherit from
:class:`requests.exceptions.RequestException`.
You can refer to :ref:`Configuration API Docs <configurations>` for immediate raising of :class:`HTTPError` exceptions
via the ``danger_mode`` option or have Requests catch the majority of :class:`requests.exceptions.RequestException` exceptions
with the ``safe_mode`` option.
-----------------------
Ready for more? Check out the :ref:`advanced <advanced>` section.

2217
ext/requests-logo.ai Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,33 @@
# -*- coding: utf-8 -*-
from . import packages
from .core import *
# __
# /__) _ _ _ _ _/ _
# / ( (- (/ (/ (- _) / _)
# /
"""
requests
~~~~~~~~
:copyright: (c) 2012 by Kenneth Reitz.
:license: ISC, see LICENSE for more details.
"""
__title__ = 'requests'
__version__ = '0.12.0'
__build__ = 0x001200
__author__ = 'Kenneth Reitz'
__license__ = 'ISC'
__copyright__ = 'Copyright 2012 Kenneth Reitz'
from . import utils
from .models import Request, Response
from .api import request, get, head, post, patch, put, delete, options
from .sessions import session, Session
from .status_codes import codes
from .exceptions import (
RequestException, Timeout, URLRequired,
TooManyRedirects, HTTPError, ConnectionError
)

117
requests/api.py Normal file
View File

@@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
"""
requests.api
~~~~~~~~~~~~
This module implements the Requests API.
:copyright: (c) 2012 by Kenneth Reitz.
:license: ISC, see LICENSE for more details.
"""
from . import sessions
def request(method, url, **kwargs):
"""Constructs and sends a :class:`Request <Request>`.
Returns :class:`Response <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 'name': file-like-objects (or {'name': ('filename', fileobj)}) for multipart encoding upload.
: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.
:param return_response: (optional) If False, an un-sent Request object will returned.
:param session: (optional) A :class:`Session` object to be used for the request.
:param config: (optional) A configuration dictionary.
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
:param prefetch: (optional) if ``True``, the response content will be immediately downloaded.
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
"""
s = kwargs.pop('session') if 'session' in kwargs else sessions.session()
return s.request(method=method, url=url, **kwargs)
def get(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 request('get', url, **kwargs)
def options(url, **kwargs):
"""Sends a OPTIONS 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 request('options', url, **kwargs)
def head(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', False)
return request('head', url, **kwargs)
def post(url, data=None, **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 request('post', url, data=data, **kwargs)
def put(url, data=None, **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 request('put', url, data=data, **kwargs)
def patch(url, data=None, **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 request('patch', url, data=data, **kwargs)
def delete(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 request('delete', url, **kwargs)

106
requests/async.py Normal file
View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
"""
requests.async
~~~~~~~~~~~~~~
This module contains an asynchronous replica of ``requests.api``, powered
by gevent. All API methods return a ``Request`` instance (as opposed to
``Response``). A list of requests can be sent with ``map()``.
"""
try:
import gevent
from gevent import monkey as curious_george
from gevent.pool import Pool
except ImportError:
raise RuntimeError('Gevent is required for requests.async.')
# Monkey-patch.
curious_george.patch_all(thread=False, select=False)
from . import api
__all__ = (
'map', 'imap',
'get', 'options', 'head', 'post', 'put', 'patch', 'delete', 'request'
)
def patched(f):
"""Patches a given API function to not send."""
def wrapped(*args, **kwargs):
kwargs['return_response'] = False
kwargs['prefetch'] = True
config = kwargs.get('config', {})
config.update(safe_mode=True)
kwargs['config'] = config
return f(*args, **kwargs)
return wrapped
def send(r, pool=None, prefetch=False):
"""Sends the request object using the specified pool. If a pool isn't
specified this method blocks. Pools are useful because you can specify size
and can hence limit concurrency."""
if pool != None:
return pool.spawn(r.send, prefetch=prefetch)
return gevent.spawn(r.send, prefetch=prefetch)
# Patched requests.api functions.
get = patched(api.get)
options = patched(api.options)
head = patched(api.head)
post = patched(api.post)
put = patched(api.put)
patch = patched(api.patch)
delete = patched(api.delete)
request = patched(api.request)
def map(requests, prefetch=True, size=None):
"""Concurrently converts a list of Requests to Responses.
:param requests: a collection of Request objects.
:param prefetch: If False, the content will not be downloaded immediately.
:param size: Specifies the number of requests to make at a time. If None, no throttling occurs.
"""
requests = list(requests)
pool = Pool(size) if size else None
jobs = [send(r, pool, prefetch=prefetch) for r in requests]
gevent.joinall(jobs)
return [r.response for r in requests]
def imap(requests, prefetch=True, size=2):
"""Concurrently converts a generator object of Requests to
a generator of Responses.
:param requests: a generator of Request objects.
:param prefetch: If False, the content will not be downloaded immediately.
:param size: Specifies the number of requests to make at a time. default is 2
"""
pool = Pool(size)
def send(r):
r.send(prefetch)
return r.response
for r in pool.imap_unordered(send, requests):
yield r
pool.join()

189
requests/auth.py Normal file
View File

@@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
"""
requests.auth
~~~~~~~~~~~~~
This module contains the authentication handlers for Requests.
"""
import time
import hashlib
from base64 import b64encode
from .compat import urlparse, str, is_py2
from .utils import randombytes, parse_dict_header
try:
from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER)
from oauthlib.common import extract_params
except (ImportError, SyntaxError):
SIGNATURE_HMAC = None
SIGNATURE_TYPE_AUTH_HEADER = None
CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
def _basic_auth_str(username, password):
"""Returns a Basic Auth string."""
return 'Basic ' + b64encode(('%s:%s' % (username, password)).encode('latin1')).strip().decode('latin1')
class AuthBase(object):
"""Base class that all auth implementations derive from"""
def __call__(self, r):
raise NotImplementedError('Auth hooks must be callable.')
class OAuth1(AuthBase):
"""Signs the request using OAuth 1 (RFC5849)"""
def __init__(self, client_key,
client_secret=None,
resource_owner_key=None,
resource_owner_secret=None,
callback_uri=None,
signature_method=SIGNATURE_HMAC,
signature_type=SIGNATURE_TYPE_AUTH_HEADER,
rsa_key=None, verifier=None):
try:
signature_type = signature_type.upper()
except AttributeError:
pass
self.client = Client(client_key, client_secret, resource_owner_key,
resource_owner_secret, callback_uri, signature_method,
signature_type, rsa_key, verifier)
def __call__(self, r):
contenttype = r.headers.get('Content-Type', None)
decoded_body = extract_params(r.data)
if contenttype == None and decoded_body != None:
r.headers['Content-Type'] = 'application/x-www-form-urlencoded'
r.url, r.headers, r.data = self.client.sign(
unicode(r.url), unicode(r.method), r.data, r.headers)
return r
class HTTPBasicAuth(AuthBase):
"""Attaches HTTP Basic Authentication to the given Request object."""
def __init__(self, username, password):
self.username = username
self.password = password
def __call__(self, r):
r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
return r
class HTTPProxyAuth(HTTPBasicAuth):
"""Attaches HTTP Proxy Authenetication to a given Request object."""
def __call__(self, r):
r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password)
return r
class HTTPDigestAuth(AuthBase):
"""Attaches HTTP Digest Authentication to the given Request object."""
def __init__(self, username, password):
self.username = username
self.password = password
def handle_401(self, r):
"""Takes the given response and tries digest-auth, if needed."""
r.request.deregister_hook('response', self.handle_401)
s_auth = r.headers.get('www-authenticate', '')
if 'digest' in s_auth.lower():
last_nonce = ''
nonce_count = 0
chal = parse_dict_header(s_auth.replace('Digest ', ''))
realm = chal['realm']
nonce = chal['nonce']
qop = chal.get('qop')
algorithm = chal.get('algorithm', 'MD5')
opaque = chal.get('opaque', None)
algorithm = algorithm.upper()
# lambdas assume digest modules are imported at the top level
if algorithm == 'MD5':
def md5_utf8(x):
if isinstance(x, str):
x = x.encode('utf-8')
return hashlib.md5(x).hexdigest()
hash_utf8 = md5_utf8
elif algorithm == 'SHA':
def sha_utf8(x):
if isinstance(x, str):
x = x.encode('utf-8')
return hashlib.sha1(x).hexdigest()
hash_utf8 = sha_utf8
# XXX MD5-sess
KD = lambda s, d: hash_utf8("%s:%s" % (s, d))
if hash_utf8 is None:
return None
# XXX not implemented yet
entdig = None
p_parsed = urlparse(r.request.url)
path = p_parsed.path
if p_parsed.query:
path += '?' + p_parsed.query
A1 = '%s:%s:%s' % (self.username, realm, self.password)
A2 = '%s:%s' % (r.request.method, path)
if qop == 'auth':
if nonce == last_nonce:
nonce_count += 1
else:
nonce_count = 1
last_nonce = nonce
ncvalue = '%08x' % nonce_count
s = str(nonce_count).encode('utf-8')
s += nonce.encode('utf-8')
s += time.ctime().encode('utf-8')
s += randombytes(8)
cnonce = (hashlib.sha1(s).hexdigest()[:16])
noncebit = "%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, hash_utf8(A2))
respdig = KD(hash_utf8(A1), noncebit)
elif qop is None:
respdig = KD(hash_utf8(A1), "%s:%s" % (nonce, hash_utf8(A2)))
else:
# XXX handle auth-int.
return None
# XXX should the partial digests be encoded too?
base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \
'response="%s"' % (self.username, realm, nonce, path, respdig)
if opaque:
base += ', opaque="%s"' % opaque
if entdig:
base += ', digest="%s"' % entdig
base += ', algorithm="%s"' % algorithm
if qop:
base += ', qop=auth, nc=%s, cnonce="%s"' % (ncvalue, cnonce)
r.request.headers['Authorization'] = 'Digest %s' % (base)
r.request.send(anyway=True)
_r = r.request.response
_r.history.append(r)
return _r
return r
def __call__(self, r):
r.register_hook('response', self.handle_401)
return r

105
requests/compat.py Normal file
View File

@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
"""
pythoncompat
"""
import sys
# -------
# Pythons
# -------
# Syntax sugar.
_ver = sys.version_info
#: Python 2.x?
is_py2 = (_ver[0] == 2)
#: Python 3.x?
is_py3 = (_ver[0] == 3)
#: Python 3.0.x
is_py30 = (is_py3 and _ver[1] == 0)
#: Python 3.1.x
is_py31 = (is_py3 and _ver[1] == 1)
#: Python 3.2.x
is_py32 = (is_py3 and _ver[1] == 2)
#: Python 3.3.x
is_py33 = (is_py3 and _ver[1] == 3)
#: Python 3.4.x
is_py34 = (is_py3 and _ver[1] == 4)
#: Python 2.7.x
is_py27 = (is_py2 and _ver[1] == 7)
#: Python 2.6.x
is_py26 = (is_py2 and _ver[1] == 6)
#: Python 2.5.x
is_py25 = (is_py2 and _ver[1] == 5)
#: Python 2.4.x
is_py24 = (is_py2 and _ver[1] == 4) # I'm assuming this is not by choice.
# ---------
# Platforms
# ---------
# Syntax sugar.
_ver = sys.version.lower()
is_pypy = ('pypy' in _ver)
is_jython = ('jython' in _ver)
is_ironpython = ('iron' in _ver)
# Assume CPython, if nothing else.
is_cpython = not any((is_pypy, is_jython, is_ironpython))
# Windows-based system.
is_windows = 'win32' in str(sys.platform).lower()
# Standard Linux 2+ system.
is_linux = ('linux' in str(sys.platform).lower())
is_osx = ('darwin' in str(sys.platform).lower())
is_hpux = ('hpux' in str(sys.platform).lower()) # Complete guess.
is_solaris = ('solar==' in str(sys.platform).lower()) # Complete guess.
# ---------
# Specifics
# ---------
if is_py2:
from urllib import quote, unquote, urlencode
from urlparse import urlparse, urlunparse, urljoin, urlsplit
from urllib2 import parse_http_list
import cookielib
from Cookie import Morsel
from StringIO import StringIO
bytes = str
str = unicode
basestring = basestring
elif is_py3:
from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote
from urllib.request import parse_http_list
from http import cookiejar as cookielib
from http.cookies import Morsel
from io import StringIO
str = str
bytes = bytes
basestring = (str,bytes)

264
requests/cookies.py Normal file
View File

@@ -0,0 +1,264 @@
"""
Compatibility code to be able to use `cookielib.CookieJar` with requests.
requests.utils imports from here, so be careful with imports.
"""
import collections
from .compat import cookielib, urlparse, Morsel
try:
import threading
# grr, pyflakes: this fixes "redefinition of unused 'threading'"
threading
except ImportError:
import dummy_threading as threading
class MockRequest(object):
"""Wraps a `requests.Request` to mimic a `urllib2.Request`.
The code in `cookielib.CookieJar` expects this interface in order to correctly
manage cookie policies, i.e., determine whether a cookie can be set, given the
domains of the request and the cookie.
The original request object is read-only. The client is responsible for collecting
the new headers via `get_new_headers()` and interpreting them appropriately. You
probably want `get_cookie_header`, defined below.
"""
def __init__(self, request):
self._r = request
self._new_headers = {}
def get_type(self):
return urlparse(self._r.full_url).scheme
def get_host(self):
return urlparse(self._r.full_url).netloc
def get_origin_req_host(self):
if self._r.response.history:
r = self._r.response.history[0]
return urlparse(r).netloc
else:
return self.get_host()
def get_full_url(self):
return self._r.full_url
def is_unverifiable(self):
# unverifiable == redirected
return bool(self._r.response.history)
def has_header(self, name):
return name in self._r.headers or name in self._new_headers
def get_header(self, name, default=None):
return self._r.headers.get(name, self._new_headers.get(name, default))
def add_header(self, key, val):
"""cookielib has no legitimate use for this method; add it back if you find one."""
raise NotImplementedError("Cookie headers should be added with add_unredirected_header()")
def add_unredirected_header(self, name, value):
self._new_headers[name] = value
def get_new_headers(self):
return self._new_headers
class MockResponse(object):
"""Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
...what? Basically, expose the parsed HTTP headers from the server response
the way `cookielib` expects to see them.
"""
def __init__(self, headers):
"""Make a MockResponse for `cookielib` to read.
:param headers: a httplib.HTTPMessage or analogous carrying the headers
"""
self._headers = headers
def info(self):
return self._headers
def getheaders(self, name):
self._headers.getheaders(name)
def extract_cookies_to_jar(jar, request, response):
"""Extract the cookies from the response into a CookieJar.
:param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar)
:param request: our own requests.Request object
:param response: urllib3.HTTPResponse object
"""
# the _original_response field is the wrapped httplib.HTTPResponse object,
# and in safe mode, it may be None if the request didn't actually complete.
# in that case, just skip the cookie extraction.
if response._original_response is not None:
req = MockRequest(request)
# pull out the HTTPMessage with the headers and put it in the mock:
res = MockResponse(response._original_response.msg)
jar.extract_cookies(res, req)
def get_cookie_header(jar, request):
"""Produce an appropriate Cookie header string to be sent with `request`, or None."""
r = MockRequest(request)
jar.add_cookie_header(r)
return r.get_new_headers().get('Cookie')
def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
"""Unsets a cookie by name, by default over all domains and paths.
Wraps CookieJar.clear(), is O(n).
"""
clearables = []
for cookie in cookiejar:
if cookie.name == name:
if domain is None or domain == cookie.domain:
if path is None or path == cookie.path:
clearables.append((cookie.domain, cookie.path, cookie.name))
for domain, path, name in clearables:
cookiejar.clear(domain, path, name)
class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
"""Compatibility class; is a cookielib.CookieJar, but exposes a dict interface.
This is the CookieJar we create by default for requests and sessions that
don't specify one, since some clients may expect response.cookies and
session.cookies to support dict operations.
Don't use the dict interface internally; it's just for compatibility with
with external client code. All `requests` code should work out of the box
with externally provided instances of CookieJar, e.g., LWPCookieJar and
FileCookieJar.
Caution: dictionary operations that are normally O(1) may be O(n).
Unlike a regular CookieJar, this class is pickleable.
"""
def get(self, name, domain=None, path=None, default=None):
try:
return self._find(name, domain, path)
except KeyError:
return default
def set(self, name, value, **kwargs):
# support client code that unsets cookies by assignment of a None value:
if value is None:
remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path'))
return
if isinstance(value, Morsel):
c = morsel_to_cookie(value)
else:
c = create_cookie(name, value, **kwargs)
self.set_cookie(c)
return c
def __getitem__(self, name):
return self._find(name)
def __setitem__(self, name, value):
self.set(name, value)
def __delitem__(self, name):
remove_cookie_by_name(self, name)
def _find(self, name, domain=None, path=None):
for cookie in iter(self):
if cookie.name == name:
if domain is None or cookie.domain == domain:
if path is None or cookie.path == path:
return cookie.value
raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
def __getstate__(self):
state = self.__dict__.copy()
# remove the unpickleable RLock object
state.pop('_cookies_lock')
return state
def __setstate__(self, state):
self.__dict__.update(state)
if '_cookies_lock' not in self.__dict__:
self._cookies_lock = threading.RLock()
def copy(self):
"""We're probably better off forbidding this."""
raise NotImplementedError
def create_cookie(name, value, **kwargs):
"""Make a cookie from underspecified parameters.
By default, the pair of `name` and `value` will be set for the domain ''
and sent on every request (this is sometimes called a "supercookie").
"""
result = dict(
version=0,
name=name,
value=value,
port=None,
domain='',
path='/',
secure=False,
expires=None,
discard=True,
comment=None,
comment_url=None,
rest={'HttpOnly': None},
rfc2109=False,
)
badargs = set(kwargs) - set(result)
if badargs:
err = 'create_cookie() got unexpected keyword arguments: %s'
raise TypeError(err % list(badargs))
result.update(kwargs)
result['port_specified'] = bool(result['port'])
result['domain_specified'] = bool(result['domain'])
result['domain_initial_dot'] = result['domain'].startswith('.')
result['path_specified'] = bool(result['path'])
return cookielib.Cookie(**result)
def morsel_to_cookie(morsel):
"""Convert a Morsel object into a Cookie containing the one k/v pair."""
c = create_cookie(
name=morsel.key,
value=morsel.value,
version=morsel['version'] or 0,
port=None,
port_specified=False,
domain=morsel['domain'],
domain_specified=bool(morsel['domain']),
domain_initial_dot=morsel['domain'].startswith('.'),
path=morsel['path'],
path_specified=bool(morsel['path']),
secure=bool(morsel['secure']),
expires=morsel['max-age'] or morsel['expires'],
discard=False,
comment=morsel['comment'],
comment_url=bool(morsel['comment']),
rest={'HttpOnly': morsel['httponly']},
rfc2109=False,
)
return c
def cookiejar_from_dict(cookie_dict, cookiejar=None):
"""Returns a CookieJar from a key/value dictionary.
:param cookie_dict: Dict of key/values to insert into CookieJar.
"""
if cookiejar is None:
cookiejar = RequestsCookieJar()
if cookie_dict is not None:
for name in cookie_dict:
cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
return cookiejar

View File

@@ -1,463 +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.
"""
import urllib
import urllib2
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
__title__ = 'requests'
__version__ = '0.2.2'
__build__ = 0x000202
__author__ = 'Kenneth Reitz'
__license__ = 'ISC'
__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)
self.method = method
def get_method(self):
if self.method:
return self.method
return urllib2.Request.get_method(self)
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):
self.url = None
self.headers = dict()
self.files = None
self.method = None
self.params = {}
self.data = {}
self.response = Response()
self.auth = None
self.cookiejar = None
self.sent = False
def __repr__(self):
return '<Request [%s]>' % (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)
auth_handler = urllib2.HTTPBasicAuthHandler(authr)
_handlers.append(auth_handler)
if self.cookiejar:
cookie_handler = urllib2.HTTPCookieProcessor(cookiejar)
_handlers.append(cookie_handler)
opener = urllib2.build_opener(*_handlers)
return opener.open
else:
return urllib2.urlopen
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,
self.response.status_code will contain the HTTPError code.
Once a request is successfully sent, `sent` will equal True.
: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, params)), method=self.method)
if self.headers:
req.headers = self.headers
opener = self._get_opener()
try:
resp = opener(req)
self._build_response(resp)
success = True
except urllib2.HTTPError as why:
self._build_response(why)
success = False
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)
success = True
except urllib2.HTTPError as why:
self._build_response(why)
success = False
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)
success = True
except urllib2.HTTPError as why:
self._build_response(why)
success = False
self.sent = True if success else False
return success
class Response(object):
"""The :class:`Request` object. All :class:`Request` objects contain a
:class:`Request.response <response>` attribute, which is an instance of
this class.
"""
def __init__(self):
self.content = None
self.status_code = None
self.headers = dict()
self.url = None
def __repr__(self):
return '<Response [%s]>' % (self.status_code)
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 __init__(self, username, password):
self.username = username
self.password = password
def get(url, params={}, headers={}, cookies=None, auth=None):
"""Sends a GET 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 headers: (optional) Dictionary of HTTP Headers to send 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()
r.method = 'GET'
r.url = url
r.params = params
r.headers = headers
r.cookiejar = cookies
r.auth = _detect_auth(url, auth)
r.send()
return r.response
def head(url, params={}, headers={}, cookies=None, auth=None):
"""Sends a HEAD 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 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()
r.method = 'HEAD'
r.url = url
# return response object
r.params = params
r.headers = headers
r.cookiejar = cookies
r.auth = _detect_auth(url, auth)
r.send()
return r.response
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 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()
r.url = url
r.method = 'POST'
r.data = data
if files:
r.files = files
r.headers = headers
r.cookiejar = cookies
r.auth = _detect_auth(url, auth)
r.send()
return r.response
def put(url, data='', 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 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()
r.url = url
r.method = 'PUT'
r.data = data
r.files = files
r.headers = headers
r.cookiejar = cookies
r.auth = _detect_auth(url, auth)
r.send()
return r.response
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 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()
r.url = url
r.method = 'DELETE'
r.headers = headers
r.cookiejar = cookies
r.auth = _detect_auth(url, auth)
r.send()
return r.response
def add_autoauth(url, authobject):
"""Registers given AuthObject to given URL domain. for auto-activation.
Once a URL is registered with an AuthObject, the configured HTTP
Authentication will be used for all requests with URLS containing the given
URL string.
Example: ::
>>> c_auth = requests.AuthObject('kennethreitz', 'xxxxxxx')
>>> requests.add_autoauth('https://convore.com/api/', c_auth)
>>> r = requests.get('https://convore.com/api/account/verify.json')
# Automatically HTTP Authenticated! Wh00t!
:param url: Base URL for given AuthObject to auto-activate for.
:param authobject: AuthObject to auto-activate.
"""
global AUTOAUTHS
AUTOAUTHS.append((url, authobject))
def _detect_auth(url, auth):
"""Returns registered AuthObject for given url if available, defaulting to
given AuthObject.
"""
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:
return auth
return None
class RequestException(Exception):
"""There was an ambiguous exception that occured while handling your request."""
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."""

51
requests/defaults.py Normal file
View File

@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
"""
requests.defaults
~~~~~~~~~~~~~~~~~
This module provides the Requests configuration defaults.
Configurations:
:base_headers: Default HTTP headers.
:verbose: Stream to write request logging to.
:max_redirects: Maximum number of redirects allowed within a request.s
:keep_alive: Reuse HTTP Connections?
:max_retries: The number of times a request should be retried in the event of a connection failure.
:danger_mode: If true, Requests will raise errors immediately.
:safe_mode: If true, Requests will catch all errors.
:strict_mode: If true, Requests will do its best to follow RFCs (e.g. POST redirects).
:pool_maxsize: The maximium size of an HTTP connection pool.
:pool_connections: The number of active HTTP connection pools to use.
:encode_uri: If true, URIs will automatically be percent-encoded.
:trust_env: If true, the surrouding environment will be trusted (environ, netrc).
"""
SCHEMAS = ['http', 'https']
from . import __version__
defaults = dict()
defaults['base_headers'] = {
'User-Agent': 'python-requests/%s' % __version__,
'Accept-Encoding': ', '.join(('identity', 'deflate', 'compress', 'gzip')),
'Accept': '*/*'
}
defaults['verbose'] = None
defaults['max_redirects'] = 30
defaults['pool_connections'] = 10
defaults['pool_maxsize'] = 10
defaults['max_retries'] = 0
defaults['danger_mode'] = False
defaults['safe_mode'] = False
defaults['strict_mode'] = False
defaults['keep_alive'] = True
defaults['encode_uri'] = True
defaults['trust_env'] = True

41
requests/exceptions.py Normal file
View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
"""
requests.exceptions
~~~~~~~~~~~~~~~~~~~
This module contains the set of Requests' exceptions.
"""
class RequestException(RuntimeError):
"""There was an ambiguous exception that occurred while handling your
request."""
class HTTPError(RequestException):
"""An HTTP error occurred."""
response = None
class ConnectionError(RequestException):
"""A Connection error occurred."""
class SSLError(ConnectionError):
"""An SSL error occurred."""
class Timeout(RequestException):
"""The request timed out."""
class URLRequired(RequestException):
"""A valid URL is required to make a request."""
class TooManyRedirects(RequestException):
"""Too many redirects."""
class MissingSchema(RequestException, ValueError):
"""The URL schema (e.g. http or https) is missing."""
class InvalidSchema(RequestException, ValueError):
"""See defaults.py for valid schemas."""
class InvalidURL(RequestException, ValueError):
""" The URL provided was somehow invalid. """

51
requests/hooks.py Normal file
View File

@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
"""
requests.hooks
~~~~~~~~~~~~~~
This module provides the capabilities for the Requests hooks system.
Available hooks:
``args``:
A dictionary of the arguments being sent to Request().
``pre_request``:
The Request object, directly after being created.
``pre_send``:
The Request object, directly before being sent.
``post_request``:
The Request object, directly after being sent.
``response``:
The response generated from a Request.
"""
import traceback
HOOKS = ('args', 'pre_request', 'pre_send', 'post_request', 'response')
def dispatch_hook(key, hooks, hook_data):
"""Dispatches a hook dictionary on a given piece of data."""
hooks = hooks or dict()
if key in hooks:
hooks = hooks.get(key)
if hasattr(hooks, '__call__'):
hooks = [hooks]
for hook in hooks:
try:
hook_data = hook(hook_data) or hook_data
except Exception:
traceback.print_exc()
return hook_data

841
requests/models.py Normal file
View File

@@ -0,0 +1,841 @@
# -*- coding: utf-8 -*-
"""
requests.models
~~~~~~~~~~~~~~~
This module contains the primary objects that power Requests.
"""
import os
from datetime import datetime
from .hooks import dispatch_hook, HOOKS
from .structures import CaseInsensitiveDict
from .status_codes import codes
from .auth import HTTPBasicAuth, HTTPProxyAuth
from .cookies import cookiejar_from_dict, extract_cookies_to_jar, get_cookie_header
from .packages.urllib3.response import HTTPResponse
from .packages.urllib3.exceptions import MaxRetryError, LocationParseError
from .packages.urllib3.exceptions import SSLError as _SSLError
from .packages.urllib3.exceptions import HTTPError as _HTTPError
from .packages.urllib3 import connectionpool, poolmanager
from .packages.urllib3.filepost import encode_multipart_formdata
from .defaults import SCHEMAS
from .exceptions import (
ConnectionError, HTTPError, RequestException, Timeout, TooManyRedirects,
URLRequired, SSLError, MissingSchema, InvalidSchema, InvalidURL)
from .utils import (
get_encoding_from_headers, stream_untransfer, guess_filename, requote_uri,
stream_decode_response_unicode, get_netrc_auth,
DEFAULT_CA_BUNDLE_PATH)
from .compat import (
cookielib, urlparse, urlunparse, urljoin, urlsplit, urlencode, str, bytes,
is_py2)
# Import chardet if it is available.
try:
import chardet
except ImportError:
pass
REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved)
CONTENT_CHUNK_SIZE = 10 * 1024
class Request(object):
"""The :class:`Request <Request>` object. It carries out all functionality of
Requests. Recommended interface is with the Requests functions.
"""
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,
config=None,
prefetch=False,
_poolmanager=None,
verify=None,
session=None,
cert=None):
#: Dictionary of configurations for this request.
self.config = dict(config or [])
#: Float describes the timeout of the request.
# (Use socket.setdefaulttimeout() as fallback)
self.timeout = timeout
#: Request URL.
self.url = url
#: Dictionary of HTTP Headers to attach to the :class:`Request <Request>`.
self.headers = dict(headers or [])
#: Dictionary of files to multipart upload (``{filename: content}``).
self.files = None
#: HTTP Method to use.
self.method = method
#: Dictionary or byte of request body data to attach to the
#: :class:`Request <Request>`.
self.data = None
#: Dictionary or byte of querystring data to attach to the
#: :class:`Request <Request>`. The dictionary values can be lists for representing
#: multivalued query parameters.
self.params = None
#: True if :class:`Request <Request>` is part of a redirect chain (disables history
#: and HTTPError storage).
self.redirect = redirect
#: Set to True if full redirects are allowed (e.g. re-POST-ing of data at new ``Location``)
self.allow_redirects = allow_redirects
# Dictionary mapping protocol to the URL of the proxy (e.g. {'http': 'foo.bar:3128'})
self.proxies = dict(proxies or [])
# If no proxies are given, allow configuration by environment variables
# HTTP_PROXY and HTTPS_PROXY.
if not self.proxies and self.config.get('trust_env'):
if 'HTTP_PROXY' in os.environ:
self.proxies['http'] = os.environ['HTTP_PROXY']
if 'HTTPS_PROXY' in os.environ:
self.proxies['https'] = os.environ['HTTPS_PROXY']
self.data = data
self.params = params
self.files = files
#: :class:`Response <Response>` instance, containing
#: content and metadata of HTTP Response, once :attr:`sent <send>`.
self.response = Response()
#: Authentication tuple or object to attach to :class:`Request <Request>`.
self.auth = auth
#: CookieJar to attach to :class:`Request <Request>`.
if isinstance(cookies, cookielib.CookieJar):
self.cookies = cookies
else:
self.cookies = cookiejar_from_dict(cookies)
#: True if Request has been sent.
self.sent = False
#: Event-handling hooks.
self.hooks = {}
for event in HOOKS:
self.hooks[event] = []
hooks = hooks or {}
for (k, v) in list(hooks.items()):
self.register_hook(event=k, hook=v)
#: Session.
self.session = session
#: SSL Verification.
self.verify = verify
#: SSL Certificate
self.cert = cert
#: Prefetch response content
self.prefetch = prefetch
if headers:
headers = CaseInsensitiveDict(self.headers)
else:
headers = CaseInsensitiveDict()
# Add configured base headers.
for (k, v) in list(self.config.get('base_headers', {}).items()):
if k not in headers:
headers[k] = v
self.headers = headers
self._poolmanager = _poolmanager
def __repr__(self):
return '<Request [%s]>' % (self.method)
def _build_response(self, resp):
"""Build internal :class:`Response <Response>` object
from given response.
"""
def build(resp):
response = Response()
# Pass settings over.
response.config = self.config
if resp:
# Fallback to None if there's no status_code, for whatever reason.
response.status_code = getattr(resp, 'status', None)
# Make headers case-insensitive.
response.headers = CaseInsensitiveDict(getattr(resp, 'headers', None))
# Set encoding.
response.encoding = get_encoding_from_headers(response.headers)
# Add new cookies from the server.
extract_cookies_to_jar(self.cookies, self, resp)
# Save cookies in Response.
response.cookies = self.cookies
# No exceptions were harmed in the making of this request.
response.error = getattr(resp, 'error', None)
# Save original response for later.
response.raw = resp
if isinstance(self.full_url, bytes):
response.url = self.full_url.decode('utf-8')
else:
response.url = self.full_url
return response
history = []
r = build(resp)
if r.status_code in REDIRECT_STATI and not self.redirect:
while (('location' in r.headers) and
((r.status_code is codes.see_other) or (self.allow_redirects))):
r.content # Consume socket so it can be released
if not len(history) < self.config.get('max_redirects'):
raise TooManyRedirects()
# Release the connection back into the pool.
r.raw.release_conn()
history.append(r)
url = r.headers['location']
data = self.data
# Handle redirection without scheme (see: RFC 1808 Section 4)
if url.startswith('//'):
parsed_rurl = urlparse(r.url)
url = '%s:%s' % (parsed_rurl.scheme, url)
# Facilitate non-RFC2616-compliant 'location' headers
# (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
if not urlparse(url).netloc:
url = urljoin(r.url,
# Compliant with RFC3986, we percent
# encode the url.
requote_uri(url))
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
if r.status_code is codes.see_other:
method = 'GET'
data = None
else:
method = self.method
# Do what the browsers do if strict_mode is off...
if (not self.config.get('strict_mode')):
if r.status_code in (codes.moved, codes.found) and self.method == 'POST':
method = 'GET'
data = None
if (r.status_code == 303) and self.method != 'HEAD':
method = 'GET'
data = None
# Remove the cookie headers that were sent.
headers = self.headers
try:
del headers['Cookie']
except KeyError:
pass
request = Request(
url=url,
headers=headers,
files=self.files,
method=method,
params=self.session.params,
auth=self.auth,
cookies=self.cookies,
redirect=True,
data=data,
config=self.config,
timeout=self.timeout,
_poolmanager=self._poolmanager,
proxies=self.proxies,
verify=self.verify,
session=self.session,
cert=self.cert
)
request.send()
r = request.response
r.history = history
self.response = r
self.response.request = self
@staticmethod
def _encode_params(data):
"""Encode parameters in a piece of data.
Will successfully encode parameters when passed as a dict or a list of
2-tuples. Order is retained if data is a list of 2-tuples but abritrary
if parameters are supplied as a dict.
"""
if isinstance(data, bytes):
return data
if isinstance(data, str):
return data
elif hasattr(data, '__iter__'):
try:
dict(data)
except ValueError:
raise ValueError('Unable to encode lists with elements that are not 2-tuples.')
params = list(data.items() if isinstance(data, dict) else data)
result = []
for k, vs in params:
for v in isinstance(vs, list) and vs or [vs]:
result.append(
(k.encode('utf-8') if isinstance(k, str) else k,
v.encode('utf-8') if isinstance(v, str) else v))
return urlencode(result, doseq=True)
else:
return data
def _encode_files(self, files):
if (not files) or isinstance(self.data, str):
return None
try:
fields = self.data.copy()
except AttributeError:
fields = dict(self.data)
for (k, v) in list(files.items()):
# support for explicit filename
if isinstance(v, (tuple, list)):
fn, fp = v
else:
fn = guess_filename(v) or k
fp = v
fields.update({k: (fn, fp.read())})
(body, content_type) = encode_multipart_formdata(fields)
return (body, content_type)
@property
def full_url(self):
"""Build the actual URL to use."""
if not self.url:
raise URLRequired()
url = self.url
# Support for unicode domain names and paths.
scheme, netloc, path, params, query, fragment = urlparse(url)
if not scheme:
raise MissingSchema("Invalid URL %r: No schema supplied" % url)
if not scheme in SCHEMAS:
raise InvalidSchema("Invalid scheme %r" % scheme)
netloc = netloc.encode('idna').decode('utf-8')
if not path:
path = '/'
if is_py2:
if isinstance(scheme, str):
scheme = scheme.encode('utf-8')
if isinstance(netloc, str):
netloc = netloc.encode('utf-8')
if isinstance(path, str):
path = path.encode('utf-8')
if isinstance(params, str):
params = params.encode('utf-8')
if isinstance(query, str):
query = query.encode('utf-8')
if isinstance(fragment, str):
fragment = fragment.encode('utf-8')
url = (urlunparse([scheme, netloc, path, params, query, fragment]))
enc_params = self._encode_params(self.params)
if enc_params:
if urlparse(url).query:
url = '%s&%s' % (url, enc_params)
else:
url = '%s?%s' % (url, enc_params)
if self.config.get('encode_uri', True):
url = requote_uri(url)
return url
@property
def path_url(self):
"""Build the path URL to use."""
url = []
p = urlsplit(self.full_url)
# Proxies use full URLs.
if p.scheme in self.proxies:
return self.full_url
path = p.path
if not path:
path = '/'
url.append(path)
query = p.query
if query:
url.append('?')
url.append(query)
return ''.join(url)
def register_hook(self, event, hook):
"""Properly register a hook."""
self.hooks[event].append(hook)
def deregister_hook(self, event, hook):
"""Deregister a previously registered hook.
Returns True if the hook existed, False if not.
"""
try:
self.hooks[event].remove(hook)
return True
except ValueError:
return False
def send(self, anyway=False, prefetch=False):
"""Sends the request. Returns True of successful, False if not.
If there was an HTTPError during transmission,
self.response.status_code will contain the HTTPError code.
Once a request is successfully sent, `sent` will equal True.
:param anyway: If True, request will be sent, even if it has
already been sent.
"""
# Build the URL
url = self.full_url
# Pre-request hook.
r = dispatch_hook('pre_request', self.hooks, self)
self.__dict__.update(r.__dict__)
# Logging
if self.config.get('verbose'):
self.config.get('verbose').write('%s %s %s\n' % (
datetime.now().isoformat(), self.method, url
))
# Nottin' on you.
body = None
content_type = None
# Use .netrc auth if none was provided.
if not self.auth and self.config.get('trust_env'):
self.auth = get_netrc_auth(url)
if self.auth:
if isinstance(self.auth, tuple) and len(self.auth) == 2:
# special-case basic HTTP auth
self.auth = HTTPBasicAuth(*self.auth)
# Allow auth to make its changes.
r = self.auth(self)
# Update self to reflect the auth changes.
self.__dict__.update(r.__dict__)
# Multi-part file uploads.
if self.files:
(body, content_type) = self._encode_files(self.files)
else:
if self.data:
body = self._encode_params(self.data)
if isinstance(self.data, str):
content_type = None
else:
content_type = 'application/x-www-form-urlencoded'
# Add content-type if it wasn't explicitly provided.
if (content_type) and (not 'content-type' in self.headers):
self.headers['Content-Type'] = content_type
_p = urlparse(url)
proxy = self.proxies.get(_p.scheme)
if proxy:
conn = poolmanager.proxy_from_url(proxy)
_proxy = urlparse(proxy)
if '@' in _proxy.netloc:
auth, url = _proxy.netloc.split('@', 1)
self.proxy_auth = HTTPProxyAuth(*auth.split(':', 1))
r = self.proxy_auth(self)
self.__dict__.update(r.__dict__)
else:
# Check to see if keep_alive is allowed.
try:
if self.config.get('keep_alive'):
conn = self._poolmanager.connection_from_url(url)
else:
conn = connectionpool.connection_from_url(url)
except LocationParseError as e:
raise InvalidURL(e)
if url.startswith('https') and self.verify:
cert_loc = None
# Allow self-specified cert location.
if self.verify is not True:
cert_loc = self.verify
# Look for configuration.
if not cert_loc and self.config.get('trust_env'):
cert_loc = os.environ.get('REQUESTS_CA_BUNDLE')
# Curl compatibility.
if not cert_loc and self.config.get('trust_env'):
cert_loc = os.environ.get('CURL_CA_BUNDLE')
if not cert_loc:
cert_loc = DEFAULT_CA_BUNDLE_PATH
if not cert_loc:
raise Exception("Could not find a suitable SSL CA certificate bundle.")
conn.cert_reqs = 'CERT_REQUIRED'
conn.ca_certs = cert_loc
else:
conn.cert_reqs = 'CERT_NONE'
conn.ca_certs = None
if self.cert and self.verify:
if len(self.cert) == 2:
conn.cert_file = self.cert[0]
conn.key_file = self.cert[1]
else:
conn.cert_file = self.cert
if not self.sent or anyway:
# Skip if 'cookie' header is explicitly set.
if 'cookie' not in self.headers:
cookie_header = get_cookie_header(self.cookies, self)
if cookie_header is not None:
self.headers['Cookie'] = cookie_header
# Pre-send hook.
r = dispatch_hook('pre_send', self.hooks, self)
self.__dict__.update(r.__dict__)
try:
# The inner try .. except re-raises certain exceptions as
# internal exception types; the outer suppresses exceptions
# when safe mode is set.
try:
# Send the request.
r = conn.urlopen(
method=self.method,
url=self.path_url,
body=body,
headers=self.headers,
redirect=False,
assert_same_host=False,
preload_content=False,
decode_content=False,
retries=self.config.get('max_retries', 0),
timeout=self.timeout,
)
self.sent = True
except MaxRetryError as e:
raise ConnectionError(e)
except (_SSLError, _HTTPError) as e:
if self.verify and isinstance(e, _SSLError):
raise SSLError(e)
raise Timeout('Request timed out.')
except RequestException as e:
if self.config.get('safe_mode', False):
# In safe mode, catch the exception and attach it to
# a blank urllib3.HTTPResponse object.
r = HTTPResponse()
r.error = e
else:
raise
# build_response can throw TooManyRedirects
try:
self._build_response(r)
except RequestException as e:
if self.config.get('safe_mode', False):
# In safe mode, catch the exception
self.response.error = e
else:
raise
# Response manipulation hook.
self.response = dispatch_hook('response', self.hooks, self.response)
# Post-request hook.
r = dispatch_hook('post_request', self.hooks, self)
self.__dict__.update(r.__dict__)
# If prefetch is True, mark content as consumed.
if prefetch or self.prefetch:
# Save the response.
self.response.content
if self.config.get('danger_mode'):
self.response.raise_for_status()
return self.sent
class Response(object):
"""The core :class:`Response <Response>` object. All
:class:`Request <Request>` objects contain a
:class:`response <Response>` attribute, which is an instance
of this class.
"""
def __init__(self):
self._content = False
self._content_consumed = False
#: Integer Code of responded HTTP Status.
self.status_code = None
#: Case-insensitive Dictionary of Response Headers.
#: For example, ``headers['content-encoding']`` will return the
#: value of a ``'Content-Encoding'`` response header.
self.headers = CaseInsensitiveDict()
#: File-like object representation of response (for advanced usage).
self.raw = None
#: Final URL location of Response.
self.url = None
#: Resulting :class:`HTTPError` of request, if one occurred.
self.error = None
#: Encoding to decode with when accessing r.content.
self.encoding = None
#: A list of :class:`Response <Response>` objects from
#: the history of the Request. Any redirect responses will end
#: up here.
self.history = []
#: The :class:`Request <Request>` that created the Response.
self.request = None
#: A CookieJar of Cookies the server sent back.
self.cookies = None
#: Dictionary of configurations for this request.
self.config = {}
def __repr__(self):
return '<Response [%s]>' % (self.status_code)
def __bool__(self):
"""Returns true if :attr:`status_code` is 'OK'."""
return self.ok
def __nonzero__(self):
"""Returns true if :attr:`status_code` is 'OK'."""
return self.ok
@property
def ok(self):
try:
self.raise_for_status()
except RequestException:
return False
return True
def iter_content(self, chunk_size=1, decode_unicode=False):
"""Iterates over the response data. This avoids reading the content
at once into memory for large responses. The chunk size is the number
of bytes it should read into memory. This is not necessarily the
length of each item returned as decoding can take place.
"""
if self._content_consumed:
raise RuntimeError(
'The content for this response was already consumed'
)
def generate():
while 1:
chunk = self.raw.read(chunk_size)
if not chunk:
break
yield chunk
self._content_consumed = True
gen = stream_untransfer(generate(), self)
if decode_unicode:
gen = stream_decode_response_unicode(gen, self)
return gen
def iter_lines(self, chunk_size=10 * 1024, decode_unicode=None):
"""Iterates over the response data, one line at a time. This
avoids reading the content at once into memory for large
responses.
"""
pending = None
for chunk in self.iter_content(
chunk_size=chunk_size,
decode_unicode=decode_unicode):
if pending is not None:
chunk = pending + chunk
lines = chunk.splitlines()
if lines[-1][-1] == chunk[-1]:
pending = lines.pop()
else:
pending = None
for line in lines:
yield line
if pending is not None:
yield pending
@property
def content(self):
"""Content of the response, in bytes."""
if self._content is False:
# Read the contents.
try:
if self._content_consumed:
raise RuntimeError(
'The content for this response was already consumed')
if self.status_code is 0:
self._content = None
else:
self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
except AttributeError:
self._content = None
self._content_consumed = True
return self._content
def _detected_encoding(self):
try:
detected = chardet.detect(self.content) or {}
return detected.get('encoding')
# Trust that chardet isn't available or something went terribly wrong.
except Exception:
pass
@property
def text(self):
"""Content of the response, in unicode.
if Response.encoding is None and chardet module is available, encoding
will be guessed.
"""
# Try charset from content-type
content = None
encoding = self.encoding
# Fallback to auto-detected encoding if chardet is available.
if self.encoding is None:
encoding = self._detected_encoding()
# Decode unicode from given encoding.
try:
content = str(self.content, encoding, errors='replace')
except LookupError:
# A LookupError is raised if the encoding was not found which could
# indicate a misspelling or similar mistake.
#
# So we try blindly encoding.
content = str(self.content, errors='replace')
except (UnicodeError, TypeError):
pass
return content
def raise_for_status(self, allow_redirects=True):
"""Raises stored :class:`HTTPError` or :class:`URLError`, if one occurred."""
if self.error:
raise self.error
if (self.status_code >= 300) and (self.status_code < 400) and not allow_redirects:
http_error = HTTPError('%s Redirection' % self.status_code)
http_error.response = self
raise http_error
elif (self.status_code >= 400) and (self.status_code < 500):
http_error = HTTPError('%s Client Error' % self.status_code)
http_error.response = self
raise http_error
elif (self.status_code >= 500) and (self.status_code < 600):
http_error = HTTPError('%s Server Error' % self.status_code)
http_error.response = self
raise http_error

View File

@@ -1 +1,3 @@
from . import poster
from __future__ import absolute_import
from . import urllib3

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from .core import dict_from_string

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
"""
oreos.core
~~~~~~~~~~
The creamy white center.
"""
from .monkeys import SimpleCookie
def dict_from_string(s):
"""Returns a MultiDict with Cookies."""
cookies = dict()
c = SimpleCookie()
c.load(s)
for k,v in c.items():
cookies.update({k: v.value})
return cookies

View File

@@ -0,0 +1,773 @@
# -*- coding: utf-8 -*-
"""
oreos.monkeys
~~~~~~~~~~~~~
Monkeypatches.
"""
#!/usr/bin/env python
#
####
# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of
# Timothy O'Malley not be used in advertising or publicity
# pertaining to distribution of the software without specific, written
# prior permission.
#
# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
####
#
# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
# by Timothy O'Malley <timo@alum.mit.edu>
#
# Cookie.py is a Python module for the handling of HTTP
# cookies as a Python dictionary. See RFC 2109 for more
# information on cookies.
#
# The original idea to treat Cookies as a dictionary came from
# Dave Mitchell (davem@magnet.com) in 1995, when he released the
# first version of nscookie.py.
#
####
r"""
Here's a sample session to show how to use this module.
At the moment, this is the only documentation.
The Basics
----------
Importing is easy..
>>> import Cookie
Most of the time you start by creating a cookie. Cookies come in
three flavors, each with slightly different encoding semantics, but
more on that later.
>>> C = Cookie.SimpleCookie()
>>> C = Cookie.SerialCookie()
>>> C = Cookie.SmartCookie()
[Note: Long-time users of Cookie.py will remember using
Cookie.Cookie() to create an Cookie object. Although deprecated, it
is still supported by the code. See the Backward Compatibility notes
for more information.]
Once you've created your Cookie, you can add values just as if it were
a dictionary.
>>> C = Cookie.SmartCookie()
>>> C["fig"] = "newton"
>>> C["sugar"] = "wafer"
>>> C.output()
'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
Notice that the printable representation of a Cookie is the
appropriate format for a Set-Cookie: header. This is the
default behavior. You can change the header and printed
attributes by using the .output() function
>>> C = Cookie.SmartCookie()
>>> C["rocky"] = "road"
>>> C["rocky"]["path"] = "/cookie"
>>> print C.output(header="Cookie:")
Cookie: rocky=road; Path=/cookie
>>> print C.output(attrs=[], header="Cookie:")
Cookie: rocky=road
The load() method of a Cookie extracts cookies from a string. In a
CGI script, you would use this method to extract the cookies from the
HTTP_COOKIE environment variable.
>>> C = Cookie.SmartCookie()
>>> C.load("chips=ahoy; vienna=finger")
>>> C.output()
'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
The load() method is darn-tootin smart about identifying cookies
within a string. Escaped quotation marks, nested semicolons, and other
such trickeries do not confuse it.
>>> C = Cookie.SmartCookie()
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
>>> print C
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Each element of the Cookie also supports all of the RFC 2109
Cookie attributes. Here's an example which sets the Path
attribute.
>>> C = Cookie.SmartCookie()
>>> C["oreo"] = "doublestuff"
>>> C["oreo"]["path"] = "/"
>>> print C
Set-Cookie: oreo=doublestuff; Path=/
Each dictionary element has a 'value' attribute, which gives you
back the value associated with the key.
>>> C = Cookie.SmartCookie()
>>> C["twix"] = "none for you"
>>> C["twix"].value
'none for you'
A Bit More Advanced
-------------------
As mentioned before, there are three different flavors of Cookie
objects, each with different encoding/decoding semantics. This
section briefly discusses the differences.
SimpleCookie
The SimpleCookie expects that all values should be standard strings.
Just to be sure, SimpleCookie invokes the str() builtin to convert
the value to a string, when the values are set dictionary-style.
>>> C = Cookie.SimpleCookie()
>>> C["number"] = 7
>>> C["string"] = "seven"
>>> C["number"].value
'7'
>>> C["string"].value
'seven'
>>> C.output()
'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
SerialCookie
The SerialCookie expects that all values should be serialized using
cPickle (or pickle, if cPickle isn't available). As a result of
serializing, SerialCookie can save almost any Python object to a
value, and recover the exact same object when the cookie has been
returned. (SerialCookie can yield some strange-looking cookie
values, however.)
>>> C = Cookie.SerialCookie()
>>> C["number"] = 7
>>> C["string"] = "seven"
>>> C["number"].value
7
>>> C["string"].value
'seven'
>>> C.output()
'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'
Be warned, however, if SerialCookie cannot de-serialize a value (because
it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
SmartCookie
The SmartCookie combines aspects of each of the other two flavors.
When setting a value in a dictionary-fashion, the SmartCookie will
serialize (ala cPickle) the value *if and only if* it isn't a
Python string. String objects are *not* serialized. Similarly,
when the load() method parses out values, it attempts to de-serialize
the value. If it fails, then it fallsback to treating the value
as a string.
>>> C = Cookie.SmartCookie()
>>> C["number"] = 7
>>> C["string"] = "seven"
>>> C["number"].value
7
>>> C["string"].value
'seven'
>>> C.output()
'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
Backwards Compatibility
-----------------------
In order to keep compatibilty with earlier versions of Cookie.py,
it is still possible to use Cookie.Cookie() to create a Cookie. In
fact, this simply returns a SmartCookie.
>>> C = Cookie.Cookie()
>>> print C.__class__.__name__
SmartCookie
Finis.
""" #"
# ^
# |----helps out font-lock
#
# Import our required modules
#
import string
try:
from cPickle import dumps, loads
except ImportError:
from pickle import dumps, loads
import re, warnings
__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
"SmartCookie","Cookie"]
_nulljoin = ''.join
_semispacejoin = '; '.join
_spacejoin = ' '.join
#
# Define an exception visible to External modules
#
class CookieError(Exception):
pass
# These quoting routines conform to the RFC2109 specification, which in
# turn references the character definitions from RFC2068. They provide
# a two-way quoting algorithm. Any non-text character is translated
# into a 4 character sequence: a forward-slash followed by the
# three-digit octal equivalent of the character. Any '\' or '"' is
# quoted with a preceeding '\' slash.
#
# These are taken from RFC2068 and RFC2109.
# _RFC2965Forbidden is the list of forbidden chars we accept anyway
# _LegalChars is the list of chars which don't require "'s
# _Translator hash-table for fast quoting
#
_RFC2965Forbidden = "[]:{}="
_LegalChars = ( string.ascii_letters + string.digits +
"!#$%&'*+-.^_`|~_@" + _RFC2965Forbidden )
_Translator = {
'\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
'\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
'\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
'\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
'\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
'\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
'\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
'\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
'\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
'\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
'\036' : '\\036', '\037' : '\\037',
# Because of the way browsers really handle cookies (as opposed
# to what the RFC says) we also encode , and ;
',' : '\\054', ';' : '\\073',
'"' : '\\"', '\\' : '\\\\',
'\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
'\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
'\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
'\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
'\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
'\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
'\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
'\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
'\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
'\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
'\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
'\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
'\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
'\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
'\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
'\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
'\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
'\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
'\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
'\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
'\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
'\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
'\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
'\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
'\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
'\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
'\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
'\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
'\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
'\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
'\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
'\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
'\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
'\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
'\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
'\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
'\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
'\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
'\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
'\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
'\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
'\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
'\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
}
_idmap = ''.join(chr(x) for x in range(256))
def _quote(str, LegalChars=_LegalChars,
idmap=_idmap, translate=string.translate):
#
# If the string does not need to be double-quoted,
# then just return the string. Otherwise, surround
# the string in doublequotes and precede quote (with a \)
# special characters.
#
if "" == translate(str, idmap, LegalChars):
return str
else:
return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
# end _quote
_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
_QuotePatt = re.compile(r"[\\].")
def _unquote(str):
# If there aren't any doublequotes,
# then there can't be any special characters. See RFC 2109.
if len(str) < 2:
return str
if str[0] != '"' or str[-1] != '"':
return str
# We have to assume that we must decode this string.
# Down to work.
# Remove the "s
str = str[1:-1]
# Check for special sequences. Examples:
# \012 --> \n
# \" --> "
#
i = 0
n = len(str)
res = []
while 0 <= i < n:
Omatch = _OctalPatt.search(str, i)
Qmatch = _QuotePatt.search(str, i)
if not Omatch and not Qmatch: # Neither matched
res.append(str[i:])
break
# else:
j = k = -1
if Omatch: j = Omatch.start(0)
if Qmatch: k = Qmatch.start(0)
if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
res.append(str[i:k])
res.append(str[k+1])
i = k+2
else: # OctalPatt matched
res.append(str[i:j])
res.append( chr( int(str[j+1:j+4], 8) ) )
i = j+4
return _nulljoin(res)
# end _unquote
# The _getdate() routine is used to set the expiration time in
# the cookie's HTTP header. By default, _getdate() returns the
# current time in the appropriate "expires" format for a
# Set-Cookie header. The one optional argument is an offset from
# now, in seconds. For example, an offset of -3600 means "one hour ago".
# The offset may be a floating point number.
#
_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
_monthname = [None,
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
from time import gmtime, time
now = time()
year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
(weekdayname[wd], day, monthname[month], year, hh, mm, ss)
#
# A class to hold ONE key,value pair.
# In a cookie, each such pair may have several attributes.
# so this class is used to keep the attributes associated
# with the appropriate key,value pair.
# This class also includes a coded_value attribute, which
# is used to hold the network representation of the
# value. This is most useful when Python objects are
# pickled for network transit.
#
class Morsel(dict):
# RFC 2109 lists these attributes as reserved:
# path comment domain
# max-age secure version
#
# For historical reasons, these attributes are also reserved:
# expires
#
# This is an extension from Microsoft:
# httponly
#
# This dictionary provides a mapping from the lowercase
# variant on the left to the appropriate traditional
# formatting on the right.
_reserved = { "expires" : "expires",
"path" : "Path",
"comment" : "Comment",
"domain" : "Domain",
"max-age" : "Max-Age",
"secure" : "secure",
"httponly" : "httponly",
"version" : "Version",
}
def __init__(self):
# Set defaults
self.key = self.value = self.coded_value = None
# Set default attributes
for K in self._reserved:
dict.__setitem__(self, K, "")
# end __init__
def __setitem__(self, K, V):
K = K.lower()
if not K in self._reserved:
raise CookieError("Invalid Attribute %s" % K)
dict.__setitem__(self, K, V)
# end __setitem__
def isReservedKey(self, K):
return K.lower() in self._reserved
# end isReservedKey
def set(self, key, val, coded_val,
LegalChars=_LegalChars,
idmap=_idmap, translate=string.translate):
# First we verify that the key isn't a reserved word
# Second we make sure it only contains legal characters
if key.lower() in self._reserved:
raise CookieError("Attempt to set a reserved key: %s" % key)
if "" != translate(key, idmap, LegalChars):
raise CookieError("Illegal key value: %s" % key)
# It's a good key, so save it.
self.key = key
self.value = val
self.coded_value = coded_val
# end set
def output(self, attrs=None, header = "Set-Cookie:"):
return "%s %s" % ( header, self.OutputString(attrs) )
__str__ = output
def __repr__(self):
return '<%s: %s=%s>' % (self.__class__.__name__,
self.key, repr(self.value) )
def js_output(self, attrs=None):
# Print javascript
return """
<script type="text/javascript">
<!-- begin hiding
document.cookie = \"%s\";
// end hiding -->
</script>
""" % ( self.OutputString(attrs).replace('"',r'\"'), )
# end js_output()
def OutputString(self, attrs=None):
# Build up our result
#
result = []
RA = result.append
# First, the key=value pair
RA("%s=%s" % (self.key, self.coded_value))
# Now add any defined attributes
if attrs is None:
attrs = self._reserved
items = self.items()
items.sort()
for K,V in items:
if V == "": continue
if K not in attrs: continue
if K == "expires" and type(V) == type(1):
RA("%s=%s" % (self._reserved[K], _getdate(V)))
elif K == "max-age" and type(V) == type(1):
RA("%s=%d" % (self._reserved[K], V))
elif K == "secure":
RA(str(self._reserved[K]))
elif K == "httponly":
RA(str(self._reserved[K]))
else:
RA("%s=%s" % (self._reserved[K], V))
# Return the result
return _semispacejoin(result)
# end OutputString
# end Morsel class
#
# Pattern for finding cookie
#
# This used to be strict parsing based on the RFC2109 and RFC2068
# specifications. I have since discovered that MSIE 3.0x doesn't
# follow the character rules outlined in those specs. As a
# result, the parsing rules here are less strict.
#
_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=\[\]\_]"
_CookiePattern = re.compile(
r"(?x)" # This is a Verbose pattern
r"(?P<key>" # Start of group 'key'
""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
r")" # End of group 'key'
r"\s*=\s*" # Equal Sign
r"(?P<val>" # Start of group 'val'
r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
r"|" # or
r"\w{3},\s[\w\d-]{9,11}\s[\d:]{8}\sGMT" # Special case for "expires" attr
r"|" # or
""+ _LegalCharsPatt +"*" # Any word or empty string
r")" # End of group 'val'
r"\s*;?" # Probably ending in a semi-colon
)
# At long last, here is the cookie class.
# Using this class is almost just like using a dictionary.
# See this module's docstring for example usage.
#
class BaseCookie(dict):
# A container class for a set of Morsels
#
def value_decode(self, val):
"""real_value, coded_value = value_decode(STRING)
Called prior to setting a cookie's value from the network
representation. The VALUE is the value read from HTTP
header.
Override this function to modify the behavior of cookies.
"""
return val, val
# end value_encode
def value_encode(self, val):
"""real_value, coded_value = value_encode(VALUE)
Called prior to setting a cookie's value from the dictionary
representation. The VALUE is the value being assigned.
Override this function to modify the behavior of cookies.
"""
strval = str(val)
return strval, strval
# end value_encode
def __init__(self, input=None):
if input: self.load(input)
# end __init__
def __set(self, key, real_value, coded_value):
"""Private method for setting a cookie's value"""
M = self.get(key, Morsel())
M.set(key, real_value, coded_value)
dict.__setitem__(self, key, M)
# end __set
def __setitem__(self, key, value):
"""Dictionary style assignment."""
rval, cval = self.value_encode(value)
self.__set(key, rval, cval)
# end __setitem__
def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
"""Return a string suitable for HTTP."""
result = []
items = self.items()
items.sort()
for K,V in items:
result.append( V.output(attrs, header) )
return sep.join(result)
# end output
__str__ = output
def __repr__(self):
L = []
items = self.items()
items.sort()
for K,V in items:
L.append( '%s=%s' % (K,repr(V.value) ) )
return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
def js_output(self, attrs=None):
"""Return a string suitable for JavaScript."""
result = []
items = self.items()
items.sort()
for K,V in items:
result.append( V.js_output(attrs) )
return _nulljoin(result)
# end js_output
def load(self, rawdata):
"""Load cookies from a string (presumably HTTP_COOKIE) or
from a dictionary. Loading cookies from a dictionary 'd'
is equivalent to calling:
map(Cookie.__setitem__, d.keys(), d.values())
"""
if type(rawdata) == type(""):
self.__ParseString(rawdata)
else:
# self.update() wouldn't call our custom __setitem__
for k, v in rawdata.items():
self[k] = v
return
# end load()
def __ParseString(self, str, patt=_CookiePattern):
i = 0 # Our starting point
n = len(str) # Length of string
M = None # current morsel
while 0 <= i < n:
# Start looking for a cookie
match = patt.search(str, i)
if not match: break # No more cookies
K,V = match.group("key"), match.group("val")
i = match.end(0)
# Parse the key, value in case it's metainfo
if K[0] == "$":
# We ignore attributes which pertain to the cookie
# mechanism as a whole. See RFC 2109.
# (Does anyone care?)
if M:
M[ K[1:] ] = V
elif K.lower() in Morsel._reserved:
if M:
M[ K ] = _unquote(V)
else:
rval, cval = self.value_decode(V)
self.__set(K, rval, cval)
M = self[K]
# end __ParseString
# end BaseCookie class
class SimpleCookie(BaseCookie):
"""SimpleCookie
SimpleCookie supports strings as cookie values. When setting
the value using the dictionary assignment notation, SimpleCookie
calls the builtin str() to convert the value to a string. Values
received from HTTP are kept as strings.
"""
def value_decode(self, val):
return _unquote( val ), val
def value_encode(self, val):
strval = str(val)
return strval, _quote( strval )
# end SimpleCookie
class SerialCookie(BaseCookie):
"""SerialCookie
SerialCookie supports arbitrary objects as cookie values. All
values are serialized (using cPickle) before being sent to the
client. All incoming values are assumed to be valid Pickle
representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
FORMAT, THEN AN EXCEPTION WILL BE RAISED.
Note: Large cookie values add overhead because they must be
retransmitted on every HTTP transaction.
Note: HTTP has a 2k limit on the size of a cookie. This class
does not check for this limit, so be careful!!!
"""
def __init__(self, input=None):
warnings.warn("SerialCookie class is insecure; do not use it",
DeprecationWarning)
BaseCookie.__init__(self, input)
# end __init__
def value_decode(self, val):
# This could raise an exception!
return loads( _unquote(val) ), val
def value_encode(self, val):
return val, _quote( dumps(val) )
# end SerialCookie
class SmartCookie(BaseCookie):
"""SmartCookie
SmartCookie supports arbitrary objects as cookie values. If the
object is a string, then it is quoted. If the object is not a
string, however, then SmartCookie will use cPickle to serialize
the object into a string representation.
Note: Large cookie values add overhead because they must be
retransmitted on every HTTP transaction.
Note: HTTP has a 2k limit on the size of a cookie. This class
does not check for this limit, so be careful!!!
"""
def __init__(self, input=None):
warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
DeprecationWarning)
BaseCookie.__init__(self, input)
# end __init__
def value_decode(self, val):
strval = _unquote(val)
try:
return loads(strval), val
except:
return strval, val
def value_encode(self, val):
if type(val) == type(""):
return val, _quote(val)
else:
return val, _quote( dumps(val) )
# end SmartCookie
###########################################################
# Backwards Compatibility: Don't break any existing code!
# We provide Cookie() as an alias for SmartCookie()
Cookie = SmartCookie
#
###########################################################
def _test():
import doctest, Cookie
return doctest.testmod(Cookie)
if __name__ == "__main__":
_test()
#Local Variables:
#tab-width: 4
#end:

View File

@@ -0,0 +1,399 @@
# -*- coding: utf-8 -*-
"""
oreos.structures
~~~~~~~~~~~~~~~~
The plastic blue packaging.
This is mostly directly stolen from mitsuhiko/werkzeug.
"""
__all__ = ('MultiDict',)
class _Missing(object):
def __repr__(self):
return 'no value'
def __reduce__(self):
return '_missing'
_missing = _Missing()
def iter_multi_items(mapping):
"""Iterates over the items of a mapping yielding keys and values
without dropping any from more complex structures.
"""
if isinstance(mapping, MultiDict):
for item in mapping.iteritems(multi=True):
yield item
elif isinstance(mapping, dict):
for key, value in mapping.iteritems():
if isinstance(value, (tuple, list)):
for value in value:
yield key, value
else:
yield key, value
else:
for item in mapping:
yield item
class TypeConversionDict(dict):
"""Works like a regular dict but the :meth:`get` method can perform
type conversions. :class:`MultiDict` and :class:`CombinedMultiDict`
are subclasses of this class and provide the same feature.
.. versionadded:: 0.5
"""
def get(self, key, default=None, type=None):
"""Return the default value if the requested data doesn't exist.
If `type` is provided and is a callable it should convert the value,
return it or raise a :exc:`ValueError` if that is not possible. In
this case the function will return the default as if the value was not
found:
>>> d = TypeConversionDict(foo='42', bar='blub')
>>> d.get('foo', type=int)
42
>>> d.get('bar', -1, type=int)
-1
:param key: The key to be looked up.
:param default: The default value to be returned if the key can't
be looked up. If not further specified `None` is
returned.
:param type: A callable that is used to cast the value in the
:class:`MultiDict`. If a :exc:`ValueError` is raised
by this callable the default value is returned.
"""
try:
rv = self[key]
if type is not None:
rv = type(rv)
except (KeyError, ValueError):
rv = default
return rv
class MultiDict(TypeConversionDict):
"""A :class:`MultiDict` is a dictionary subclass customized to deal with
multiple values for the same key which is for example used by the parsing
functions in the wrappers. This is necessary because some HTML form
elements pass multiple values for the same key.
:class:`MultiDict` implements all standard dictionary methods.
Internally, it saves all values for a key as a list, but the standard dict
access methods will only return the first value for a key. If you want to
gain access to the other values, too, you have to use the `list` methods as
explained below.
Basic Usage:
>>> d = MultiDict([('a', 'b'), ('a', 'c')])
>>> d
MultiDict([('a', 'b'), ('a', 'c')])
>>> d['a']
'b'
>>> d.getlist('a')
['b', 'c']
>>> 'a' in d
True
It behaves like a normal dict thus all dict functions will only return the
first value when multiple values for one key are found.
From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP
exceptions.
A :class:`MultiDict` can be constructed from an iterable of
``(key, value)`` tuples, a dict, a :class:`MultiDict` or from Werkzeug 0.2
onwards some keyword parameters.
:param mapping: the initial value for the :class:`MultiDict`. Either a
regular dict, an iterable of ``(key, value)`` tuples
or `None`.
"""
def __init__(self, mapping=None):
if isinstance(mapping, MultiDict):
dict.__init__(self, ((k, l[:]) for k, l in mapping.iterlists()))
elif isinstance(mapping, dict):
tmp = {}
for key, value in mapping.iteritems():
if isinstance(value, (tuple, list)):
value = list(value)
else:
value = [value]
tmp[key] = value
dict.__init__(self, tmp)
else:
tmp = {}
for key, value in mapping or ():
tmp.setdefault(key, []).append(value)
dict.__init__(self, tmp)
def __getstate__(self):
return dict(self.lists())
def __setstate__(self, value):
dict.clear(self)
dict.update(self, value)
def __iter__(self):
return self.iterkeys()
def __getitem__(self, key):
"""Return the first data value for this key;
raises KeyError if not found.
:param key: The key to be looked up.
:raise KeyError: if the key does not exist.
"""
if key in self:
return dict.__getitem__(self, key)[0]
raise KeyError(key)
def __setitem__(self, key, value):
"""Like :meth:`add` but removes an existing key first.
:param key: the key for the value.
:param value: the value to set.
"""
dict.__setitem__(self, key, [value])
def add(self, key, value):
"""Adds a new value for the key.
.. versionadded:: 0.6
:param key: the key for the value.
:param value: the value to add.
"""
dict.setdefault(self, key, []).append(value)
def getlist(self, key, type=None):
"""Return the list of items for a given key. If that key is not in the
`MultiDict`, the return value will be an empty list. Just as `get`
`getlist` accepts a `type` parameter. All items will be converted
with the callable defined there.
:param key: The key to be looked up.
:param type: A callable that is used to cast the value in the
:class:`MultiDict`. If a :exc:`ValueError` is raised
by this callable the value will be removed from the list.
:return: a :class:`list` of all the values for the key.
"""
try:
rv = dict.__getitem__(self, key)
except KeyError:
return []
if type is None:
return list(rv)
result = []
for item in rv:
try:
result.append(type(item))
except ValueError:
pass
return result
def setlist(self, key, new_list):
"""Remove the old values for a key and add new ones. Note that the list
you pass the values in will be shallow-copied before it is inserted in
the dictionary.
>>> d = MultiDict()
>>> d.setlist('foo', ['1', '2'])
>>> d['foo']
'1'
>>> d.getlist('foo')
['1', '2']
:param key: The key for which the values are set.
:param new_list: An iterable with the new values for the key. Old values
are removed first.
"""
dict.__setitem__(self, key, list(new_list))
def setdefault(self, key, default=None):
"""Returns the value for the key if it is in the dict, otherwise it
returns `default` and sets that value for `key`.
:param key: The key to be looked up.
:param default: The default value to be returned if the key is not
in the dict. If not further specified it's `None`.
"""
if key not in self:
self[key] = default
else:
default = self[key]
return default
def setlistdefault(self, key, default_list=None):
"""Like `setdefault` but sets multiple values. The list returned
is not a copy, but the list that is actually used internally. This
means that you can put new values into the dict by appending items
to the list:
>>> d = MultiDict({"foo": 1})
>>> d.setlistdefault("foo").extend([2, 3])
>>> d.getlist("foo")
[1, 2, 3]
:param key: The key to be looked up.
:param default: An iterable of default values. It is either copied
(in case it was a list) or converted into a list
before returned.
:return: a :class:`list`
"""
if key not in self:
default_list = list(default_list or ())
dict.__setitem__(self, key, default_list)
else:
default_list = dict.__getitem__(self, key)
return default_list
def items(self, multi=False):
"""Return a list of ``(key, value)`` pairs.
:param multi: If set to `True` the list returned will have a
pair for each value of each key. Otherwise it
will only contain pairs for the first value of
each key.
:return: a :class:`list`
"""
return list(self.iteritems(multi))
def lists(self):
"""Return a list of ``(key, values)`` pairs, where values is the list of
all values associated with the key.
:return: a :class:`list`
"""
return list(self.iterlists())
def values(self):
"""Returns a list of the first value on every key's value list.
:return: a :class:`list`.
"""
return [self[key] for key in self.iterkeys()]
def listvalues(self):
"""Return a list of all values associated with a key. Zipping
:meth:`keys` and this is the same as calling :meth:`lists`:
>>> d = MultiDict({"foo": [1, 2, 3]})
>>> zip(d.keys(), d.listvalues()) == d.lists()
True
:return: a :class:`list`
"""
return list(self.iterlistvalues())
def iteritems(self, multi=False):
"""Like :meth:`items` but returns an iterator."""
for key, values in dict.iteritems(self):
if multi:
for value in values:
yield key, value
else:
yield key, values[0]
def iterlists(self):
"""Like :meth:`items` but returns an iterator."""
for key, values in dict.iteritems(self):
yield key, list(values)
def itervalues(self):
"""Like :meth:`values` but returns an iterator."""
for values in dict.itervalues(self):
yield values[0]
def iterlistvalues(self):
"""Like :meth:`listvalues` but returns an iterator."""
return dict.itervalues(self)
def copy(self):
"""Return a shallow copy of this object."""
return self.__class__(self)
def to_dict(self, flat=True):
"""Return the contents as regular dict. If `flat` is `True` the
returned dict will only have the first item present, if `flat` is
`False` all values will be returned as lists.
:param flat: If set to `False` the dict returned will have lists
with all the values in it. Otherwise it will only
contain the first value for each key.
:return: a :class:`dict`
"""
if flat:
return dict(self.iteritems())
return dict(self.lists())
def update(self, other_dict):
"""update() extends rather than replaces existing key lists."""
for key, value in iter_multi_items(other_dict):
MultiDict.add(self, key, value)
def pop(self, key, default=_missing):
"""Pop the first item for a list on the dict. Afterwards the
key is removed from the dict, so additional values are discarded:
>>> d = MultiDict({"foo": [1, 2, 3]})
>>> d.pop("foo")
1
>>> "foo" in d
False
:param key: the key to pop.
:param default: if provided the value to return if the key was
not in the dictionary.
"""
try:
return dict.pop(self, key)[0]
except KeyError as e:
if default is not _missing:
return default
raise KeyError(str(e))
def popitem(self):
"""Pop an item from the dict."""
try:
item = dict.popitem(self)
return (item[0], item[1][0])
except KeyError as e:
raise KeyError(str(e))
def poplist(self, key):
"""Pop the list for a key from the dict. If the key is not in the dict
an empty list is returned.
.. versionchanged:: 0.5
If the key does no longer exist a list is returned instead of
raising an error.
"""
return dict.pop(self, key, [])
def popitemlist(self):
"""Pop a ``(key, list)`` tuple from the dict."""
try:
return dict.popitem(self)
except KeyError as e:
raise KeyError(str(e))
def __copy__(self):
return self.copy()
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.items(multi=True))

View File

@@ -1,32 +0,0 @@
# Copyright (c) 2010 Chris AtLee
#
# 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.
"""poster module
Support for streaming HTTP uploads, and multipart/form-data encoding
```poster.version``` is a 3-tuple of integers representing the version number.
New releases of poster will always have a version number that compares greater
than an older version of poster.
New in version 0.6."""
from . import streaminghttp
from . import encode
version = (0, 8, 0) # Thanks JP!

View File

@@ -1,414 +0,0 @@
"""multipart/form-data encoding module
This module provides functions that faciliate encoding name/value pairs
as multipart/form-data suitable for a HTTP POST or PUT request.
multipart/form-data is the standard way to upload files over HTTP"""
__all__ = ['gen_boundary', 'encode_and_quote', 'MultipartParam',
'encode_string', 'encode_file_header', 'get_body_size', 'get_headers',
'multipart_encode']
try:
import uuid
def gen_boundary():
"""Returns a random string to use as the boundary for a message"""
return uuid.uuid4().hex
except ImportError:
import random, sha
def gen_boundary():
"""Returns a random string to use as the boundary for a message"""
bits = random.getrandbits(160)
return sha.new(str(bits)).hexdigest()
import urllib, re, os, mimetypes
try:
from email.header import Header
except ImportError:
# Python 2.4
from email.Header import Header
def encode_and_quote(data):
"""If ``data`` is unicode, return urllib.quote_plus(data.encode("utf-8"))
otherwise return urllib.quote_plus(data)"""
if data is None:
return None
if isinstance(data, unicode):
data = data.encode("utf-8")
return urllib.quote_plus(data)
def _strify(s):
"""If s is a unicode string, encode it to UTF-8 and return the results,
otherwise return str(s), or None if s is None"""
if s is None:
return None
if isinstance(s, unicode):
return s.encode("utf-8")
return str(s)
class MultipartParam(object):
"""Represents a single parameter in a multipart/form-data request
``name`` is the name of this parameter.
If ``value`` is set, it must be a string or unicode object to use as the
data for this parameter.
If ``filename`` is set, it is what to say that this parameter's filename
is. Note that this does not have to be the actual filename any local file.
If ``filetype`` is set, it is used as the Content-Type for this parameter.
If unset it defaults to "text/plain; charset=utf8"
If ``filesize`` is set, it specifies the length of the file ``fileobj``
If ``fileobj`` is set, it must be a file-like object that supports
.read().
Both ``value`` and ``fileobj`` must not be set, doing so will
raise a ValueError assertion.
If ``fileobj`` is set, and ``filesize`` is not specified, then
the file's size will be determined first by stat'ing ``fileobj``'s
file descriptor, and if that fails, by seeking to the end of the file,
recording the current position as the size, and then by seeking back to the
beginning of the file.
``cb`` is a callable which will be called from iter_encode with (self,
current, total), representing the current parameter, current amount
transferred, and the total size.
"""
def __init__(self, name, value=None, filename=None, filetype=None,
filesize=None, fileobj=None, cb=None):
self.name = Header(name).encode()
self.value = _strify(value)
if filename is None:
self.filename = None
else:
if isinstance(filename, unicode):
# Encode with XML entities
self.filename = filename.encode("ascii", "xmlcharrefreplace")
else:
self.filename = str(filename)
self.filename = self.filename.encode("string_escape").\
replace('"', '\\"')
self.filetype = _strify(filetype)
self.filesize = filesize
self.fileobj = fileobj
self.cb = cb
if self.value is not None and self.fileobj is not None:
raise ValueError("Only one of value or fileobj may be specified")
if fileobj is not None and filesize is None:
# Try and determine the file size
try:
self.filesize = os.fstat(fileobj.fileno()).st_size
except (OSError, AttributeError):
try:
fileobj.seek(0, 2)
self.filesize = fileobj.tell()
fileobj.seek(0)
except:
raise ValueError("Could not determine filesize")
def __cmp__(self, other):
attrs = ['name', 'value', 'filename', 'filetype', 'filesize', 'fileobj']
myattrs = [getattr(self, a) for a in attrs]
oattrs = [getattr(other, a) for a in attrs]
return cmp(myattrs, oattrs)
def reset(self):
if self.fileobj is not None:
self.fileobj.seek(0)
elif self.value is None:
raise ValueError("Don't know how to reset this parameter")
@classmethod
def from_file(cls, paramname, filename):
"""Returns a new MultipartParam object constructed from the local
file at ``filename``.
``filesize`` is determined by os.path.getsize(``filename``)
``filetype`` is determined by mimetypes.guess_type(``filename``)[0]
``filename`` is set to os.path.basename(``filename``)
"""
return cls(paramname, filename=os.path.basename(filename),
filetype=mimetypes.guess_type(filename)[0],
filesize=os.path.getsize(filename),
fileobj=open(filename, "rb"))
@classmethod
def from_params(cls, params):
"""Returns a list of MultipartParam objects from a sequence of
name, value pairs, MultipartParam instances,
or from a mapping of names to values
The values may be strings or file objects, or MultipartParam objects.
MultipartParam object names must match the given names in the
name,value pairs or mapping, if applicable."""
if hasattr(params, 'items'):
params = params.items()
retval = []
for item in params:
if isinstance(item, cls):
retval.append(item)
continue
name, value = item
if isinstance(value, cls):
assert value.name == name
retval.append(value)
continue
if hasattr(value, 'read'):
# Looks like a file object
filename = getattr(value, 'name', None)
if filename is not None:
filetype = mimetypes.guess_type(filename)[0]
else:
filetype = None
retval.append(cls(name=name, filename=filename,
filetype=filetype, fileobj=value))
else:
retval.append(cls(name, value))
return retval
def encode_hdr(self, boundary):
"""Returns the header of the encoding of this parameter"""
boundary = encode_and_quote(boundary)
headers = ["--%s" % boundary]
if self.filename:
disposition = 'form-data; name="%s"; filename="%s"' % (self.name,
self.filename)
else:
disposition = 'form-data; name="%s"' % self.name
headers.append("Content-Disposition: %s" % disposition)
if self.filetype:
filetype = self.filetype
else:
filetype = "text/plain; charset=utf-8"
headers.append("Content-Type: %s" % filetype)
headers.append("")
headers.append("")
return "\r\n".join(headers)
def encode(self, boundary):
"""Returns the string encoding of this parameter"""
if self.value is None:
value = self.fileobj.read()
else:
value = self.value
if re.search("^--%s$" % re.escape(boundary), value, re.M):
raise ValueError("boundary found in encoded string")
return "%s%s\r\n" % (self.encode_hdr(boundary), value)
def iter_encode(self, boundary, blocksize=4096):
"""Yields the encoding of this parameter
If self.fileobj is set, then blocks of ``blocksize`` bytes are read and
yielded."""
total = self.get_size(boundary)
current = 0
if self.value is not None:
block = self.encode(boundary)
current += len(block)
yield block
if self.cb:
self.cb(self, current, total)
else:
block = self.encode_hdr(boundary)
current += len(block)
yield block
if self.cb:
self.cb(self, current, total)
last_block = ""
encoded_boundary = "--%s" % encode_and_quote(boundary)
boundary_exp = re.compile("^%s$" % re.escape(encoded_boundary),
re.M)
while True:
block = self.fileobj.read(blocksize)
if not block:
current += 2
yield "\r\n"
if self.cb:
self.cb(self, current, total)
break
last_block += block
if boundary_exp.search(last_block):
raise ValueError("boundary found in file data")
last_block = last_block[-len(encoded_boundary)-2:]
current += len(block)
yield block
if self.cb:
self.cb(self, current, total)
def get_size(self, boundary):
"""Returns the size in bytes that this param will be when encoded
with the given boundary."""
if self.filesize is not None:
valuesize = self.filesize
else:
valuesize = len(self.value)
return len(self.encode_hdr(boundary)) + 2 + valuesize
def encode_string(boundary, name, value):
"""Returns ``name`` and ``value`` encoded as a multipart/form-data
variable. ``boundary`` is the boundary string used throughout
a single request to separate variables."""
return MultipartParam(name, value).encode(boundary)
def encode_file_header(boundary, paramname, filesize, filename=None,
filetype=None):
"""Returns the leading data for a multipart/form-data field that contains
file data.
``boundary`` is the boundary string used throughout a single request to
separate variables.
``paramname`` is the name of the variable in this request.
``filesize`` is the size of the file data.
``filename`` if specified is the filename to give to this field. This
field is only useful to the server for determining the original filename.
``filetype`` if specified is the MIME type of this file.
The actual file data should be sent after this header has been sent.
"""
return MultipartParam(paramname, filesize=filesize, filename=filename,
filetype=filetype).encode_hdr(boundary)
def get_body_size(params, boundary):
"""Returns the number of bytes that the multipart/form-data encoding
of ``params`` will be."""
size = sum(p.get_size(boundary) for p in MultipartParam.from_params(params))
return size + len(boundary) + 6
def get_headers(params, boundary):
"""Returns a dictionary with Content-Type and Content-Length headers
for the multipart/form-data encoding of ``params``."""
headers = {}
boundary = urllib.quote_plus(boundary)
headers['Content-Type'] = "multipart/form-data; boundary=%s" % boundary
headers['Content-Length'] = str(get_body_size(params, boundary))
return headers
class multipart_yielder:
def __init__(self, params, boundary, cb):
self.params = params
self.boundary = boundary
self.cb = cb
self.i = 0
self.p = None
self.param_iter = None
self.current = 0
self.total = get_body_size(params, boundary)
def __iter__(self):
return self
def next(self):
"""generator function to yield multipart/form-data representation
of parameters"""
if self.param_iter is not None:
try:
block = self.param_iter.next()
self.current += len(block)
if self.cb:
self.cb(self.p, self.current, self.total)
return block
except StopIteration:
self.p = None
self.param_iter = None
if self.i is None:
raise StopIteration
elif self.i >= len(self.params):
self.param_iter = None
self.p = None
self.i = None
block = "--%s--\r\n" % self.boundary
self.current += len(block)
if self.cb:
self.cb(self.p, self.current, self.total)
return block
self.p = self.params[self.i]
self.param_iter = self.p.iter_encode(self.boundary)
self.i += 1
return self.next()
def reset(self):
self.i = 0
self.current = 0
for param in self.params:
param.reset()
def multipart_encode(params, boundary=None, cb=None):
"""Encode ``params`` as multipart/form-data.
``params`` should be a sequence of (name, value) pairs or MultipartParam
objects, or a mapping of names to values.
Values are either strings parameter values, or file-like objects to use as
the parameter value. The file-like objects must support .read() and either
.fileno() or both .seek() and .tell().
If ``boundary`` is set, then it as used as the MIME boundary. Otherwise
a randomly generated boundary will be used. In either case, if the
boundary string appears in the parameter values a ValueError will be
raised.
If ``cb`` is set, it should be a callback which will get called as blocks
of data are encoded. It will be called with (param, current, total),
indicating the current parameter being encoded, the current amount encoded,
and the total amount to encode.
Returns a tuple of `datagen`, `headers`, where `datagen` is a
generator that will yield blocks of data that make up the encoded
parameters, and `headers` is a dictionary with the assoicated
Content-Type and Content-Length headers.
Examples:
>>> datagen, headers = multipart_encode( [("key", "value1"), ("key", "value2")] )
>>> s = "".join(datagen)
>>> assert "value2" in s and "value1" in s
>>> p = MultipartParam("key", "value2")
>>> datagen, headers = multipart_encode( [("key", "value1"), p] )
>>> s = "".join(datagen)
>>> assert "value2" in s and "value1" in s
>>> datagen, headers = multipart_encode( {"key": "value1"} )
>>> s = "".join(datagen)
>>> assert "value2" not in s and "value1" in s
"""
if boundary is None:
boundary = gen_boundary()
else:
boundary = urllib.quote_plus(boundary)
headers = get_headers(params, boundary)
params = MultipartParam.from_params(params)
return multipart_yielder(params, boundary, cb), headers

View File

@@ -1,197 +0,0 @@
"""Streaming HTTP uploads module.
This module extends the standard httplib and urllib2 objects so that
iterable objects can be used in the body of HTTP requests.
In most cases all one should have to do is call :func:`register_openers()`
to register the new streaming http handlers which will take priority over
the default handlers, and then you can use iterable objects in the body
of HTTP requests.
**N.B.** You must specify a Content-Length header if using an iterable object
since there is no way to determine in advance the total size that will be
yielded, and there is no way to reset an interator.
Example usage:
>>> from StringIO import StringIO
>>> import urllib2, poster.streaminghttp
>>> opener = poster.streaminghttp.register_openers()
>>> s = "Test file data"
>>> f = StringIO(s)
>>> req = urllib2.Request("http://localhost:5000", f,
... {'Content-Length': str(len(s))})
"""
import httplib, urllib2, socket
from httplib import NotConnected
__all__ = ['StreamingHTTPConnection', 'StreamingHTTPRedirectHandler',
'StreamingHTTPHandler', 'register_openers']
if hasattr(httplib, 'HTTPS'):
__all__.extend(['StreamingHTTPSHandler', 'StreamingHTTPSConnection'])
class _StreamingHTTPMixin:
"""Mixin class for HTTP and HTTPS connections that implements a streaming
send method."""
def send(self, value):
"""Send ``value`` to the server.
``value`` can be a string object, a file-like object that supports
a .read() method, or an iterable object that supports a .next()
method.
"""
# Based on python 2.6's httplib.HTTPConnection.send()
if self.sock is None:
if self.auto_open:
self.connect()
else:
raise NotConnected()
# send the data to the server. if we get a broken pipe, then close
# the socket. we want to reconnect when somebody tries to send again.
#
# NOTE: we DO propagate the error, though, because we cannot simply
# ignore the error... the caller will know if they can retry.
if self.debuglevel > 0:
print "send:", repr(value)
try:
blocksize = 8192
if hasattr(value, 'read') :
if hasattr(value, 'seek'):
value.seek(0)
if self.debuglevel > 0:
print "sendIng a read()able"
data = value.read(blocksize)
while data:
self.sock.sendall(data)
data = value.read(blocksize)
elif hasattr(value, 'next'):
if hasattr(value, 'reset'):
value.reset()
if self.debuglevel > 0:
print "sendIng an iterable"
for data in value:
self.sock.sendall(data)
else:
self.sock.sendall(value)
except socket.error, v:
if v[0] == 32: # Broken pipe
self.close()
raise
class StreamingHTTPConnection(_StreamingHTTPMixin, httplib.HTTPConnection):
"""Subclass of `httplib.HTTPConnection` that overrides the `send()` method
to support iterable body objects"""
class StreamingHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
"""Subclass of `urllib2.HTTPRedirectHandler` that overrides the
`redirect_request` method to properly handle redirected POST requests
This class is required because python 2.5's HTTPRedirectHandler does
not remove the Content-Type or Content-Length headers when requesting
the new resource, but the body of the original request is not preserved.
"""
handler_order = urllib2.HTTPRedirectHandler.handler_order - 1
# From python2.6 urllib2's HTTPRedirectHandler
def redirect_request(self, req, fp, code, msg, headers, newurl):
"""Return a Request or None in response to a redirect.
This is called by the http_error_30x methods when a
redirection response is received. If a redirection should
take place, return a new Request to allow http_error_30x to
perform the redirect. Otherwise, raise HTTPError if no-one
else should try to handle this url. Return None if you can't
but another Handler might.
"""
m = req.get_method()
if (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
or code in (301, 302, 303) and m == "POST"):
# Strictly (according to RFC 2616), 301 or 302 in response
# to a POST MUST NOT cause a redirection without confirmation
# from the user (of urllib2, in this case). In practice,
# essentially all clients do redirect in this case, so we
# do the same.
# be conciliant with URIs containing a space
newurl = newurl.replace(' ', '%20')
newheaders = dict((k, v) for k, v in req.headers.items()
if k.lower() not in (
"content-length", "content-type")
)
return urllib2.Request(newurl,
headers=newheaders,
origin_req_host=req.get_origin_req_host(),
unverifiable=True)
else:
raise urllib2.HTTPError(req.get_full_url(), code, msg, headers, fp)
class StreamingHTTPHandler(urllib2.HTTPHandler):
"""Subclass of `urllib2.HTTPHandler` that uses
StreamingHTTPConnection as its http connection class."""
handler_order = urllib2.HTTPHandler.handler_order - 1
def http_open(self, req):
"""Open a StreamingHTTPConnection for the given request"""
return self.do_open(StreamingHTTPConnection, req)
def http_request(self, req):
"""Handle a HTTP request. Make sure that Content-Length is specified
if we're using an interable value"""
# Make sure that if we're using an iterable object as the request
# body, that we've also specified Content-Length
if req.has_data():
data = req.get_data()
if hasattr(data, 'read') or hasattr(data, 'next'):
if not req.has_header('Content-length'):
raise ValueError(
"No Content-Length specified for iterable body")
return urllib2.HTTPHandler.do_request_(self, req)
if hasattr(httplib, 'HTTPS'):
class StreamingHTTPSConnection(_StreamingHTTPMixin,
httplib.HTTPSConnection):
"""Subclass of `httplib.HTTSConnection` that overrides the `send()`
method to support iterable body objects"""
class StreamingHTTPSHandler(urllib2.HTTPSHandler):
"""Subclass of `urllib2.HTTPSHandler` that uses
StreamingHTTPSConnection as its http connection class."""
handler_order = urllib2.HTTPSHandler.handler_order - 1
def https_open(self, req):
return self.do_open(StreamingHTTPSConnection, req)
def https_request(self, req):
# Make sure that if we're using an iterable object as the request
# body, that we've also specified Content-Length
if req.has_data():
data = req.get_data()
if hasattr(data, 'read') or hasattr(data, 'next'):
if not req.has_header('Content-length'):
raise ValueError(
"No Content-Length specified for iterable body")
return urllib2.HTTPSHandler.do_request_(self, req)
def register_openers():
"""Register the streaming http handlers in the global urllib2 default
opener object.
Returns the created OpenerDirector object."""
handlers = [StreamingHTTPHandler, StreamingHTTPRedirectHandler]
if hasattr(httplib, "HTTPS"):
handlers.append(StreamingHTTPSHandler)
opener = urllib2.build_opener(*handlers)
urllib2.install_opener(opener)
return opener

View File

@@ -0,0 +1,42 @@
# urllib3/__init__.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""
urllib3 - Thread-safe connection pooling and re-using.
"""
__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)'
__license__ = 'MIT'
__version__ = 'dev'
from .connectionpool import (
HTTPConnectionPool,
HTTPSConnectionPool,
connection_from_url
)
from . import exceptions
from .filepost import encode_multipart_formdata
from .poolmanager import PoolManager, ProxyManager, proxy_from_url
from .response import HTTPResponse
from .util import make_headers, get_host
# Set default logging handler to avoid "No handler found" warnings.
import logging
try:
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
logging.getLogger(__name__).addHandler(NullHandler())
# ... Clean up.
del logging
del NullHandler

View File

@@ -0,0 +1,131 @@
# urllib3/_collections.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from collections import deque
from threading import RLock
__all__ = ['RecentlyUsedContainer']
class AccessEntry(object):
__slots__ = ('key', 'is_valid')
def __init__(self, key, is_valid=True):
self.key = key
self.is_valid = is_valid
class RecentlyUsedContainer(dict):
"""
Provides a dict-like that maintains up to ``maxsize`` keys while throwing
away the least-recently-used keys beyond ``maxsize``.
"""
# If len(self.access_log) exceeds self._maxsize * CLEANUP_FACTOR, then we
# will attempt to cleanup the invalidated entries in the access_log
# datastructure during the next 'get' operation.
CLEANUP_FACTOR = 10
def __init__(self, maxsize=10):
self._maxsize = maxsize
self._container = {}
# We use a deque to to store our keys ordered by the last access.
self.access_log = deque()
self.access_log_lock = RLock()
# We look up the access log entry by the key to invalidate it so we can
# insert a new authorative entry at the head without having to dig and
# find the old entry for removal immediately.
self.access_lookup = {}
# Trigger a heap cleanup when we get past this size
self.access_log_limit = maxsize * self.CLEANUP_FACTOR
def _invalidate_entry(self, key):
"If exists: Invalidate old entry and return it."
old_entry = self.access_lookup.get(key)
if old_entry:
old_entry.is_valid = False
return old_entry
def _push_entry(self, key):
"Push entry onto our access log, invalidate the old entry if exists."
self._invalidate_entry(key)
new_entry = AccessEntry(key)
self.access_lookup[key] = new_entry
self.access_log_lock.acquire()
self.access_log.appendleft(new_entry)
self.access_log_lock.release()
def _prune_entries(self, num):
"Pop entries from our access log until we popped ``num`` valid ones."
while num > 0:
self.access_log_lock.acquire()
p = self.access_log.pop()
self.access_log_lock.release()
if not p.is_valid:
continue # Invalidated entry, skip
dict.pop(self, p.key, None)
self.access_lookup.pop(p.key, None)
num -= 1
def _prune_invalidated_entries(self):
"Rebuild our access_log without the invalidated entries."
self.access_log_lock.acquire()
self.access_log = deque(e for e in self.access_log if e.is_valid)
self.access_log_lock.release()
def _get_ordered_access_keys(self):
"Return ordered access keys for inspection. Used for testing."
self.access_log_lock.acquire()
r = [e.key for e in self.access_log if e.is_valid]
self.access_log_lock.release()
return r
def __getitem__(self, key):
item = dict.get(self, key)
if not item:
raise KeyError(key)
# Insert new entry with new high priority, also implicitly invalidates
# the old entry.
self._push_entry(key)
if len(self.access_log) > self.access_log_limit:
# Heap is getting too big, try to clean up any tailing invalidated
# entries.
self._prune_invalidated_entries()
return item
def __setitem__(self, key, item):
# Add item to our container and access log
dict.__setitem__(self, key, item)
self._push_entry(key)
# Discard invalid and excess entries
self._prune_entries(len(self) - self._maxsize)
def __delitem__(self, key):
self._invalidate_entry(key)
self.access_lookup.pop(key, None)
dict.__delitem__(self, key)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default

View File

@@ -0,0 +1,522 @@
# urllib3/connectionpool.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
import logging
import socket
from socket import error as SocketError, timeout as SocketTimeout
try: # Python 3
from http.client import HTTPConnection, HTTPException
from http.client import HTTP_PORT, HTTPS_PORT
except ImportError:
from httplib import HTTPConnection, HTTPException
from httplib import HTTP_PORT, HTTPS_PORT
try: # Python 3
from queue import LifoQueue, Empty, Full
except ImportError:
from Queue import LifoQueue, Empty, Full
try: # Compiled with SSL?
HTTPSConnection = object
BaseSSLError = None
ssl = None
try: # Python 3
from http.client import HTTPSConnection
except ImportError:
from httplib import HTTPSConnection
import ssl
BaseSSLError = ssl.SSLError
except (ImportError, AttributeError):
pass
from .request import RequestMethods
from .response import HTTPResponse
from .util import get_host, is_connection_dropped
from .exceptions import (
EmptyPoolError,
HostChangedError,
MaxRetryError,
SSLError,
TimeoutError,
)
from .packages.ssl_match_hostname import match_hostname, CertificateError
from .packages import six
xrange = six.moves.xrange
log = logging.getLogger(__name__)
_Default = object()
port_by_scheme = {
'http': HTTP_PORT,
'https': HTTPS_PORT,
}
## Connection objects (extension of httplib)
class VerifiedHTTPSConnection(HTTPSConnection):
"""
Based on httplib.HTTPSConnection but wraps the socket with
SSL certification.
"""
cert_reqs = None
ca_certs = None
def set_cert(self, key_file=None, cert_file=None,
cert_reqs='CERT_NONE', ca_certs=None):
ssl_req_scheme = {
'CERT_NONE': ssl.CERT_NONE,
'CERT_OPTIONAL': ssl.CERT_OPTIONAL,
'CERT_REQUIRED': ssl.CERT_REQUIRED
}
self.key_file = key_file
self.cert_file = cert_file
self.cert_reqs = ssl_req_scheme.get(cert_reqs) or ssl.CERT_NONE
self.ca_certs = ca_certs
def connect(self):
# Add certificate verification
sock = socket.create_connection((self.host, self.port), self.timeout)
# Wrap socket using verification with the root certs in
# trusted_root_certs
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=self.cert_reqs,
ca_certs=self.ca_certs)
if self.ca_certs:
match_hostname(self.sock.getpeercert(), self.host)
## Pool objects
class ConnectionPool(object):
"""
Base class for all connection pools, such as
:class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
"""
scheme = None
QueueCls = LifoQueue
def __init__(self, host, port=None):
self.host = host
self.port = port
def __str__(self):
return '%s(host=%r, port=%r)' % (type(self).__name__,
self.host, self.port)
class HTTPConnectionPool(ConnectionPool, RequestMethods):
"""
Thread-safe connection pool for one host.
:param host:
Host used for this HTTP Connection (e.g. "localhost"), passed into
:class:`httplib.HTTPConnection`.
:param port:
Port used for this HTTP Connection (None is equivalent to 80), passed
into :class:`httplib.HTTPConnection`.
:param strict:
Causes BadStatusLine to be raised if the status line can't be parsed
as a valid HTTP/1.0 or 1.1 status line, passed into
:class:`httplib.HTTPConnection`.
:param timeout:
Socket timeout for each individual connection, can be a float. None
disables timeout.
:param maxsize:
Number of connections to save that can be reused. More than 1 is useful
in multithreaded situations. If ``block`` is set to false, more
connections will be created but they will not be saved once they've
been used.
:param block:
If set to True, no more than ``maxsize`` connections will be used at
a time. When no free connections are available, the call will block
until a connection has been released. This is a useful side effect for
particular multithreaded situations where one does not want to use more
than maxsize connections per host to prevent flooding.
:param headers:
Headers to include with all requests, unless other headers are given
explicitly.
"""
scheme = 'http'
def __init__(self, host, port=None, strict=False, timeout=None, maxsize=1,
block=False, headers=None):
super(HTTPConnectionPool, self).__init__(host, port)
self.strict = strict
self.timeout = timeout
self.pool = self.QueueCls(maxsize)
self.block = block
self.headers = headers or {}
# Fill the queue up so that doing get() on it will block properly
for _ in xrange(maxsize):
self.pool.put(None)
# These are mostly for testing and debugging purposes.
self.num_connections = 0
self.num_requests = 0
def _new_conn(self):
"""
Return a fresh :class:`httplib.HTTPConnection`.
"""
self.num_connections += 1
log.info("Starting new HTTP connection (%d): %s" %
(self.num_connections, self.host))
return HTTPConnection(host=self.host, port=self.port)
def _get_conn(self, timeout=None):
"""
Get a connection. Will return a pooled connection if one is available.
If no connections are available and :prop:`.block` is ``False``, then a
fresh connection is returned.
:param timeout:
Seconds to wait before giving up and raising
:class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and
:prop:`.block` is ``True``.
"""
conn = None
try:
conn = self.pool.get(block=self.block, timeout=timeout)
# If this is a persistent connection, check if it got disconnected
if conn and is_connection_dropped(conn):
log.info("Resetting dropped connection: %s" % self.host)
conn.close()
except Empty:
if self.block:
raise EmptyPoolError(self,
"Pool reached maximum size and no more "
"connections are allowed.")
pass # Oh well, we'll create a new connection then
return conn or self._new_conn()
def _put_conn(self, conn):
"""
Put a connection back into the pool.
:param conn:
Connection object for the current host and port as returned by
:meth:`._new_conn` or :meth:`._get_conn`.
If the pool is already full, the connection is discarded because we
exceeded maxsize. If connections are discarded frequently, then maxsize
should be increased.
"""
try:
self.pool.put(conn, block=False)
except Full:
# This should never happen if self.block == True
log.warning("HttpConnectionPool is full, discarding connection: %s"
% self.host)
def _make_request(self, conn, method, url, timeout=_Default,
**httplib_request_kw):
"""
Perform a request on a given httplib connection object taken from our
pool.
"""
self.num_requests += 1
if timeout is _Default:
timeout = self.timeout
conn.timeout = timeout # This only does anything in Py26+
conn.request(method, url, **httplib_request_kw)
# Set timeout
sock = getattr(conn, 'sock', False) # AppEngine doesn't have sock attr.
if sock:
sock.settimeout(timeout)
httplib_response = conn.getresponse()
# AppEngine doesn't have a version attr.
http_version = getattr(conn, '_http_vsn_str', 'HTTP/?'),
log.debug("\"%s %s %s\" %s %s" % (method, url, http_version,
httplib_response.status,
httplib_response.length))
return httplib_response
def is_same_host(self, url):
"""
Check if the given ``url`` is a member of the same host as this
connection pool.
"""
# TODO: Add optional support for socket.gethostbyname checking.
scheme, host, port = get_host(url)
if self.port and not port:
# Use explicit default port for comparison when none is given.
port = port_by_scheme.get(scheme)
return (url.startswith('/') or
(scheme, host, port) == (self.scheme, self.host, self.port))
def urlopen(self, method, url, body=None, headers=None, retries=3,
redirect=True, assert_same_host=True, timeout=_Default,
pool_timeout=None, release_conn=None, **response_kw):
"""
Get a connection from the pool and perform an HTTP request. This is the
lowest level call for making a request, so you'll need to specify all
the raw details.
.. note::
More commonly, it's appropriate to use a convenience method provided
by :class:`.RequestMethods`, such as :meth:`request`.
.. note::
`release_conn` will only behave as expected if
`preload_content=False` because we want to make
`preload_content=False` the default behaviour someday soon without
breaking backwards compatibility.
:param method:
HTTP request method (such as GET, POST, PUT, etc.)
:param body:
Data to send in the request body (useful for creating
POST requests, see HTTPConnectionPool.post_url for
more convenience).
:param headers:
Dictionary of custom headers to send, such as User-Agent,
If-None-Match, etc. If None, pool headers are used. If provided,
these headers completely replace any pool-specific headers.
:param retries:
Number of retries to allow before raising a MaxRetryError exception.
:param redirect:
Automatically handle redirects (status codes 301, 302, 303, 307),
each redirect counts as a retry.
:param assert_same_host:
If ``True``, will make sure that the host of the pool requests is
consistent else will raise HostChangedError. When False, you can
use the pool on an HTTP proxy and request foreign hosts.
:param timeout:
If specified, overrides the default timeout for this one request.
:param pool_timeout:
If set and the pool is set to block=True, then this method will
block for ``pool_timeout`` seconds and raise EmptyPoolError if no
connection is available within the time period.
:param release_conn:
If False, then the urlopen call will not release the connection
back into the pool once a response is received (but will release if
you read the entire contents of the response such as when
`preload_content=True`). This is useful if you're not preloading
the response's content immediately. You will need to call
``r.release_conn()`` on the response ``r`` to return the connection
back into the pool. If None, it takes the value of
``response_kw.get('preload_content', True)``.
:param \**response_kw:
Additional parameters are passed to
:meth:`urllib3.response.HTTPResponse.from_httplib`
"""
if headers is None:
headers = self.headers
if retries < 0:
raise MaxRetryError(self, url)
if timeout is _Default:
timeout = self.timeout
if release_conn is None:
release_conn = response_kw.get('preload_content', True)
# Check host
if assert_same_host and not self.is_same_host(url):
host = "%s://%s" % (self.scheme, self.host)
if self.port:
host = "%s:%d" % (host, self.port)
raise HostChangedError(self, url, retries - 1)
conn = None
try:
# Request a connection from the queue
# (Could raise SocketError: Bad file descriptor)
conn = self._get_conn(timeout=pool_timeout)
# Make the request on the httplib connection object
httplib_response = self._make_request(conn, method, url,
timeout=timeout,
body=body, headers=headers)
# If we're going to release the connection in ``finally:``, then
# the request doesn't need to know about the connection. Otherwise
# it will also try to release it and we'll have a double-release
# mess.
response_conn = not release_conn and conn
# Import httplib's response into our own wrapper object
response = HTTPResponse.from_httplib(httplib_response,
pool=self,
connection=response_conn,
**response_kw)
# else:
# The connection will be put back into the pool when
# ``response.release_conn()`` is called (implicitly by
# ``response.read()``)
except Empty as e:
# Timed out by queue
raise TimeoutError(self, "Request timed out. (pool_timeout=%s)" %
pool_timeout)
except SocketTimeout as e:
# Timed out by socket
raise TimeoutError(self, "Request timed out. (timeout=%s)" %
timeout)
except BaseSSLError as e:
# SSL certificate error
raise SSLError(e)
except CertificateError as e:
# Name mismatch
raise SSLError(e)
except (HTTPException, SocketError) as e:
# Connection broken, discard. It will be replaced next _get_conn().
conn = None
# This is necessary so we can access e below
err = e
finally:
if conn and release_conn:
# Put the connection back to be reused
self._put_conn(conn)
if not conn:
log.warn("Retrying (%d attempts remain) after connection "
"broken by '%r': %s" % (retries, err, url))
return self.urlopen(method, url, body, headers, retries - 1,
redirect, assert_same_host) # Try again
# Handle redirect?
redirect_location = redirect and response.get_redirect_location()
if redirect_location:
log.info("Redirecting %s -> %s" % (url, redirect_location))
return self.urlopen(method, redirect_location, body, headers,
retries - 1, redirect, assert_same_host)
return response
class HTTPSConnectionPool(HTTPConnectionPool):
"""
Same as :class:`.HTTPConnectionPool`, but HTTPS.
When Python is compiled with the :mod:`ssl` module, then
:class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates,
instead of :class:httplib.HTTPSConnection`.
The ``key_file``, ``cert_file``, ``cert_reqs``, and ``ca_certs`` parameters
are only used if :mod:`ssl` is available and are fed into
:meth:`ssl.wrap_socket` to upgrade the connection socket into an SSL socket.
"""
scheme = 'https'
def __init__(self, host, port=None,
strict=False, timeout=None, maxsize=1,
block=False, headers=None,
key_file=None, cert_file=None,
cert_reqs='CERT_NONE', ca_certs=None):
super(HTTPSConnectionPool, self).__init__(host, port,
strict, timeout, maxsize,
block, headers)
self.key_file = key_file
self.cert_file = cert_file
self.cert_reqs = cert_reqs
self.ca_certs = ca_certs
def _new_conn(self):
"""
Return a fresh :class:`httplib.HTTPSConnection`.
"""
self.num_connections += 1
log.info("Starting new HTTPS connection (%d): %s"
% (self.num_connections, self.host))
if not ssl: # Platform-specific: Python compiled without +ssl
if not HTTPSConnection or HTTPSConnection is object:
raise SSLError("Can't connect to HTTPS URL because the SSL "
"module is not available.")
return HTTPSConnection(host=self.host, port=self.port)
connection = VerifiedHTTPSConnection(host=self.host, port=self.port)
connection.set_cert(key_file=self.key_file, cert_file=self.cert_file,
cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
return connection
def connection_from_url(url, **kw):
"""
Given a url, return an :class:`.ConnectionPool` instance of its host.
This is a shortcut for not having to parse out the scheme, host, and port
of the url before creating an :class:`.ConnectionPool` instance.
:param url:
Absolute URL string that must include the scheme. Port is optional.
:param \**kw:
Passes additional parameters to the constructor of the appropriate
:class:`.ConnectionPool`. Useful for specifying things like
timeout, maxsize, headers, etc.
Example: ::
>>> conn = connection_from_url('http://google.com/')
>>> r = conn.request('GET', '/')
"""
scheme, host, port = get_host(url)
if scheme == 'https':
return HTTPSConnectionPool(host, port=port, **kw)
else:
return HTTPConnectionPool(host, port=port, **kw)

View File

@@ -0,0 +1,120 @@
# urllib3/contrib/ntlmpool.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""
NTLM authenticating pool, contributed by erikcederstran
Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10
"""
try:
from http.client import HTTPSConnection
except ImportError:
from httplib import HTTPSConnection
from logging import getLogger
from ntlm import ntlm
from urllib3 import HTTPSConnectionPool
log = getLogger(__name__)
class NTLMConnectionPool(HTTPSConnectionPool):
"""
Implements an NTLM authentication version of an urllib3 connection pool
"""
scheme = 'https'
def __init__(self, user, pw, authurl, *args, **kwargs):
"""
authurl is a random URL on the server that is protected by NTLM.
user is the Windows user, probably in the DOMAIN\username format.
pw is the password for the user.
"""
super(NTLMConnectionPool, self).__init__(*args, **kwargs)
self.authurl = authurl
self.rawuser = user
user_parts = user.split('\\', 1)
self.domain = user_parts[0].upper()
self.user = user_parts[1]
self.pw = pw
def _new_conn(self):
# Performs the NTLM handshake that secures the connection. The socket
# must be kept open while requests are performed.
self.num_connections += 1
log.debug('Starting NTLM HTTPS connection no. %d: https://%s%s' %
(self.num_connections, self.host, self.authurl))
headers = {}
headers['Connection'] = 'Keep-Alive'
req_header = 'Authorization'
resp_header = 'www-authenticate'
conn = HTTPSConnection(host=self.host, port=self.port)
# Send negotiation message
headers[req_header] = (
'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(self.rawuser))
log.debug('Request headers: %s' % headers)
conn.request('GET', self.authurl, None, headers)
res = conn.getresponse()
reshdr = dict(res.getheaders())
log.debug('Response status: %s %s' % (res.status, res.reason))
log.debug('Response headers: %s' % reshdr)
log.debug('Response data: %s [...]' % res.read(100))
# Remove the reference to the socket, so that it can not be closed by
# the response object (we want to keep the socket open)
res.fp = None
# Server should respond with a challenge message
auth_header_values = reshdr[resp_header].split(', ')
auth_header_value = None
for s in auth_header_values:
if s[:5] == 'NTLM ':
auth_header_value = s[5:]
if auth_header_value is None:
raise Exception('Unexpected %s response header: %s' %
(resp_header, reshdr[resp_header]))
# Send authentication message
ServerChallenge, NegotiateFlags = \
ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value)
auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge,
self.user,
self.domain,
self.pw,
NegotiateFlags)
headers[req_header] = 'NTLM %s' % auth_msg
log.debug('Request headers: %s' % headers)
conn.request('GET', self.authurl, None, headers)
res = conn.getresponse()
log.debug('Response status: %s %s' % (res.status, res.reason))
log.debug('Response headers: %s' % dict(res.getheaders()))
log.debug('Response data: %s [...]' % res.read()[:100])
if res.status != 200:
if res.status == 401:
raise Exception('Server rejected request: wrong '
'username or password')
raise Exception('Wrong server response: %s %s' %
(res.status, res.reason))
res.fp = None
log.debug('Connection established')
return conn
def urlopen(self, method, url, body=None, headers=None, retries=3,
redirect=True, assert_same_host=True):
if headers is None:
headers = {}
headers['Connection'] = 'Keep-Alive'
return super(NTLMConnectionPool, self).urlopen(method, url, body,
headers, retries,
redirect,
assert_same_host)

View File

@@ -0,0 +1,67 @@
# urllib3/exceptions.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
## Base Exceptions
class HTTPError(Exception):
"Base exception used by this module."
pass
class PoolError(HTTPError):
"Base exception for errors caused within a pool."
def __init__(self, pool, message):
self.pool = pool
HTTPError.__init__(self, "%s: %s" % (pool, message))
class SSLError(HTTPError):
"Raised when SSL certificate fails in an HTTPS connection."
pass
## Leaf Exceptions
class MaxRetryError(PoolError):
"Raised when the maximum number of retries is exceeded."
def __init__(self, pool, url):
message = "Max retries exceeded with url: %s" % url
PoolError.__init__(self, pool, message)
self.url = url
class HostChangedError(PoolError):
"Raised when an existing pool gets a request for a foreign host."
def __init__(self, pool, url, retries=3):
message = "Tried to open a foreign host with url: %s" % url
PoolError.__init__(self, pool, message)
self.url = url
self.retries = retries
class TimeoutError(PoolError):
"Raised when a socket timeout occurs."
pass
class EmptyPoolError(PoolError):
"Raised when a pool runs out of connections and no more are allowed."
pass
class LocationParseError(ValueError, HTTPError):
"Raised when get_host or similar fails to parse the URL input."
def __init__(self, location):
message = "Failed to parse: %s" % location
super(LocationParseError, self).__init__(self, message)
self.location = location

View File

@@ -0,0 +1,88 @@
# urllib3/filepost.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
import codecs
import mimetypes
try:
from mimetools import choose_boundary
except ImportError:
from .packages.mimetools_choose_boundary import choose_boundary
from io import BytesIO
from .packages import six
from .packages.six import b
writer = codecs.lookup('utf-8')[3]
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
def iter_fields(fields):
"""
Iterate over fields.
Supports list of (k, v) tuples and dicts.
"""
if isinstance(fields, dict):
return ((k, v) for k, v in six.iteritems(fields))
return ((k, v) for k, v in fields)
def encode_multipart_formdata(fields, boundary=None):
"""
Encode a dictionary of ``fields`` using the multipart/form-data mime format.
:param fields:
Dictionary of fields or list of (key, value) field tuples. The key is
treated as the field name, and the value as the body of the form-data
bytes. If the value is a tuple of two elements, then the first element
is treated as the filename of the form-data section.
Field names and filenames must be unicode.
:param boundary:
If not specified, then a random boundary will be generated using
:func:`mimetools.choose_boundary`.
"""
body = BytesIO()
if boundary is None:
boundary = choose_boundary()
for fieldname, value in iter_fields(fields):
body.write(b('--%s\r\n' % (boundary)))
if isinstance(value, tuple):
filename, data = value
writer(body).write('Content-Disposition: form-data; name="%s"; '
'filename="%s"\r\n' % (fieldname, filename))
body.write(b('Content-Type: %s\r\n\r\n' %
(get_content_type(filename))))
else:
data = value
writer(body).write('Content-Disposition: form-data; name="%s"\r\n'
% (fieldname))
body.write(b'Content-Type: text/plain\r\n\r\n')
if isinstance(data, int):
data = str(data) # Backwards compatibility
if isinstance(data, six.text_type):
writer(body).write(data)
else:
body.write(data)
body.write(b'\r\n')
body.write(b('--%s--\r\n' % (boundary)))
content_type = b('multipart/form-data; boundary=%s' % boundary)
return body.getvalue(), content_type

View File

@@ -0,0 +1,4 @@
from __future__ import absolute_import
from . import ssl_match_hostname

View File

@@ -0,0 +1,47 @@
"""The function mimetools.choose_boundary() from Python 2.7, which seems to
have disappeared in Python 3 (although email.generator._make_boundary() might
work as a replacement?).
Tweaked to use lock from threading rather than thread.
"""
import os
from threading import Lock
_counter_lock = Lock()
_counter = 0
def _get_next_counter():
global _counter
with _counter_lock:
_counter += 1
return _counter
_prefix = None
def choose_boundary():
"""Return a string usable as a multipart boundary.
The string chosen is unique within a single program run, and
incorporates the user id (if available), process id (if available),
and current time. So it's very unlikely the returned string appears
in message text, but there's no guarantee.
The boundary contains dots so you have to quote it in the header."""
global _prefix
import time
if _prefix is None:
import socket
try:
hostid = socket.gethostbyname(socket.gethostname())
except socket.gaierror:
hostid = '127.0.0.1'
try:
uid = repr(os.getuid())
except AttributeError:
uid = '1'
try:
pid = repr(os.getpid())
except AttributeError:
pid = '1'
_prefix = hostid + '.' + uid + '.' + pid
return "%s.%.3f.%d" % (_prefix, time.time(), _get_next_counter())

View File

@@ -0,0 +1,372 @@
"""Utilities for writing code that runs on Python 2 and 3"""
#Copyright (c) 2010-2011 Benjamin Peterson
#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.
import operator
import sys
import types
__author__ = "Benjamin Peterson <benjamin@python.org>"
__version__ = "1.1.0"
# True if we are running on Python 3.
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str,
integer_types = int,
class_types = type,
text_type = str
binary_type = bytes
MAXSIZE = sys.maxsize
else:
string_types = basestring,
integer_types = (int, long)
class_types = (type, types.ClassType)
text_type = unicode
binary_type = str
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
class X(object):
def __len__(self):
return 1 << 31
try:
len(X())
except OverflowError:
# 32-bit
MAXSIZE = int((1 << 31) - 1)
else:
# 64-bit
MAXSIZE = int((1 << 63) - 1)
del X
def _add_doc(func, doc):
"""Add documentation to a function."""
func.__doc__ = doc
def _import_module(name):
"""Import module, returning the module after the last dot."""
__import__(name)
return sys.modules[name]
class _LazyDescr(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, tp):
result = self._resolve()
setattr(obj, self.name, result)
# This is a bit ugly, but it avoids running this again.
delattr(tp, self.name)
return result
class MovedModule(_LazyDescr):
def __init__(self, name, old, new=None):
super(MovedModule, self).__init__(name)
if PY3:
if new is None:
new = name
self.mod = new
else:
self.mod = old
def _resolve(self):
return _import_module(self.mod)
class MovedAttribute(_LazyDescr):
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
super(MovedAttribute, self).__init__(name)
if PY3:
if new_mod is None:
new_mod = name
self.mod = new_mod
if new_attr is None:
if old_attr is None:
new_attr = name
else:
new_attr = old_attr
self.attr = new_attr
else:
self.mod = old_mod
if old_attr is None:
old_attr = name
self.attr = old_attr
def _resolve(self):
module = _import_module(self.mod)
return getattr(module, self.attr)
class _MovedItems(types.ModuleType):
"""Lazy loading of moved objects"""
_moved_attributes = [
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
MovedAttribute("reduce", "__builtin__", "functools"),
MovedAttribute("StringIO", "StringIO", "io"),
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
MovedModule("copyreg", "copy_reg"),
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
MovedModule("http_cookies", "Cookie", "http.cookies"),
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
MovedModule("html_parser", "HTMLParser", "html.parser"),
MovedModule("http_client", "httplib", "http.client"),
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
MovedModule("cPickle", "cPickle", "pickle"),
MovedModule("queue", "Queue"),
MovedModule("reprlib", "repr"),
MovedModule("socketserver", "SocketServer"),
MovedModule("tkinter", "Tkinter"),
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
MovedModule("tkinter_colorchooser", "tkColorChooser",
"tkinter.colorchooser"),
MovedModule("tkinter_commondialog", "tkCommonDialog",
"tkinter.commondialog"),
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
"tkinter.simpledialog"),
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
MovedModule("winreg", "_winreg"),
]
for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr)
del attr
moves = sys.modules["six.moves"] = _MovedItems("moves")
def add_move(move):
"""Add an item to six.moves."""
setattr(_MovedItems, move.name, move)
def remove_move(name):
"""Remove item from six.moves."""
try:
delattr(_MovedItems, name)
except AttributeError:
try:
del moves.__dict__[name]
except KeyError:
raise AttributeError("no such move, %r" % (name,))
if PY3:
_meth_func = "__func__"
_meth_self = "__self__"
_func_code = "__code__"
_func_defaults = "__defaults__"
_iterkeys = "keys"
_itervalues = "values"
_iteritems = "items"
else:
_meth_func = "im_func"
_meth_self = "im_self"
_func_code = "func_code"
_func_defaults = "func_defaults"
_iterkeys = "iterkeys"
_itervalues = "itervalues"
_iteritems = "iteritems"
if PY3:
def get_unbound_function(unbound):
return unbound
advance_iterator = next
def callable(obj):
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
else:
def get_unbound_function(unbound):
return unbound.im_func
def advance_iterator(it):
return it.next()
callable = callable
_add_doc(get_unbound_function,
"""Get the function out of a possibly unbound function""")
get_method_function = operator.attrgetter(_meth_func)
get_method_self = operator.attrgetter(_meth_self)
get_function_code = operator.attrgetter(_func_code)
get_function_defaults = operator.attrgetter(_func_defaults)
def iterkeys(d):
"""Return an iterator over the keys of a dictionary."""
return getattr(d, _iterkeys)()
def itervalues(d):
"""Return an iterator over the values of a dictionary."""
return getattr(d, _itervalues)()
def iteritems(d):
"""Return an iterator over the (key, value) pairs of a dictionary."""
return getattr(d, _iteritems)()
if PY3:
def b(s):
return s.encode("latin-1")
def u(s):
return s
if sys.version_info[1] <= 1:
def int2byte(i):
return bytes((i,))
else:
# This is about 2x faster than the implementation above on 3.2+
int2byte = operator.methodcaller("to_bytes", 1, "big")
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
else:
def b(s):
return s
def u(s):
return unicode(s, "unicode_escape")
int2byte = chr
import StringIO
StringIO = BytesIO = StringIO.StringIO
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")
if PY3:
import builtins
exec_ = getattr(builtins, "exec")
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
print_ = getattr(builtins, "print")
del builtins
else:
def exec_(code, globs=None, locs=None):
"""Execute code in a namespace."""
if globs is None:
frame = sys._getframe(1)
globs = frame.f_globals
if locs is None:
locs = frame.f_locals
del frame
elif locs is None:
locs = globs
exec("""exec code in globs, locs""")
exec_("""def reraise(tp, value, tb=None):
raise tp, value, tb
""")
def print_(*args, **kwargs):
"""The new-style print function."""
fp = kwargs.pop("file", sys.stdout)
if fp is None:
return
def write(data):
if not isinstance(data, basestring):
data = str(data)
fp.write(data)
want_unicode = False
sep = kwargs.pop("sep", None)
if sep is not None:
if isinstance(sep, unicode):
want_unicode = True
elif not isinstance(sep, str):
raise TypeError("sep must be None or a string")
end = kwargs.pop("end", None)
if end is not None:
if isinstance(end, unicode):
want_unicode = True
elif not isinstance(end, str):
raise TypeError("end must be None or a string")
if kwargs:
raise TypeError("invalid keyword arguments to print()")
if not want_unicode:
for arg in args:
if isinstance(arg, unicode):
want_unicode = True
break
if want_unicode:
newline = unicode("\n")
space = unicode(" ")
else:
newline = "\n"
space = " "
if sep is None:
sep = space
if end is None:
end = newline
for i, arg in enumerate(args):
if i:
write(sep)
write(arg)
write(end)
_add_doc(reraise, """Reraise an exception.""")
def with_metaclass(meta, base=object):
"""Create a base class with a metaclass."""
return meta("NewBase", (base,), {})

View File

@@ -0,0 +1,61 @@
"""The match_hostname() function from Python 3.2, essential when using SSL."""
import re
__version__ = '3.2.2'
class CertificateError(ValueError):
pass
def _dnsname_to_pat(dn):
pats = []
for frag in dn.split(r'.'):
if frag == '*':
# When '*' is a fragment by itself, it matches a non-empty dotless
# fragment.
pats.append('[^.]+')
else:
# Otherwise, '*' matches any dotless fragment.
frag = re.escape(frag)
pats.append(frag.replace(r'\*', '[^.]*'))
return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
def match_hostname(cert, hostname):
"""Verify that *cert* (in decoded format as returned by
SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules
are mostly followed, but IP addresses are not accepted for *hostname*.
CertificateError is raised on failure. On success, the function
returns nothing.
"""
if not cert:
raise ValueError("empty or no certificate")
dnsnames = []
san = cert.get('subjectAltName', ())
for key, value in san:
if key == 'DNS':
if _dnsname_to_pat(value).match(hostname):
return
dnsnames.append(value)
if not dnsnames:
# The subject is only checked when there is no dNSName entry
# in subjectAltName
for sub in cert.get('subject', ()):
for key, value in sub:
# XXX according to RFC 2818, the most specific Common Name
# must be used.
if key == 'commonName':
if _dnsname_to_pat(value).match(hostname):
return
dnsnames.append(value)
if len(dnsnames) > 1:
raise CertificateError("hostname %r "
"doesn't match either of %s"
% (hostname, ', '.join(map(repr, dnsnames))))
elif len(dnsnames) == 1:
raise CertificateError("hostname %r "
"doesn't match %r"
% (hostname, dnsnames[0]))
else:
raise CertificateError("no appropriate commonName or "
"subjectAltName fields were found")

View File

@@ -0,0 +1,138 @@
# urllib3/poolmanager.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
import logging
from ._collections import RecentlyUsedContainer
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool
from .connectionpool import get_host, connection_from_url, port_by_scheme
from .exceptions import HostChangedError
from .request import RequestMethods
__all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url']
pool_classes_by_scheme = {
'http': HTTPConnectionPool,
'https': HTTPSConnectionPool,
}
log = logging.getLogger(__name__)
class PoolManager(RequestMethods):
"""
Allows for arbitrary requests while transparently keeping track of
necessary connection pools for you.
:param num_pools:
Number of connection pools to cache before discarding the least recently
used pool.
:param \**connection_pool_kw:
Additional parameters are used to create fresh
:class:`urllib3.connectionpool.ConnectionPool` instances.
Example: ::
>>> manager = PoolManager(num_pools=2)
>>> r = manager.urlopen("http://google.com/")
>>> r = manager.urlopen("http://google.com/mail")
>>> r = manager.urlopen("http://yahoo.com/")
>>> len(manager.pools)
2
"""
# TODO: Make sure there are no memory leaks here.
def __init__(self, num_pools=10, **connection_pool_kw):
self.connection_pool_kw = connection_pool_kw
self.pools = RecentlyUsedContainer(num_pools)
def connection_from_host(self, host, port=80, scheme='http'):
"""
Get a :class:`ConnectionPool` based on the host, port, and scheme.
Note that an appropriate ``port`` value is required here to normalize
connection pools in our container most effectively.
"""
pool_key = (scheme, host, port)
# If the scheme, host, or port doesn't match existing open connections,
# open a new ConnectionPool.
pool = self.pools.get(pool_key)
if pool:
return pool
# Make a fresh ConnectionPool of the desired type
pool_cls = pool_classes_by_scheme[scheme]
pool = pool_cls(host, port, **self.connection_pool_kw)
self.pools[pool_key] = pool
return pool
def connection_from_url(self, url):
"""
Similar to :func:`urllib3.connectionpool.connection_from_url` but
doesn't pass any additional parameters to the
:class:`urllib3.connectionpool.ConnectionPool` constructor.
Additional parameters are taken from the :class:`.PoolManager`
constructor.
"""
scheme, host, port = get_host(url)
port = port or port_by_scheme.get(scheme, 80)
return self.connection_from_host(host, port=port, scheme=scheme)
def urlopen(self, method, url, **kw):
"""
Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen`.
``url`` must be absolute, such that an appropriate
:class:`urllib3.connectionpool.ConnectionPool` can be chosen for it.
"""
conn = self.connection_from_url(url)
try:
return conn.urlopen(method, url, **kw)
except HostChangedError as e:
kw['retries'] = e.retries # Persist retries countdown
return self.urlopen(method, e.url, **kw)
class ProxyManager(RequestMethods):
"""
Given a ConnectionPool to a proxy, the ProxyManager's ``urlopen`` method
will make requests to any url through the defined proxy.
"""
def __init__(self, proxy_pool):
self.proxy_pool = proxy_pool
def _set_proxy_headers(self, headers=None):
headers = headers or {}
# Same headers are curl passes for --proxy1.0
headers['Accept'] = '*/*'
headers['Proxy-Connection'] = 'Keep-Alive'
return headers
def urlopen(self, method, url, **kw):
"Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute."
kw['assert_same_host'] = False
kw['headers'] = self._set_proxy_headers(kw.get('headers'))
return self.proxy_pool.urlopen(method, url, **kw)
def proxy_from_url(url, **pool_kw):
proxy_pool = connection_from_url(url, **pool_kw)
return ProxyManager(proxy_pool)

View File

@@ -0,0 +1,128 @@
# urllib3/request.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
try:
from urllib.parse import urlencode
except ImportError:
from urllib import urlencode
from .filepost import encode_multipart_formdata
__all__ = ['RequestMethods']
class RequestMethods(object):
"""
Convenience mixin for classes who implement a :meth:`urlopen` method, such
as :class:`~urllib3.connectionpool.HTTPConnectionPool` and
:class:`~urllib3.poolmanager.PoolManager`.
Provides behavior for making common types of HTTP request methods and
decides which type of request field encoding to use.
Specifically,
:meth:`.request_encode_url` is for sending requests whose fields are encoded
in the URL (such as GET, HEAD, DELETE).
:meth:`.request_encode_body` is for sending requests whose fields are
encoded in the *body* of the request using multipart or www-orm-urlencoded
(such as for POST, PUT, PATCH).
:meth:`.request` is for making any kind of request, it will look up the
appropriate encoding format and use one of the above two methods to make
the request.
"""
_encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS'])
_encode_body_methods = set(['PATCH', 'POST', 'PUT', 'TRACE'])
def urlopen(self, method, url, body=None, headers=None,
encode_multipart=True, multipart_boundary=None,
**kw): # Abstract
raise NotImplemented("Classes extending RequestMethods must implement "
"their own ``urlopen`` method.")
def request(self, method, url, fields=None, headers=None, **urlopen_kw):
"""
Make a request using :meth:`urlopen` with the appropriate encoding of
``fields`` based on the ``method`` used.
This is a convenience method that requires the least amount of manual
effort. It can be used in most situations, while still having the option
to drop down to more specific methods when necessary, such as
:meth:`request_encode_url`, :meth:`request_encode_body`,
or even the lowest level :meth:`urlopen`.
"""
method = method.upper()
if method in self._encode_url_methods:
return self.request_encode_url(method, url, fields=fields,
headers=headers,
**urlopen_kw)
else:
return self.request_encode_body(method, url, fields=fields,
headers=headers,
**urlopen_kw)
def request_encode_url(self, method, url, fields=None, **urlopen_kw):
"""
Make a request using :meth:`urlopen` with the ``fields`` encoded in
the url. This is useful for request methods like GET, HEAD, DELETE, etc.
"""
if fields:
url += '?' + urlencode(fields)
return self.urlopen(method, url, **urlopen_kw)
def request_encode_body(self, method, url, fields=None, headers=None,
encode_multipart=True, multipart_boundary=None,
**urlopen_kw):
"""
Make a request using :meth:`urlopen` with the ``fields`` encoded in
the body. This is useful for request methods like POST, PUT, PATCH, etc.
When ``encode_multipart=True`` (default), then
:meth:`urllib3.filepost.encode_multipart_formdata` is used to encode the
payload with the appropriate content type. Otherwise
:meth:`urllib.urlencode` is used with the
'application/x-www-form-urlencoded' content type.
Multipart encoding must be used when posting files, and it's reasonably
safe to use it in other times too. However, it may break request signing,
such as with OAuth.
Supports an optional ``fields`` parameter of key/value strings AND
key/filetuple. A filetuple is a (filename, data) tuple. For example: ::
fields = {
'foo': 'bar',
'fakefile': ('foofile.txt', 'contents of foofile'),
'realfile': ('barfile.txt', open('realfile').read()),
'nonamefile': ('contents of nonamefile field'),
}
When uploading a file, providing a filename (the first parameter of the
tuple) is optional but recommended to best mimick behavior of browsers.
Note that if ``headers`` are supplied, the 'Content-Type' header will be
overwritten because it depends on the dynamic random boundary string
which is used to compose the body of the request. The random boundary
string can be explicitly set with the ``multipart_boundary`` parameter.
"""
if encode_multipart:
body, content_type = encode_multipart_formdata(fields or {},
boundary=multipart_boundary)
else:
body, content_type = (urlencode(fields or {}),
'application/x-www-form-urlencoded')
headers = headers or {}
headers.update({'Content-Type': content_type})
return self.urlopen(method, url, body=body, headers=headers,
**urlopen_kw)

View File

@@ -0,0 +1,202 @@
# urllib3/response.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
import gzip
import logging
import zlib
from io import BytesIO
from .exceptions import HTTPError
from .packages.six import string_types as basestring
log = logging.getLogger(__name__)
def decode_gzip(data):
gzipper = gzip.GzipFile(fileobj=BytesIO(data))
return gzipper.read()
def decode_deflate(data):
try:
return zlib.decompress(data)
except zlib.error:
return zlib.decompress(data, -zlib.MAX_WBITS)
class HTTPResponse(object):
"""
HTTP Response container.
Backwards-compatible to httplib's HTTPResponse but the response ``body`` is
loaded and decoded on-demand when the ``data`` property is accessed.
Extra parameters for behaviour not present in httplib.HTTPResponse:
:param preload_content:
If True, the response's body will be preloaded during construction.
:param decode_content:
If True, attempts to decode specific content-encoding's based on headers
(like 'gzip' and 'deflate') will be skipped and raw data will be used
instead.
:param original_response:
When this HTTPResponse wrapper is generated from an httplib.HTTPResponse
object, it's convenient to include the original for debug purposes. It's
otherwise unused.
"""
CONTENT_DECODERS = {
'gzip': decode_gzip,
'deflate': decode_deflate,
}
def __init__(self, body='', headers=None, status=0, version=0, reason=None,
strict=0, preload_content=True, decode_content=True,
original_response=None, pool=None, connection=None):
self.headers = headers or {}
self.status = status
self.version = version
self.reason = reason
self.strict = strict
self._decode_content = decode_content
self._body = body if body and isinstance(body, basestring) else None
self._fp = None
self._original_response = original_response
self._pool = pool
self._connection = connection
if hasattr(body, 'read'):
self._fp = body
if preload_content and not self._body:
self._body = self.read(decode_content=decode_content)
def get_redirect_location(self):
"""
Should we redirect and where to?
:returns: Truthy redirect location string if we got a redirect status
code and valid location. ``None`` if redirect status and no
location. ``False`` if not a redirect status code.
"""
if self.status in [301, 302, 303, 307]:
return self.headers.get('location')
return False
def release_conn(self):
if not self._pool or not self._connection:
return
self._pool._put_conn(self._connection)
self._connection = None
@property
def data(self):
# For backwords-compat with earlier urllib3 0.4 and earlier.
if self._body:
return self._body
if self._fp:
return self.read(cache_content=True)
def read(self, amt=None, decode_content=None, cache_content=False):
"""
Similar to :meth:`httplib.HTTPResponse.read`, but with two additional
parameters: ``decode_content`` and ``cache_content``.
:param amt:
How much of the content to read. If specified, decoding and caching
is skipped because we can't decode partial content nor does it make
sense to cache partial content as the full response.
:param decode_content:
If True, will attempt to decode the body based on the
'content-encoding' header. (Overridden if ``amt`` is set.)
:param cache_content:
If True, will save the returned data such that the same result is
returned despite of the state of the underlying file object. This
is useful if you want the ``.data`` property to continue working
after having ``.read()`` the file object. (Overridden if ``amt`` is
set.)
"""
content_encoding = self.headers.get('content-encoding')
decoder = self.CONTENT_DECODERS.get(content_encoding)
if decode_content is None:
decode_content = self._decode_content
if self._fp is None:
return
try:
if amt is None:
# cStringIO doesn't like amt=None
data = self._fp.read()
else:
return self._fp.read(amt)
try:
if decode_content and decoder:
data = decoder(data)
except IOError:
raise HTTPError("Received response with content-encoding: %s, but "
"failed to decode it." % content_encoding)
if cache_content:
self._body = data
return data
finally:
if self._original_response and self._original_response.isclosed():
self.release_conn()
@classmethod
def from_httplib(ResponseCls, r, **response_kw):
"""
Given an :class:`httplib.HTTPResponse` instance ``r``, return a
corresponding :class:`urllib3.response.HTTPResponse` object.
Remaining parameters are passed to the HTTPResponse constructor, along
with ``original_response=r``.
"""
# Normalize headers between different versions of Python
headers = {}
for k, v in r.getheaders():
# Python 3: Header keys are returned capitalised
k = k.lower()
has_value = headers.get(k)
if has_value: # Python 3: Repeating header keys are unmerged.
v = ', '.join([has_value, v])
headers[k] = v
# HTTPResponse objects in Python 3 don't have a .strict attribute
strict = getattr(r, 'strict', 0)
return ResponseCls(body=r,
headers=headers,
status=r.status,
version=r.version,
reason=r.reason,
strict=strict,
original_response=r,
**response_kw)
# Backwards-compatibility methods for httplib.HTTPResponse
def getheaders(self):
return self.headers
def getheader(self, name, default=None):
return self.headers.get(name, default)

View File

@@ -0,0 +1,136 @@
# urllib3/util.py
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from base64 import b64encode
try:
from select import poll, POLLIN
except ImportError: # `poll` doesn't exist on OSX and other platforms
poll = False
try:
from select import select
except ImportError: # `select` doesn't exist on AppEngine.
select = False
from .packages import six
from .exceptions import LocationParseError
def make_headers(keep_alive=None, accept_encoding=None, user_agent=None,
basic_auth=None):
"""
Shortcuts for generating request headers.
:param keep_alive:
If ``True``, adds 'connection: keep-alive' header.
:param accept_encoding:
Can be a boolean, list, or string.
``True`` translates to 'gzip,deflate'.
List will get joined by comma.
String will be used as provided.
:param user_agent:
String representing the user-agent you want, such as
"python-urllib3/0.6"
:param basic_auth:
Colon-separated username:password string for 'authorization: basic ...'
auth header.
Example: ::
>>> make_headers(keep_alive=True, user_agent="Batman/1.0")
{'connection': 'keep-alive', 'user-agent': 'Batman/1.0'}
>>> make_headers(accept_encoding=True)
{'accept-encoding': 'gzip,deflate'}
"""
headers = {}
if accept_encoding:
if isinstance(accept_encoding, str):
pass
elif isinstance(accept_encoding, list):
accept_encoding = ','.join(accept_encoding)
else:
accept_encoding = 'gzip,deflate'
headers['accept-encoding'] = accept_encoding
if user_agent:
headers['user-agent'] = user_agent
if keep_alive:
headers['connection'] = 'keep-alive'
if basic_auth:
headers['authorization'] = 'Basic ' + \
b64encode(six.b(basic_auth)).decode('utf-8')
return headers
def get_host(url):
"""
Given a url, return its scheme, host and port (None if it's not there).
For example: ::
>>> get_host('http://google.com/mail/')
('http', 'google.com', None)
>>> get_host('google.com:80')
('http', 'google.com', 80)
"""
# This code is actually similar to urlparse.urlsplit, but much
# simplified for our needs.
port = None
scheme = 'http'
if '://' in url:
scheme, url = url.split('://', 1)
if '/' in url:
url, _path = url.split('/', 1)
if '@' in url:
_auth, url = url.split('@', 1)
if ':' in url:
url, port = url.split(':', 1)
if not port.isdigit():
raise LocationParseError("Failed to parse: %s" % url)
port = int(port)
return scheme, url, port
def is_connection_dropped(conn):
"""
Returns True if the connection is dropped and should be closed.
:param conn:
``HTTPConnection`` object.
Note: For platforms like AppEngine, this will always return ``False`` to
let the platform handle connection recycling transparently for us.
"""
sock = getattr(conn, 'sock', False)
if not sock: #Platform-specific: AppEngine
return False
if not poll: # Platform-specific
if not select: #Platform-specific: AppEngine
return False
return select([sock], [], [], 0.0)[0]
# This version is better on platforms that support it.
p = poll()
p.register(sock, POLLIN)
for (fno, ev) in p.poll(0.0):
if fno == sock.fileno():
# Either data is buffered (bad), or the connection is dropped.
return True

327
requests/sessions.py Normal file
View File

@@ -0,0 +1,327 @@
# -*- coding: utf-8 -*-
"""
requests.session
~~~~~~~~~~~~~~~~
This module provides a Session object to manage and persist settings across
requests (cookies, auth, proxies).
"""
from .compat import cookielib
from .cookies import cookiejar_from_dict, remove_cookie_by_name
from .defaults import defaults
from .models import Request
from .hooks import dispatch_hook
from .utils import header_expand
from .packages.urllib3.poolmanager import PoolManager
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 isinstance(local_kwarg, str):
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 list(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',
'params', 'config', 'verify', 'cert', 'prefetch']
def __init__(self,
headers=None,
cookies=None,
auth=None,
timeout=None,
proxies=None,
hooks=None,
params=None,
config=None,
prefetch=False,
verify=True,
cert=None):
self.headers = headers or {}
self.auth = auth
self.timeout = timeout
self.proxies = proxies or {}
self.hooks = hooks or {}
self.params = params or {}
self.config = config or {}
self.prefetch = prefetch
self.verify = verify
self.cert = cert
for (k, v) in list(defaults.items()):
self.config.setdefault(k, v)
self.init_poolmanager()
# Set up a CookieJar to be used by default
if isinstance(cookies, cookielib.CookieJar):
self.cookies = cookies
else:
self.cookies = cookiejar_from_dict(cookies)
def init_poolmanager(self):
self.poolmanager = PoolManager(
num_pools=self.config.get('pool_connections'),
maxsize=self.config.get('pool_maxsize')
)
def __repr__(self):
return '<requests-client at 0x%x>' % (id(self))
def __enter__(self):
return self
def __exit__(self, *args):
pass
def request(self, method, url,
params=None,
data=None,
headers=None,
cookies=None,
files=None,
auth=None,
timeout=None,
allow_redirects=True,
proxies=None,
hooks=None,
return_response=True,
config=None,
prefetch=False,
verify=None,
cert=None):
"""Constructs and sends a :class:`Request <Request>`.
Returns :class:`Response <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) Auth tuple or callable 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 by default.
: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.
:param prefetch: (optional) if ``True``, the response content will be immediately downloaded.
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
"""
method = str(method).upper()
# Default empty dicts for dict params.
data = {} if data is None else data
files = {} if files is None else files
headers = {} if headers is None else headers
params = {} if params is None else params
hooks = {} if hooks is None else hooks
prefetch = self.prefetch or prefetch
# use session's hooks as defaults
for key, cb in list(self.hooks.items()):
hooks.setdefault(key, cb)
# Expand header values.
if headers:
for k, v in list(headers.items()) or {}:
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,
allow_redirects=allow_redirects,
proxies=proxies,
config=config,
prefetch=prefetch,
verify=verify,
cert=cert,
_poolmanager=self.poolmanager
)
# merge session cookies into passed-in ones
dead_cookies = None
# passed-in cookies must become a CookieJar:
if not isinstance(cookies, cookielib.CookieJar):
args['cookies'] = cookiejar_from_dict(cookies)
# support unsetting cookies that have been passed in with None values
# this is only meaningful when `cookies` is a dict ---
# for a real CookieJar, the client should use session.cookies.clear()
if cookies is not None:
dead_cookies = [name for name in cookies if cookies[name] is None]
# merge the session's cookies into the passed-in cookies:
for cookie in self.cookies:
args['cookies'].set_cookie(cookie)
# remove the unset cookies from the jar we'll be using with the current request
# (but not from the session's own store of cookies):
if dead_cookies is not None:
for name in dead_cookies:
remove_cookie_by_name(args['cookies'], name)
# Merge local kwargs with session kwargs.
for attr in self.__attrs__:
# we already merged cookies:
if attr == 'cookies':
continue
session_val = getattr(self, attr, None)
local_val = args.get(attr)
args[attr] = merge_kwargs(local_val, session_val)
# Arguments manipulation hook.
args = dispatch_hook('args', args['hooks'], args)
# Create the (empty) response.
r = Request(**args)
# Give the response some context.
r.session = self
# Don't send if asked nicely.
if not return_response:
return r
# Send the HTTP Request.
r.send(prefetch=prefetch)
# Send any cookies back up the to the session.
for cookie in r.response.cookies:
self.cookies.set_cookie(cookie)
# Return the 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 options(self, url, **kwargs):
"""Sends a OPTIONS 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('options', 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', False)
return self.request('head', url, **kwargs)
def post(self, url, data=None, **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=None, **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(self, url, data=None, **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=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 __getstate__(self):
return dict((attr, getattr(self, attr, None)) for attr in self.__attrs__)
def __setstate__(self, state):
for attr, value in state.items():
setattr(self, attr, value)
self.init_poolmanager()
def session(**kwargs):
"""Returns a :class:`Session` for context-management."""
return Session(**kwargs)

86
requests/status_codes.py Normal file
View File

@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from .structures import LookupDict
_codes = {
# Informational.
100: ('continue',),
101: ('switching_protocols',),
102: ('processing',),
103: ('checkpoint',),
122: ('uri_too_long', 'request_uri_too_long'),
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/'),
201: ('created',),
202: ('accepted',),
203: ('non_authoritative_info', 'non_authoritative_information'),
204: ('no_content',),
205: ('reset_content', 'reset'),
206: ('partial_content', 'partial'),
207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
208: ('im_used',),
# Redirection.
300: ('multiple_choices',),
301: ('moved_permanently', 'moved', '\\o-'),
302: ('found',),
303: ('see_other', 'other'),
304: ('not_modified',),
305: ('use_proxy',),
306: ('switch_proxy',),
307: ('temporary_redirect', 'temporary_moved', 'temporary'),
308: ('resume_incomplete', 'resume'),
# Client Error.
400: ('bad_request', 'bad'),
401: ('unauthorized',),
402: ('payment_required', 'payment'),
403: ('forbidden',),
404: ('not_found', '-o-'),
405: ('method_not_allowed', 'not_allowed'),
406: ('not_acceptable',),
407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
408: ('request_timeout', 'timeout'),
409: ('conflict',),
410: ('gone',),
411: ('length_required',),
412: ('precondition_failed', 'precondition'),
413: ('request_entity_too_large',),
414: ('request_uri_too_large',),
415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
417: ('expectation_failed',),
418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
422: ('unprocessable_entity', 'unprocessable'),
423: ('locked',),
424: ('failed_dependency', 'dependency'),
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'),
499: ('client_closed_request',),
# Server Error.
500: ('internal_server_error', 'server_error', '/o\\'),
501: ('not_implemented',),
502: ('bad_gateway',),
503: ('service_unavailable', 'unavailable'),
504: ('gateway_timeout',),
505: ('http_version_not_supported', 'http_version'),
506: ('variant_also_negotiates',),
507: ('insufficient_storage',),
509: ('bandwidth_limit_exceeded', 'bandwidth'),
510: ('not_extended',),
}
codes = LookupDict(name='status_codes')
for (code, titles) in list(_codes.items()):
for title in titles:
setattr(codes, title, code)
if not title.startswith('\\'):
setattr(codes, title.upper(), code)

66
requests/structures.py Normal file
View File

@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
"""
requests.structures
~~~~~~~~~~~~~~~~~~~
Data structures that power Requests.
"""
class CaseInsensitiveDict(dict):
"""Case-insensitive Dictionary
For example, ``headers['content-encoding']`` will return the
value of a ``'Content-Encoding'`` response header."""
@property
def lower_keys(self):
if not hasattr(self, '_lower_keys') or not self._lower_keys:
self._lower_keys = dict((k.lower(), k) for k in list(self.keys()))
return self._lower_keys
def _clear_lower_keys(self):
if hasattr(self, '_lower_keys'):
self._lower_keys.clear()
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
self._clear_lower_keys()
def __delitem__(self, key):
dict.__delitem__(self, key)
self._lower_keys.clear()
def __contains__(self, key):
return key.lower() in self.lower_keys
def __getitem__(self, key):
# We allow fall-through here, so values default to None
if key in self:
return dict.__getitem__(self, self.lower_keys[key.lower()])
def get(self, key, default=None):
if key in self:
return self[key]
else:
return default
class LookupDict(dict):
"""Dictionary lookup object."""
def __init__(self, name=None):
self.name = name
super(LookupDict, self).__init__()
def __repr__(self):
return '<lookup \'%s\'>' % (self.name)
def __getitem__(self, key):
# We allow fall-through here, so values default to None
return self.__dict__.get(key, None)
def get(self, key, default=None):
return self.__dict__.get(key, default)

448
requests/utils.py Normal file
View File

@@ -0,0 +1,448 @@
# -*- coding: utf-8 -*-
"""
requests.utils
~~~~~~~~~~~~~~
This module provides utility functions that are used within Requests
that are also useful for external consumption.
"""
import cgi
import codecs
import os
import random
import re
import zlib
from netrc import netrc, NetrcParseError
from .compat import parse_http_list as _parse_list_header
from .compat import quote, is_py2, urlparse
from .compat import basestring, bytes, str
from .cookies import RequestsCookieJar, cookiejar_from_dict
_hush_pyflakes = (RequestsCookieJar,)
CERTIFI_BUNDLE_PATH = None
try:
# see if requests's own CA certificate bundle is installed
import certifi
CERTIFI_BUNDLE_PATH = certifi.where()
except ImportError:
pass
NETRC_FILES = ('.netrc', '_netrc')
# common paths for the OS's CA certificate bundle
POSSIBLE_CA_BUNDLE_PATHS = [
# Red Hat, CentOS, Fedora and friends (provided by the ca-certificates package):
'/etc/pki/tls/certs/ca-bundle.crt',
# Ubuntu, Debian, and friends (provided by the ca-certificates package):
'/etc/ssl/certs/ca-certificates.crt',
# FreeBSD (provided by the ca_root_nss package):
'/usr/local/share/certs/ca-root-nss.crt',
]
def get_os_ca_bundle_path():
"""Try to pick an available CA certificate bundle provided by the OS."""
for path in POSSIBLE_CA_BUNDLE_PATHS:
if os.path.exists(path):
return path
return None
# if certifi is installed, use its CA bundle;
# otherwise, try and use the OS bundle
DEFAULT_CA_BUNDLE_PATH = CERTIFI_BUNDLE_PATH or get_os_ca_bundle_path()
def dict_to_sequence(d):
"""Returns an internal sequence dictionary update."""
if hasattr(d, 'items'):
d = d.items()
return d
def get_netrc_auth(url):
"""Returns the Requests tuple auth for a given url from netrc."""
try:
locations = (os.path.expanduser('~/{0}'.format(f)) for f in NETRC_FILES)
netrc_path = None
for loc in locations:
if os.path.exists(loc) and not netrc_path:
netrc_path = loc
# Abort early if there isn't one.
if netrc_path is None:
return netrc_path
ri = urlparse(url)
# Strip port numbers from netloc
host = ri.netloc.split(':')[0]
try:
_netrc = netrc(netrc_path).authenticators(host)
if _netrc:
# Return with login / password
login_i = (0 if _netrc[0] else 1)
return (_netrc[login_i], _netrc[2])
except (NetrcParseError, IOError):
# If there was a parsing error or a permissions issue reading the file,
# we'll just skip netrc auth
pass
# AppEngine hackiness.
except AttributeError:
pass
def guess_filename(obj):
"""Tries to guess the filename of the given object."""
name = getattr(obj, 'name', None)
if name and name[0] != '<' and name[-1] != '>':
return name
# From mitsuhiko/werkzeug (used with permission).
def parse_list_header(value):
"""Parse lists as described by RFC 2068 Section 2.
In particular, parse comma-separated lists where the elements of
the list may include quoted-strings. A quoted-string could
contain a comma. A non-quoted string could have quotes in the
middle. Quotes are removed automatically after parsing.
It basically works like :func:`parse_set_header` just that items
may appear multiple times and case sensitivity is preserved.
The return value is a standard :class:`list`:
>>> parse_list_header('token, "quoted value"')
['token', 'quoted value']
To create a header from the :class:`list` again, use the
:func:`dump_header` function.
:param value: a string with a list header.
:return: :class:`list`
"""
result = []
for item in _parse_list_header(value):
if item[:1] == item[-1:] == '"':
item = unquote_header_value(item[1:-1])
result.append(item)
return result
# From mitsuhiko/werkzeug (used with permission).
def parse_dict_header(value):
"""Parse lists of key, value pairs as described by RFC 2068 Section 2 and
convert them into a python dict:
>>> d = parse_dict_header('foo="is a fish", bar="as well"')
>>> type(d) is dict
True
>>> sorted(d.items())
[('bar', 'as well'), ('foo', 'is a fish')]
If there is no value for a key it will be `None`:
>>> parse_dict_header('key_without_value')
{'key_without_value': None}
To create a header from the :class:`dict` again, use the
:func:`dump_header` function.
:param value: a string with a dict header.
:return: :class:`dict`
"""
result = {}
for item in _parse_list_header(value):
if '=' not in item:
result[item] = None
continue
name, value = item.split('=', 1)
if value[:1] == value[-1:] == '"':
value = unquote_header_value(value[1:-1])
result[name] = value
return result
# From mitsuhiko/werkzeug (used with permission).
def unquote_header_value(value, is_filename=False):
r"""Unquotes a header value. (Reversal of :func:`quote_header_value`).
This does not use the real unquoting but what browsers are actually
using for quoting.
:param value: the header value to unquote.
"""
if value and value[0] == value[-1] == '"':
# this is not the real unquoting, but fixing this so that the
# RFC is met will result in bugs with internet explorer and
# probably some other browsers as well. IE for example is
# uploading files with "C:\foo\bar.txt" as filename
value = value[1:-1]
# if this is a filename and the starting characters look like
# a UNC path, then just return the value without quotes. Using the
# replace sequence below on a UNC path has the effect of turning
# the leading double slash into a single slash and then
# _fix_ie_filename() doesn't work correctly. See #458.
if not is_filename or value[:2] != '\\\\':
return value.replace('\\\\', '\\').replace('\\"', '"')
return value
def header_expand(headers):
"""Returns an HTTP Header value string from a dictionary.
Example expansion::
{'text/x-dvi': {'q': '.8', 'mxb': '100000', 'mxt': '5.0'}, 'text/x-c': {}}
# Accept: text/x-dvi; q=.8; mxb=100000; mxt=5.0, text/x-c
(('text/x-dvi', {'q': '.8', 'mxb': '100000', 'mxt': '5.0'}), ('text/x-c', {}))
# Accept: text/x-dvi; q=.8; mxb=100000; mxt=5.0, text/x-c
"""
collector = []
if isinstance(headers, dict):
headers = list(headers.items())
elif isinstance(headers, basestring):
return headers
elif isinstance(headers, str):
# As discussed in https://github.com/kennethreitz/requests/issues/400
# latin-1 is the most conservative encoding used on the web. Anyone
# who needs more can encode to a byte-string before calling
return headers.encode("latin-1")
elif headers is None:
return headers
for i, (value, params) in enumerate(headers):
_params = []
for (p_k, p_v) in list(params.items()):
_params.append('%s=%s' % (p_k, p_v))
collector.append(value)
collector.append('; ')
if len(params):
collector.append('; '.join(_params))
if not len(headers) == i + 1:
collector.append(', ')
# Remove trailing separators.
if collector[-1] in (', ', '; '):
del collector[-1]
return ''.join(collector)
def randombytes(n):
"""Return n random bytes."""
if is_py2:
L = [chr(random.randrange(0, 256)) for i in range(n)]
else:
L = [chr(random.randrange(0, 256)).encode('utf-8') for i in range(n)]
return b"".join(L)
def dict_from_cookiejar(cj):
"""Returns a key/value dictionary from a CookieJar.
:param cj: CookieJar object to extract cookies from.
"""
cookie_dict = {}
for _, cookies in list(cj._cookies.items()):
for _, cookies in list(cookies.items()):
for cookie in list(cookies.values()):
# print cookie
cookie_dict[cookie.name] = cookie.value
return cookie_dict
def add_dict_to_cookiejar(cj, cookie_dict):
"""Returns a CookieJar from a key/value dictionary.
:param cj: CookieJar to insert cookies into.
:param cookie_dict: Dict of key/values to insert into CookieJar.
"""
cj2 = cookiejar_from_dict(cookie_dict)
for cookie in cj2:
cj.set_cookie(cookie)
return cj
def get_encodings_from_content(content):
"""Returns encodings from given content string.
:param content: bytestring to extract encodings from.
"""
charset_re = re.compile(r'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I)
return charset_re.findall(content)
def get_encoding_from_headers(headers):
"""Returns encodings from given HTTP Header Dict.
:param headers: dictionary to extract encoding from.
"""
content_type = headers.get('content-type')
if not content_type:
return None
content_type, params = cgi.parse_header(content_type)
if 'charset' in params:
return params['charset'].strip("'\"")
if 'text' in content_type:
return 'ISO-8859-1'
def stream_decode_response_unicode(iterator, r):
"""Stream decodes a iterator."""
if r.encoding is None:
for item in iterator:
yield item
return
decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace')
for chunk in iterator:
rv = decoder.decode(chunk)
if rv:
yield rv
rv = decoder.decode('', final=True)
if rv:
yield rv
def get_unicode_from_response(r):
"""Returns the requested content back in unicode.
:param r: Response object to get unicode content from.
Tried:
1. charset from content-type
2. every encodings from ``<meta ... charset=XXX>``
3. fall back and replace all unicode characters
"""
tried_encodings = []
# Try charset from content-type
encoding = get_encoding_from_headers(r.headers)
if encoding:
try:
return str(r.content, encoding)
except UnicodeError:
tried_encodings.append(encoding)
# Fall back:
try:
return str(r.content, encoding, errors='replace')
except TypeError:
return r.content
def stream_decompress(iterator, mode='gzip'):
"""
Stream decodes an iterator over compressed data
:param iterator: An iterator over compressed data
:param mode: 'gzip' or 'deflate'
:return: An iterator over decompressed data
"""
if mode not in ['gzip', 'deflate']:
raise ValueError('stream_decompress mode must be gzip or deflate')
zlib_mode = 16 + zlib.MAX_WBITS if mode == 'gzip' else -zlib.MAX_WBITS
dec = zlib.decompressobj(zlib_mode)
try:
for chunk in iterator:
rv = dec.decompress(chunk)
if rv:
yield rv
except zlib.error:
# If there was an error decompressing, just return the raw chunk
yield chunk
# Continue to return the rest of the raw data
for chunk in iterator:
yield chunk
else:
# Make sure everything has been returned from the decompression object
buf = dec.decompress(bytes())
rv = buf + dec.flush()
if rv:
yield rv
def stream_untransfer(gen, resp):
if 'gzip' in resp.headers.get('content-encoding', ''):
gen = stream_decompress(gen, mode='gzip')
elif 'deflate' in resp.headers.get('content-encoding', ''):
gen = stream_decompress(gen, mode='deflate')
return gen
# The unreserved URI characters (RFC 3986)
UNRESERVED_SET = frozenset(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~")
def unquote_unreserved(uri):
"""Un-escape any percent-escape sequences in a URI that are unreserved
characters.
This leaves all reserved, illegal and non-ASCII bytes encoded.
"""
parts = uri.split('%')
for i in range(1, len(parts)):
h = parts[i][0:2]
if len(h) == 2:
c = chr(int(h, 16))
if c in UNRESERVED_SET:
parts[i] = c + parts[i][2:]
else:
parts[i] = '%' + parts[i]
else:
parts[i] = '%' + parts[i]
return ''.join(parts)
def requote_uri(uri):
"""Re-quote the given URI.
This function passes the given URI through an unquote/quote cycle to
ensure that it is fully and consistently quoted.
"""
# Unquote only the unreserved characters
# Then quote only illegal characters (do not quote reserved, unreserved,
# or '%')
return quote(unquote_unreserved(uri), safe="!#$%&'()*+,/:;=?@[]~")

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
nose
rudolf2
git+git://github.com/idangazit/oauthlib.git

107
setup.py Normal file → Executable file
View File

@@ -1,51 +1,80 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
"""
distutils/setuptools install script. See inline comments for packaging documentation.
"""
import sys
from distutils.core import setup
import requests
from requests.compat import is_py3
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
if sys.argv[-1] == "publish":
os.system("python setup.py sdist upload")
sys.exit()
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")
sys.exit()
required = []
packages = [
'requests',
'requests.packages',
'requests.packages.urllib3',
'requests.packages.urllib3.packages',
'requests.packages.urllib3.packages.ssl_match_hostname',
'requests.packages.urllib3.packages.mimetools_choose_boundary',
]
# if python > 2.6, require simplejson
# certifi is a Python package containing a CA certificate bundle for SSL verification.
# On certain supported platforms (e.g., Red Hat / Debian / FreeBSD), Requests can
# use the system CA bundle instead; see `requests.utils` for details.
# If your platform is supported, set `requires` to [] instead:
requires = ['certifi>=0.0.7']
# chardet is used to optimally guess the encodings of pages that don't declare one.
# At this time, chardet is not a required dependency. However, it's sufficiently
# important that pip/setuptools should install it when it's unavailable.
if is_py3:
chardet_package = 'chardet2'
else:
chardet_package = 'chardet>=1.0.0'
requires.append('oauthlib>=0.1.0,<0.2.0')
requires.append(chardet_package)
# The async API in requests.async requires the gevent package.
# This is also not a required dependency.
extras_require = {
'async': ['gevent'],
}
setup(
name='requests',
version='0.2.2',
description='Awesome Python HTTP Library that\'s actually usable.',
long_description=open('README.rst').read() + '\n\n' +
open('HISTORY.rst').read(),
author='Kenneth Reitz',
author_email='me@kennethreitz.com',
url='https://github.com/kennethreitz/requests',
packages= [
'requests',
'requests.packages',
'requests.packages.poster'
],
install_requires=required,
license='ISC',
classifiers=(
# 'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: ISC License (ISCL)',
'Programming Language :: Python',
# 'Programming Language :: Python :: 2.5',
name='requests',
version=requests.__version__,
description='Python HTTP for Humans.',
long_description=open('README.rst').read() + '\n\n' +
open('HISTORY.rst').read(),
author='Kenneth Reitz',
author_email='me@kennethreitz.com',
url='http://python-requests.org',
packages=packages,
package_data={'': ['LICENSE', 'NOTICE']},
include_package_data=True,
install_requires=requires,
extras_require=extras_require,
license=open("LICENSE").read(),
classifiers=(
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: ISC License (ISCL)',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
# 'Programming Language :: Python :: 3.0',
# 'Programming Language :: Python :: 3.1',
),
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.0',
'Programming Language :: Python :: 3.1',
),
)

View File

@@ -1,61 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
from cStringIO import StringIO
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')
url = 'https://convore.com/api/account/verify.json'
r = requests.get(url, auth=auth)
self.assertEqual(r.status_code, 200)
def test_POSTBIN_GET_POST_FILES(self):
bin = requests.post('http://www.postbin.org/')
self.assertEqual(bin.status_code, 200)
post = requests.post(bin.url, data={'some': 'data'})
self.assertEqual(post.status_code, 201)
post2 = requests.post(bin.url, files={'some': StringIO('data')})
self.assertEqual(post2.status_code, 201)
if __name__ == '__main__':
unittest.main()

166
tests/test_cookies.py Executable file
View File

@@ -0,0 +1,166 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
import os
import tempfile
import unittest
# Path hack.
sys.path.insert(0, os.path.abspath('..'))
import requests
from requests.compat import cookielib
# More hacks
sys.path.append('.')
from test_requests import httpbin, TestBaseMixin
class CookieTests(TestBaseMixin, unittest.TestCase):
def test_cookies_from_response(self):
"""Basic test that we correctly parse received cookies in the Response object."""
r = requests.get(httpbin('cookies', 'set', 'myname', 'myvalue'))
# test deprecated dictionary interface
self.assertEqual(r.cookies['myname'], 'myvalue')
# test CookieJar interface
jar = r.cookies
self.assertEqual(len(jar), 1)
cookie_from_jar = list(jar)[0]
self.assertCookieHas(cookie_from_jar, name='myname', value='myvalue')
q = requests.get(httpbin('cookies'), cookies=jar)
self.assertEqual(json.loads(q.text)['cookies'], {'myname': 'myvalue'})
def test_crossdomain_cookies(self):
"""Cookies should not be sent to domains they didn't originate from."""
r = requests.get("http://github.com")
c = r.cookies
# github should send us cookies
self.assertGreaterEqual(len(c), 1)
# github cookies should not be sent to httpbin.org:
r2 = requests.get(httpbin('cookies'), cookies=c)
self.assertEqual(json.loads(r2.text)['cookies'], {})
# let's do this again using the session object
s = requests.session()
s.get("http://github.com")
self.assertGreaterEqual(len(s.cookies), 1)
r = s.get(httpbin('cookies'))
self.assertEqual(json.loads(r.text)['cookies'], {})
# we can set a cookie and get exactly that same-domain cookie back:
r = s.get(httpbin('cookies', 'set', 'myname', 'myvalue'))
self.assertEqual(json.loads(r.text)['cookies'], {'myname': 'myvalue'})
def test_overwrite(self):
"""Cookies should get overwritten when appropriate."""
r = requests.get(httpbin('cookies', 'set', 'shimon', 'yochai'))
cookies = r.cookies
requests.get(httpbin('cookies', 'set', 'elazar', 'shimon'), cookies=cookies)
r = requests.get(httpbin('cookies'), cookies=cookies)
self.assertEqual(json.loads(r.text)['cookies'],
{'shimon': 'yochai', 'elazar': 'shimon'})
# overwrite the value of 'shimon'
r = requests.get(httpbin('cookies', 'set', 'shimon', 'gamaliel'), cookies=cookies)
self.assertEqual(len(cookies), 2)
r = requests.get(httpbin('cookies'), cookies=cookies)
self.assertEqual(json.loads(r.text)['cookies'],
{'shimon': 'gamaliel', 'elazar': 'shimon'})
def test_redirects(self):
"""Test that cookies set by a 302 page are correctly processed."""
r = requests.get(httpbin('cookies', 'set', 'redirects', 'work'))
self.assertEqual(r.history[0].status_code, 302)
expected_cookies = {'redirects': 'work'}
self.assertEqual(json.loads(r.text)['cookies'], expected_cookies)
r2 = requests.get(httpbin('cookies', 'set', 'very', 'well'), cookies=r.cookies)
expected_cookies = {'redirects': 'work', 'very': 'well'}
self.assertEqual(json.loads(r2.text)['cookies'], expected_cookies)
self.assertIs(r.cookies, r2.cookies)
def test_none_cookie(self):
"""Regression test: don't send a Cookie header with a string value of 'None'!"""
page = json.loads(requests.get(httpbin('headers')).text)
self.assertNotIn('Cookie', page['headers'])
class LWPCookieJarTest(TestBaseMixin, unittest.TestCase):
"""Check store/load of cookies to FileCookieJar's, specifically LWPCookieJar's."""
COOKIEJAR_CLASS = cookielib.LWPCookieJar
def setUp(self):
# blank the file
self.cookiejar_file = tempfile.NamedTemporaryFile()
self.cookiejar_filename = self.cookiejar_file.name
cookiejar = self.COOKIEJAR_CLASS(self.cookiejar_filename)
cookiejar.save()
def tearDown(self):
try:
self.cookiejar_file.close()
except OSError:
pass
def test_cookiejar_persistence(self):
"""Test that we can save cookies to a FileCookieJar."""
cookiejar = self.COOKIEJAR_CLASS(self.cookiejar_filename)
cookiejar.load()
# initially should be blank
self.assertEqual(len(cookiejar), 0)
response = requests.get(httpbin('cookies', 'set', 'key', 'value'), cookies=cookiejar)
self.assertEqual(len(cookiejar), 1)
cookie = list(cookiejar)[0]
self.assertEqual(json.loads(response.text)['cookies'], {'key': 'value'})
self.assertCookieHas(cookie, name='key', value='value')
# save and reload the cookies from the file:
cookiejar.save(ignore_discard=True)
cookiejar_2 = self.COOKIEJAR_CLASS(self.cookiejar_filename)
cookiejar_2.load(ignore_discard=True)
self.assertEqual(len(cookiejar_2), 1)
cookie_2 = list(cookiejar_2)[0]
# this cookie should have been saved with the correct domain restriction:
self.assertCookieHas(cookie_2, name='key', value='value',
domain='httpbin.org', path='/')
# httpbin sets session cookies, so if we don't ignore the discard attribute,
# there should be no cookie:
cookiejar_3 = self.COOKIEJAR_CLASS(self.cookiejar_filename)
cookiejar_3.load()
self.assertEqual(len(cookiejar_3), 0)
def test_crossdomain(self):
"""Test persistence of the domains associated with the cookies."""
cookiejar = self.COOKIEJAR_CLASS(self.cookiejar_filename)
cookiejar.load()
self.assertEqual(len(cookiejar), 0)
# github sets a cookie
requests.get("http://github.com", cookies=cookiejar)
num_github_cookies = len(cookiejar)
self.assertGreaterEqual(num_github_cookies, 1)
# httpbin sets another
requests.get(httpbin('cookies', 'set', 'key', 'value'), cookies=cookiejar)
num_total_cookies = len(cookiejar)
self.assertGreaterEqual(num_total_cookies, 2)
self.assertGreater(num_total_cookies, num_github_cookies)
# save and load
cookiejar.save(ignore_discard=True)
cookiejar_2 = self.COOKIEJAR_CLASS(self.cookiejar_filename)
cookiejar_2.load(ignore_discard=True)
self.assertEqual(len(cookiejar_2), num_total_cookies)
r = requests.get(httpbin('cookies'), cookies=cookiejar_2)
self.assertEqual(json.loads(r.text)['cookies'], {'key': 'value'})
class MozCookieJarTest(LWPCookieJarTest):
"""Same test, but substitute MozillaCookieJar."""
COOKIEJAR_CLASS = cookielib.MozillaCookieJar
if __name__ == '__main__':
unittest.main()

851
tests/test_requests.py Executable file
View File

@@ -0,0 +1,851 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# from __future__ import unicode_literals
# Path hack.
import sys
import os
sys.path.insert(0, os.path.abspath('..'))
import json
import os
import unittest
import pickle
import requests
from requests.compat import str, StringIO
# import envoy
from requests import HTTPError
from requests import get, post, head, put
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
if 'HTTPBIN_URL' not in os.environ:
os.environ['HTTPBIN_URL'] = 'http://httpbin.org/'
HTTPBIN_URL = os.environ.get('HTTPBIN_URL')
def httpbin(*suffix):
"""Returns url for HTTPBIN resource."""
return HTTPBIN_URL + '/'.join(suffix)
SERVICES = (httpbin, )
_httpbin = False
class TestSetup(object):
"""Requests test cases."""
# It goes to eleven.
_multiprocess_can_split_ = True
def setUp(self):
global _httpbin
if (not 'HTTPBIN_URL' in os.environ) and not _httpbin:
# c = envoy.connect('httpbin %s' % (PORT))
# time.sleep(1)
_httpbin = True
class TestBaseMixin(object):
def assertCookieHas(self, cookie, **kwargs):
"""Assert that a cookie has various specified properties."""
for attr, expected_value in kwargs.items():
message = 'Failed comparison for %s' % (attr,)
self.assertEqual(getattr(cookie, attr), expected_value, message)
class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
"""Requests test cases."""
def test_entry_points(self):
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, get, 'hiwpefhipowhefopw')
def test_path_is_not_double_encoded(self):
request = requests.Request("http://0.0.0.0/get/test case")
self.assertEqual(request.path_url, "/get/test%20case")
def test_HTTP_200_OK_GET(self):
r = get(httpbin('get'))
self.assertEqual(r.status_code, 200)
def test_response_sent(self):
r = get(httpbin('get'))
self.assertTrue(r.request.sent)
def test_HTTP_302_ALLOW_REDIRECT_GET(self):
r = get(httpbin('redirect', '1'))
self.assertEqual(r.status_code, 200)
def test_HTTP_302_GET(self):
r = get(httpbin('redirect', '1'), allow_redirects=False)
self.assertEqual(r.status_code, 302)
def test_HTTP_200_OK_GET_WITH_PARAMS(self):
heads = {'User-agent': 'Mozilla/5.0'}
r = get(httpbin('user-agent'), headers=heads)
assert heads['User-agent'] in r.text
self.assertEqual(r.status_code, 200)
def test_HTTP_200_OK_GET_WITH_MIXED_PARAMS(self):
heads = {'User-agent': 'Mozilla/5.0'}
r = get(httpbin('get') + '?test=true', params={'q': 'test'}, headers=heads)
self.assertEqual(r.status_code, 200)
# def test_unicode_headers(self):
# # Simply calling requests with a unicode instance should simply work
# # when the characters are all representable using latin-1:
# heads = { u'User-Agent': u'Requests Test Suite' }
# requests.get(url=httpbin('get'), headers=heads)
# # Characters outside latin-1 should raise an exception:
# heads = { u'User-Agent': u'\u30cd\u30c3\u30c8\u30ef\u30fc\u30af' }
# self.assertRaises(UnicodeEncodeError, requests.get,
# url=httpbin('get'), headers=heads)
# def test_session_with_escaped_url(self):
# # Test a URL that contains percent-escaped characters
# # This URL should not be modified (double-escaped)
# # Tests:
# # - Quoted illegal characters ("%20" (' '), "%3C" ('<'), "%3E" ('>'))
# # - Quoted reserved characters ("%25" ('%'), "%23" ('#'), "%2F" ('/'))
# # - Quoted non-ASCII characters ("%C3%98", "%C3%A5")
# path_fully_escaped = '%3Ca%25b%23c%2Fd%3E/%C3%98%20%C3%A5'
# url = httpbin('get/' + path_fully_escaped)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/' + path_fully_escaped))
# # Test that illegal characters in a path get properly percent-escaped
# # Tests:
# # - Bare illegal characters (space, '<')
# # - Bare non-ASCII characters ('\u00d8')
# path = u'<a%25b%23c%2Fd%3E/\u00d8 %C3%A5'
# url = httpbin('get/' + path)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/' + path_fully_escaped))
# # Test that reserved characters in a path do not get percent-escaped
# # Tests:
# # - All reserved characters (RFC 3986), except '?', '#', '[' and ']',
# # which are not allowed in the path, and ';' which delimits
# # parameters.
# # All such characters must be allowed bare in path, and must not be
# # encoded.
# # - Special unreserved characters (RFC 3986), which should not be
# # encoded (even though it wouldn't hurt).
# path_reserved = '!$&\'()*+,/:=@-._~'
# url = httpbin('get/' + path_reserved)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/' + path_reserved))
# # Test that percent-encoded unreserved characters in a path get
# # normalised to their un-encoded forms.
# path_unreserved = 'ABCDwxyz1234-._~'
# path_unreserved_escaped = '%41%42%43%44%77%78%79%7A%31%32%33%34%2D%2E%5F%7E'
# url = httpbin('get/' + path_unreserved_escaped)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/' + path_unreserved))
# # Re-run all of the same tests on the query part of the URI
# query_fully_escaped = '%3Ca%25b%23c%2Fd%3E=%C3%98%20%C3%A5'
# url = httpbin('get/?' + query_fully_escaped)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/?' + query_fully_escaped))
# query = u'<a%25b%23c%2Fd%3E=\u00d8 %C3%A5'
# url = httpbin('get/?' + query)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/?' + query_fully_escaped))
# # The legal characters in query happens to be the same as in path
# query_reserved = '!$&\'()*+,/:=@-._~'
# url = httpbin('get/?' + query_reserved)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/?' + query_reserved))
# query_unreserved = 'ABCDwxyz=1234-._~'
# query_unreserved_escaped = '%41%42%43%44%77%78%79%7A=%31%32%33%34%2D%2E%5F%7E'
# url = httpbin('get/?' + query_unreserved_escaped)
# response = get(url)
# self.assertEqual(response.url, httpbin('get/?' + query_unreserved))
def test_user_agent_transfers(self):
"""Issue XX"""
heads = {
'User-agent':
'Mozilla/5.0 (github.com/kennethreitz/requests)'
}
r = get(httpbin('user-agent'), headers=heads)
self.assertTrue(heads['User-agent'] in r.text)
heads = {
'user-agent':
'Mozilla/5.0 (github.com/kennethreitz/requests)'
}
r = get(httpbin('user-agent'), headers=heads)
self.assertTrue(heads['user-agent'] in r.text)
def test_HTTP_200_OK_HEAD(self):
r = head(httpbin('get'))
self.assertEqual(r.status_code, 200)
def test_HTTP_200_OK_PUT(self):
r = put(httpbin('put'))
self.assertEqual(r.status_code, 200)
def test_BASICAUTH_TUPLE_HTTP_200_OK_GET(self):
for service in SERVICES:
auth = ('user', 'pass')
url = service('basic-auth', 'user', 'pass')
r = get(url, auth=auth)
self.assertEqual(r.status_code, 200)
r = get(url)
self.assertEqual(r.status_code, 401)
s = requests.session(auth=auth)
r = get(url, session=s)
self.assertEqual(r.status_code, 200)
def test_BASICAUTH_HTTP_200_OK_GET(self):
for service in SERVICES:
auth = HTTPBasicAuth('user', 'pass')
url = service('basic-auth', 'user', 'pass')
r = get(url, auth=auth)
self.assertEqual(r.status_code, 200)
auth = ('user', 'pass')
r = get(url, auth=auth)
self.assertEqual(r.status_code, 200)
r = get(url)
self.assertEqual(r.status_code, 401)
s = requests.session(auth=auth)
r = get(url, session=s)
self.assertEqual(r.status_code, 200)
def test_DIGESTAUTH_HTTP_200_OK_GET(self):
for service in SERVICES:
auth = HTTPDigestAuth('user', 'pass')
url = service('digest-auth', 'auth', 'user', 'pass')
r = get(url, auth=auth)
self.assertEqual(r.status_code, 200)
r = get(url)
self.assertEqual(r.status_code, 401)
s = requests.session(auth=auth)
r = get(url, session=s)
self.assertEqual(r.status_code, 200)
def test_DIGESTAUTH_WRONG_HTTP_401_GET(self):
for service in SERVICES:
auth = HTTPDigestAuth('user', 'wrongpass')
url = service('digest-auth', 'auth', 'user', 'pass')
r = get(url, auth=auth)
self.assertEqual(r.status_code, 401)
s = requests.session(auth=auth)
r = get(url, session=s)
self.assertEqual(r.status_code, 401)
def test_POSTBIN_GET_POST_FILES(self):
for service in SERVICES:
url = service('post')
post1 = post(url).raise_for_status()
post1 = post(url, data={'some': 'data'})
self.assertEqual(post1.status_code, 200)
with open(__file__) as f:
post2 = post(url, files={'some': f})
self.assertEqual(post2.status_code, 200)
post3 = post(url, data='[{"some": "json"}]')
self.assertEqual(post3.status_code, 200)
def test_POSTBIN_GET_POST_FILES_WITH_PARAMS(self):
for service in SERVICES:
with open(__file__) as f:
url = service('post')
post1 = post(url,
files={'some': f},
data={'some': 'data'})
self.assertEqual(post1.status_code, 200)
def test_POSTBIN_GET_POST_FILES_WITH_HEADERS(self):
for service in SERVICES:
url = service('post')
with open(__file__) as f:
post2 = post(url,
files={'some': f},
headers={'User-Agent': 'requests-tests'})
self.assertEqual(post2.status_code, 200)
def test_nonzero_evaluation(self):
for service in SERVICES:
r = get(service('status', '500'))
self.assertEqual(bool(r), False)
r = get(service('/get'))
self.assertEqual(bool(r), True)
def test_request_ok_set(self):
for service in SERVICES:
r = get(service('status', '404'))
# print r.status_code
# r.raise_for_status()
self.assertEqual(r.ok, False)
def test_status_raising(self):
r = get(httpbin('status', '404'))
self.assertRaises(HTTPError, r.raise_for_status)
r = get(httpbin('status', '200'))
self.assertFalse(r.error)
r.raise_for_status()
def test_default_status_raising(self):
config = {'danger_mode': True}
args = [httpbin('status', '404')]
kwargs = dict(config=config)
self.assertRaises(HTTPError, get, *args, **kwargs)
r = get(httpbin('status', '200'))
self.assertEqual(r.status_code, 200)
def test_decompress_gzip(self):
r = get(httpbin('gzip'))
r.content.decode('ascii')
def test_response_has_unicode_url(self):
for service in SERVICES:
url = service('get')
response = get(url)
assert isinstance(response.url, str)
def test_unicode_get(self):
for service in SERVICES:
url = service('/get')
get(url, params={'foo': 'føø'})
get(url, params={'føø': 'føø'})
get(url, params={'føø': 'føø'})
get(url, params={'foo': 'foo'})
get(service('ø'), params={'foo': 'foo'})
def test_httpauth_recursion(self):
http_auth = HTTPBasicAuth('user', 'BADpass')
for service in SERVICES:
r = get(service('basic-auth', 'user', 'pass'), auth=http_auth)
self.assertEqual(r.status_code, 401)
def test_urlencoded_post_data(self):
for service in SERVICES:
r = post(service('post'), data=dict(test='fooaowpeuf'))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
self.assertEqual(r.url, service('post'))
rbody = json.loads(r.text)
self.assertEqual(rbody.get('form'), dict(test='fooaowpeuf'))
self.assertEqual(rbody.get('data'), '')
def test_nonurlencoded_post_data(self):
for service in SERVICES:
r = post(service('post'), data='fooaowpeuf')
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
self.assertEqual(r.url, service('post'))
rbody = json.loads(r.text)
# Body wasn't valid url encoded data, so the server returns None as
# "form" and the raw body as "data".
assert rbody.get('form') in (None, {})
self.assertEqual(rbody.get('data'), 'fooaowpeuf')
def test_urlencoded_post_querystring(self):
for service in SERVICES:
r = post(service('post'), params=dict(test='fooaowpeuf'))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
self.assertEqual(r.url, service('post?test=fooaowpeuf'))
rbody = json.loads(r.text)
self.assertEqual(rbody.get('form'), {}) # No form supplied
self.assertEqual(rbody.get('data'), '')
def test_urlencoded_post_query_and_data(self):
for service in SERVICES:
r = post(
service('post'),
params=dict(test='fooaowpeuf'),
data=dict(test2="foobar"))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
self.assertEqual(r.url, service('post?test=fooaowpeuf'))
rbody = json.loads(r.text)
self.assertEqual(rbody.get('form'), dict(test2='foobar'))
self.assertEqual(rbody.get('data'), '')
def test_nonurlencoded_postdata(self):
for service in SERVICES:
r = post(service('post'), data="foobar")
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
rbody = json.loads(r.text)
assert rbody.get('form') in (None, {})
self.assertEqual(rbody.get('data'), 'foobar')
def test_urlencoded_get_query_multivalued_param(self):
for service in SERVICES:
r = get(service('get'), params=dict(test=['foo', 'baz']))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.url, service('get?test=foo&test=baz'))
def test_urlencoded_post_querystring_multivalued(self):
for service in SERVICES:
r = post(service('post'), params=dict(test=['foo', 'baz']))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
self.assertEqual(r.url, service('post?test=foo&test=baz'))
rbody = json.loads(r.text)
self.assertEqual(rbody.get('form'), {}) # No form supplied
self.assertEqual(rbody.get('data'), '')
def test_urlencoded_post_query_multivalued_and_data(self):
for service in SERVICES:
r = post(
service('post'),
params=dict(test=['foo', 'baz']),
data=dict(test2="foobar", test3=['foo', 'baz']))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['content-type'], 'application/json')
self.assertEqual(r.url, service('post?test=foo&test=baz'))
# print(r.text)
# print('-----------------------')
rbody = json.loads(r.text)
self.assertEqual(rbody.get('form'), dict(test2='foobar', test3=['foo', 'baz']))
self.assertEqual(rbody.get('data'), '')
def test_GET_no_redirect(self):
for service in SERVICES:
r = get(service('redirect', '3'), allow_redirects=False)
self.assertEqual(r.status_code, 302)
self.assertEqual(len(r.history), 0)
def test_HEAD_no_redirect(self):
for service in SERVICES:
r = head(service('redirect', '3'), allow_redirects=False)
self.assertEqual(r.status_code, 302)
self.assertEqual(len(r.history), 0)
def test_redirect_history(self):
for service in SERVICES:
r = get(service('redirect', '3'))
self.assertEqual(r.status_code, 200)
self.assertEqual(len(r.history), 3)
def test_relative_redirect_history(self):
for service in SERVICES:
r = get(service('relative-redirect', '3'))
self.assertEqual(r.status_code, 200)
self.assertEqual(len(r.history), 3)
def test_session_HTTP_200_OK_GET(self):
s = requests.session()
r = get(httpbin('get'), session=s)
self.assertEqual(r.status_code, 200)
def test_session_persistent_headers(self):
heads = {'User-agent': 'Mozilla/5.0'}
s = requests.session()
s.headers = heads
# Make 2 requests from Session object, should send header both times
r1 = get(httpbin('user-agent'), session=s)
assert heads['User-agent'] in r1.text
r2 = get(httpbin('user-agent'), session=s)
assert heads['User-agent'] in r2.text
new_heads = {'User-agent': 'blah'}
r3 = get(httpbin('user-agent'), headers=new_heads, session=s)
assert new_heads['User-agent'] in r3.text
self.assertEqual(r2.status_code, 200)
def test_single_hook(self):
def add_foo_header(args):
if not args.get('headers'):
args['headers'] = {}
args['headers'].update({
'X-Foo': 'foo'
})
return args
for service in SERVICES:
url = service('headers')
response = get(url=url, hooks={'args': add_foo_header})
assert 'foo' in response.text
def test_multiple_hooks(self):
def add_foo_header(args):
if not args.get('headers'):
args['headers'] = {}
args['headers'].update({
'X-Foo': 'foo'
})
return args
def add_bar_header(args):
if not args.get('headers'):
args['headers'] = {}
args['headers'].update({
'X-Bar': 'bar'
})
return args
for service in SERVICES:
url = service('headers')
response = get(url=url,
hooks={
'args': [add_foo_header, add_bar_header]
}
)
assert 'foo' in response.text
assert 'bar' in response.text
def test_session_persistent_cookies(self):
s = requests.session()
# Internally dispatched cookies are sent.
_c = {'kenneth': 'reitz', 'bessie': 'monke'}
r = get(httpbin('cookies'), cookies=_c, session=s)
r = get(httpbin('cookies'), session=s)
# Those cookies persist transparently.
c = json.loads(r.text).get('cookies')
self.assertEqual(c, _c)
# Double check.
r = get(httpbin('cookies'), cookies={}, session=s)
c = json.loads(r.text).get('cookies')
self.assertEqual(c, _c)
# Remove a cookie by setting it's value to None.
r = get(httpbin('cookies'), cookies={'bessie': None}, session=s)
c = json.loads(r.text).get('cookies')
del _c['bessie']
self.assertEqual(c, _c)
# Test session-level cookies.
s = requests.session(cookies=_c)
r = get(httpbin('cookies'), session=s)
c = json.loads(r.text).get('cookies')
self.assertEqual(c, _c)
# Have the server set a cookie.
r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, session=s)
c = json.loads(r.text).get('cookies')
assert 'k' in c
# And server-set cookie persistience.
r = get(httpbin('cookies'), session=s)
c = json.loads(r.text).get('cookies')
assert 'k' in c
def test_session_persistent_params(self):
params = {'a': 'a_test'}
s = requests.session()
s.params = params
# Make 2 requests from Session object, should send header both times
r1 = get(httpbin('get'), session=s)
assert params['a'] in r1.text
params2 = {'b': 'b_test'}
r2 = get(httpbin('get'), params=params2, session=s)
assert params['a'] in r2.text
assert params2['b'] in r2.text
params3 = {'b': 'b_test', 'a': None, 'c': 'c_test'}
r3 = get(httpbin('get'), params=params3, session=s)
assert not params['a'] in r3.text
assert params3['b'] in r3.text
assert params3['c'] in r3.text
def test_session_pickling(self):
s = requests.session(
headers={'header': 'value'},
cookies={'a-cookie': 'cookie-value'},
auth=('username', 'password'))
ds = pickle.loads(pickle.dumps(s))
self.assertEqual(s.headers, ds.headers)
self.assertEqual(s.auth, ds.auth)
# Cookie doesn't have a good __eq__, so verify manually:
self.assertEqual(len(ds.cookies), 1)
for cookie in ds.cookies:
self.assertCookieHas(cookie, name='a-cookie', value='cookie-value')
def test_unpickled_session_requests(self):
s = requests.session()
r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, session=s)
c = json.loads(r.text).get('cookies')
assert 'k' in c
ds = pickle.loads(pickle.dumps(s))
r = get(httpbin('cookies'), session=ds)
c = json.loads(r.text).get('cookies')
assert 'k' in c
ds1 = pickle.loads(pickle.dumps(requests.session()))
ds2 = pickle.loads(pickle.dumps(requests.session(prefetch=True)))
assert not ds1.prefetch
assert ds2.prefetch
def test_invalid_content(self):
# WARNING: if you're using a terrible DNS provider (comcast),
# this will fail.
try:
hah = 'http://somedomainthatclearlydoesntexistg.com'
r = get(hah, allow_redirects=False)
except requests.ConnectionError:
pass # \o/
else:
assert False
config = {'safe_mode': True}
r = get(hah, allow_redirects=False, config=config)
assert r.content == None
def test_cached_response(self):
r1 = get(httpbin('get'), prefetch=False)
assert not r1._content
assert r1.content
assert r1.text
r2 = get(httpbin('get'), prefetch=True)
assert r2._content
assert r2.content
assert r2.text
def test_iter_lines(self):
lines = (0, 2, 10, 100)
for i in lines:
r = get(httpbin('stream', str(i)), prefetch=False)
lines = list(r.iter_lines())
len_lines = len(lines)
self.assertEqual(i, len_lines)
# Tests that trailing whitespaces within lines do not get stripped.
# Tests that a trailing non-terminated line does not get stripped.
quote = (
'''Agamemnon \n'''
'''\tWhy will he not upon our fair request\r\n'''
'''\tUntent his person and share the air with us?'''
)
# Make a request and monkey-patch its contents
r = get(httpbin('get'))
r.raw = StringIO(quote)
lines = list(r.iter_lines())
len_lines = len(lines)
self.assertEqual(len_lines, 3)
joined = lines[0] + '\n' + lines[1] + '\r\n' + lines[2]
self.assertEqual(joined, quote)
def test_safe_mode(self):
safe = requests.session(config=dict(safe_mode=True))
# Safe mode creates empty responses for failed requests.
# Iterating on these responses should produce empty sequences
r = get('http://_/', session=safe)
self.assertEqual(list(r.iter_lines()), [])
assert isinstance(r.error, requests.exceptions.ConnectionError)
r = get('http://_/', session=safe)
self.assertEqual(list(r.iter_content()), [])
assert isinstance(r.error, requests.exceptions.ConnectionError)
# When not in safe mode, should raise Timeout exception
self.assertRaises(
requests.exceptions.Timeout,
get,
httpbin('stream', '1000'), timeout=0.0001)
# In safe mode, should return a blank response
r = get(httpbin('stream', '1000'), timeout=0.0001,
config=dict(safe_mode=True))
assert r.content is None
assert isinstance(r.error, requests.exceptions.Timeout)
def test_upload_binary_data(self):
requests.get(httpbin('post'), auth=('a', 'b'), data='\xff')
def test_useful_exception_for_invalid_port(self):
# If we pass a legitimate URL with an invalid port, we should fail.
self.assertRaises(
ValueError,
get,
'http://google.com:banana')
def test_useful_exception_for_invalid_scheme(self):
# If we pass a legitimate URL with a scheme not supported
# by requests, we should fail.
self.assertRaises(
ValueError,
get,
'ftp://ftp.kernel.org/pub/')
def test_can_have_none_in_header_values(self):
try:
# Don't choke on headers with none in the value.
requests.get(httpbin('headers'), headers={'Foo': None})
except TypeError:
self.fail()
def test_danger_mode_redirects(self):
s = requests.session()
s.config['danger_mode'] = True
s.get(httpbin('redirect', '4'))
def test_empty_response(self):
r = requests.get(httpbin('status', '404'))
r.text
if __name__ == '__main__':
unittest.main()

67
tests/test_requests_async.py Executable file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Path hack.
import sys, os
sys.path.insert(0, os.path.abspath('..'))
import sys
import unittest
import select
has_poll = hasattr(select, "poll")
from requests import async
sys.path.append('.')
from test_requests import httpbin, RequestsTestSuite, SERVICES
class RequestsTestSuiteUsingAsyncApi(RequestsTestSuite):
"""Requests async test cases."""
def patched(f):
"""Automatically send request after creation."""
def wrapped(*args, **kwargs):
request = f(*args, **kwargs)
return async.map([request])[0]
return wrapped
# Patched requests.api functions.
global request
request = patched(async.request)
global delete, get, head, options, patch, post, put
delete = patched(async.delete)
get = patched(async.get)
head = patched(async.head)
options = patched(async.options)
patch = patched(async.patch)
post = patched(async.post)
put = patched(async.put)
def test_entry_points(self):
async.request
async.delete
async.get
async.head
async.options
async.patch
async.post
async.put
async.map
async.send
def test_select_poll(self):
"""Test to make sure we don't overwrite the poll"""
self.assertEqual(hasattr(select, "poll"), has_poll)
if __name__ == '__main__':
unittest.main()

131
tests/test_requests_ext.py Normal file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Path hack.
import sys, os
sys.path.insert(0, os.path.abspath('..'))
import unittest
import requests
from requests.compat import is_py2, is_py3
try:
import omnijson as json
except ImportError:
import json
class RequestsTestSuite(unittest.TestCase):
"""Requests test cases."""
# It goes to eleven.
_multiprocess_can_split_ = True
def test_addition(self):
assert (1 + 1) == 2
def test_ssl_hostname_ok(self):
requests.get('https://github.com', verify=True)
def test_ssl_hostname_not_ok(self):
requests.get('https://kennethreitz.com', verify=False)
self.assertRaises(requests.exceptions.SSLError, requests.get, 'https://kennethreitz.com')
def test_ssl_hostname_session_not_ok(self):
s = requests.session()
self.assertRaises(requests.exceptions.SSLError, s.get, 'https://kennethreitz.com')
s.get('https://kennethreitz.com', verify=False)
def test_binary_post(self):
'''We need to be careful how we build the utf-8 string since
unicode literals are a syntax error in python3
'''
if is_py2:
# Blasphemy!
utf8_string = eval("u'Smörgås'.encode('utf-8')")
elif is_py3:
utf8_string = 'Smörgås'.encode('utf-8')
else:
raise EnvironmentError('Flesh out this test for your environment.')
requests.post('http://www.google.com/', data=utf8_string)
def test_unicode_error(self):
url = 'http://blip.fm/~1abvfu'
requests.get(url)
def test_chunked_head_redirect(self):
url = "http://t.co/NFrx0zLG"
r = requests.head(url, allow_redirects=True)
self.assertEqual(r.status_code, 200)
def test_unicode_redirect(self):
'''This url redirects to a location that has a nonstandard
character in it, that breaks requests in python2.7
After some research, the cause was identified as an unintended
sideeffect of overriding of str with unicode.
In the case that the redirected url is actually a malformed
"bytes" object, i.e. a string with character c where
ord(c) > 127,
then unicode(url) breaks.
'''
r = requests.get('http://www.marketwire.com/mw/release.' +
'do?id=1628202&sourceType=3')
assert r.ok
def test_unicode_url_outright(self):
'''This url visits in my browser'''
r = requests.get('http://www.marketwire.com/press-release/' +
'jp-morgan-behauptet-sich-der-spitze-euro' +
'p%C3%A4ischer-anleihe-analysten-laut-umf' +
'rageergebnissen-1628202.htm')
assert r.ok
def test_redirect_encoding(self):
'''This url redirects to
http://www.dealipedia.com/deal_view_investment.php?r=20012'''
r = requests.get('http://feedproxy.google.com/~r/Dealipedia' +
'News/~3/BQtUJRJeZlo/deal_view_investment.' +
'php')
assert r.ok
def test_cookies_on_redirects(self):
"""Test interaction between cookie handling and redirection."""
# get a cookie for tinyurl.com ONLY
s = requests.session()
s.get(url='http://tinyurl.com/preview.php?disable=1')
# we should have set a cookie for tinyurl: preview=0
self.assertIn('preview', s.cookies)
self.assertEqual(s.cookies['preview'], '0')
self.assertEqual(list(s.cookies)[0].name, 'preview')
self.assertEqual(list(s.cookies)[0].domain, 'tinyurl.com')
# get cookies on another domain
r2 = s.get(url='http://httpbin.org/cookies')
# the cookie is not there
self.assertNotIn('preview', json.loads(r2.text)['cookies'])
# this redirects to another domain, httpbin.org
# cookies of the first domain should NOT be sent to the next one
r3 = s.get(url='http://tinyurl.com/7zp3jnr')
assert r3.url == 'http://httpbin.org/cookies'
self.assertNotIn('preview', json.loads(r2.text)['cookies'])
if __name__ == '__main__':
unittest.main()

31
tests/test_requests_https.py Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
import json
import unittest
# Path hack.
sys.path.insert(0, os.path.abspath('..'))
import requests
class HTTPSTest(unittest.TestCase):
"""Smoke test for https functionality."""
smoke_url = "https://github.com"
def perform_smoke_test(self, verify=False):
result = requests.get(self.smoke_url, verify=verify)
self.assertEqual(result.status_code, 200)
def test_smoke(self):
"""Smoke test without verification."""
self.perform_smoke_test(verify=False)
def test_smoke_verified(self):
"""Smoke test with SSL verification."""
self.perform_smoke_test(verify=True)
if __name__ == '__main__':
unittest.main()