Skip to content

Commit

Permalink
Adjustments per review of #9
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Nov 18, 2017
1 parent 4259514 commit bdf4e73
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 33 deletions.
2 changes: 1 addition & 1 deletion docs/api.rst
Expand Up @@ -200,7 +200,7 @@ also means that if the last-access-time + the-resolution < now, then
the session is considered to have timed out.

The default resolution is 10 minutes (600 seconds), meaning that a
users session will actually time out sometime between 50 and 60
user's session will actually time out sometime between 50 and 60
minutes.

>>> data_container.resolution
Expand Down
6 changes: 3 additions & 3 deletions docs/conf.py
Expand Up @@ -271,13 +271,13 @@
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'https://docs.python.org/': None,
'https://persistent.readthedocs.io/en/latest/': None,
'https://zopeannotation.readthedocs.io/en/latest/': None,
'https://zopeconfiguration.readthedocs.io/en/latest/': None,
'https://zopeinterface.readthedocs.io/en/latest/': None,
'https://zopelocation.readthedocs.io/en/latest/': None,
'https://persistent.readthedocs.io/en/latest/': None,
'https://zopeminmax.readthedocs.io/en/latest/': None,
'https://zopeconfiguration.readthedocs.io/en/latest/': None,
'https://zopetraversing.readthedocs.io/en/latest/': None,
'https://zopeannotation.readthedocs.io/en/latest/': None,
}

autodoc_default_flags = ['members', 'show-inheritance']
Expand Down
2 changes: 1 addition & 1 deletion docs/design.rst
Expand Up @@ -99,7 +99,7 @@ terms of total session time, or maximum inactive time, or some
combination.

There are a number of ways to approach this. You can expire client
IDs. You can expire session data.
identifiers. You can expire session data.

Data Expiration
===============
Expand Down
11 changes: 7 additions & 4 deletions src/zope/session/http.py
Expand Up @@ -556,7 +556,10 @@ def setRequestId(self, request, id):
response.setHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT')

def notifyVirtualHostChanged(event):
"""Adjust cookie paths when `IVirtualHostRequest` information changes.
"""
Adjust cookie paths when
`zope.publisher.interfaces.http.IVirtualHostRequest` information
changes.
Given an event, this method should call a `CookieClientIdManager`'s
setRequestId if a cookie is present in the response for that manager. To
Expand Down Expand Up @@ -593,7 +596,7 @@ def notifyVirtualHostChanged(event):
'bar'
If a server in front of Zope manages the ClientIds (Apache, Nginx), we
don't need to take care about the cookies
don't need to take care about the cookies:
>>> manager2 = DummyManager()
>>> manager2.thirdparty = True
Expand All @@ -614,11 +617,11 @@ def notifyVirtualHostChanged(event):
>>> event2.request = None
>>> notifyVirtualHostChanged(event2)
Cleanup of the utility registration:
.. doctest::
:hide:
>>> import zope.component.testing
>>> zope.component.testing.tearDown()
"""
# the event sends us a IHTTPApplicationRequest, but we need a
# IHTTPRequest for the response attribute, and so does the cookie-
Expand Down
23 changes: 12 additions & 11 deletions src/zope/session/interfaces.py
Expand Up @@ -29,7 +29,8 @@ class IClientIdManager(Interface):
"""

