class count1:
def GET(self):
s.session.count += 1
return str(s.session.count)
class count2:
def GET(self):
s.session.count += 1
yield str(s.session.count)
With above two handlers differs only in the way returning information (the 2nd one being a generator), web.py session actually works with the first one but not the second case.
Simple scenario is:
Web.py uses "processor", similar to Chain-of-Responsibility in GoF patterns, to add processing steps to the handler functions. Session, implemented this way, saves session information automatically when the handler is called and finished:
# session.py L83
def _processor(self, handler):
"""Application processor to setup session for every request"""
self._cleanup()
self._load()
try:
return handler()
finally:
self._save()
In usual case (or: count1), then handler() calls the whole handler function and return the string as the result, which is fine. And the session object has all update in-place then _save()ed in the finally block.
In the generator (or, count2) case though, the handler() only returns a generator object of count2.GET (bound to some object) but the handler code is not actually started. Therefore, when self._save() is being called, it's actually before the session counter update. Web.py then uses itertools.chain to unroll the generator and get all output to the client, after the handle_with_processors() call in application.py line 279, which is all too late already.
I believe that the correct way is actually unroll the generator before returning from the handler() call (application.py line 239, "return self.handle()"). But this hasn't been verified and I need insights onto this.
Link to issue on GitHub: https://github.com/webpy/webpy/issues/235