ZPatterns, Transactions, _register/_unregister
Hi, I've encountered some weird behaviour in the ZPatterns Transactional class when I was trying to write a User Source for the Login Manager Product. I'm using Zope 2.2.0 with LoginManager 0.8.7a1 and ZPatterns 0.4.1snap1 The problem is that _unregister seems to be trying to delete the _v_registered attribute of an object that doesn't have it set whenever I return None from authenticateUser(). The weird thing is that the object seems to be _register()ed and _v_registered appears to be set to 1 in _register(), but when _unregister() is called it has the value 'None' again. I've attached my code that's trying to implement the UserSource. here is what my modified _register and _unregister functions look like: def _register(self): f=open('/tmp/zopelog', 'a', 0) f.write('Register %s(%s)\n' % (self.id, str(self))) f.write('Before: %s._v_registered=%s\n' % (self.id, getattr(self, '_v_registered', 'N/A'))) for i in traceback.format_stack(): f.write(i) if self._v_registered: return get_transaction().register(Reporter(self)) self._v_registered = 1 f.write('After: %s._v_registered=%s\n' % (self.id, getattr(self, '_v_registered', 'N/A'))) f.close() def _unregister(self): f=open('/tmp/zopelog', 'a', 0) f.write('Unregister %s(%s)\nBefore: %s._v_registered=%s\n' \ % (self.id, str(self), self.id, getattr(self, '_v_registered', 'N/A'))) f.close() del self._v_registered and this is a sample log: Register UserSource(<NisUserSource instance at 85ab2e8>) Before: UserSource._v_registered=None File "/home/picard/bpe/Zope-2.2.0-src/ZServer/PubCore/ZServerPublisher.py", line 95, in __init__ response=response) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/ZPublisher/Publish.py", line 222, in publish_module response = publish(request, module_name, after_list, debug=debug) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/ZPublisher/Publish.py", line 162, in publish object=request.traverse(path, validated_hook=validated_hook) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/ZPublisher/BaseRequest.py", line 427, in traverse else: user=v(request, auth, roles) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/Products/LoginManager/LoginManager.py", line 110, in validate user = _DefaultAuth.findLogin(self, request, auth, user, roles) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/Products/LoginManager/LoginMethods.py", line 147, in findLogin user = manager.getItem(name) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/Products/LoginManager/LoginManager.py", line 65, in getItem user = source.__of__(self).getItem(name) File "/home/picard/bpe/Zope-2.2.0-src/lib/python/Products/ZPatterns/Rack.py", line 61, in getItem self._registerCanonical(k,item) # XXX Should we cache non-existence? File "/home/picard/bpe/Zope-2.2.0-src/lib/python/Products/ZPatterns/DataManagers.py", line 52, in _registerCanonical self._register() File "/home/picard/bpe/Zope-2.2.0-src/lib/python/Products/ZPatterns/Transactions.py", line 47, in _register for i in traceback.format_stack(): After: UserSource._v_registered=1 Unregister UserSource(<NisUserSource instance at 85ab2e8>) Before: UserSource._v_registered=None
At 11:13 AM 8/14/00 +0200, Bob Pepin wrote:
Hi, I've encountered some weird behaviour in the ZPatterns Transactional class when I was trying to write a User Source for the Login Manager Product.
I'm using Zope 2.2.0 with LoginManager 0.8.7a1 and ZPatterns 0.4.1snap1
The problem is that _unregister seems to be trying to delete the _v_registered attribute of an object that doesn't have it set whenever I return None from authenticateUser(). The weird thing is that the object seems to be _register()ed and _v_registered appears to be set to 1 in _register(), but when _unregister() is called it has the value 'None' again.
Hmmm. Just a thought, but, does your user source object change itself in any way during the transaction? It is possible that it is getting reloaded from the ZODB during transaction abort, and that would delete the _v_registered attribute and mess the whole thing up. Looking at your source code, I see that you are incrementing self.i in your dbg() method, which is called from other methods that would be active during the transaction, so this would produce the behavior you're seeing. Specifically, failing to authorize a user results in an Zope exception being thrown, causing the transaction to roll back. As part of the rollback, the ZODB will invalidate the in-memory state of your UserSource object (since it was changed during the transaction) and the _v_ attribute values are lost. Ironically, you could fix this by changing your debug code to use a _v_ attribute as well. Arguably this behavior is an architectural flaw in either Transactional or the way it is used in DataManager derivatives such as Rack and UserSource. I'll have to give it some thought, but the cure may be worse than the disease as I suspect it may require circular references. :(
participants (2)
-
Bob Pepin -
Phillip J. Eby