Adding dictionary storage for #319.

DictionaryStorage implements an optionally-locked storage over a dictionary-like object.
This commit is contained in:
Jon Wayne Parrott
2015-11-24 13:40:26 -08:00
parent d783f1c84a
commit 782db0bddc
4 changed files with 184 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
oauth2client.contrib.dictionary_storage module
==============================================
.. automodule:: oauth2client.contrib.dictionary_storage
:members:
:undoc-members:
:show-inheritance:

View File

@@ -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

View 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)

View 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()