Adding dictionary storage for #319.
DictionaryStorage implements an optionally-locked storage over a dictionary-like object.
This commit is contained in:
7
docs/source/oauth2client.contrib.dictionary_storage.rst
Normal file
7
docs/source/oauth2client.contrib.dictionary_storage.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
oauth2client.contrib.dictionary_storage module
|
||||
==============================================
|
||||
|
||||
.. automodule:: oauth2client.contrib.dictionary_storage
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -15,6 +15,7 @@ Submodules
|
||||
|
||||
oauth2client.contrib.appengine
|
||||
oauth2client.contrib.devshell
|
||||
oauth2client.contrib.dictionary_storage
|
||||
oauth2client.contrib.django_orm
|
||||
oauth2client.contrib.flask_util
|
||||
oauth2client.contrib.gce
|
||||
|
||||
66
oauth2client/contrib/dictionary_storage.py
Normal file
66
oauth2client/contrib/dictionary_storage.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# Copyright 2016 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Dictionary storage for OAuth2 Credentials."""
|
||||
|
||||
from oauth2client.client import OAuth2Credentials
|
||||
from oauth2client.client import Storage
|
||||
|
||||
|
||||
class DictionaryStorage(Storage):
|
||||
"""Store and retrieve credentials to and from a dictionary-like object.
|
||||
|
||||
Args:
|
||||
dictionary: A dictionary or dictionary-like object.
|
||||
key: A string or other hashable. The credentials will be stored in
|
||||
``dictionary[key]``.
|
||||
lock: An optional threading.Lock-like object. The lock will be
|
||||
acquired before anything is written or read from the
|
||||
dictionary.
|
||||
"""
|
||||
|
||||
def __init__(self, dictionary, key, lock=None):
|
||||
"""Construct a DictionaryStorage instance."""
|
||||
super(DictionaryStorage, self).__init__(lock=lock)
|
||||
self._dictionary = dictionary
|
||||
self._key = key
|
||||
|
||||
def locked_get(self):
|
||||
"""Retrieve the credentials from the dictionary, if they exist.
|
||||
|
||||
Returns: A :class:`oauth2client.client.OAuth2Credentials` instance.
|
||||
"""
|
||||
serialized = self._dictionary.get(self._key)
|
||||
|
||||
if serialized is None:
|
||||
return None
|
||||
|
||||
credentials = OAuth2Credentials.from_json(serialized)
|
||||
credentials.set_store(self)
|
||||
|
||||
return credentials
|
||||
|
||||
def locked_put(self, credentials):
|
||||
"""Save the credentials to the dictionary.
|
||||
|
||||
Args:
|
||||
credentials: A :class:`oauth2client.client.OAuth2Credentials`
|
||||
instance.
|
||||
"""
|
||||
serialized = credentials.to_json()
|
||||
self._dictionary[self._key] = serialized
|
||||
|
||||
def locked_delete(self):
|
||||
"""Remove the credentials from the dictionary, if they exist."""
|
||||
self._dictionary.pop(self._key, None)
|
||||
110
tests/contrib/test_dictionary_storage.py
Normal file
110
tests/contrib/test_dictionary_storage.py
Normal file
@@ -0,0 +1,110 @@
|
||||
# Copyright 2016 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Unit tests for oauth2client.contrib.dictionary_storage"""
|
||||
|
||||
import unittest2
|
||||
|
||||
from oauth2client import GOOGLE_TOKEN_URI
|
||||
from oauth2client.client import OAuth2Credentials
|
||||
from oauth2client.contrib.dictionary_storage import DictionaryStorage
|
||||
|
||||
|
||||
def _generate_credentials(scopes=None):
|
||||
return OAuth2Credentials(
|
||||
'access_tokenz',
|
||||
'client_idz',
|
||||
'client_secretz',
|
||||
'refresh_tokenz',
|
||||
'3600',
|
||||
GOOGLE_TOKEN_URI,
|
||||
'Test',
|
||||
id_token={
|
||||
'sub': '123',
|
||||
'email': 'user@example.com'
|
||||
},
|
||||
scopes=scopes)
|
||||
|
||||
|
||||
class DictionaryStorageTests(unittest2.TestCase):
|
||||
|
||||
def test_constructor_defaults(self):
|
||||
dictionary = {}
|
||||
key = 'test-key'
|
||||
storage = DictionaryStorage(dictionary, key)
|
||||
|
||||
self.assertEqual(dictionary, storage._dictionary)
|
||||
self.assertEqual(key, storage._key)
|
||||
self.assertIsNone(storage._lock)
|
||||
|
||||
def test_constructor_explicit(self):
|
||||
dictionary = {}
|
||||
key = 'test-key'
|
||||
storage = DictionaryStorage(dictionary, key)
|
||||
|
||||
lock = object()
|
||||
storage = DictionaryStorage(dictionary, key, lock=lock)
|
||||
self.assertEqual(storage._lock, lock)
|
||||
|
||||
def test_get(self):
|
||||
credentials = _generate_credentials()
|
||||
dictionary = {}
|
||||
key = 'credentials'
|
||||
storage = DictionaryStorage(dictionary, key)
|
||||
|
||||
self.assertIsNone(storage.get())
|
||||
|
||||
dictionary[key] = credentials.to_json()
|
||||
returned = storage.get()
|
||||
|
||||
self.assertIsNotNone(returned)
|
||||
self.assertEqual(returned.access_token, credentials.access_token)
|
||||
self.assertEqual(returned.id_token, credentials.id_token)
|
||||
self.assertEqual(returned.refresh_token, credentials.refresh_token)
|
||||
self.assertEqual(returned.client_id, credentials.client_id)
|
||||
|
||||
def test_put(self):
|
||||
credentials = _generate_credentials()
|
||||
dictionary = {}
|
||||
key = 'credentials'
|
||||
storage = DictionaryStorage(dictionary, key)
|
||||
|
||||
storage.put(credentials)
|
||||
returned = storage.get()
|
||||
|
||||
self.assertIn(key, dictionary)
|
||||
self.assertIsNotNone(returned)
|
||||
self.assertEqual(returned.access_token, credentials.access_token)
|
||||
self.assertEqual(returned.id_token, credentials.id_token)
|
||||
self.assertEqual(returned.refresh_token, credentials.refresh_token)
|
||||
self.assertEqual(returned.client_id, credentials.client_id)
|
||||
|
||||
def test_delete(self):
|
||||
credentials = _generate_credentials()
|
||||
dictionary = {}
|
||||
key = 'credentials'
|
||||
storage = DictionaryStorage(dictionary, key)
|
||||
|
||||
storage.put(credentials)
|
||||
|
||||
self.assertIn(key, dictionary)
|
||||
|
||||
storage.delete()
|
||||
|
||||
self.assertNotIn(key, dictionary)
|
||||
self.assertIsNone(storage.get())
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: NO COVER
|
||||
unittest2.main()
|
||||
Reference in New Issue
Block a user