Permalink
Browse files

Changing settings structure

  • Loading branch information...
1 parent 694e52c commit 35a9a97b0b3807315b8c68870dfce16e98b50070 @diogobaeder committed Oct 28, 2011
Showing with 146 additions and 69 deletions.
  1. +15 −12 README.markdown
  2. +1 −1 pycket/notification.py
  3. +33 −13 pycket/session.py
  4. +3 −0 tests/test_functional.py
  5. +22 −6 tests/test_notification.py
  6. +72 −37 tests/test_session.py
View
@@ -61,30 +61,33 @@ print session['gimme'] # 'Fire!'
```
## Settings
-pycket understands two types of settings, which must be items in the application's settings:
+pycket understands the following application settings:
-1. "pycket_redis": this is a dictionary containing any items that should be repassed to the redis.Redis instance to be used in the session manager (such as "host" and "port"); Notice, however, that if you want to change the dataset numbers to be used for sessions and notifications, use "db_sessions" and "db_notifications", respectively, instead of "db" (they will be converted to the "db" parameter that is passed to the Redis client for each manager afterwards);
-2. "pycket_cookies": this is a dictionary containing all settings to be repassed to the RequestHandler.set_secure_cookie. If they don't contain "expires" or "expires_days" items, they will be set as None, which means that the default behaviour for the sessions is to last on browser session. (And deleted as soon as the user closes the browser.) Notice that the sessions in the database last for one day, though.
+1. ["pycket"]: this is the main settings dictionary for pycket. It must contain at least the "engine" name, in order to decide which backend to use.
+1. ["pycket"]["storage"]: this is a dictionary containing any items that should be repassed to the storage client to be used in the session manager (such as "host" and "port"); Notice, however, that if you want to change the dataset numbers to be used for Redis sessions and notifications, use "db_sessions" and "db_notifications", respectively, instead of "db" (they will be converted to the "db" parameter that is passed to the Redis client for each manager afterwards);
+2. ["pycket"]["cookies"]: this is a dictionary containing all settings to be repassed to the RequestHandler.set_secure_cookie. If they don't contain "expires" or "expires_days" items, they will be set as None, which means that the default behaviour for the sessions is to last on browser session. (And deleted as soon as the user closes the browser.) Notice that the sessions in the database last for one day, though.
Example:
```python
application = tornado.web.Application([
(r'/', MainHandler),
], **{
- 'pycket_redis': {
- 'host': 'localhost',
- 'port': 6379,
- 'db_sessions': 10,
- 'db_notifications': 11,
- }
- 'pycket_cookies': {
- 'expires_days': 120,
+ 'pycket': {
+ 'storage': {
+ 'host': 'localhost',
+ 'port': 6379,
+ 'db_sessions': 10,
+ 'db_notifications': 11,
+ },
+ 'cookies': {
+ 'expires_days': 120,
+ }
}
)
```
-The default dataset numbers for sessions and notifications are, respectively, 0 and 1.
+The default dataset numbers for sessions and notifications are, respectively, 0 and 1, but in this example they've been set as 10 and 11.
## Notifications
This feature is almost equal to the sessions, but slightly different:
View
@@ -5,7 +5,7 @@
deletes it from the database after retrieving;
2. The objects are stored in db 1 (for default) instead of 0 to avoid conflicts
with sessions. (You can change this setting with the "db_notifications" setting
-in the "pycket_redis" setting.)
+in the "storage" setting.)
'''
from pycket.session import create_mixin, SessionManager, SessionMixin
View
@@ -4,20 +4,25 @@
SessionMixin.
It's mandatory that you set the "cookie_secret" in your application settings,
-because the session ID is stored in a secure manner.
+because the session ID is stored in a secure manner. It's also mandatory that
+you have a "pycket" dictionary containing at least an "engine" element that
+tells which engine you want to use.
-If you want to change the settings that are passed to the Redis client, set a
-"pycket_redis" dictionary with the intended Redis settings in your Tornado
-application settings. All these settings are passed to the redis.Redis client,
-except for the "db_sessions" and "db_notifications". These settings can contain
-numbers to change the datasets used for persistence, if you don't want to use
-the default numbers.
+Supported engines, for now, are:
+- Redis
+
+If you want to change the settings that are passed to the storage client, set a
+"storage" dictionary in the "pycket" settings with the intended storage settings
+in your Tornado application settings. When you're using Redis, all these
+settings are passed to the redis.Redis client, except for the "db_sessions" and
+"db_notifications". These settings can contain numbers to change the datasets
+used for persistence, if you don't want to use the default numbers.
If you want to change the cookie settings passed to the handler, set a
-"pycket_cookies" setting with the items you want. This is also valid for
-"expires" and "expires_days", which, by default, will be None, therefore making
-the sessions expire on browser close, but, if you set them, your custom values
-will override the default behaviour.
+"cookies" setting in the "pycket" settings with the items you want.
+This is also valid for "expires" and "expires_days", which, by default, will be
+None, therefore making the sessions expire on browser close, but, if you set
+them, your custom values will override the default behaviour.
'''
from uuid import uuid4
@@ -53,13 +58,24 @@ def __init__(self, handler):
'''
self.handler = handler
+ self.settings = {}
self.__setup_driver()
def __setup_driver(self):
- storage_settings = self.handler.settings.get('pycket_redis', {})
+ self.__setup_settings()
+ storage_settings = self.settings.get('storage', {})
factory = DriverFactory()
self.driver = factory.create('redis', storage_settings, self.STORAGE_CATEGORY)
+ def __setup_settings(self):
+ pycket_settings = self.handler.settings.get('pycket')
+ if not pycket_settings:
+ raise ConfigurationError('The "pycket" configurations are missing')
+ engine = pycket_settings.get('engine')
+ if not engine:
+ raise ConfigurationError('You must define an engine to be used with pycket')
+ self.settings = pycket_settings
+
def set(self, name, value):
'''
Sets a value for "name". It may be any pickable (see "pickle" module
@@ -142,7 +158,7 @@ def __change_session(self, callback):
self.__set_session_in_db(session)
def __cookie_settings(self):
- cookie_settings = self.handler.settings.get('pycket_cookies', {})
+ cookie_settings = self.settings.get('cookies', {})
cookie_settings.setdefault('expires', None)
cookie_settings.setdefault('expires_days', None)
return cookie_settings
@@ -171,6 +187,10 @@ def session(self):
return create_mixin(self, '__session_manager', SessionManager)
+class ConfigurationError(Exception):
+ pass
+
+
def create_mixin(context, manager_property, manager_class):
if not hasattr(context, manager_property):
setattr(context, manager_property, manager_class(context))
View
@@ -31,6 +31,9 @@ def get_secure_cookie(self, *args, **kwargs):
(r'/', SimpleHandler),
], **{
'cookie_secret': 'Python rocks!',
+ 'pycket': {
+ 'engine': 'redis',
+ }
})
@istest
View
@@ -23,7 +23,11 @@ class NotificationMixinTest(TestCase):
@istest
def starts_handler_with_session_manager(self):
class StubHandler(NotificationMixin):
- settings = {}
+ settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
self.assertIsInstance(StubHandler().notifications, NotificationManager)
@@ -86,7 +90,11 @@ def doesnt_conflict_with_sessions(self):
class StubHandler(SessionMixin, NotificationMixin):
session_id = 'session-id'
- settings = {}
+ settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
def get_secure_cookie(self, name):
return self.session_id
@@ -107,9 +115,12 @@ def test(self):
def uses_custom_notifications_database_if_provided(self):
handler = StubHandler()
handler.settings = {
- 'pycket_redis': {
- 'db_sessions': 10,
- 'db_notifications': 11,
+ 'pycket': {
+ 'engine': 'redis',
+ 'storage': {
+ 'db_sessions': 10,
+ 'db_notifications': 11,
+ }
}
}
manager = NotificationManager(handler)
@@ -121,7 +132,12 @@ class StubHandler(object):
session_id = 'session-id'
def __init__(self, settings=None):
- self.settings = settings if settings is not None else {}
+ default_settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
+ self.settings = settings if settings is not None else default_settings
def get_secure_cookie(self, name):
return self.session_id
View
@@ -6,7 +6,7 @@
import redis
from pycket.driver import RedisDriver
-from pycket.session import SessionManager, SessionMixin
+from pycket.session import ConfigurationError, SessionManager, SessionMixin
skip_slow_tests = False
@@ -16,10 +16,34 @@ class SessionMixinTest(TestCase):
@istest
def starts_handler_with_session_manager(self):
class StubHandler(SessionMixin):
- settings = {}
+ settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
self.assertIsInstance(StubHandler().session, SessionManager)
+ @istest
+ @raises(ConfigurationError)
+ def cannot_start_driver_without_pycket_settings(self):
+ class StubHandler(SessionMixin):
+ settings = {}
+
+ StubHandler().session.get('something')
+
+ @istest
+ @raises(ConfigurationError)
+ def cannot_start_driver_without_pycket_engine(self):
+ class StubHandler(SessionMixin):
+ settings = {
+ 'pycket': {
+ 'not-an-engine': 'something-useless',
+ }
+ }
+
+ StubHandler().session.get('something')
+
class RedisTestCase(TestCase):
dataset = None
@@ -36,7 +60,11 @@ def sets_session_id_on_cookies(self):
test_case = self
class StubHandler(SessionMixin):
- settings = {}
+ settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
def get_secure_cookie(self, name):
test_case.assertEqual(name, 'PYCKET_ID')
self.cookie_set = True
@@ -60,7 +88,11 @@ def does_not_set_session_id_if_already_exists(self):
test_case = self
class StubHandler(SessionMixin):
- settings = {}
+ settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
def get_secure_cookie(self, name):
self.cookie_retrieved = True
return 'some-id'
@@ -158,24 +190,6 @@ def cannot_retrieve_object_if_passed_from_expiration(self):
self.assertIsNone(manager.get('foo'))
- @istest
- def repasses_pycket_redis_settings_to_client(self):
- test_case = self
- settings = {'was_retrieved': False}
-
- class StubSettings(dict):
- def get(self, name, default):
- test_case.assertEqual(name, 'pycket_redis')
- test_case.assertEqual(default, {})
- settings['was_retrieved'] = True
- return default
-
- handler = StubHandler(StubSettings())
- manager = SessionManager(handler)
- manager.get('some value to setup the dataset')
-
- self.assertTrue(settings['was_retrieved'])
-
@istest
def retrieves_object_with_dict_key(self):
handler = StubHandler()
@@ -216,7 +230,11 @@ def sets_session_id_to_last_a_browser_session_as_default(self):
test_case = self
class StubHandler(SessionMixin):
- settings = {}
+ settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
def get_secure_cookie(self, name):
return None
@@ -234,9 +252,12 @@ def repasses_cookies_options(self):
class StubHandler(SessionMixin):
settings = {
- 'pycket_cookies': {
- 'foo': 'bar',
- }
+ 'pycket': {
+ 'engine': 'redis',
+ 'cookies': {
+ 'foo': 'bar',
+ }
+ },
}
def get_secure_cookie(self, name):
return None
@@ -254,9 +275,12 @@ def uses_custom_expires_if_provided(self):
class StubHandler(SessionMixin):
settings = {
- 'pycket_cookies': {
- 'expires': 'St. Neversday',
- }
+ 'pycket': {
+ 'engine': 'redis',
+ 'cookies': {
+ 'expires': 'St. Neversday',
+ }
+ },
}
def get_secure_cookie(self, name):
return None
@@ -274,9 +298,12 @@ def uses_custom_expires_days_if_provided(self):
class StubHandler(SessionMixin):
settings = {
- 'pycket_cookies': {
- 'expires_days': 'St. Neversday',
- }
+ 'pycket': {
+ 'engine': 'redis',
+ 'cookies': {
+ 'expires_days': 'St. Neversday',
+ }
+ },
}
def get_secure_cookie(self, name):
return None
@@ -292,10 +319,13 @@ def set_secure_cookie(self, *args, **kwargs):
def uses_custom_sessions_database_if_provided(self):
handler = StubHandler()
handler.settings = {
- 'pycket_redis': {
- 'db_sessions': 10,
- 'db_notifications': 11,
- }
+ 'pycket': {
+ 'engine': 'redis',
+ 'storage': {
+ 'db_sessions': 10,
+ 'db_notifications': 11,
+ }
+ },
}
manager = SessionManager(handler)
manager.set('foo', 'bar')
@@ -384,7 +414,12 @@ class StubHandler(object):
session_id = 'session-id'
def __init__(self, settings=None):
- self.settings = settings if settings is not None else {}
+ default_settings = {
+ 'pycket': {
+ 'engine': 'redis',
+ }
+ }
+ self.settings = settings if settings is not None else default_settings
def get_secure_cookie(self, name):
return self.session_id

0 comments on commit 35a9a97

Please sign in to comment.