pyramid_redis_sessions
pyramid_redis_sessions copied to clipboard
suggestion: multiple, configurable, request properties
I'm looking at ditching Beaker, and wanted to make a suggestion/request. (i'd be wiling to code this too).
I would like the request property to be configurable, and to be able to run multiple sessions on a single request.
A practical example would be adding a secondary https-only session as request.session_https
Thanks for starting a discussion on this! My first thought is that modifying the request
object directly is outside the scope of pyramid session libraries. Pyramid has a session hook that lets you register a session factory (a function that returns a function that takes a request
and returns a session), which it then calls whenever someone accesses request.session
. The session libraries do not actually add themselves to request.session
since that's a pyramid level interface and not a session level interface.
Within the callable returned by the session factory (i.e. the function called when request.session
is accessed) we can modify a specific request
instance. We use this to add an existing redis callable to the pyramid registry after the first use, and you can already override how that part works (for instance, setting and obtaining multiple redis instances based on some criteria) using redis.sessions.client_callable
: http://pyramid-redis-sessions.readthedocs.org/en/latest/advanced.html#supplying-your-own-redis-client
Otherwise you could try defining your own session factory (see http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-session-factory) to wrap one or more other session factories so you can dispatch based on request properties like the scheme) if you want to use request.session
to manage multiple types of sessions.
Setting those alternatives aside, I think the only way to do exactly what you asked would be to add a new request method for session_https
and any others you want that would either wrap request.session
usage or manually use one or more session factories. More on request methods here: http://docs.pylonsproject.org/docs/pyramid/en/latest/api/config.html#pyramid.config.Configurator.add_request_method
Although a session library could use the configurator to add one or more request methods at config time, this is pretty far outside the scope of intended session usage and would be highly app specific. It's more common to handle that at the app level, or via a small library (possibly making use of pyramid's includeme
so you can add it to your includes
in place of a lower level session library). You could then have pyramid_redis_sessions
or Beaker
as a dependency and use their session factories directly however you wanted. Let me know if I've misunderstood or you want to discuss further though. Thanks!
You both understand what I want to do and misunderstand me (the later of which is entirely my fault).
Adding a new request property is well outside the scope, and I don't think that should be included. In virtually any implementation of this, more app-level hacking is needed (more on that in a the next paragraph). I'm primarily concerned with making that "doable" with this library. Having a library that fully supports/automates that would be great, but I'd be content with the ability to easily leverage existing code. (sidenote: i'd really love for pyramid to support separate http and https sessions itself, but I lost that battle long ago).
We're doing this now with pyramid_beaker using a rather simple technique, but it requires a trivial manual sync whenever that module is updated (which is, thankfully, never). I created a new class ISessionHttpsFactory(ISessionFactory)
, [I think this was because I had to due to pyramid internals, but it could have just been a bad working knowledge of interfaces] and then register it into pyramid in a similar manner to how pyramid implements the regular ISession during a NewRequest event. The beaker.session code is entirely self-contained, so the only thing I need to keep in sync is some config argument coercion and then I can piggyback off their factory configuration.
pyramid_redis_sessions
is built quite a bit differently though. There are a few points in the code that specifically address request.session
, and there's a lot more code in the factory. IIRC it was mostly in the cookie code.
So stated differently, beaker.session is largely unaware of request.session; pyramid_redis_sessions is somewhat dependent on it -- and what I'd like to do is to make those various lookups more configurable so the package could be more easily repurposed onto alternate request attributes.
I see now; thanks. I believe the only references to request.session
are in the callback functions that handle setting or deleting cookies. I haven't worked through this part in a while but I think there are conditions where the request
that gets passed into the cookie callback could be different/modified from the time the callback itself is created.
For instance, the _cookie_callback
function's use of request.session
(https://github.com/ericrasmussen/pyramid_redis_sessions/blob/master/pyramid_redis_sessions/init.py#L302-L315) needs to see if the current session has been invalidated. This is to prevent a cookie from being set if the session becomes invalidated at any point. The tricky part is when we eventually add this function as a request callback (https://github.com/ericrasmussen/pyramid_redis_sessions/blob/master/pyramid_redis_sessions/init.py#L234-L241) it has to be able to get to the session via the request, and the only pyramid-supported way of doing that is accessing request.session
.
This isn't something I'm up to addressing right now but if you want to contribute a fix I'm definitely open to it. I'm sure there's a way to refactor it to depend on elements of the request not in the session (maybe using request.registry
), or if all else fails, adding a new override function (see https://github.com/ericrasmussen/pyramid_redis_sessions/blob/master/pyramid_redis_sessions/init.py#L79-L82 for examples) to obtain the session from a request. The default function would be something like lambda request: request.session
, and you'd be able to pass in your own there to get around it.
There might be some other benefits to the latter idea (allowing an override function for obtaining the current session), including being able to specify your own callback in your ini
file and far less work to maintain backwards compatibility.
Ok great! Since you're open to it, I'll generate a PR as a suggestion in a few days. I just didn't want to fork and build out on this and have the maintainers morally opposed to the idea. That would create more work in the long run.
I was thinking about using a getattr, but a generator function/lamba is a much better idea.