def getClientId(request):
"""Return the client id for the given request as a string.
"""
Return the client id for the given request as a string.
If the request doesn't have an attached sessionId a new one will be
generated.
Expand All @@ -38,19 +39,19 @@ def getClientId(request):
session id will be preserved. Depending on the specific method,
further action might be necessary on the part of the user. See the
documentation for the specific implementation and its interfaces.
"""


class IClientId(Interface):
"""A unique id representing a session"""
"""A unique id representing a session."""

def __str__():
"""As a unique ASCII string"""


class ISessionDataContainer(IReadMapping, IWriteMapping):
"""Stores data objects for sessions.
"""
Stores data objects for sessions.
The object implementing this interface is responsible for expiring data as
it feels appropriate.
Expand All @@ -60,9 +61,8 @@ class ISessionDataContainer(IReadMapping, IWriteMapping):
session_data_container[client_id][product_id][key] = value
Note that this interface does not support the full mapping interface -
the keys need to remain secret so we can't give access to keys(),
values() etc.
the keys need to remain secret so we can't give access to :meth:`keys`,
:meth:`values` etc.
"""
timeout = schema.Int(
title=_(u"Timeout"),
Expand Down Expand Up @@ -108,7 +108,7 @@ class ISession(Interface):

def __getitem__(product_id):
"""
Return the relevant `ISessionData`
Return the relevant `ISessionData`.
This involves locating the correct `ISessionDataContainer` for the
given product id, determining the client id, and returning the
Expand All @@ -128,14 +128,15 @@ def get(product_id, default=None):

class ISessionData(IMapping):
"""
Storage for a particular product id's session data
Storage for a particular product id's session data.
Contains 0 or more `ISessionPkgData` instances
Contains 0 or more `ISessionPkgData` instances.
"""

def getLastAccessTime():
"""
Return approximate epoch time this `ISessionData` was last retrieved.
Return approximate epoch time this `ISessionData` was last
retrieved.
"""

def setLastAccessTime():
Expand Down
45 changes: 32 additions & 13 deletions src/zope/session/session.py
Expand Up @@ -68,20 +68,28 @@ def digestEncode(s):
@zope.component.adapter(IRequest)
class ClientId(text_type):
"""
Default implementation of `zope.session.interfaces.IClientId`
Default implementation of `zope.session.interfaces.IClientId`.
.. doctest::
:hide:
>>> from zope.publisher.http import HTTPRequest
>>> from io import BytesIO
>>> request = HTTPRequest(BytesIO(), {}, None)
>>> from zope.session.interfaces import IClientIdManager
>>> from zope.session.http import CookieClientIdManager
>>> zope.component.provideUtility(CookieClientIdManager(), IClientIdManager)
`ClientId` objects for the same request should be equal:
>>> request = HTTPRequest(BytesIO(), {}, None)
>>> id1 = ClientId(request)
>>> id2 = ClientId(request)
>>> id1 == id2
True
.. doctest::
:hide:
>>> from zope.testing import cleanup
>>> cleanup.tearDown()
Expand Down Expand Up @@ -406,6 +414,9 @@ def get(self, pkg_id, default=None):
"""
Get session data.
.. doctest::
:hide:
>>> from zope.publisher.interfaces import IRequest
>>> from zope.publisher.http import HTTPRequest
>>> from io import BytesIO
Expand All @@ -417,29 +428,33 @@ def get(self, pkg_id, default=None):
>>> sdc = PersistentSessionDataContainer()
>>> zope.component.provideUtility(sdc, ISessionDataContainer, '')
>>> request = HTTPRequest(BytesIO(), {}, None)
If we use `get` we get `None` or *default* returned if the *pkg_id*
is not there.
is not there:
>>> request = HTTPRequest(BytesIO(), {}, None)
>>> session = Session(request).get('not.there', 'default')
>>> session
'default'
This method is lazy and does not create the session data.
This method is lazy and does not create the session data:
>>> session = Session(request).get('not.there')
>>> session is None
True
The ``__getitem__`` method instead creates the data.
The ``__getitem__`` method instead creates the data:
>>> session = Session(request)['not.there']
>>> session is None
False
>>> session = Session(request).get('not.there')
>>> session is None
False
.. doctest::
:hide:
>>> import zope.testing.cleanup
>>> zope.testing.cleanup.tearDown()
"""
Expand All @@ -461,6 +476,9 @@ def __getitem__(self, pkg_id):
"""
Get or create session data.
.. doctest::
:hide:
>>> from zope.publisher.interfaces import IRequest
>>> from zope.publisher.http import HTTPRequest
>>> from io import BytesIO
Expand All @@ -473,30 +491,28 @@ def __getitem__(self, pkg_id):
>>> for product_id in ('', 'products.foo', 'products.bar'):
... zope.component.provideUtility(sdc, ISessionDataContainer, product_id)
Setup some sessions, each with a distinct namespace:
>>> request = HTTPRequest(BytesIO(), {}, None)
>>> request2 = HTTPRequest(BytesIO(), {}, None)
>>> ISession.providedBy(Session(request))
True
Setup some sessions, each with a distinct namespace
>>> session1 = Session(request)['products.foo']
>>> session2 = Session(request)['products.bar']
>>> session3 = Session(request2)['products.bar']
If we use the same parameters, we should retrieve the
same object
same object:
>>> session1 is Session(request)['products.foo']
True
Make sure it returned sane values
Make sure it returned sane values:
>>> ISessionPkgData.providedBy(session1)
True
Make sure that pkg_ids don't share a namespace.
Make sure that pkg_ids don't share a namespace:
>>> session1['color'] = 'red'
>>> session2['color'] = 'blue'
Expand All @@ -508,6 +524,9 @@ def __getitem__(self, pkg_id):
>>> session3['color']
'vomit'
.. doctest::
:hide:
>>> from zope.testing import cleanup
>>> cleanup.tearDown()
Expand Down

0 comments on commit bdf4e73

Please sign in to comment.