Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
History
-------

Unreleased
++++++++++

- ``OAuth2Session`` is picklable again: the internal no-op ``auth`` handler is
a module-level function instead of a lambda, so sessions can be used in a
``multiprocessing`` context. Fixes `oauthlib #849
<https://github.com/oauthlib/oauthlib/issues/849>`_.

v2.0.0 (22 March 2024)
++++++++++++++++++++++++

Expand Down
13 changes: 12 additions & 1 deletion requests_oauthlib/oauth2_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@
log = logging.getLogger(__name__)


def _no_op_auth(request):
"""A no-op ``requests`` auth handler that returns the request unchanged.

``requests`` calls ``auth(request)`` and uses the returned request, so this
prevents any automatic auth (e.g. from ``.netrc``); see GH #278. It is
defined at module level rather than as a lambda so that ``OAuth2Session``
instances remain picklable (GH #849).
"""
return request


class TokenUpdated(Warning):
def __init__(self, token):
super(TokenUpdated, self).__init__()
Expand Down Expand Up @@ -91,7 +102,7 @@ def __init__(

# Ensure that requests doesn't do any automatic auth. See #278.
# The default behavior can be re-enabled by setting auth to None.
self.auth = lambda r: r
self.auth = _no_op_auth

# Allow customizations for non compliant providers through various
# hooks to adjust requests and responses.
Expand Down
14 changes: 14 additions & 0 deletions tests/test_oauth2_session.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import pickle
import time
import tempfile
import shutil
Expand Down Expand Up @@ -59,6 +60,19 @@ def setUp(self):
]
self.all_clients = self.clients + [self.client_MobileApplication]

def test_pickle(self):
# OAuth2Session must be picklable so it can be used in a
# multiprocessing context; a lambda in __init__ used to break this
# with "Can't pickle local object ...<lambda>" (#849).
for client in self.all_clients:
sess = OAuth2Session(client=client, token=self.token)
restored = pickle.loads(pickle.dumps(sess))
self.assertIsInstance(restored, OAuth2Session)
# The no-op auth handler must survive pickling and still return
# the request unchanged (disabling requests' automatic auth).
request = mock.sentinel.request
self.assertIs(restored.auth(request), request)

def test_add_token(self):
token = "Bearer " + self.token["access_token"]

Expand Down