From 7fdb09b766a84534dadfb56e46033697292cab60 Mon Sep 17 00:00:00 2001
From: Idan Gazit
Date: Thu, 17 Nov 2011 13:44:13 +0200
Subject: [PATCH 01/15] Converted auth to use callable objects instead of
tuples.
My attempt to address #275 on kennethreitz/requests.
---
docs/user/advanced.rst | 33 ++++++++---------
docs/user/quickstart.rst | 6 ++--
requests/auth.py | 76 ++++++++++++++--------------------------
requests/models.py | 10 ++----
test_requests.py | 7 ++--
5 files changed, 55 insertions(+), 77 deletions(-)
diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst
index 0c26f2d3..05267816 100644
--- a/docs/user/advanced.rst
+++ b/docs/user/advanced.rst
@@ -211,32 +211,33 @@ Custom Authentication
Requests allows you to use specify your own authentication mechanism.
-When you pass our authentication tuple to a request method, the first
-string is the type of authentication. 'basic' is inferred if none is
-provided.
+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.
-You can pass in a callable object instead of a string for the first item
-in the tuple, and it will be used in place of the built in authentication
-callbacks.
+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.
-We simply need to define a callback function that will be used to update the
-Request object, right before it is dispatched.
-
::
- def pizza_auth(r, username):
- """Attaches HTTP Pizza Authentication to the given Request object.
- """
- r.headers['X-Pizza'] = username
-
- return r
+ 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=(pizza_auth, 'kenneth'))
+ >>> requests.get('http://pizzabin.org/admin', auth=PizzaAuth('kenneth'))
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index 542a5bc6..cf8d1a71 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -235,7 +235,8 @@ authentication, but the most common is HTTP Basic Auth.
Making requests with Basic Auth is extremely simple::
- >>> requests.get('https://api.github.com/user', auth=('user', 'pass'))
+ >>> from requests.auth import HTTPBasicAuth
+ >>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
OAuth Authentication
@@ -249,8 +250,9 @@ 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=('digest', 'user', 'pass'))
+ >>> requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
diff --git a/requests/auth.py b/requests/auth.py
index aabeb866..fad6eb79 100644
--- a/requests/auth.py
+++ b/requests/auth.py
@@ -16,26 +16,32 @@ from urlparse import urlparse
from .utils import randombytes, parse_dict_header
-def http_basic(r, username, password):
- """Attaches HTTP Basic Authentication to the given Request object.
- Arguments should be considered non-positional.
+class AuthBase(object):
+ """Base class that all auth implementations derive from"""
- """
- username = str(username)
- password = str(password)
-
- auth_s = b64encode('%s:%s' % (username, password))
- r.headers['Authorization'] = ('Basic %s' % auth_s)
-
- return r
+ def __call__(self, r):
+ raise NotImplementedError('Auth hooks must be callable.')
-def http_digest(r, username, password):
- """Attaches HTTP Digest Authentication to the given Request object.
- Arguments should be considered non-positional.
- """
+class HTTPBasicAuth(AuthBase):
+ """Attaches HTTP Basic Authentication to the given Request object."""
+ def __init__(self, username, password):
+ self.username = str(username)
+ self.password = str(password)
- def handle_401(r):
+ def __call__(self, r):
+ auth_s = b64encode('%s:%s' % (self.username, self.password))
+ r.headers['Authorization'] = ('Basic %s' % auth_s)
+ 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."""
s_auth = r.headers.get('www-authenticate', '')
@@ -70,7 +76,7 @@ def http_digest(r, username, password):
p_parsed = urlparse(r.request.url)
path = p_parsed.path + p_parsed.query
- A1 = "%s:%s:%s" % (username, realm, password)
+ A1 = "%s:%s:%s" % (self.username, realm, self.password)
A2 = "%s:%s" % (r.request.method, path)
if qop == 'auth':
@@ -95,7 +101,7 @@ def http_digest(r, username, password):
# XXX should the partial digests be encoded too?
base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \
- 'response="%s"' % (username, realm, nonce, path, respdig)
+ 'response="%s"' % (self.username, realm, nonce, path, respdig)
if opaque:
base += ', opaque="%s"' % opaque
if entdig:
@@ -104,7 +110,6 @@ def http_digest(r, username, password):
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
@@ -114,33 +119,6 @@ def http_digest(r, username, password):
return r
- r.hooks['response'] = handle_401
- return r
-
-
-def dispatch(t):
- """Given an auth tuple, return an expanded version."""
-
- if not t:
- return t
- else:
- t = list(t)
-
- # Make sure they're passing in something.
- assert len(t) >= 2
-
- # If only two items are passed in, assume HTTPBasic.
- if (len(t) == 2):
- t.insert(0, 'basic')
-
- # Allow built-in string referenced auths.
- if isinstance(t[0], basestring):
- if t[0] in ('basic', 'forced_basic'):
- t[0] = http_basic
- elif t[0] in ('digest',):
- t[0] = http_digest
-
- # Return a custom callable.
- return (t[0], tuple(t[1:]))
-
-
+ def __call__(self, r):
+ r.hooks['response'] = self.handle_401
+ return r
diff --git a/requests/models.py b/requests/models.py
index 97237e77..9c4d1333 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -14,7 +14,6 @@ from Cookie import SimpleCookie
from urlparse import urlparse, urlunparse, urljoin, urlsplit
from datetime import datetime
-from .auth import dispatch as auth_dispatch
from .hooks import dispatch_hook
from .structures import CaseInsensitiveDict
from .status_codes import codes
@@ -99,8 +98,7 @@ class Request(object):
self.response = Response()
#: Authentication tuple to attach to :class:`Request `.
- self._auth = auth
- self.auth = auth_dispatch(auth)
+ self.auth = auth
#: CookieJar to attach to :class:`Request `.
self.cookies = dict(cookies or [])
@@ -235,7 +233,7 @@ class Request(object):
files=self.files,
method=method,
params=self.session.params,
- auth=self._auth,
+ auth=self.auth,
cookies=cookies,
redirect=True,
config=self.config,
@@ -392,10 +390,8 @@ class Request(object):
if self.auth:
- auth_func, auth_args = self.auth
-
# Allow auth to make its changes.
- r = auth_func(self, *auth_args)
+ r = self.auth(self)
# Update self to reflect the auth changes.
self.__dict__.update(r.__dict__)
diff --git a/test_requests.py b/test_requests.py
index 61953a37..1cd73cfb 100755
--- a/test_requests.py
+++ b/test_requests.py
@@ -10,6 +10,7 @@ import unittest
import requests
import envoy
from requests import HTTPError
+from requests.auth import HTTPBasicAuth, HTTPDigestAuth
try:
import omnijson as json
@@ -144,7 +145,7 @@ class RequestsTestSuite(unittest.TestCase):
for service in SERVICES:
- auth = ('user', 'pass')
+ auth = HTTPBasicAuth('user', 'pass')
url = service('basic-auth', 'user', 'pass')
r = requests.get(url, auth=auth)
@@ -163,7 +164,7 @@ class RequestsTestSuite(unittest.TestCase):
for service in SERVICES:
- auth = ('digest', 'user', 'pass')
+ auth = HTTPDigestAuth('user', 'pass')
url = service('digest-auth', 'auth', 'user', 'pass')
r = requests.get(url, auth=auth)
@@ -270,7 +271,7 @@ class RequestsTestSuite(unittest.TestCase):
def test_httpauth_recursion(self):
- http_auth = ('user', 'BADpass')
+ http_auth = HTTPBasicAuth('user', 'BADpass')
for service in SERVICES:
r = requests.get(service('basic-auth', 'user', 'pass'), auth=http_auth)
From 9d8d1d14f1aae1933440920953ef7841c449bef0 Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sat, 19 Nov 2011 16:28:22 -0500
Subject: [PATCH 02/15] package
---
setup.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 17e612ba..53e770a4 100755
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,8 @@ setup(
packages= [
'requests',
'requests.packages',
- 'requests.packages.urllib3'
+ 'requests.packages.urllib3',
+ 'requests.packages.oreos'
],
install_requires=required,
license='ISC',
From 1933d3c70768db0e8ed509f683f9b830b6bfc44c Mon Sep 17 00:00:00 2001
From: Idan Gazit
Date: Sat, 19 Nov 2011 23:59:27 +0200
Subject: [PATCH 03/15] Added support for HTTP Basic Auth credentials in
2-tuple
---
docs/user/quickstart.rst | 19 +++++++++++++++----
requests/models.py | 8 ++++++--
test_requests.py | 19 +++++++++++++++++++
3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index cf8d1a71..3a4a91ff 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -239,11 +239,15 @@ Making requests with Basic Auth is extremely simple::
>>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
-OAuth Authentication
---------------------
+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'))
+
+
+Providing the credentials as a tuple in this fashion is functionally equivalent
+to the ``HTTPBasicAuth`` example above.
-Miguel Araujo's `requests-oauth `_ project provides a simple interface for
-establishing OAuth connections. Documentation and examples can be found on the requests-oauth `git repository `_.
Digest Authentication
---------------------
@@ -256,6 +260,13 @@ Another popular form of web service protection is Digest Authentication::
+OAuth Authentication
+--------------------
+
+Miguel Araujo's `requests-oauth `_ project provides a simple interface for
+establishing OAuth connections. Documentation and examples can be found on the requests-oauth `git repository `_.
+
+
Redirection and History
-----------------------
diff --git a/requests/models.py b/requests/models.py
index 9c4d1333..0053c08a 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -17,6 +17,7 @@ from datetime import datetime
from .hooks import dispatch_hook
from .structures import CaseInsensitiveDict
from .status_codes import codes
+from .auth import HTTPBasicAuth
from .packages.urllib3.exceptions import MaxRetryError
from .packages.urllib3.exceptions import SSLError as _SSLError
from .packages.urllib3.exceptions import HTTPError as _HTTPError
@@ -97,7 +98,7 @@ class Request(object):
#: content and metadata of HTTP Response, once :attr:`sent `.
self.response = Response()
- #: Authentication tuple to attach to :class:`Request `.
+ #: Authentication tuple or object to attach to :class:`Request `.
self.auth = auth
#: CookieJar to attach to :class:`Request `.
@@ -388,8 +389,11 @@ class Request(object):
if (content_type) and (not 'content-type' in self.headers):
self.headers['Content-Type'] = content_type
-
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)
diff --git a/test_requests.py b/test_requests.py
index 1cd73cfb..9ac6b51c 100755
--- a/test_requests.py
+++ b/test_requests.py
@@ -141,6 +141,25 @@ class RequestsTestSuite(unittest.TestCase):
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 = requests.get(url, auth=auth)
+ self.assertEqual(r.status_code, 200)
+
+ r = requests.get(url)
+ self.assertEqual(r.status_code, 401)
+
+
+ s = requests.session(auth=auth)
+ r = s.get(url)
+ self.assertEqual(r.status_code, 200)
+
+
def test_BASICAUTH_HTTP_200_OK_GET(self):
for service in SERVICES:
From 8ae4b440e347a232167caea2a64949efd35a7827 Mon Sep 17 00:00:00 2001
From: Robert Gieseke
Date: Sun, 20 Nov 2011 10:14:51 +0100
Subject: [PATCH 04/15] Display full URL when logging.
---
requests/models.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/requests/models.py b/requests/models.py
index 0be3e896..ab121b96 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -344,15 +344,15 @@ class Request(object):
already been sent.
"""
+ # Build the URL
+ url = self.full_url
+
# Logging
if self.config.get('verbose'):
self.config.get('verbose').write('%s %s %s\n' % (
- datetime.now().isoformat(), self.method, self.url
+ datetime.now().isoformat(), self.method, url
))
- # Build the URL
- url = self.full_url
-
# Nottin' on you.
body = None
content_type = None
From 99b6e3594078da14161000ee7eec3985468ee82e Mon Sep 17 00:00:00 2001
From: Shrikant Sharat Kandula
Date: Fri, 25 Nov 2011 07:45:12 +0530
Subject: [PATCH 05/15] Allow generators or any iterators for async.map
---
requests/async.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/requests/async.py b/requests/async.py
index 8bafb1ee..c91025fc 100644
--- a/requests/async.py
+++ b/requests/async.py
@@ -71,6 +71,8 @@ def map(requests, prefetch=True, size=None):
:param size: Specifies the number of requests to make at a time. If None, no throttling occurs.
"""
+ requests = list(requests)
+
if size:
pool = Pool(size)
pool.map(send, requests)
From 5c72601599b085985f5b345717e8e8d127091c81 Mon Sep 17 00:00:00 2001
From: Shrikant Sharat
Date: Fri, 25 Nov 2011 08:32:07 +0530
Subject: [PATCH 06/15] 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.
---
requests/api.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/requests/api.py b/requests/api.py
index 9e0c96f5..21c7c7a8 100644
--- a/requests/api.py
+++ b/requests/api.py
@@ -27,6 +27,7 @@ def request(method, url,
hooks=None,
return_response=True,
prefetch=False,
+ use_session=None,
config=None):
"""Constructs and sends a :class:`Request `.
Returns :class:`Response ` object.
@@ -43,10 +44,11 @@ def request(method, url,
: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 use_session: (optional) A :class:`Session` object to be used for the request.
:param config: (optional) A configuration dictionary.
"""
- s = session()
+ s = use_session or session()
return s.request(
method=method,
url=url,
From a350ceffb934b4bced2eadd1cb7338dcb04fe598 Mon Sep 17 00:00:00 2001
From: Shrikant Sharat
Date: Fri, 25 Nov 2011 11:41:40 +0530
Subject: [PATCH 07/15] Rename use_session to session.
---
requests/api.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/requests/api.py b/requests/api.py
index 21c7c7a8..0b124e03 100644
--- a/requests/api.py
+++ b/requests/api.py
@@ -11,7 +11,7 @@ This module implements the Requests API.
"""
-from .sessions import session
+from . import sessions
def request(method, url,
@@ -27,7 +27,7 @@ def request(method, url,
hooks=None,
return_response=True,
prefetch=False,
- use_session=None,
+ session=None,
config=None):
"""Constructs and sends a :class:`Request `.
Returns :class:`Response ` object.
@@ -44,11 +44,11 @@ def request(method, url,
: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 use_session: (optional) A :class:`Session` object to be used for the request.
+ :param session: (optional) A :class:`Session` object to be used for the request.
:param config: (optional) A configuration dictionary.
"""
- s = use_session or session()
+ s = session or sessions.session()
return s.request(
method=method,
url=url,
From 65c06579b477d64c10c3f544c00832f81d0d1d6f Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sat, 26 Nov 2011 10:10:57 -0500
Subject: [PATCH 08/15] Update AUTHORS.rst
---
AUTHORS.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/AUTHORS.rst b/AUTHORS.rst
index ef2c060b..b27737fd 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -60,4 +60,5 @@ Patches and Suggestions
- Juergen Brendel
- Juan Riaza
- Ryan Kelly
-- Rolando Espinoza La fuente
\ No newline at end of file
+- Rolando Espinoza La fuente
+- Robert Gieseke
\ No newline at end of file
From c74b66a53e21b209531be87f9d8374ceb4542d9e Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sun, 27 Nov 2011 10:00:40 -0500
Subject: [PATCH 09/15] v0.8.3
---
HISTORY.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/HISTORY.rst b/HISTORY.rst
index d7b023a0..4cc45fab 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,6 +1,13 @@
History
-------
+0.8.3 (2011-11-26)
+++++++++++++++++++
+
+* 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)
++++++++++++++++++
From ba00c4411c2465ddb203ce812240d8d961ff7860 Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sun, 27 Nov 2011 10:00:47 -0500
Subject: [PATCH 10/15] add github buttons to sidebars
---
docs/_templates/sidebarintro.html | 5 +++++
docs/_templates/sidebarlogo.html | 4 ++++
2 files changed, 9 insertions(+)
diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html
index a13888a7..6917cc0f 100644
--- a/docs/_templates/sidebarintro.html
+++ b/docs/_templates/sidebarintro.html
@@ -4,6 +4,11 @@
+
+
+
+
Requests is an elegant and simple HTTP library for Python, built for
human beings. You are currently looking at the documentation of the
diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html
index 3b62ed23..bd9a7201 100644
--- a/docs/_templates/sidebarlogo.html
+++ b/docs/_templates/sidebarlogo.html
@@ -3,6 +3,10 @@
+
+
+
Requests is an elegant and simple HTTP library for Python, built for
From 356bf42373f16ec9754cc73c63bc116a46e2f239 Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sun, 27 Nov 2011 10:06:39 -0500
Subject: [PATCH 11/15] v0.8.3
---
requests/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/requests/__init__.py b/requests/__init__.py
index 9d2319a5..e09c8345 100644
--- a/requests/__init__.py
+++ b/requests/__init__.py
@@ -15,8 +15,8 @@ requests
"""
__title__ = 'requests'
-__version__ = '0.8.2'
-__build__ = 0x000802
+__version__ = '0.8.3'
+__build__ = 0x000803
__author__ = 'Kenneth Reitz'
__license__ = 'ISC'
__copyright__ = 'Copyright 2011 Kenneth Reitz'
From 9f29a31f662ba389e6276962df93451084dddc24 Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sun, 27 Nov 2011 10:08:19 -0500
Subject: [PATCH 12/15] v0.8.3
---
AUTHORS.rst | 3 ++-
HISTORY.rst | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/AUTHORS.rst b/AUTHORS.rst
index b27737fd..43644e52 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -61,4 +61,5 @@ Patches and Suggestions
- Juan Riaza
- Ryan Kelly
- Rolando Espinoza La fuente
-- Robert Gieseke
\ No newline at end of file
+- Robert Gieseke
+- Idan Gazit
\ No newline at end of file
diff --git a/HISTORY.rst b/HISTORY.rst
index 4cc45fab..487cc867 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,7 +1,7 @@
History
-------
-0.8.3 (2011-11-26)
+0.8.3 (2011-11-27)
++++++++++++++++++
* Converted auth system to use simpler callable objects.
From e7ed1224d222838ef9addf3bfa188ece82c9f9e7 Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Sun, 27 Nov 2011 10:32:36 -0500
Subject: [PATCH 13/15] flattr
---
docs/_templates/sidebarintro.html | 14 +++++++++++++-
docs/_templates/sidebarlogo.html | 10 ++++++++++
docs/_themes/kr/layout.html | 11 +++++++++++
3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html
index 6917cc0f..862ad976 100644
--- a/docs/_templates/sidebarintro.html
+++ b/docs/_templates/sidebarintro.html
@@ -15,6 +15,17 @@
development release.
+
+
Support Requests
+
+ If you love Requests, consider making a small donation on Flattr:
+
+
+
+
+
+
Feedback
Feedback is greatly appreciated. If you have any questions, comments,
@@ -25,8 +36,9 @@
diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html
index bd9a7201..0260ad6d 100644
--- a/docs/_templates/sidebarlogo.html
+++ b/docs/_templates/sidebarlogo.html
@@ -12,4 +12,14 @@
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.
+
+
+
Support Requests
+
+ If you love Requests, consider making a small donation on Flattr:
+
+
+
+
\ No newline at end of file
diff --git a/docs/_themes/kr/layout.html b/docs/_themes/kr/layout.html
index 7a9c7e0c..5e68347b 100644
--- a/docs/_themes/kr/layout.html
+++ b/docs/_themes/kr/layout.html
@@ -14,6 +14,17 @@
+